diff options
| author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-10-12 14:27:29 +0200 |
|---|---|---|
| committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-10-13 09:35:20 +0000 |
| commit | c30a6232df03e1efbd9f3b226777b07e087a1122 (patch) | |
| tree | e992f45784689f373bcc38d1b79a239ebe17ee23 /chromium/net | |
| parent | 7b5b123ac58f58ffde0f4f6e488bcd09aa4decd3 (diff) | |
| download | qtwebengine-chromium-85-based.tar.gz | |
BASELINE: Update Chromium to 85.0.4183.14085-based
Change-Id: Iaa42f4680837c57725b1344f108c0196741f6057
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/net')
721 files changed, 29983 insertions, 22863 deletions
diff --git a/chromium/net/BUILD.gn b/chromium/net/BUILD.gn index 9712bc3e46a..81f30ec6213 100644 --- a/chromium/net/BUILD.gn +++ b/chromium/net/BUILD.gn @@ -87,10 +87,6 @@ buildflag_header("buildflags") { config("net_internal_config") { defines = [ "NET_IMPLEMENTATION" ] - if (use_kerberos && is_android) { - include_dirs = [ "/usr/include/kerberosV" ] - } - if (enable_built_in_dns) { defines += [ "ENABLE_BUILT_IN_DNS" ] } @@ -546,12 +542,16 @@ component("net") { "cookies/canonical_cookie.h", "cookies/cookie_access_delegate.cc", "cookies/cookie_access_delegate.h", + "cookies/cookie_access_result.cc", + "cookies/cookie_access_result.h", "cookies/cookie_change_dispatcher.cc", "cookies/cookie_change_dispatcher.h", "cookies/cookie_constants.cc", "cookies/cookie_constants.h", "cookies/cookie_deletion_info.cc", "cookies/cookie_deletion_info.h", + "cookies/cookie_inclusion_status.cc", + "cookies/cookie_inclusion_status.h", "cookies/cookie_monster.cc", "cookies/cookie_monster.h", "cookies/cookie_monster_change_dispatcher.cc", @@ -667,8 +667,6 @@ component("net") { "http/bidirectional_stream_request_info.h", "http/broken_alternative_services.cc", "http/broken_alternative_services.h", - "http/failing_http_transaction_factory.cc", - "http/failing_http_transaction_factory.h", "http/http_auth.cc", "http/http_auth.h", "http/http_auth_cache.cc", @@ -916,6 +914,8 @@ component("net") { "quic/quic_clock_skew_detector.h", "quic/quic_connection_logger.cc", "quic/quic_connection_logger.h", + "quic/quic_connectivity_monitor.cc", + "quic/quic_connectivity_monitor.h", "quic/quic_connectivity_probing_manager.cc", "quic/quic_connectivity_probing_manager.h", "quic/quic_context.cc", @@ -941,8 +941,8 @@ component("net") { "quic/quic_stream_factory.h", "quic/quic_transport_client.cc", "quic/quic_transport_client.h", - "quic/quic_utils_chromium.cc", - "quic/quic_utils_chromium.h", + "quic/quic_transport_error.cc", + "quic/quic_transport_error.h", "quiche/common/platform/impl/quiche_arraysize_impl.h", "quiche/common/platform/impl/quiche_endian_impl.h", "quiche/common/platform/impl/quiche_export_impl.h", @@ -953,6 +953,8 @@ component("net") { "quiche/common/platform/impl/quiche_str_cat_impl.h", "quiche/common/platform/impl/quiche_string_piece_impl.h", "quiche/common/platform/impl/quiche_text_utils_impl.h", + "quiche/common/platform/impl/quiche_time_utils_impl.cc", + "quiche/common/platform/impl/quiche_time_utils_impl.h", "quiche/common/platform/impl/quiche_unordered_containers_impl.h", "socket/client_socket_factory.cc", "socket/client_socket_factory.h", @@ -1413,8 +1415,8 @@ component("net") { ] } - # Use getifaddrs() on POSIX platforms, except Linux and Android. - if (is_posix && !is_linux && !is_android) { + # Use getifaddrs() on POSIX platforms, except Linux. + if (is_posix && !is_linux) { sources += [ "base/network_interfaces_getifaddrs.cc", "base/network_interfaces_getifaddrs.h", @@ -1430,18 +1432,15 @@ component("net") { "cert/known_roots_nss.h", "cert/nss_cert_database.cc", "cert/nss_cert_database.h", + "cert/test_root_certs_builtin.cc", + "cert/x509_util_nss.cc", + "cert/x509_util_nss.h", "third_party/mozilla_security_manager/nsNSSCertificateDB.cpp", "third_party/mozilla_security_manager/nsNSSCertificateDB.h", "third_party/mozilla_security_manager/nsPKCS12Blob.cpp", "third_party/mozilla_security_manager/nsPKCS12Blob.h", "third_party/nss/ssl/cmpcert.cc", "third_party/nss/ssl/cmpcert.h", - - # These files are part of the partial implementation of NSS for - # cert verification, so keep them in that case. - "cert/test_root_certs_nss.cc", - "cert/x509_util_nss.cc", - "cert/x509_util_nss.h", ] if (!is_chromecast) { sources += [ @@ -1461,7 +1460,7 @@ component("net") { "base/network_interfaces_fuchsia.cc", "base/network_interfaces_fuchsia.h", "base/platform_mime_util_fuchsia.cc", - "cert/test_root_certs_fuchsia.cc", + "cert/test_root_certs_builtin.cc", ] } @@ -1868,6 +1867,9 @@ bundle_data("test_support_bundle_data") { "data/ssl/certificates/2048-rsa-ee-by-prime256v1-ecdsa-intermediate.pem", "data/ssl/certificates/2048-rsa-intermediate.pem", "data/ssl/certificates/2048-rsa-root.pem", + "data/ssl/certificates/398_days_1_second_after_2020_09_01.pem", + "data/ssl/certificates/398_days_after_2020_09_01.pem", + "data/ssl/certificates/399_days_after_2020_09_01.pem", "data/ssl/certificates/39_months_after_2015_04.pem", "data/ssl/certificates/39_months_based_on_last_day.pem", "data/ssl/certificates/40_months_after_2015_04.pem", @@ -1928,6 +1930,7 @@ bundle_data("test_support_bundle_data") { "data/ssl/certificates/crlset_by_leaf_spki.raw", "data/ssl/certificates/crlset_by_leaf_subject_no_spki.raw", "data/ssl/certificates/crlset_by_root_serial.raw", + "data/ssl/certificates/crlset_by_root_spki.raw", "data/ssl/certificates/crlset_by_root_subject.raw", "data/ssl/certificates/crlset_by_root_subject_no_spki.raw", "data/ssl/certificates/crlset_known_interception_by_root.raw", @@ -2029,6 +2032,7 @@ bundle_data("test_support_bundle_data") { "data/ssl/certificates/quic-leaf-cert.key.pkcs8.pem", "data/ssl/certificates/quic-leaf-cert.key.sct", "data/ssl/certificates/quic-root.pem", + "data/ssl/certificates/quic-short-lived.pem", "data/ssl/certificates/redundant-server-chain.pem", "data/ssl/certificates/redundant-validated-chain-root.pem", "data/ssl/certificates/redundant-validated-chain.pem", @@ -2196,8 +2200,6 @@ static_library("test_support") { "test/url_request/url_request_hanging_read_job.h", "test/url_request/url_request_mock_data_job.cc", "test/url_request/url_request_mock_data_job.h", - "test/url_request/url_request_slow_download_job.cc", - "test/url_request/url_request_slow_download_job.h", "url_request/test_url_fetcher_factory.cc", "url_request/test_url_fetcher_factory.h", "url_request/url_request_test_util.cc", @@ -3112,6 +3114,7 @@ bundle_data("net_unittests_bundle_data") { "data/url_request_unittest/308-without-location-header", "data/url_request_unittest/308-without-location-header.mock-http-headers", "data/url_request_unittest/BullRunSpeech.txt", + "data/url_request_unittest/BullRunSpeech.txt.deflate", "data/url_request_unittest/content-type-normalization.html", "data/url_request_unittest/content-type-normalization.html.mock-http-headers", "data/url_request_unittest/expect-ct-header-multiple.html", @@ -4205,6 +4208,7 @@ test("net_unittests") { "cookies/canonical_cookie_unittest.cc", "cookies/cookie_constants_unittest.cc", "cookies/cookie_deletion_info_unittest.cc", + "cookies/cookie_inclusion_status_unittest.cc", "cookies/cookie_monster_unittest.cc", "cookies/cookie_util_unittest.cc", "cookies/parsed_cookie_unittest.cc", @@ -4280,6 +4284,8 @@ test("net_unittests") { "http/mock_allow_http_auth_preferences.h", "http/structured_headers_generated_unittest.cc", "http/structured_headers_unittest.cc", + "http/test_upload_data_stream_not_allow_http1.cc", + "http/test_upload_data_stream_not_allow_http1.h", "http/transport_security_persister_unittest.cc", "http/transport_security_state_unittest.cc", "http/url_security_manager_unittest.cc", @@ -4344,7 +4350,6 @@ test("net_unittests") { "quic/quic_test_packet_maker.cc", "quic/quic_test_packet_maker.h", "quic/quic_transport_end_to_end_test.cc", - "quic/quic_utils_chromium_test.cc", "quic/test_quic_crypto_client_config_handle.cc", "quic/test_quic_crypto_client_config_handle.h", "socket/client_socket_pool_base_unittest.cc", @@ -4799,6 +4804,9 @@ test("net_unittests") { "//testing/android/native_test:native_test_native_code", ] android_manifest = "//net/android/unittest_support/AndroidManifest.xml" + + # Cronet still supports kitkat. + min_sdk_version = 19 sources += [ "base/address_tracker_linux_unittest.cc", "base/network_interfaces_linux_unittest.cc", diff --git a/chromium/net/OWNERS b/chromium/net/OWNERS index 46e4d5e3448..2ee09fd6d7c 100644 --- a/chromium/net/OWNERS +++ b/chromium/net/OWNERS @@ -9,7 +9,6 @@ mmenke@chromium.org morlovich@chromium.org nharper@chromium.org pauljensen@chromium.org -rch@chromium.org rsleevi@chromium.org zhongyi@chromium.org diff --git a/chromium/net/android/BUILD.gn b/chromium/net/android/BUILD.gn index 8547015246c..33030438765 100644 --- a/chromium/net/android/BUILD.gn +++ b/chromium/net/android/BUILD.gn @@ -139,6 +139,9 @@ android_apk("net_test_support_apk") { # just disable it. enable_multidex = false + # Cronet still supports kitkat. + min_sdk_version = 19 + deps = [ ":net_java_test_support", ":net_java_test_support_provider", diff --git a/chromium/net/base/address_tracker_linux.cc b/chromium/net/base/address_tracker_linux.cc index ffb6e6ef211..b9e76f900ef 100644 --- a/chromium/net/base/address_tracker_linux.cc +++ b/chromium/net/base/address_tracker_linux.cc @@ -17,8 +17,13 @@ #include "base/optional.h" #include "base/posix/eintr_wrapper.h" #include "base/threading/scoped_blocking_call.h" +#include "build/build_config.h" #include "net/base/network_interfaces_linux.h" +#if defined(OS_ANDROID) +#include "base/android/build_info.h" +#endif + namespace net { namespace internal { @@ -177,6 +182,14 @@ AddressTrackerLinux::AddressTrackerLinux( AddressTrackerLinux::~AddressTrackerLinux() = default; void AddressTrackerLinux::Init() { +#if defined(OS_ANDROID) + // RTM_GETLINK stopped working in Android 11 (see + // https://developer.android.com/preview/privacy/mac-address), + // so AddressTrackerLinux should not be used in later versions + // of Android. Chromium code doesn't need it past Android P. + DCHECK_LT(base::android::BuildInfo::GetInstance()->sdk_int(), + base::android::SDK_VERSION_P); +#endif netlink_fd_.reset(socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)); if (!netlink_fd_.is_valid()) { PLOG(ERROR) << "Could not create NETLINK socket"; diff --git a/chromium/net/base/address_tracker_linux_unittest.cc b/chromium/net/base/address_tracker_linux_unittest.cc index 0ad83bf0363..eff90ed009e 100644 --- a/chromium/net/base/address_tracker_linux_unittest.cc +++ b/chromium/net/base/address_tracker_linux_unittest.cc @@ -16,9 +16,14 @@ #include "base/test/spin_wait.h" #include "base/test/task_environment.h" #include "base/threading/simple_thread.h" +#include "build/build_config.h" #include "net/base/ip_address.h" #include "testing/gtest/include/gtest/gtest.h" +#if defined(OS_ANDROID) +#include "base/android/build_info.h" +#endif + #ifndef IFA_F_HOMEADDRESS #define IFA_F_HOMEADDRESS 0x10 #endif @@ -685,6 +690,12 @@ TEST_F(AddressTrackerLinuxTest, NonTrackingMode) { } TEST_F(AddressTrackerLinuxTest, NonTrackingModeInit) { +#if defined(OS_ANDROID) + // Calling Init() on Android P+ isn't supported. + if (base::android::BuildInfo::GetInstance()->sdk_int() >= + base::android::SDK_VERSION_P) + return; +#endif AddressTrackerLinux tracker; tracker.Init(); } @@ -721,6 +732,12 @@ class GetCurrentConnectionTypeRunner }; TEST_F(AddressTrackerLinuxTest, BroadcastInit) { +#if defined(OS_ANDROID) + // Calling Init() on Android P+ isn't supported. + if (base::android::BuildInfo::GetInstance()->sdk_int() >= + base::android::SDK_VERSION_P) + return; +#endif base::test::TaskEnvironment task_environment( base::test::TaskEnvironment::MainThreadType::IO); InitializeAddressTracker(true); diff --git a/chromium/net/base/backoff_entry_serializer_fuzzer.cc b/chromium/net/base/backoff_entry_serializer_fuzzer.cc index d66eacbd443..2ec426af293 100644 --- a/chromium/net/base/backoff_entry_serializer_fuzzer.cc +++ b/chromium/net/base/backoff_entry_serializer_fuzzer.cc @@ -8,8 +8,10 @@ #include <memory> #include "base/json/json_reader.h" +#include "base/logging.h" #include "base/optional.h" #include "base/strings/string_piece_forward.h" +#include "base/time/tick_clock.h" #include "base/time/time.h" #include "net/base/backoff_entry.h" #include "net/base/backoff_entry_serializer.h" @@ -32,11 +34,18 @@ class ProtoTranslator { BackoffEntry::Policy policy() const { return PolicyFromProto(input_.policy()); } - base::Time parse_time() const { return TimeFromProto(input_.parse_time()); } + base::Time parse_time() const { + return base::Time() + + base::TimeDelta::FromMicroseconds(input_.parse_time()); + } base::Time serialize_time() const { - return TimeFromProto(input_.serialize_time()); + return base::Time() + + base::TimeDelta::FromMicroseconds(input_.serialize_time()); + } + base::TimeTicks now_ticks() const { + return base::TimeTicks() + + base::TimeDelta::FromMicroseconds(input_.now_ticks()); } - base::Optional<base::Value> serialized_entry() const { json_proto::JsonProtoConverter converter; std::string json_array = converter.Convert(input_.serialized_entry()); @@ -49,24 +58,33 @@ class ProtoTranslator { static BackoffEntry::Policy PolicyFromProto( const fuzz_proto::BackoffEntryPolicy& policy) { - return BackoffEntry::Policy{ - .num_errors_to_ignore = policy.num_errors_to_ignore(), - .initial_delay_ms = policy.initial_delay_ms(), - .multiply_factor = policy.multiply_factor(), - .jitter_factor = policy.jitter_factor(), - .maximum_backoff_ms = policy.maximum_backoff_ms(), - .entry_lifetime_ms = policy.entry_lifetime_ms(), - .always_use_initial_delay = policy.always_use_initial_delay(), - }; + BackoffEntry::Policy new_policy; + new_policy.num_errors_to_ignore = policy.num_errors_to_ignore(); + new_policy.initial_delay_ms = policy.initial_delay_ms(); + new_policy.multiply_factor = policy.multiply_factor(); + new_policy.jitter_factor = policy.jitter_factor(); + new_policy.maximum_backoff_ms = policy.maximum_backoff_ms(); + new_policy.entry_lifetime_ms = policy.entry_lifetime_ms(); + new_policy.always_use_initial_delay = policy.always_use_initial_delay(); + return new_policy; } +}; - static base::Time TimeFromProto(uint64_t raw_time) { - return base::Time() + base::TimeDelta::FromMicroseconds(raw_time); - } +class MockClock : public base::TickClock { + public: + MockClock() = default; + ~MockClock() override = default; + + void SetNow(base::TimeTicks now) { now_ = now; } + base::TimeTicks NowTicks() const override { return now_; } + + private: + base::TimeTicks now_; }; // Tests the "deserialize-reserialize" property. Deserializes a BackoffEntry -// from JSON, reserializes it, and checks that the JSON values match. +// from JSON, reserializes it, then deserializes again. Holding time constant, +// we check that the parsed BackoffEntry values are equivalent. void TestDeserialize(const ProtoTranslator& translator) { // Attempt to convert the json_proto.ArrayValue to a base::Value. base::Optional<base::Value> value = translator.serialized_entry(); @@ -76,19 +94,30 @@ void TestDeserialize(const ProtoTranslator& translator) { BackoffEntry::Policy policy = translator.policy(); + MockClock clock; + clock.SetNow(translator.now_ticks()); + // Attempt to deserialize a BackoffEntry. std::unique_ptr<BackoffEntry> entry = - BackoffEntrySerializer::DeserializeFromValue(*value, &policy, nullptr, + BackoffEntrySerializer::DeserializeFromValue(*value, &policy, &clock, translator.parse_time()); if (!entry) return; - // Serializing |entry| it should recreate the original JSON input! std::unique_ptr<base::Value> reserialized = - BackoffEntrySerializer::SerializeToValue(*entry, - translator.serialize_time()); + BackoffEntrySerializer::SerializeToValue(*entry, translator.parse_time()); CHECK(reserialized); - CHECK_EQ(*reserialized, *value); + + // Due to fuzzy interpretation in BackoffEntrySerializer:: + // DeserializeFromValue, we cannot assert that |*reserialized == *value|. + // Rather, we can deserialize |reserialized| and check that the result is + // equivalent to |entry|. + std::unique_ptr<BackoffEntry> entry_reparsed = + BackoffEntrySerializer::DeserializeFromValue( + *reserialized, &policy, &clock, translator.parse_time()); + CHECK(entry_reparsed); + CHECK_EQ(entry->failure_count(), entry_reparsed->failure_count()); + CHECK_EQ(entry->GetReleaseTime(), entry_reparsed->GetReleaseTime()); } // Tests the "serialize-deserialize" property. Serializes an arbitrary @@ -105,10 +134,13 @@ void TestSerialize(const ProtoTranslator& translator) { translator.serialize_time()); CHECK(serialized); + MockClock clock; + clock.SetNow(translator.now_ticks()); + // Deserialize it. std::unique_ptr<BackoffEntry> deserialized_entry = - BackoffEntrySerializer::DeserializeFromValue( - *serialized, &policy, nullptr, translator.parse_time()); + BackoffEntrySerializer::DeserializeFromValue(*serialized, &policy, &clock, + translator.parse_time()); // Even though SerializeToValue was successful, we're not guaranteed to have a // |deserialized_entry|. One reason deserialization may fail is if the parsed // |absolute_release_time_us| is below zero. @@ -134,8 +166,8 @@ DEFINE_PROTO_FUZZER(const fuzz_proto::FuzzerInput& input) { } ProtoTranslator translator(input); - TestSerialize(translator); TestDeserialize(translator); + TestSerialize(translator); } } // namespace net diff --git a/chromium/net/base/backoff_entry_serializer_fuzzer_input.proto b/chromium/net/base/backoff_entry_serializer_fuzzer_input.proto index d92f72eca9b..06cb247dd2a 100644 --- a/chromium/net/base/backoff_entry_serializer_fuzzer_input.proto +++ b/chromium/net/base/backoff_entry_serializer_fuzzer_input.proto @@ -9,9 +9,11 @@ package fuzz_proto; import "testing/libfuzzer/proto/json.proto"; message FuzzerInput { - // Using int64 to match base::Time's internal representation. + // Using int64 to match internal representation of base::Time and + // base::TimeTicks. required int64 parse_time = 1; required int64 serialize_time = 2; + required int64 now_ticks = 5; required BackoffEntryPolicy policy = 3; required json_proto.ArrayValue serialized_entry = 4; } diff --git a/chromium/net/base/features.cc b/chromium/net/base/features.cc index b6b6c2dedd5..1b97b20d324 100644 --- a/chromium/net/base/features.cc +++ b/chromium/net/base/features.cc @@ -3,6 +3,9 @@ // found in the LICENSE file. #include "net/base/features.h" + +#include <vector> + #include "build/build_config.h" namespace net { @@ -11,6 +14,9 @@ namespace features { const base::Feature kAcceptLanguageHeader{"AcceptLanguageHeader", base::FEATURE_ENABLED_BY_DEFAULT}; +const base::Feature kCapReferrerToOriginOnCrossOrigin{ + "CapReferrerToOriginOnCrossOrigin", base::FEATURE_DISABLED_BY_DEFAULT}; + const base::Feature kDnsHttpssvc{"DnsHttpssvc", base::FEATURE_DISABLED_BY_DEFAULT}; @@ -20,12 +26,34 @@ const base::FeatureParam<bool> kDnsHttpssvcUseHttpssvc{ const base::FeatureParam<bool> kDnsHttpssvcUseIntegrity{ &kDnsHttpssvc, "DnsHttpssvcUseIntegrity", false}; +const base::FeatureParam<bool> kDnsHttpssvcEnableQueryOverInsecure{ + &kDnsHttpssvc, "DnsHttpssvcEnableQueryOverInsecure", false}; + const base::FeatureParam<int> kDnsHttpssvcExtraTimeMs{ &kDnsHttpssvc, "DnsHttpssvcExtraTimeMs", 10}; const base::FeatureParam<int> kDnsHttpssvcExtraTimePercent{ &kDnsHttpssvc, "DnsHttpssvcExtraTimePercent", 5}; +const base::FeatureParam<std::string> kDnsHttpssvcExperimentDomains{ + &kDnsHttpssvc, "DnsHttpssvcExperimentDomains", ""}; + +const base::FeatureParam<std::string> kDnsHttpssvcControlDomains{ + &kDnsHttpssvc, "DnsHttpssvcControlDomains", ""}; + +const base::FeatureParam<bool> kDnsHttpssvcControlDomainWildcard{ + &kDnsHttpssvc, "DnsHttpssvcControlDomainWildcard", false}; + +const base::Feature kAvoidH2Reprioritization{"AvoidH2Reprioritization", + base::FEATURE_DISABLED_BY_DEFAULT}; + +namespace dns_httpssvc_experiment { +base::TimeDelta GetExtraTimeAbsolute() { + DCHECK(base::FeatureList::IsEnabled(features::kDnsHttpssvc)); + return base::TimeDelta::FromMilliseconds(kDnsHttpssvcExtraTimeMs.Get()); +} +} // namespace dns_httpssvc_experiment + const base::Feature kEnableTLS13EarlyData{"EnableTLS13EarlyData", base::FEATURE_DISABLED_BY_DEFAULT}; @@ -50,6 +78,28 @@ const base::Feature kPartitionSSLSessionsByNetworkIsolationKey{ "PartitionSSLSessionsByNetworkIsolationKey", base::FEATURE_DISABLED_BY_DEFAULT}; +const base::Feature kPartitionExpectCTStateByNetworkIsolationKey{ + "PartitionExpectCTStateByNetworkIsolationKey", + base::FEATURE_DISABLED_BY_DEFAULT}; + +const base::Feature kExpectCTPruning{"ExpectCTPruning", + base::FEATURE_ENABLED_BY_DEFAULT}; + +NET_EXPORT extern const base::FeatureParam<int> + kExpectCTPruneMax(&kExpectCTPruning, "ExpectCTPruneMax", 2000); +NET_EXPORT extern const base::FeatureParam<int> + kExpectCTPruneMin(&kExpectCTPruning, "ExpectCTPruneMin", 1800); +NET_EXPORT extern const base::FeatureParam<int> kExpectCTSafeFromPruneDays( + &kExpectCTPruning, + "ExpectCTSafeFromPruneDays", + 40); +NET_EXPORT extern const base::FeatureParam<int> kExpectCTMaxEntriesPerNik( + &kExpectCTPruning, + "ExpectCTMaxEntriesPerNik", + 20); +NET_EXPORT extern const base::FeatureParam<int> + kExpectCTPruneDelaySecs(&kExpectCTPruning, "ExpectCTPruneDelaySecs", 60); + const base::Feature kTLS13KeyUpdate{"TLS13KeyUpdate", base::FEATURE_DISABLED_BY_DEFAULT}; @@ -59,24 +109,11 @@ const base::Feature kPostQuantumCECPQ2{"PostQuantumCECPQ2", const base::Feature kNetUnusedIdleSocketTimeout{ "NetUnusedIdleSocketTimeout", base::FEATURE_DISABLED_BY_DEFAULT}; -const base::Feature kRequestEsniDnsRecords{"RequestEsniDnsRecords", - base::FEATURE_DISABLED_BY_DEFAULT}; -base::TimeDelta EsniDnsMaxAbsoluteAdditionalWait() { - DCHECK(base::FeatureList::IsEnabled(kRequestEsniDnsRecords)); - return base::TimeDelta::FromMilliseconds( - kEsniDnsMaxAbsoluteAdditionalWaitMilliseconds.Get()); -} -const base::FeatureParam<int> kEsniDnsMaxAbsoluteAdditionalWaitMilliseconds{ - &kRequestEsniDnsRecords, "EsniDnsMaxAbsoluteAdditionalWaitMilliseconds", - 10}; -const base::FeatureParam<int> kEsniDnsMaxRelativeAdditionalWaitPercent{ - &kRequestEsniDnsRecords, "EsniDnsMaxRelativeAdditionalWaitPercent", 5}; - -const base::Feature kSameSiteByDefaultCookies{ - "SameSiteByDefaultCookies", base::FEATURE_DISABLED_BY_DEFAULT}; +const base::Feature kSameSiteByDefaultCookies{"SameSiteByDefaultCookies", + base::FEATURE_ENABLED_BY_DEFAULT}; const base::Feature kCookiesWithoutSameSiteMustBeSecure{ - "CookiesWithoutSameSiteMustBeSecure", base::FEATURE_DISABLED_BY_DEFAULT}; + "CookiesWithoutSameSiteMustBeSecure", base::FEATURE_ENABLED_BY_DEFAULT}; const base::Feature kShortLaxAllowUnsafeThreshold{ "ShortLaxAllowUnsafeThreshold", base::FEATURE_DISABLED_BY_DEFAULT}; @@ -100,10 +137,6 @@ const base::FeatureParam<int> &kRecentCreationTimeGrantsLegacyCookieSemantics, "RecentCreationTimeGrantsLegacyCookieSemanticsMilliseconds", 0}; -const base::Feature kBlockExternalRequestsFromNonSecureInitiators{ - "BlockExternalRequestsFromNonSecureInitiators", - base::FEATURE_DISABLED_BY_DEFAULT}; - #if BUILDFLAG(BUILTIN_CERT_VERIFIER_FEATURE_SUPPORTED) const base::Feature kCertVerifierBuiltinFeature{ "CertVerifierBuiltin", base::FEATURE_DISABLED_BY_DEFAULT}; @@ -114,7 +147,7 @@ const base::Feature kAppendFrameOriginToNetworkIsolationKey{ const base::Feature kUseRegistrableDomainInNetworkIsolationKey{ "UseRegistrableDomainInNetworkIsolationKey", - base::FEATURE_DISABLED_BY_DEFAULT}; + base::FEATURE_ENABLED_BY_DEFAULT}; const base::Feature kTurnOffStreamingMediaCaching{ "TurnOffStreamingMediaCaching", base::FEATURE_DISABLED_BY_DEFAULT}; @@ -128,5 +161,8 @@ const base::Feature kSchemefulSameSite{"SchemefulSameSite", const base::Feature kTLSLegacyCryptoFallbackForMetrics{ "TLSLegacyCryptoFallbackForMetrics", base::FEATURE_ENABLED_BY_DEFAULT}; +const base::Feature kUseLookalikesForNavigationSuggestions{ + "UseLookalikesForNavigationSuggestions", base::FEATURE_DISABLED_BY_DEFAULT}; + } // namespace features } // namespace net diff --git a/chromium/net/base/features.h b/chromium/net/base/features.h index b6b2a4cccf7..a6767bfbe57 100644 --- a/chromium/net/base/features.h +++ b/chromium/net/base/features.h @@ -5,8 +5,12 @@ #ifndef NET_BASE_FEATURES_H_ #define NET_BASE_FEATURES_H_ +#include <string> + #include "base/feature_list.h" #include "base/metrics/field_trial_params.h" +#include "base/strings/string_piece.h" +#include "base/time/time.h" #include "net/base/net_export.h" #include "net/net_buildflags.h" @@ -17,6 +21,10 @@ namespace features { // https://github.com/WICG/lang-client-hint proposes that we deprecate. NET_EXPORT extern const base::Feature kAcceptLanguageHeader; +// When kCapReferrerToOriginOnCrossOrigin is enabled, HTTP referrers on cross- +// origin requests are restricted to contain at most the source origin. +NET_EXPORT extern const base::Feature kCapReferrerToOriginOnCrossOrigin; + // Enables TLS 1.3 early data. NET_EXPORT extern const base::Feature kEnableTLS13EarlyData; @@ -25,6 +33,9 @@ NET_EXPORT extern const base::Feature kEnableTLS13EarlyData; // cause us to upgrade the URL to HTTPS and/or to attempt QUIC. NET_EXPORT extern const base::Feature kDnsHttpssvc; +// Disable H2 reprioritization, in order to measure its impact. +NET_EXPORT extern const base::Feature kAvoidH2Reprioritization; + // Determine which kind of record should be queried: HTTPSSVC or INTEGRITY. No // more than one of these feature parameters should be enabled at once. In the // event that both are enabled, |kDnsHttpssvcUseIntegrity| takes priority, and @@ -32,6 +43,10 @@ NET_EXPORT extern const base::Feature kDnsHttpssvc; NET_EXPORT extern const base::FeatureParam<bool> kDnsHttpssvcUseHttpssvc; NET_EXPORT extern const base::FeatureParam<bool> kDnsHttpssvcUseIntegrity; +// Enable HTTPSSVC or INTEGRITY to be queried over insecure DNS. +NET_EXPORT extern const base::FeatureParam<bool> + kDnsHttpssvcEnableQueryOverInsecure; + // If we are still waiting for an HTTPSSVC or INTEGRITY query after all the // other queries in a DnsTask have completed, we will compute a timeout for the // remaining query. The timeout will be the min of: @@ -41,6 +56,35 @@ NET_EXPORT extern const base::FeatureParam<bool> kDnsHttpssvcUseIntegrity; NET_EXPORT extern const base::FeatureParam<int> kDnsHttpssvcExtraTimeMs; NET_EXPORT extern const base::FeatureParam<int> kDnsHttpssvcExtraTimePercent; +// These parameters, respectively, are the list of experimental and control +// domains for which we will query HTTPSSVC or INTEGRITY records. We expect +// valid INTEGRITY results for experiment domains. We expect no INTEGRITY +// results for control domains. +// +// The format of both parameters is a comma-separated list of domains. +// Whitespace around domain names is permitted. Trailing comma is optional. +// +// See helper functions: +// |dns_httpssvc_experiment::GetDnsHttpssvcExperimentDomains| and +// |dns_httpssvc_experiment::GetDnsHttpssvcControlDomains|. +NET_EXPORT extern const base::FeatureParam<std::string> + kDnsHttpssvcExperimentDomains; +NET_EXPORT extern const base::FeatureParam<std::string> + kDnsHttpssvcControlDomains; + +// This param controls how we determine whether a domain is an experimental or +// control domain. When false, domains must be in |kDnsHttpssvcControlDomains| +// to be considered a control. When true, we ignore |kDnsHttpssvcControlDomains| +// and any non-experiment domain (not in |kDnsHttpssvcExperimentDomains|) is +// considered a control domain. +NET_EXPORT extern const base::FeatureParam<bool> + kDnsHttpssvcControlDomainWildcard; + +namespace dns_httpssvc_experiment { +// Get the value of |kDnsHttpssvcExtraTimeMs|. +NET_EXPORT base::TimeDelta GetExtraTimeAbsolute(); +} // namespace dns_httpssvc_experiment + // Enables optimizing the network quality estimation algorithms in network // quality estimator (NQE). NET_EXPORT extern const base::Feature kNetworkQualityEstimator; @@ -72,6 +116,36 @@ NET_EXPORT extern const base::Feature NET_EXPORT extern const base::Feature kPartitionSSLSessionsByNetworkIsolationKey; +// Partitions Expect-CT data by NetworkIsolationKey. This only affects the +// Expect-CT data itself. Regardless of this value, reports will be uploaded +// using the associated NetworkIsolationKey, when one's available. +// +// This feature requires kPartitionConnectionsByNetworkIsolationKey, +// kPartitionHttpServerPropertiesByNetworkIsolationKey, and +// kPartitionConnectionsByNetworkIsolationKey to all be enabled to work. +NET_EXPORT extern const base::Feature + kPartitionExpectCTStateByNetworkIsolationKey; + +// Enables limiting the size of Expect-CT table. +NET_EXPORT extern const base::Feature kExpectCTPruning; + +// FeatureParams associated with kExpectCTPruning. + +// Expect-CT pruning runs when this many entries are hit. +NET_EXPORT extern const base::FeatureParam<int> kExpectCTPruneMax; +// The Expect-CT pruning logic attempts to reduce entries to at most this many. +NET_EXPORT extern const base::FeatureParam<int> kExpectCTPruneMin; +// Non-transient entries with |enforce| set are safe from being pruned if +// they're less than this many days old, unless the number of entries exceeds +// |kExpectCTMaxEntriesPerNik|. +NET_EXPORT extern const base::FeatureParam<int> kExpectCTSafeFromPruneDays; +// If, after pruning transient, non-enforced, old Expect-CT entries, +// kExpectCTPruneMin is still exceeded, then all NetworkIsolationKeys will be +// capped to this many entries, based on last observation date. +NET_EXPORT extern const base::FeatureParam<int> kExpectCTMaxEntriesPerNik; +// Minimum delay between successive prunings of Expect-CT entries, in seconds. +NET_EXPORT extern const base::FeatureParam<int> kExpectCTPruneDelaySecs; + // Enables sending TLS 1.3 Key Update messages on TLS 1.3 connections in order // to ensure that this corner of the spec is exercised. This is currently // disabled by default because we discovered incompatibilities with some @@ -84,25 +158,6 @@ NET_EXPORT extern const base::Feature kPostQuantumCECPQ2; // Changes the timeout after which unused sockets idle sockets are cleaned up. NET_EXPORT extern const base::Feature kNetUnusedIdleSocketTimeout; -// Enables the built-in resolver requesting ESNI (TLS 1.3 Encrypted -// Server Name Indication) records alongside IPv4 and IPv6 address records -// during DNS over HTTPS (DoH) host resolution. -NET_EXPORT extern const base::Feature kRequestEsniDnsRecords; -// Returns a TimeDelta of value kEsniDnsMaxAbsoluteAdditionalWaitMilliseconds -// milliseconds (see immediately below). -NET_EXPORT base::TimeDelta EsniDnsMaxAbsoluteAdditionalWait(); -// The following two parameters specify the amount of extra time to wait for a -// long-running ESNI DNS transaction after the successful conclusion of -// concurrent A and AAAA transactions. This timeout will have value -// min{kEsniDnsMaxAbsoluteAdditionalWaitMilliseconds, -// (100% + kEsniDnsMaxRelativeAdditionalWaitPercent) -// * max{time elapsed for the concurrent A query, -// time elapsed for the concurrent AAAA query}}. -NET_EXPORT extern const base::FeatureParam<int> - kEsniDnsMaxAbsoluteAdditionalWaitMilliseconds; -NET_EXPORT extern const base::FeatureParam<int> - kEsniDnsMaxRelativeAdditionalWaitPercent; - // When enabled, makes cookies without a SameSite attribute behave like // SameSite=Lax cookies by default, and requires SameSite=None to be specified // in order to make cookies available in a third-party context. When disabled, @@ -158,12 +213,6 @@ NET_EXPORT extern const base::Feature NET_EXPORT extern const base::FeatureParam<int> kRecentCreationTimeGrantsLegacyCookieSemanticsMilliseconds; -// When enabled, blocks external requests coming from non-secure contexts. An -// external request is a request that crosses a network boundary from a more -// public address space into a less public address space. -NET_EXPORT extern const base::Feature - kBlockExternalRequestsFromNonSecureInitiators; - #if BUILDFLAG(BUILTIN_CERT_VERIFIER_FEATURE_SUPPORTED) // When enabled, use the builtin cert verifier instead of the platform verifier. NET_EXPORT extern const base::Feature kCertVerifierBuiltinFeature; @@ -192,6 +241,10 @@ NET_EXPORT extern const base::Feature kSchemefulSameSite; // those algorithms. If disabled, the algorithms will always be offered. NET_EXPORT extern const base::Feature kTLSLegacyCryptoFallbackForMetrics; +// When enabled, DNS_PROBE_FINISHED_NXDOMAIN error pages may show +// locally-generated suggestions to visit similar domains. +NET_EXPORT extern const base::Feature kUseLookalikesForNavigationSuggestions; + } // namespace features } // namespace net diff --git a/chromium/net/base/file_stream_context.cc b/chromium/net/base/file_stream_context.cc index 73e4843b902..f2009c8aef5 100644 --- a/chromium/net/base/file_stream_context.cc +++ b/chromium/net/base/file_stream_context.cc @@ -9,6 +9,7 @@ #include "base/bind.h" #include "base/files/file_path.h" #include "base/location.h" +#include "base/logging.h" #include "base/task_runner.h" #include "base/task_runner_util.h" #include "base/threading/thread_restrictions.h" diff --git a/chromium/net/base/file_stream_context.h b/chromium/net/base/file_stream_context.h index dcd5b3fae1a..7aae431b4d1 100644 --- a/chromium/net/base/file_stream_context.h +++ b/chromium/net/base/file_stream_context.h @@ -30,6 +30,7 @@ #include <stdint.h> #include "base/files/file.h" +#include "base/logging.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/message_loop/message_pump_for_io.h" diff --git a/chromium/net/base/ip_address.cc b/chromium/net/base/ip_address.cc index 03a4df02dfc..ec095c44934 100644 --- a/chromium/net/base/ip_address.cc +++ b/chromium/net/base/ip_address.cc @@ -22,6 +22,8 @@ namespace net { namespace { +bool g_consider_loopback_ip_to_be_publicly_routable_for_testing = false; + // The prefix for IPv6 mapped IPv4 addresses. // https://tools.ietf.org/html/rfc4291#section-2.5.5.2 constexpr uint8_t kIPv4MappedPrefix[] = {0, 0, 0, 0, 0, 0, @@ -234,6 +236,11 @@ bool IPAddress::IsValid() const { } bool IPAddress::IsPubliclyRoutable() const { + if (g_consider_loopback_ip_to_be_publicly_routable_for_testing && + IsLoopback()) { + return true; + } + if (IsIPv4()) { return IsPubliclyRoutableIPv4(ip_address_); } else if (IsIPv6()) { @@ -242,6 +249,11 @@ bool IPAddress::IsPubliclyRoutable() const { return true; } +// static +void IPAddress::ConsiderLoopbackIPToBePubliclyRoutableForTesting() { + g_consider_loopback_ip_to_be_publicly_routable_for_testing = true; +} + bool IPAddress::IsZero() const { for (auto x : ip_address_) { if (x != 0) diff --git a/chromium/net/base/ip_address.h b/chromium/net/base/ip_address.h index 829095bc3a4..c3249b7c88d 100644 --- a/chromium/net/base/ip_address.h +++ b/chromium/net/base/ip_address.h @@ -157,6 +157,10 @@ class NET_EXPORT IPAddress { // IPv4-mapped-to-IPv6 addresses are considered publicly routable. bool IsPubliclyRoutable() const; + // Let future IsPubliclyRoutable() calls in the current process always return + // true for a loopback ip. + static void ConsiderLoopbackIPToBePubliclyRoutableForTesting(); + // Returns true if the IP is "zero" (e.g. the 0.0.0.0 IPv4 address). bool IsZero() const; diff --git a/chromium/net/base/ip_address_unittest.cc b/chromium/net/base/ip_address_unittest.cc index 6ec78d6c38e..8a9b90022b1 100644 --- a/chromium/net/base/ip_address_unittest.cc +++ b/chromium/net/base/ip_address_unittest.cc @@ -302,6 +302,16 @@ TEST(IPAddressTest, IsPubliclyRoutableIPv6) { } } +TEST(IPAddressTest, ConsiderLoopbackIPToBePubliclyRoutableForTestingMethod) { + IPAddress address; + EXPECT_TRUE(address.AssignFromIPLiteral("127.0.0.1")); + ASSERT_TRUE(address.IsValid()); + EXPECT_FALSE(address.IsPubliclyRoutable()); + + IPAddress::ConsiderLoopbackIPToBePubliclyRoutableForTesting(); + EXPECT_TRUE(address.IsPubliclyRoutable()); +} + TEST(IPAddressTest, IsZero) { uint8_t address1[4] = {}; IPAddress zero_ipv4_address(address1); diff --git a/chromium/net/base/load_timing_info.h b/chromium/net/base/load_timing_info.h index e3ff12e34da..6952fc557ce 100644 --- a/chromium/net/base/load_timing_info.h +++ b/chromium/net/base/load_timing_info.h @@ -27,7 +27,6 @@ namespace net { // The general order for events is: // request_start // service_worker_start_time -// service_worker_ready_time // proxy_start // proxy_end // dns_start @@ -38,6 +37,10 @@ namespace net { // connect_end // send_start // send_end +// service_worker_ready_time +// service_worker_fetch_start +// service_worker_respond_with_settled +// first_early_hints_time // receive_headers_start // receive_headers_end // @@ -149,7 +152,16 @@ struct NET_EXPORT LoadTimingInfo { // if this is greater than |request_start|. base::TimeTicks service_worker_ready_time; - // The time spent determing which proxy to use. Null when there is no PAC. + // The time when serviceworker fetch event was popped off the event queue + // and fetch event handler started running. + // If the response is not provided by the ServiceWorker, kept empty. + base::TimeTicks service_worker_fetch_start; + + // The time when serviceworker's fetch event's respondWith promise was + // settled. If the response is not provided by the ServiceWorker, kept empty. + base::TimeTicks service_worker_respond_with_settled; + + // The time spent determining which proxy to use. Null when there is no PAC. base::TimeTicks proxy_resolve_start; base::TimeTicks proxy_resolve_end; @@ -167,6 +179,9 @@ struct NET_EXPORT LoadTimingInfo { base::TimeTicks receive_headers_start; base::TimeTicks receive_headers_end; + // The time that the first 103 Early Hints response is received. + base::TimeTicks first_early_hints_time; + // In case the resource was proactively pushed by the server, these are // the times that push started and ended. Note that push_end will be null // if the request is still being transmitted, i.e. the underlying h2 stream diff --git a/chromium/net/base/load_timing_info_test_util.cc b/chromium/net/base/load_timing_info_test_util.cc index 84410d560b9..e84d4bd127b 100644 --- a/chromium/net/base/load_timing_info_test_util.cc +++ b/chromium/net/base/load_timing_info_test_util.cc @@ -54,6 +54,7 @@ void ExpectLoadTimingHasOnlyConnectionTimes( EXPECT_TRUE(load_timing_info.send_start.is_null()); EXPECT_TRUE(load_timing_info.send_end.is_null()); EXPECT_TRUE(load_timing_info.receive_headers_end.is_null()); + EXPECT_TRUE(load_timing_info.first_early_hints_time.is_null()); EXPECT_TRUE(load_timing_info.push_start.is_null()); EXPECT_TRUE(load_timing_info.push_end.is_null()); } diff --git a/chromium/net/base/net_error_list.h b/chromium/net/base/net_error_list.h index 758c9b18350..7682241352a 100644 --- a/chromium/net/base/net_error_list.h +++ b/chromium/net/base/net_error_list.h @@ -121,6 +121,12 @@ NET_ERROR(BLOCKED_BY_RESPONSE, -27) // requests. Used for NetworkSecurityPolicy on Android. NET_ERROR(CLEARTEXT_NOT_PERMITTED, -29) +// The request was blocked by a Content Security Policy +NET_ERROR(BLOCKED_BY_CSP, -30) + +// The request was blocked because of no H/2 or QUIC session. +NET_ERROR(H2_OR_QUIC_REQUIRED, -31) + // A connection was closed (corresponding to a TCP FIN). NET_ERROR(CONNECTION_CLOSED, -100) diff --git a/chromium/net/base/net_errors.cc b/chromium/net/base/net_errors.cc index 25d46b434d0..06ba2d9174c 100644 --- a/chromium/net/base/net_errors.cc +++ b/chromium/net/base/net_errors.cc @@ -69,6 +69,17 @@ bool IsHostnameResolutionError(int error) { return error == ERR_NAME_NOT_RESOLVED; } +bool IsRequestBlockedError(int error) { + switch (error) { + case ERR_BLOCKED_BY_CLIENT: + case ERR_BLOCKED_BY_ADMINISTRATOR: + case ERR_BLOCKED_BY_CSP: + return true; + default: + return false; + } +} + Error FileErrorToNetError(base::File::Error file_error) { switch (file_error) { case base::File::FILE_OK: diff --git a/chromium/net/base/net_errors.h b/chromium/net/base/net_errors.h index bbd870e1c16..d2807f53999 100644 --- a/chromium/net/base/net_errors.h +++ b/chromium/net/base/net_errors.h @@ -50,6 +50,9 @@ NET_EXPORT bool IsClientCertificateError(int error); // Returns true if |error| is an error from hostname resolution. NET_EXPORT bool IsHostnameResolutionError(int error); +// Returns true if |error| means that the request has been blocked. +NET_EXPORT bool IsRequestBlockedError(int error); + // Map system error code to Error. NET_EXPORT Error MapSystemError(logging::SystemErrorCode os_error); diff --git a/chromium/net/base/net_errors_posix.cc b/chromium/net/base/net_errors_posix.cc index 13e14a736c8..2e4fd240aaa 100644 --- a/chromium/net/base/net_errors_posix.cc +++ b/chromium/net/base/net_errors_posix.cc @@ -17,7 +17,8 @@ namespace net { Error MapSystemError(logging::SystemErrorCode os_error) { if (os_error != 0) - DVLOG(2) << "Error " << os_error; + DVLOG(2) << "Error " << os_error << ": " + << logging::SystemErrorCodeToString(os_error); // There are numerous posix error codes, but these are the ones we thus far // find interesting. diff --git a/chromium/net/base/network_change_notifier_fuchsia.cc b/chromium/net/base/network_change_notifier_fuchsia.cc index a6d67e35f42..e5cde0787f8 100644 --- a/chromium/net/base/network_change_notifier_fuchsia.cc +++ b/chromium/net/base/network_change_notifier_fuchsia.cc @@ -11,8 +11,8 @@ #include <vector> #include "base/bind.h" -#include "base/fuchsia/default_context.h" #include "base/fuchsia/fuchsia_logging.h" +#include "base/fuchsia/process_context.h" #include "base/optional.h" #include "base/run_loop.h" #include "net/base/network_interfaces.h" @@ -22,11 +22,10 @@ namespace net { NetworkChangeNotifierFuchsia::NetworkChangeNotifierFuchsia( uint32_t required_features) - : NetworkChangeNotifierFuchsia( - base::fuchsia::ComponentContextForCurrentProcess() - ->svc() - ->Connect<fuchsia::netstack::Netstack>(), - required_features) {} + : NetworkChangeNotifierFuchsia(base::ComponentContextForProcess() + ->svc() + ->Connect<fuchsia::netstack::Netstack>(), + required_features) {} NetworkChangeNotifierFuchsia::NetworkChangeNotifierFuchsia( fuchsia::netstack::NetstackPtr netstack, diff --git a/chromium/net/base/network_change_notifier_fuchsia_unittest.cc b/chromium/net/base/network_change_notifier_fuchsia_unittest.cc index e5ca7faa080..f6354fadb8e 100644 --- a/chromium/net/base/network_change_notifier_fuchsia_unittest.cc +++ b/chromium/net/base/network_change_notifier_fuchsia_unittest.cc @@ -12,6 +12,7 @@ #include "base/auto_reset.h" #include "base/bind.h" +#include "base/logging.h" #include "base/run_loop.h" #include "base/test/task_environment.h" #include "base/threading/sequence_bound.h" diff --git a/chromium/net/base/network_change_notifier_mac.cc b/chromium/net/base/network_change_notifier_mac.cc index 91cf418ef43..23cc7fd3536 100644 --- a/chromium/net/base/network_change_notifier_mac.cc +++ b/chromium/net/base/network_change_notifier_mac.cc @@ -8,6 +8,7 @@ #include <resolv.h> #include "base/bind.h" +#include "base/logging.h" #include "base/macros.h" #include "base/sequenced_task_runner.h" #include "base/task/post_task.h" diff --git a/chromium/net/base/network_config_watcher_mac.cc b/chromium/net/base/network_config_watcher_mac.cc index fb6362c832e..ea499cf3126 100644 --- a/chromium/net/base/network_config_watcher_mac.cc +++ b/chromium/net/base/network_config_watcher_mac.cc @@ -8,6 +8,7 @@ #include "base/bind.h" #include "base/compiler_specific.h" +#include "base/logging.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/message_loop/message_pump_type.h" diff --git a/chromium/net/base/network_delegate.cc b/chromium/net/base/network_delegate.cc index a98b95e8e8c..80592ea985d 100644 --- a/chromium/net/base/network_delegate.cc +++ b/chromium/net/base/network_delegate.cc @@ -101,11 +101,10 @@ void NetworkDelegate::NotifyPACScriptError(int line_number, } bool NetworkDelegate::CanGetCookies(const URLRequest& request, - const CookieList& cookie_list, bool allowed_from_caller) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK(!(request.load_flags() & LOAD_DO_NOT_SEND_COOKIES)); - return OnCanGetCookies(request, cookie_list, allowed_from_caller); + return OnCanGetCookies(request, allowed_from_caller); } bool NetworkDelegate::CanSetCookie(const URLRequest& request, diff --git a/chromium/net/base/network_delegate.h b/chromium/net/base/network_delegate.h index c06f365312e..c00f0ccd3b5 100644 --- a/chromium/net/base/network_delegate.h +++ b/chromium/net/base/network_delegate.h @@ -73,7 +73,6 @@ class NET_EXPORT NetworkDelegate { void NotifyURLRequestDestroyed(URLRequest* request); void NotifyPACScriptError(int line_number, const base::string16& error); bool CanGetCookies(const URLRequest& request, - const CookieList& cookie_list, bool allowed_from_caller); bool CanSetCookie(const URLRequest& request, const net::CanonicalCookie& cookie, @@ -206,7 +205,6 @@ class NET_EXPORT NetworkDelegate { // allowed from any higher level delegates (for example, in a // LayeredNetworkDelegate). Any custom logic should be ANDed with this bool. virtual bool OnCanGetCookies(const URLRequest& request, - const CookieList& cookie_list, bool allowed_from_caller) = 0; // Called when a cookie is set to allow the network delegate to block access diff --git a/chromium/net/base/network_delegate_impl.cc b/chromium/net/base/network_delegate_impl.cc index 44a232b5a60..822bedc22a8 100644 --- a/chromium/net/base/network_delegate_impl.cc +++ b/chromium/net/base/network_delegate_impl.cc @@ -49,7 +49,6 @@ void NetworkDelegateImpl::OnPACScriptError(int line_number, } bool NetworkDelegateImpl::OnCanGetCookies(const URLRequest& request, - const CookieList& cookie_list, bool allowed_from_caller) { return allowed_from_caller; } diff --git a/chromium/net/base/network_delegate_impl.h b/chromium/net/base/network_delegate_impl.h index 46554d70035..323dade2a5a 100644 --- a/chromium/net/base/network_delegate_impl.h +++ b/chromium/net/base/network_delegate_impl.h @@ -62,7 +62,6 @@ class NET_EXPORT NetworkDelegateImpl : public NetworkDelegate { void OnPACScriptError(int line_number, const base::string16& error) override; bool OnCanGetCookies(const URLRequest& request, - const CookieList& cookie_list, bool allowed_from_caller) override; bool OnCanSetCookie(const URLRequest& request, diff --git a/chromium/net/base/network_interfaces.cc b/chromium/net/base/network_interfaces.cc index 8ba3df11e2f..29df129a49b 100644 --- a/chromium/net/base/network_interfaces.cc +++ b/chromium/net/base/network_interfaces.cc @@ -4,6 +4,7 @@ #include "net/base/network_interfaces.h" +#include "base/logging.h" #include "build/build_config.h" #if defined(OS_POSIX) diff --git a/chromium/net/base/network_interfaces_fuchsia.cc b/chromium/net/base/network_interfaces_fuchsia.cc index 794f6d157fe..864f68ab8b5 100644 --- a/chromium/net/base/network_interfaces_fuchsia.cc +++ b/chromium/net/base/network_interfaces_fuchsia.cc @@ -13,8 +13,8 @@ #include <utility> #include "base/format_macros.h" -#include "base/fuchsia/default_context.h" #include "base/fuchsia/fuchsia_logging.h" +#include "base/fuchsia/process_context.h" #include "base/strings/stringprintf.h" #include "net/base/ip_endpoint.h" #include "net/base/network_interfaces.h" @@ -107,8 +107,7 @@ bool GetNetworkList(NetworkInterfaceList* networks, int policy) { DCHECK(networks); fuchsia::netstack::NetstackSyncPtr netstack; - base::fuchsia::ComponentContextForCurrentProcess()->svc()->Connect( - netstack.NewRequest()); + base::ComponentContextForProcess()->svc()->Connect(netstack.NewRequest()); // TODO(kmarshall): Use NetworkChangeNotifier's cached interface list. std::vector<fuchsia::netstack::NetInterface> interfaces; diff --git a/chromium/net/base/network_interfaces_getifaddrs.cc b/chromium/net/base/network_interfaces_getifaddrs.cc index c340cced979..7ce0429489e 100644 --- a/chromium/net/base/network_interfaces_getifaddrs.cc +++ b/chromium/net/base/network_interfaces_getifaddrs.cc @@ -30,6 +30,16 @@ #include <sys/ioctl.h> #endif // !OS_IOS +#if defined(OS_ANDROID) +#include "base/android/build_info.h" +// Declare getifaddrs() and freeifaddrs() weakly as they're only available +// on Android N+. +extern "C" { +int getifaddrs(struct ifaddrs** __list_ptr) __attribute__((weak_import)); +void freeifaddrs(struct ifaddrs* __ptr) __attribute__((weak_import)); +} +#endif // OS_ANDROID + namespace net { namespace internal { @@ -209,7 +219,18 @@ bool IfaddrsToNetworkInterfaceList(int policy, } // namespace internal +// This version of GetNetworkList() can only be called on Android N+, so give it +// a different and internal name so it isn't invoked mistakenly. +#if defined(OS_ANDROID) +namespace internal { +bool GetNetworkListUsingGetifaddrs(NetworkInterfaceList* networks, int policy) { + DCHECK_GE(base::android::BuildInfo::GetInstance()->sdk_int(), + base::android::SDK_VERSION_NOUGAT); + DCHECK(getifaddrs); + DCHECK(freeifaddrs); +#else bool GetNetworkList(NetworkInterfaceList* networks, int policy) { +#endif if (networks == NULL) return false; @@ -235,9 +256,14 @@ bool GetNetworkList(NetworkInterfaceList* networks, int policy) { return result; } +#if defined(OS_ANDROID) +} // namespace internal +// For Android use GetWifiSSID() impl in network_interfaces_linux.cc. +#else std::string GetWifiSSID() { NOTIMPLEMENTED(); return std::string(); } +#endif } // namespace net diff --git a/chromium/net/base/network_interfaces_getifaddrs.h b/chromium/net/base/network_interfaces_getifaddrs.h index 7ec8081a648..f2d9ae1578c 100644 --- a/chromium/net/base/network_interfaces_getifaddrs.h +++ b/chromium/net/base/network_interfaces_getifaddrs.h @@ -13,6 +13,7 @@ // This file defines IfaddrsToNetworkInterfaceList() so it can be called in // unittests. +#include "build/build_config.h" #include "net/base/net_export.h" #include "net/base/network_interfaces.h" @@ -51,6 +52,12 @@ NET_EXPORT_PRIVATE bool IfaddrsToNetworkInterfaceList( IPAttributesGetter* ip_attributes_getter, NetworkInterfaceList* networks); +#if defined(OS_ANDROID) +// A version of GetNetworkList() that uses getifaddrs(). Only callable on +// Android N+ where getifaddrs() was available. +bool GetNetworkListUsingGetifaddrs(NetworkInterfaceList* networks, int policy); +#endif + } // namespace internal } // namespace net diff --git a/chromium/net/base/network_interfaces_linux.cc b/chromium/net/base/network_interfaces_linux.cc index 616e77a83be..cad5f1d8721 100644 --- a/chromium/net/base/network_interfaces_linux.cc +++ b/chromium/net/base/network_interfaces_linux.cc @@ -22,6 +22,7 @@ #include "base/strings/string_tokenizer.h" #include "base/strings/string_util.h" #include "base/threading/thread_restrictions.h" +#include "build/build_config.h" #include "net/base/address_tracker_linux.h" #include "net/base/escape.h" #include "net/base/ip_endpoint.h" @@ -30,7 +31,9 @@ #include "url/gurl.h" #if defined(OS_ANDROID) +#include "base/android/build_info.h" #include "net/android/network_library.h" +#include "net/base/network_interfaces_getifaddrs.h" #endif namespace net { @@ -211,6 +214,20 @@ bool GetNetworkList(NetworkInterfaceList* networks, int policy) { if (networks == NULL) return false; +#if defined(OS_ANDROID) + // On Android 11 RTM_GETLINK (used by AddressTrackerLinux) no longer works as + // per https://developer.android.com/preview/privacy/mac-address so instead + // use getifaddrs() which is supported since Android N. + if (base::android::BuildInfo::GetInstance()->sdk_int() >= + base::android::SDK_VERSION_NOUGAT) { + bool ret = internal::GetNetworkListUsingGetifaddrs(networks, policy); + // Use GetInterfaceConnectionType() to sharpen up interface types. + for (NetworkInterface& network : *networks) + network.type = internal::GetInterfaceConnectionType(network.name); + return ret; + } +#endif + internal::AddressTrackerLinux tracker; tracker.Init(); diff --git a/chromium/net/base/network_interfaces_win_unittest.cc b/chromium/net/base/network_interfaces_win_unittest.cc index 51417189fa0..32763aa95d2 100644 --- a/chromium/net/base/network_interfaces_win_unittest.cc +++ b/chromium/net/base/network_interfaces_win_unittest.cc @@ -11,6 +11,7 @@ #include <string> #include <unordered_set> +#include "base/logging.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" #include "net/base/ip_endpoint.h" diff --git a/chromium/net/base/priority_queue.h b/chromium/net/base/priority_queue.h index ab8ee22a019..c4c30fa45c0 100644 --- a/chromium/net/base/priority_queue.h +++ b/chromium/net/base/priority_queue.h @@ -13,7 +13,7 @@ #include "base/bind.h" #include "base/callback.h" -#include "base/logging.h" +#include "base/check_op.h" #include "base/macros.h" #include "base/threading/thread_checker.h" diff --git a/chromium/net/base/privacy_mode.h b/chromium/net/base/privacy_mode.h index c3d128d83ac..90e99dd3bcc 100644 --- a/chromium/net/base/privacy_mode.h +++ b/chromium/net/base/privacy_mode.h @@ -12,6 +12,10 @@ namespace net { enum PrivacyMode { PRIVACY_MODE_DISABLED = 0, PRIVACY_MODE_ENABLED = 1, + + // Due to http://crbug.com/775438, PRIVACY_MODE_ENABLED still sends client + // certs. This mode ensures that the request is sent without client certs. + PRIVACY_MODE_ENABLED_WITHOUT_CLIENT_CERTS = 2, }; } // namespace net diff --git a/chromium/net/base/upload_data_stream.cc b/chromium/net/base/upload_data_stream.cc index edcba234fc5..bd5aea1bf31 100644 --- a/chromium/net/base/upload_data_stream.cc +++ b/chromium/net/base/upload_data_stream.cc @@ -190,4 +190,8 @@ UploadProgress UploadDataStream::GetUploadProgress() const { return UploadProgress(current_position_, total_size_); } +bool UploadDataStream::AllowHTTP1() const { + return true; +} + } // namespace net diff --git a/chromium/net/base/upload_data_stream.h b/chromium/net/base/upload_data_stream.h index b9645ec5a09..807efa13978 100644 --- a/chromium/net/base/upload_data_stream.h +++ b/chromium/net/base/upload_data_stream.h @@ -95,6 +95,10 @@ class NET_EXPORT UploadDataStream { // empty UploadProgress. virtual UploadProgress GetUploadProgress() const; + // Indicates whether fetch upload streaming is allowed/rejected over H/1. + // Even if this is false but there is a QUIC/H2 stream, the upload is allowed. + virtual bool AllowHTTP1() const; + protected: // Must be called by subclasses when InitInternal and ReadInternal complete // asynchronously. diff --git a/chromium/net/cert/cert_verifier.cc b/chromium/net/cert/cert_verifier.cc index 580c7212d65..6504721e2fa 100644 --- a/chromium/net/cert/cert_verifier.cc +++ b/chromium/net/cert/cert_verifier.cc @@ -120,11 +120,13 @@ bool operator==(const CertVerifier::Config& lhs, return std::tie( lhs.enable_rev_checking, lhs.require_rev_checking_local_anchors, lhs.enable_sha1_local_anchors, lhs.disable_symantec_enforcement, - lhs.crl_set, lhs.additional_trust_anchors) == + lhs.crl_set, lhs.additional_trust_anchors, + lhs.additional_untrusted_authorities) == std::tie( rhs.enable_rev_checking, rhs.require_rev_checking_local_anchors, rhs.enable_sha1_local_anchors, rhs.disable_symantec_enforcement, - rhs.crl_set, rhs.additional_trust_anchors); + rhs.crl_set, rhs.additional_trust_anchors, + rhs.additional_untrusted_authorities); } bool operator!=(const CertVerifier::Config& lhs, diff --git a/chromium/net/cert/cert_verifier.h b/chromium/net/cert/cert_verifier.h index 5c9c3798925..bcb768a353e 100644 --- a/chromium/net/cert/cert_verifier.h +++ b/chromium/net/cert/cert_verifier.h @@ -65,6 +65,12 @@ class NET_EXPORT CertVerifier { // system store. This is implementation-specific plumbing for passing // additional anchors through. CertificateList additional_trust_anchors; + + // Additional temporary certs to consider as intermediates during path + // validation. Ordinarily, implementations of CertVerifier use intermediate + // certs from the configured system store. This is implementation-specific + // plumbing for passing additional intermediates through. + CertificateList additional_untrusted_authorities; }; class Request { diff --git a/chromium/net/cert/cert_verify_proc.cc b/chromium/net/cert/cert_verify_proc.cc index b6502664174..0b7e5f9d1a4 100644 --- a/chromium/net/cert/cert_verify_proc.cc +++ b/chromium/net/cert/cert_verify_proc.cc @@ -935,6 +935,9 @@ bool CertVerifyProc::HasTooLongValidity(const X509Certificate& cert) { base::Time::UnixEpoch() + base::TimeDelta::FromSeconds(1519862400); const base::Time time_2019_07_01 = base::Time::UnixEpoch() + base::TimeDelta::FromSeconds(1561939200); + // From Chrome Root Certificate Policy + const base::Time time_2020_09_01 = + base::Time::UnixEpoch() + base::TimeDelta::FromSeconds(1598918400); // Compute the maximally permissive interpretations, accounting for leap // years. @@ -957,21 +960,27 @@ bool CertVerifyProc::HasTooLongValidity(const X509Certificate& cert) { return true; } - // For certificates issued after the BR effective date of 1 July 2012: 60 - // months. + // For certificates issued on-or-after the BR effective date of 1 July 2012: + // 60 months. if (start >= time_2012_07_01 && validity_duration > kSixtyMonths) return true; - // For certificates issued after 1 April 2015: 39 months. + // For certificates issued on-or-after 1 April 2015: 39 months. if (start >= time_2015_04_01 && validity_duration > kThirtyNineMonths) return true; - // For certificates issued after 1 March 2018: 825 days. + // For certificates issued on-or-after 1 March 2018: 825 days. if (start >= time_2018_03_01 && validity_duration > base::TimeDelta::FromDays(825)) { return true; } + // For certificates issued on-or-after 1 September 2020: 398 days. + if (start >= time_2020_09_01 && + validity_duration > base::TimeDelta::FromDays(398)) { + return true; + } + return false; } diff --git a/chromium/net/cert/cert_verify_proc_ios.cc b/chromium/net/cert/cert_verify_proc_ios.cc index 59624eb894d..ed9234dd80e 100644 --- a/chromium/net/cert/cert_verify_proc_ios.cc +++ b/chromium/net/cert/cert_verify_proc_ios.cc @@ -10,6 +10,7 @@ #include "base/mac/foundation_util.h" #include "base/mac/mac_logging.h" #include "base/mac/scoped_cftyperef.h" +#include "base/notreached.h" #include "crypto/sha2.h" #include "net/base/net_errors.h" #include "net/cert/asn1_util.h" diff --git a/chromium/net/cert/cert_verify_proc_unittest.cc b/chromium/net/cert/cert_verify_proc_unittest.cc index e8cbe147cee..ffb85e65fce 100644 --- a/chromium/net/cert/cert_verify_proc_unittest.cc +++ b/chromium/net/cert/cert_verify_proc_unittest.cc @@ -1499,6 +1499,9 @@ TEST(CertVerifyProcTest, TestHasTooLongValidity) { {"826_days_after_2018_03_01.pem", true}, {"825_days_1_second_after_2018_03_01.pem", true}, {"39_months_based_on_last_day.pem", false}, + {"398_days_after_2020_09_01.pem", false}, + {"399_days_after_2020_09_01.pem", true}, + {"398_days_1_second_after_2020_09_01.pem", true}, }; base::FilePath certs_dir = GetTestCertsDirectory(); diff --git a/chromium/net/cert/ct_log_verifier.cc b/chromium/net/cert/ct_log_verifier.cc index e255cae67ef..70cc5e1001f 100644 --- a/chromium/net/cert/ct_log_verifier.cc +++ b/chromium/net/cert/ct_log_verifier.cc @@ -9,6 +9,7 @@ #include <vector> #include "base/logging.h" +#include "base/notreached.h" #include "crypto/openssl_util.h" #include "crypto/sha2.h" #include "net/cert/ct_log_verifier_util.h" diff --git a/chromium/net/cert/ct_sct_to_string.cc b/chromium/net/cert/ct_sct_to_string.cc index adbb712af75..211f7ea264a 100644 --- a/chromium/net/cert/ct_sct_to_string.cc +++ b/chromium/net/cert/ct_sct_to_string.cc @@ -5,6 +5,7 @@ #include "net/cert/ct_sct_to_string.h" #include "base/logging.h" +#include "base/notreached.h" namespace net { diff --git a/chromium/net/cert/ev_root_ca_metadata.cc b/chromium/net/cert/ev_root_ca_metadata.cc index 052161a3498..13b5a55d77c 100644 --- a/chromium/net/cert/ev_root_ca_metadata.cc +++ b/chromium/net/cert/ev_root_ca_metadata.cc @@ -4,12 +4,7 @@ #include "net/cert/ev_root_ca_metadata.h" -#if defined(USE_NSS_CERTS) -#include <cert.h> -#include <pkcs11n.h> -#include <secerr.h> -#include <secoid.h> -#elif defined(OS_WIN) +#if defined(OS_WIN) #include <stdlib.h> #endif @@ -19,9 +14,7 @@ #include "base/logging.h" #include "base/strings/string_piece.h" #include "net/der/input.h" -#if defined(USE_NSS_CERTS) -#include "crypto/nss_util.h" -#elif defined(PLATFORM_USES_CHROMIUM_EV_METADATA) || defined(OS_WIN) +#if defined(PLATFORM_USES_CHROMIUM_EV_METADATA) #include "third_party/boringssl/src/include/openssl/bytestring.h" #include "third_party/boringssl/src/include/openssl/mem.h" #endif @@ -57,19 +50,8 @@ static const EVMetadata kEvRootCaMetadata[] = { { // AC Camerfirma uses the last two arcs to track how the private key // is managed - the effective verification policy is the same. - "1.3.6.1.4.1.17326.10.14.2.1.2", "1.3.6.1.4.1.17326.10.14.2.2.2", - }, - }, - // AC Camerfirma S.A. Global Chambersign Root - 2008 - // https://server2.camerfirma.com:8082 - { - {{0x13, 0x63, 0x35, 0x43, 0x93, 0x34, 0xa7, 0x69, 0x80, 0x16, 0xa0, - 0xd3, 0x24, 0xde, 0x72, 0x28, 0x4e, 0x07, 0x9d, 0x7b, 0x52, 0x20, - 0xbb, 0x8f, 0xbd, 0x74, 0x78, 0x16, 0xee, 0xbe, 0xba, 0xca}}, - { - // AC Camerfirma uses the last two arcs to track how the private key - // is managed - the effective verification policy is the same. - "1.3.6.1.4.1.17326.10.8.12.1.2", "1.3.6.1.4.1.17326.10.8.12.2.2", + "1.3.6.1.4.1.17326.10.14.2.1.2", + "1.3.6.1.4.1.17326.10.14.2.2.2", }, }, // AddTrust External CA Root @@ -173,14 +155,6 @@ static const EVMetadata kEvRootCaMetadata[] = { 0xac, 0x95, 0xcd, 0x4b, 0x93, 0xdb, 0xf3, 0xf2, 0x6a, 0xeb}}, {"1.3.6.1.4.1.6334.1.100.1", ""}, }, - // Buypass Class 3 CA 1 - // https://valid.evident.ca13.ssl.buypass.no/ - { - {{0xb7, 0xb1, 0x2b, 0x17, 0x1f, 0x82, 0x1d, 0xaa, 0x99, 0x0c, 0xd0, - 0xfe, 0x50, 0x87, 0xb1, 0x28, 0x44, 0x8b, 0xa8, 0xe5, 0x18, 0x4f, - 0x84, 0xc5, 0x1e, 0x02, 0xb5, 0xc8, 0xfb, 0x96, 0x2b, 0x24}}, - {"2.16.578.1.26.1.3.3", ""}, - }, // Buypass Class 3 Root CA // https://valid.evident.ca23.ssl.buypass.no/ { @@ -189,14 +163,6 @@ static const EVMetadata kEvRootCaMetadata[] = { 0x29, 0xb4, 0xae, 0x1d, 0x5b, 0x93, 0x32, 0xe6, 0xb2, 0x4d}}, {"2.16.578.1.26.1.3.3", ""}, }, - // CertPlus Class 2 Primary CA (KEYNECTIS) - // https://www.keynectis.com/ - { - {{0x0f, 0x99, 0x3c, 0x8a, 0xef, 0x97, 0xba, 0xaf, 0x56, 0x87, 0x14, - 0x0e, 0xd5, 0x9a, 0xd1, 0x82, 0x1b, 0xb4, 0xaf, 0xac, 0xf0, 0xaa, - 0x9a, 0x58, 0xb5, 0xd5, 0x7a, 0x33, 0x8a, 0x3a, 0xfb, 0xcb}}, - {"1.3.6.1.4.1.22234.2.5.2.3.1", ""}, - }, // Certum Trusted Network CA // https://juice.certum.pl/ { @@ -213,15 +179,6 @@ static const EVMetadata kEvRootCaMetadata[] = { 0x2e, 0xf8, 0x00, 0xf3, 0x55, 0xc4, 0xc5, 0xfd, 0x70, 0xfd}}, {"2.16.156.112554.3", ""}, }, - // China Internet Network Information Center EV Certificates Root - // https://evdemo.cnnic.cn/ - { - // Root - {{0x1c, 0x01, 0xc6, 0xf4, 0xdb, 0xb2, 0xfe, 0xfc, 0x22, 0x55, 0x8b, - 0x2b, 0xca, 0x32, 0x56, 0x3f, 0x49, 0x84, 0x4a, 0xcf, 0xc3, 0x2b, - 0x7b, 0xe4, 0xb0, 0xff, 0x59, 0x9f, 0x9e, 0x8c, 0x7a, 0xf7}}, - {"1.3.6.1.4.1.29836.1.10", ""}, - }, // COMODO Certification Authority // https://secure.comodo.com/ { @@ -271,6 +228,22 @@ static const EVMetadata kEvRootCaMetadata[] = { 0xbc, 0xf1, 0xdf, 0x69, 0x56, 0x1e, 0x3d, 0xc6, 0x32, 0x5c}}, {"2.16.840.1.114412.2.1", ""}, }, + // DigiCert Assured ID Root G2 + // https://assured-id-root-g2.chain-demos.digicert.com/ + { + {{0x7d, 0x05, 0xeb, 0xb6, 0x82, 0x33, 0x9f, 0x8c, 0x94, 0x51, 0xee, + 0x09, 0x4e, 0xeb, 0xfe, 0xfa, 0x79, 0x53, 0xa1, 0x14, 0xed, 0xb2, + 0xf4, 0x49, 0x49, 0x45, 0x2f, 0xab, 0x7d, 0x2f, 0xc1, 0x85}}, + {"2.16.840.1.114412.2.1", ""}, + }, + // DigiCert Assured ID Root G3 + // https://assured-id-root-g3.chain-demos.digicert.com/ + { + {{0x7e, 0x37, 0xcb, 0x8b, 0x4c, 0x47, 0x09, 0x0c, 0xab, 0x36, 0x55, + 0x1b, 0xa6, 0xf4, 0x5d, 0xb8, 0x40, 0x68, 0x0f, 0xba, 0x16, 0x6a, + 0x95, 0x2d, 0xb1, 0x00, 0x71, 0x7f, 0x43, 0x05, 0x3f, 0xc2}}, + {"2.16.840.1.114412.2.1", ""}, + }, // DigiCert Global Root CA // https://global-root-ca.chain-demos.digicert.com/ { @@ -319,13 +292,13 @@ static const EVMetadata kEvRootCaMetadata[] = { 0xd4, 0x73, 0x0c, 0x84, 0xea, 0xf1, 0xf3, 0xd3, 0x48, 0x81}}, {"1.3.6.1.4.1.4788.2.202.1", ""}, }, - // Entrust.net Secure Server Certification Authority - // https://www.entrust.net/ + // emSign Root CA - G1 + // https://testevg1.emsign.com/ { - {{0x62, 0xf2, 0x40, 0x27, 0x8c, 0x56, 0x4c, 0x4d, 0xd8, 0xbf, 0x7d, - 0x9d, 0x4f, 0x6f, 0x36, 0x6e, 0xa8, 0x94, 0xd2, 0x2f, 0x5f, 0x34, - 0xd9, 0x89, 0xa9, 0x83, 0xac, 0xec, 0x2f, 0xff, 0xed, 0x50}}, - {"2.16.840.1.114028.10.1.2", ""}, + {{0x40, 0xf6, 0xaf, 0x03, 0x46, 0xa9, 0x9a, 0xa1, 0xcd, 0x1d, 0x55, + 0x5a, 0x4e, 0x9c, 0xce, 0x62, 0xc7, 0xf9, 0x63, 0x46, 0x03, 0xee, + 0x40, 0x66, 0x15, 0x83, 0x3d, 0xc8, 0xc8, 0xd0, 0x03, 0x67}}, + {"2.23.140.1.1", ""}, }, // Entrust Root Certification Authority // https://www.entrust.net/ @@ -351,14 +324,6 @@ static const EVMetadata kEvRootCaMetadata[] = { 0xab, 0x1d, 0x3b, 0x8e, 0xb0, 0x70, 0xe5, 0x6e, 0xdf, 0xf5}}, {"2.16.840.1.114028.10.1.2", ""}, }, - // Equifax Secure Certificate Authority (GeoTrust) - // https://www.geotrust.com/ - { - {{0x08, 0x29, 0x7a, 0x40, 0x47, 0xdb, 0xa2, 0x36, 0x80, 0xc7, 0x31, - 0xdb, 0x6e, 0x31, 0x76, 0x53, 0xca, 0x78, 0x48, 0xe1, 0xbe, 0xbd, - 0x3a, 0x0b, 0x01, 0x79, 0xa7, 0x07, 0xf9, 0x2c, 0xf1, 0x78}}, - {"1.3.6.1.4.1.14370.1.6", ""}, - }, // E-Tugra Certification Authority // https://sslev.e-tugra.com.tr { @@ -367,36 +332,6 @@ static const EVMetadata kEvRootCaMetadata[] = { 0x65, 0xea, 0x89, 0x39, 0x11, 0xf5, 0x5e, 0x55, 0xf2, 0x3c}}, {"2.16.792.3.0.4.1.1.4", ""}, }, - // GeoTrust Primary Certification Authority - // https://www.geotrust.com/ - { - {{0x37, 0xd5, 0x10, 0x06, 0xc5, 0x12, 0xea, 0xab, 0x62, 0x64, 0x21, - 0xf1, 0xec, 0x8c, 0x92, 0x01, 0x3f, 0xc5, 0xf8, 0x2a, 0xe9, 0x8e, - 0xe5, 0x33, 0xeb, 0x46, 0x19, 0xb8, 0xde, 0xb4, 0xd0, 0x6c}}, - {"1.3.6.1.4.1.14370.1.6", ""}, - }, - // GeoTrust Primary Certification Authority - G2 - { - {{0x5e, 0xdb, 0x7a, 0xc4, 0x3b, 0x82, 0xa0, 0x6a, 0x87, 0x61, 0xe8, - 0xd7, 0xbe, 0x49, 0x79, 0xeb, 0xf2, 0x61, 0x1f, 0x7d, 0xd7, 0x9b, - 0xf9, 0x1c, 0x1c, 0x6b, 0x56, 0x6a, 0x21, 0x9e, 0xd7, 0x66}}, - {"1.3.6.1.4.1.14370.1.6", ""}, - }, - // GeoTrust Primary Certification Authority - G3 - { - {{0xb4, 0x78, 0xb8, 0x12, 0x25, 0x0d, 0xf8, 0x78, 0x63, 0x5c, 0x2a, - 0xa7, 0xec, 0x7d, 0x15, 0x5e, 0xaa, 0x62, 0x5e, 0xe8, 0x29, 0x16, - 0xe2, 0xcd, 0x29, 0x43, 0x61, 0x88, 0x6c, 0xd1, 0xfb, 0xd4}}, - {"1.3.6.1.4.1.14370.1.6", ""}, - }, - // GlobalSign Root CA - R2 - // https://www.globalsign.com/ - { - {{0xca, 0x42, 0xdd, 0x41, 0x74, 0x5f, 0xd0, 0xb8, 0x1e, 0xb9, 0x02, - 0x36, 0x2c, 0xf9, 0xd8, 0xbf, 0x71, 0x9d, 0xa1, 0xbd, 0x1b, 0x1e, - 0xfc, 0x94, 0x6f, 0x5b, 0x4c, 0x99, 0xf4, 0x2c, 0x1b, 0x9e}}, - {"1.3.6.1.4.1.4146.1.1", ""}, - }, // GlobalSign Root CA { {{0xeb, 0xd4, 0x10, 0x40, 0xe4, 0xbb, 0x3e, 0xc7, 0x42, 0xc9, 0xe3, @@ -412,14 +347,6 @@ static const EVMetadata kEvRootCaMetadata[] = { 0x63, 0x5a, 0x7c, 0xf4, 0x72, 0x0d, 0xc9, 0x63, 0xc5, 0x3b}}, {"1.3.6.1.4.1.4146.1.1", ""}, }, - // GlobalSign ECC Root CA - R4 - // https://2038r4.globalsign.com - { - {{0xbe, 0xc9, 0x49, 0x11, 0xc2, 0x95, 0x56, 0x76, 0xdb, 0x6c, 0x0a, - 0x55, 0x09, 0x86, 0xd7, 0x6e, 0x3b, 0xa0, 0x05, 0x66, 0x7c, 0x44, - 0x2c, 0x97, 0x62, 0xb4, 0xfb, 0xb7, 0x73, 0xde, 0x22, 0x8c}}, - {"1.3.6.1.4.1.4146.1.1", ""}, - }, // GlobalSign ECC Root CA - R5 // https://2038r5.globalsign.com/ { @@ -444,13 +371,13 @@ static const EVMetadata kEvRootCaMetadata[] = { 0x63, 0xe2, 0x74, 0x9d, 0xd3, 0xac, 0xa9, 0x19, 0x8e, 0xda}}, {"2.16.840.1.114413.1.7.23.3", ""}, }, - // GTE CyberTrust Global Root - // https://www.cybertrust.ne.jp/ + // Hongkong Post Root CA 3 + // https://valid-ev.ecert.gov.hk/ { - {{0xa5, 0x31, 0x25, 0x18, 0x8d, 0x21, 0x10, 0xaa, 0x96, 0x4b, 0x02, - 0xc7, 0xb7, 0xc6, 0xda, 0x32, 0x03, 0x17, 0x08, 0x94, 0xe5, 0xfb, - 0x71, 0xff, 0xfb, 0x66, 0x67, 0xd5, 0xe6, 0x81, 0x0a, 0x36}}, - {"1.3.6.1.4.1.6334.1.100.1", ""}, + {{0x5a, 0x2f, 0xc0, 0x3f, 0x0c, 0x83, 0xb0, 0x90, 0xbb, 0xfa, 0x40, + 0x60, 0x4b, 0x09, 0x88, 0x44, 0x6c, 0x76, 0x36, 0x18, 0x3d, 0xf9, + 0x84, 0x6e, 0x17, 0x10, 0x1a, 0x44, 0x7f, 0xb8, 0xef, 0xd6}}, + {"2.23.140.1.1", ""}, }, // Izenpe.com - SHA256 root // The first OID is for businesses and the second for government entities. @@ -545,14 +472,6 @@ static const EVMetadata kEvRootCaMetadata[] = { 0x82, 0x01, 0x78, 0x95, 0x97, 0x4a, 0x99, 0x02, 0x6b, 0x6c}}, {"1.2.392.200091.100.721.1", ""}, }, - // Security Communication EV RootCA1 - // https://www.secomtrust.net/contact/form.html - { - {{0xa2, 0x2d, 0xba, 0x68, 0x1e, 0x97, 0x37, 0x6e, 0x2d, 0x39, 0x7d, - 0x72, 0x8a, 0xae, 0x3a, 0x9b, 0x62, 0x96, 0xb9, 0xfd, 0xba, 0x60, - 0xbc, 0x2e, 0x11, 0xf6, 0x47, 0xf2, 0xc6, 0x75, 0xfb, 0x37}}, - {"1.2.392.200091.100.721.1", ""}, - }, // Security Communication EV RootCA2 // https://www.secomtrust.net/contact/form.html { @@ -561,6 +480,22 @@ static const EVMetadata kEvRootCaMetadata[] = { 0xd2, 0xb5, 0x21, 0x48, 0x4a, 0xa4, 0x7a, 0x0e, 0xbe, 0xf6}}, {"1.2.392.200091.100.721.1", ""}, }, + // SSL.com EV Root Certification Authority ECC + // https://test-ev-ecc.ssl.com/ + { + {{0x22, 0xa2, 0xc1, 0xf7, 0xbd, 0xed, 0x70, 0x4c, 0xc1, 0xe7, 0x01, + 0xb5, 0xf4, 0x08, 0xc3, 0x10, 0x88, 0x0f, 0xe9, 0x56, 0xb5, 0xde, + 0x2a, 0x4a, 0x44, 0xf9, 0x9c, 0x87, 0x3a, 0x25, 0xa7, 0xc8}}, + {"2.23.140.1.1", ""}, + }, + // SSL.com EV Root Certification Authority RSA R2 + // https://test-ev-rsa.ssl.com/ + { + {{0x2e, 0x7b, 0xf1, 0x6c, 0xc2, 0x24, 0x85, 0xa7, 0xbb, 0xe2, 0xaa, + 0x86, 0x96, 0x75, 0x07, 0x61, 0xb0, 0xae, 0x39, 0xbe, 0x3b, 0x2f, + 0xe9, 0xd0, 0xcc, 0x6d, 0x4e, 0xf7, 0x34, 0x91, 0x42, 0x5c}}, + {"2.23.140.1.1", ""}, + }, // Staat der Nederlanden EV Root CA // https://pkioevssl-v.quovadisglobal.com/ { @@ -569,14 +504,6 @@ static const EVMetadata kEvRootCaMetadata[] = { 0x9d, 0x8a, 0x90, 0x7a, 0xc4, 0xcb, 0x5d, 0xad, 0xc1, 0x5a}}, {"2.16.528.1.1003.1.2.7", ""}, }, - // StartCom Certification Authority - // https://www.startssl.com/ - { - {{0xc7, 0x66, 0xa9, 0xbe, 0xf2, 0xd4, 0x07, 0x1c, 0x86, 0x3a, 0x31, - 0xaa, 0x49, 0x20, 0xe8, 0x13, 0xb2, 0xd1, 0x98, 0x60, 0x8c, 0xb7, - 0xb7, 0xcf, 0xe2, 0x11, 0x43, 0xb8, 0x36, 0xdf, 0x09, 0xea}}, - {"1.3.6.1.4.1.23223.1.1.1", ""}, - }, // Starfield Class 2 Certification Authority // https://www.starfieldtech.com/ { @@ -609,44 +536,6 @@ static const EVMetadata kEvRootCaMetadata[] = { 0x8f, 0x64, 0x7c, 0x68, 0x81, 0xf2, 0xc8, 0x35, 0x7b, 0x95}}, {"2.16.756.1.89.1.2.1.1", ""}, }, - // Swisscom Root EV CA 2 - // https://test-quarz-ev-ca-2.pre.swissdigicert.ch - { - {{0xd9, 0x5f, 0xea, 0x3c, 0xa4, 0xee, 0xdc, 0xe7, 0x4c, 0xd7, 0x6e, - 0x75, 0xfc, 0x6d, 0x1f, 0xf6, 0x2c, 0x44, 0x1f, 0x0f, 0xa8, 0xbc, - 0x77, 0xf0, 0x34, 0xb1, 0x9e, 0x5d, 0xb2, 0x58, 0x01, 0x5d}}, - {"2.16.756.1.83.21.0", ""}, - }, - // Thawte Premium Server CA - // https://www.thawte.com/ - { - {{0xab, 0x70, 0x36, 0x36, 0x5c, 0x71, 0x54, 0xaa, 0x29, 0xc2, 0xc2, - 0x9f, 0x5d, 0x41, 0x91, 0x16, 0x3b, 0x16, 0x2a, 0x22, 0x25, 0x01, - 0x13, 0x57, 0xd5, 0x6d, 0x07, 0xff, 0xa7, 0xbc, 0x1f, 0x72}}, - {"2.16.840.1.113733.1.7.48.1", ""}, - }, - // thawte Primary Root CA - // https://www.thawte.com/ - { - {{0x8d, 0x72, 0x2f, 0x81, 0xa9, 0xc1, 0x13, 0xc0, 0x79, 0x1d, 0xf1, - 0x36, 0xa2, 0x96, 0x6d, 0xb2, 0x6c, 0x95, 0x0a, 0x97, 0x1d, 0xb4, - 0x6b, 0x41, 0x99, 0xf4, 0xea, 0x54, 0xb7, 0x8b, 0xfb, 0x9f}}, - {"2.16.840.1.113733.1.7.48.1", ""}, - }, - // thawte Primary Root CA - G2 - { - {{0xa4, 0x31, 0x0d, 0x50, 0xaf, 0x18, 0xa6, 0x44, 0x71, 0x90, 0x37, - 0x2a, 0x86, 0xaf, 0xaf, 0x8b, 0x95, 0x1f, 0xfb, 0x43, 0x1d, 0x83, - 0x7f, 0x1e, 0x56, 0x88, 0xb4, 0x59, 0x71, 0xed, 0x15, 0x57}}, - {"2.16.840.1.113733.1.7.48.1", ""}, - }, - // thawte Primary Root CA - G3 - { - {{0x4b, 0x03, 0xf4, 0x58, 0x07, 0xad, 0x70, 0xf2, 0x1b, 0xfc, 0x2c, - 0xae, 0x71, 0xc9, 0xfd, 0xe4, 0x60, 0x4c, 0x06, 0x4c, 0xf5, 0xff, - 0xb6, 0x86, 0xba, 0xe5, 0xdb, 0xaa, 0xd7, 0xfd, 0xd3, 0x4c}}, - {"2.16.840.1.113733.1.7.48.1", ""}, - }, // TWCA Global Root CA // https://evssldemo3.twca.com.tw/index.html { @@ -671,6 +560,14 @@ static const EVMetadata kEvRootCaMetadata[] = { 0x7e, 0x31, 0x70, 0x7a, 0xf3, 0xe9, 0x6d, 0x52, 0x2b, 0xbd}}, {"1.3.6.1.4.1.7879.13.24.1", ""}, }, + // UCA Extended Validation Root + // https://rsaevg1.good.sheca.com/ + { + {{0xd4, 0x3a, 0xf9, 0xb3, 0x54, 0x73, 0x75, 0x5c, 0x96, 0x84, 0xfc, + 0x06, 0xd7, 0xd8, 0xcb, 0x70, 0xee, 0x5c, 0x28, 0xe7, 0x73, 0xfb, + 0x29, 0x4e, 0xb4, 0x1e, 0xe7, 0x17, 0x22, 0x92, 0x4d, 0x24}}, + {"2.23.140.1.1", ""}, + }, // USERTrust ECC Certification Authority // https://usertrustecccertificationauthority-ev.comodoca.com/ { @@ -687,63 +584,6 @@ static const EVMetadata kEvRootCaMetadata[] = { 0x89, 0x64, 0xb1, 0x74, 0x6d, 0x46, 0xc3, 0xd4, 0xcb, 0xd2}}, {"1.3.6.1.4.1.6449.1.2.1.5.1", ""}, }, - // UTN-USERFirst-Hardware - { - {{0x6e, 0xa5, 0x47, 0x41, 0xd0, 0x04, 0x66, 0x7e, 0xed, 0x1b, 0x48, - 0x16, 0x63, 0x4a, 0xa3, 0xa7, 0x9e, 0x6e, 0x4b, 0x96, 0x95, 0x0f, - 0x82, 0x79, 0xda, 0xfc, 0x8d, 0x9b, 0xd8, 0x81, 0x21, 0x37}}, - { - "1.3.6.1.4.1.6449.1.2.1.5.1", - // This is the Network Solutions EV OID. However, this root - // cross-certifies NetSol and so we need it here too. - "1.3.6.1.4.1.782.1.2.1.8.1", - }, - }, - // ValiCert Class 2 Policy Validation Authority - { - {{0x58, 0xd0, 0x17, 0x27, 0x9c, 0xd4, 0xdc, 0x63, 0xab, 0xdd, 0xb1, - 0x96, 0xa6, 0xc9, 0x90, 0x6c, 0x30, 0xc4, 0xe0, 0x87, 0x83, 0xea, - 0xe8, 0xc1, 0x60, 0x99, 0x54, 0xd6, 0x93, 0x55, 0x59, 0x6b}}, - {"2.16.840.1.114413.1.7.23.3", "2.16.840.1.114414.1.7.23.3"}, - }, - // VeriSign Class 3 Public Primary Certification Authority - // https://www.verisign.com/ - { - {{0xe7, 0x68, 0x56, 0x34, 0xef, 0xac, 0xf6, 0x9a, 0xce, 0x93, 0x9a, - 0x6b, 0x25, 0x5b, 0x7b, 0x4f, 0xab, 0xef, 0x42, 0x93, 0x5b, 0x50, - 0xa2, 0x65, 0xac, 0xb5, 0xcb, 0x60, 0x27, 0xe4, 0x4e, 0x70}}, - {"2.16.840.1.113733.1.7.23.6", ""}, - }, - // VeriSign Class 3 Public Primary Certification Authority - G4 - { - {{0x69, 0xdd, 0xd7, 0xea, 0x90, 0xbb, 0x57, 0xc9, 0x3e, 0x13, 0x5d, - 0xc8, 0x5e, 0xa6, 0xfc, 0xd5, 0x48, 0x0b, 0x60, 0x32, 0x39, 0xbd, - 0xc4, 0x54, 0xfc, 0x75, 0x8b, 0x2a, 0x26, 0xcf, 0x7f, 0x79}}, - {"2.16.840.1.113733.1.7.23.6", ""}, - }, - // VeriSign Class 3 Public Primary Certification Authority - G5 - // https://www.verisign.com/ - { - {{0x9a, 0xcf, 0xab, 0x7e, 0x43, 0xc8, 0xd8, 0x80, 0xd0, 0x6b, 0x26, - 0x2a, 0x94, 0xde, 0xee, 0xe4, 0xb4, 0x65, 0x99, 0x89, 0xc3, 0xd0, - 0xca, 0xf1, 0x9b, 0xaf, 0x64, 0x05, 0xe4, 0x1a, 0xb7, 0xdf}}, - {"2.16.840.1.113733.1.7.23.6", ""}, - }, - // VeriSign Universal Root Certification Authority - { - {{0x23, 0x99, 0x56, 0x11, 0x27, 0xa5, 0x71, 0x25, 0xde, 0x8c, 0xef, - 0xea, 0x61, 0x0d, 0xdf, 0x2f, 0xa0, 0x78, 0xb5, 0xc8, 0x06, 0x7f, - 0x4e, 0x82, 0x82, 0x90, 0xbf, 0xb8, 0x60, 0xe8, 0x4b, 0x3c}}, - {"2.16.840.1.113733.1.7.23.6", ""}, - }, - // Wells Fargo WellsSecure Public Root Certificate Authority - // https://nerys.wellsfargo.com/test.html - { - {{0xa7, 0x12, 0x72, 0xae, 0xaa, 0xa3, 0xcf, 0xe8, 0x72, 0x7f, 0x7f, - 0xb3, 0x9f, 0x0f, 0xb3, 0xd1, 0xe5, 0x42, 0x6e, 0x90, 0x60, 0xb0, - 0x6e, 0xe6, 0xf1, 0x3e, 0x9a, 0x3c, 0x58, 0x33, 0xcd, 0x43}}, - {"2.16.840.1.114171.500.9", ""}, - }, // XRamp Global Certification Authority { {{0xce, 0xcd, 0xdc, 0x90, 0x50, 0x99, 0xd8, 0xda, 0xdf, 0xc5, 0xb1, @@ -763,113 +603,7 @@ EVRootCAMetadata* EVRootCAMetadata::GetInstance() { return g_ev_root_ca_metadata.Pointer(); } -#if defined(USE_NSS_CERTS) - -namespace { -// Converts a DER-encoded OID (without leading tag and length) to a SECOidTag. -// -// Returns true if it was able to find an *existing* SECOidTag (it will not -// register one if missing). -// -// Since all the EV OIDs are registered during EVRootCAMetadata's constructor, -// doing a lookup only needs to consider existing OID tags. -bool ConvertBytesToSecOidTag(const der::Input& oid, SECOidTag* out) { - SECItem item; - item.data = const_cast<uint8_t*>(oid.UnsafeData()); - item.len = oid.Length(); - *out = SECOID_FindOIDTag(&item); - return *out != SEC_OID_UNKNOWN; -} - -} // namespace - -bool EVRootCAMetadata::IsEVPolicyOID(PolicyOID policy_oid) const { - return policy_oids_.find(policy_oid) != policy_oids_.end(); -} - -bool EVRootCAMetadata::IsEVPolicyOIDGivenBytes( - const der::Input& policy_oid) const { - SECOidTag oid_tag; - return ConvertBytesToSecOidTag(policy_oid, &oid_tag) && - IsEVPolicyOID(oid_tag); -} - -bool EVRootCAMetadata::HasEVPolicyOID(const SHA256HashValue& fingerprint, - PolicyOID policy_oid) const { - auto iter = ev_policy_.find(fingerprint); - if (iter == ev_policy_.end()) - return false; - return std::find(iter->second.begin(), iter->second.end(), policy_oid) != - iter->second.end(); -} - -bool EVRootCAMetadata::HasEVPolicyOIDGivenBytes( - const SHA256HashValue& fingerprint, - const der::Input& policy_oid) const { - SECOidTag oid_tag; - return ConvertBytesToSecOidTag(policy_oid, &oid_tag) && - HasEVPolicyOID(fingerprint, oid_tag); -} - -// static -bool EVRootCAMetadata::IsCaBrowserForumEvOid(PolicyOID policy_oid) { - // OID: 2.23.140.1.1 - const uint8_t kCabEvOid[] = {0x67, 0x81, 0x0c, 0x01, 0x01}; - SECItem item; - item.data = const_cast<uint8_t*>(&kCabEvOid[0]); - item.len = sizeof(kCabEvOid); - return policy_oid == SECOID_FindOIDTag(&item); -} - -bool EVRootCAMetadata::AddEVCA(const SHA256HashValue& fingerprint, - const char* policy) { - if (ev_policy_.find(fingerprint) != ev_policy_.end()) - return false; - - PolicyOID oid; - if (!RegisterOID(policy, &oid)) - return false; - - ev_policy_[fingerprint].push_back(oid); - policy_oids_.insert(oid); - - return true; -} - -bool EVRootCAMetadata::RemoveEVCA(const SHA256HashValue& fingerprint) { - auto it = ev_policy_.find(fingerprint); - if (it == ev_policy_.end()) - return false; - PolicyOID oid = it->second[0]; - ev_policy_.erase(it); - policy_oids_.erase(oid); - return true; -} - -// static -bool EVRootCAMetadata::RegisterOID(const char* policy, - PolicyOID* out) { - PRUint8 buf[64]; - SECItem oid_item; - oid_item.data = buf; - oid_item.len = sizeof(buf); - SECStatus status = SEC_StringToOID(NULL, &oid_item, policy, 0); - if (status != SECSuccess) - return false; - - // Register the OID. - SECOidData od; - od.oid.len = oid_item.len; - od.oid.data = oid_item.data; - od.offset = SEC_OID_UNKNOWN; - od.desc = policy; - od.mechanism = CKM_INVALID_MECHANISM; - od.supportedExtension = INVALID_CERT_EXTENSION; - *out = SECOID_AddEntry(&od); - return *out != SEC_OID_UNKNOWN; -} - -#elif defined(OS_WIN) +#if defined(OS_WIN) namespace { @@ -1084,24 +818,7 @@ bool EVRootCAMetadata::RemoveEVCA(const SHA256HashValue& fingerprint) { EVRootCAMetadata::EVRootCAMetadata() { // Constructs the object from the raw metadata in kEvRootCaMetadata. -#if defined(USE_NSS_CERTS) - crypto::EnsureNSSInit(); - - for (const auto& ev_root : kEvRootCaMetadata) { - for (const auto& policy : ev_root.policy_oids) { - if (policy.empty()) - break; - PolicyOID policy_oid; - if (!RegisterOID(policy.data(), &policy_oid)) { - LOG(ERROR) << "Failed to register OID: " << policy; - continue; - } - - ev_policy_[ev_root.fingerprint].push_back(policy_oid); - policy_oids_.insert(policy_oid); - } - } -#elif defined(PLATFORM_USES_CHROMIUM_EV_METADATA) && !defined(OS_WIN) +#if defined(PLATFORM_USES_CHROMIUM_EV_METADATA) && !defined(OS_WIN) for (const auto& ev_root : kEvRootCaMetadata) { for (const auto& policy : ev_root.policy_oids) { if (policy.empty()) diff --git a/chromium/net/cert/ev_root_ca_metadata.h b/chromium/net/cert/ev_root_ca_metadata.h index 42daddbd8bd..b79206e9141 100644 --- a/chromium/net/cert/ev_root_ca_metadata.h +++ b/chromium/net/cert/ev_root_ca_metadata.h @@ -7,10 +7,6 @@ #include "build/build_config.h" -#if defined(USE_NSS_CERTS) -#include <secoidt.h> -#endif - #include <map> #include <set> #include <string> @@ -42,9 +38,7 @@ class Input; // extended-validation (EV) certificates. class NET_EXPORT_PRIVATE EVRootCAMetadata { public: -#if defined(USE_NSS_CERTS) - typedef SECOidTag PolicyOID; -#elif defined(OS_WIN) +#if defined(OS_WIN) typedef const char* PolicyOID; #else // DER-encoded OID value (no tag or length). @@ -90,16 +84,7 @@ class NET_EXPORT_PRIVATE EVRootCAMetadata { EVRootCAMetadata(); ~EVRootCAMetadata(); -#if defined(USE_NSS_CERTS) - using PolicyOIDMap = std::map<SHA256HashValue, std::vector<PolicyOID>>; - - // RegisterOID registers |policy|, a policy OID in dotted string form, and - // writes the memoized form to |*out|. It returns true on success. - static bool RegisterOID(const char* policy, PolicyOID* out); - - PolicyOIDMap ev_policy_; - std::set<PolicyOID> policy_oids_; -#elif defined(OS_WIN) +#if defined(OS_WIN) using ExtraEVCAMap = std::map<SHA256HashValue, std::string>; // extra_cas_ contains any EV CA metadata that was added at runtime. diff --git a/chromium/net/cert/ev_root_ca_metadata_unittest.cc b/chromium/net/cert/ev_root_ca_metadata_unittest.cc index bb69645df5e..56ffc5e643e 100644 --- a/chromium/net/cert/ev_root_ca_metadata_unittest.cc +++ b/chromium/net/cert/ev_root_ca_metadata_unittest.cc @@ -10,132 +10,74 @@ #include "net/test/cert_test_util.h" #include "testing/gtest/include/gtest/gtest.h" -#if defined(USE_NSS_CERTS) -#include "crypto/nss_util.h" -#include "crypto/scoped_nss_types.h" -#endif - namespace net { namespace { -#if defined(USE_NSS_CERTS) || defined(OS_WIN) -const char kVerisignPolicyStr[] = "2.16.840.1.113733.1.7.23.6"; -const char kThawtePolicyStr[] = "2.16.840.1.113733.1.7.48.1"; +#if defined(OS_WIN) const char kFakePolicyStr[] = "2.16.840.1.42"; const char kCabEvPolicyStr[] = "2.23.140.1.1"; -#elif defined(OS_MACOSX) +const char kStarfieldPolicyStr[] = "2.16.840.1.114414.1.7.23.3"; +#elif defined(PLATFORM_USES_CHROMIUM_EV_METADATA) const char kFakePolicyStr[] = "2.16.840.1.42"; #endif -#if defined(USE_NSS_CERTS) || defined(OS_WIN) || defined(OS_MACOSX) +#if defined(PLATFORM_USES_CHROMIUM_EV_METADATA) // DER OID values (no tag or length). -const uint8_t kVerisignPolicyBytes[] = {0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, - 0x45, 0x01, 0x07, 0x17, 0x06}; -const uint8_t kThawtePolicyBytes[] = {0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, - 0x45, 0x01, 0x07, 0x30, 0x01}; const uint8_t kFakePolicyBytes[] = {0x60, 0x86, 0x48, 0x01, 0x2a}; const uint8_t kCabEvPolicyBytes[] = {0x67, 0x81, 0x0c, 0x01, 0x01}; +const uint8_t kStarfieldPolicyBytes[] = {0x60, 0x86, 0x48, 0x01, 0x86, 0xFD, + 0x6E, 0x01, 0x07, 0x17, 0x03}; -const SHA256HashValue kVerisignFingerprint = { - {0xe7, 0x68, 0x56, 0x34, 0xef, 0xac, 0xf6, 0x9a, 0xce, 0x93, 0x9a, - 0x6b, 0x25, 0x5b, 0x7b, 0x4f, 0xab, 0xef, 0x42, 0x93, 0x5b, 0x50, - 0xa2, 0x65, 0xac, 0xb5, 0xcb, 0x60, 0x27, 0xe4, 0x4e, 0x70}}; const SHA256HashValue kFakeFingerprint = { {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}}; +const SHA256HashValue kStarfieldFingerprint = { + {0x14, 0x65, 0xfa, 0x20, 0x53, 0x97, 0xb8, 0x76, 0xfa, 0xa6, 0xf0, + 0xa9, 0x95, 0x8e, 0x55, 0x90, 0xe4, 0x0f, 0xcc, 0x7f, 0xaa, 0x4f, + 0xb7, 0xc2, 0xc8, 0x67, 0x75, 0x21, 0xfb, 0x5f, 0xb6, 0x58}}; class EVOidData { public: EVOidData(); bool Init(); - EVRootCAMetadata::PolicyOID verisign_policy; - der::Input verisign_policy_bytes; - - EVRootCAMetadata::PolicyOID thawte_policy; - der::Input thawte_policy_bytes; - EVRootCAMetadata::PolicyOID fake_policy; der::Input fake_policy_bytes; EVRootCAMetadata::PolicyOID cab_ev_policy; der::Input cab_ev_policy_bytes; -}; - -#endif // defined(USE_NSS_CERTS) || defined(OS_WIN) || defined(OS_MACOSX) - -#if defined(USE_NSS_CERTS) - -SECOidTag RegisterOID(PLArenaPool* arena, const char* oid_string) { - SECOidData oid_data; - memset(&oid_data, 0, sizeof(oid_data)); - oid_data.offset = SEC_OID_UNKNOWN; - oid_data.desc = oid_string; - oid_data.mechanism = CKM_INVALID_MECHANISM; - oid_data.supportedExtension = INVALID_CERT_EXTENSION; - SECStatus rv = SEC_StringToOID(arena, &oid_data.oid, oid_string, 0); - if (rv != SECSuccess) - return SEC_OID_UNKNOWN; - - return SECOID_AddEntry(&oid_data); -} - -EVOidData::EVOidData() - : verisign_policy(SEC_OID_UNKNOWN), - verisign_policy_bytes(kVerisignPolicyBytes), - thawte_policy(SEC_OID_UNKNOWN), - thawte_policy_bytes(kThawtePolicyBytes), - fake_policy(SEC_OID_UNKNOWN), - fake_policy_bytes(kFakePolicyBytes), - cab_ev_policy(SEC_OID_UNKNOWN), - cab_ev_policy_bytes(kCabEvPolicyBytes) {} + EVRootCAMetadata::PolicyOID starfield_policy; + der::Input starfield_policy_bytes; +}; -bool EVOidData::Init() { - crypto::EnsureNSSInit(); - crypto::ScopedPLArenaPool pool(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); - if (!pool.get()) - return false; - - verisign_policy = RegisterOID(pool.get(), kVerisignPolicyStr); - thawte_policy = RegisterOID(pool.get(), kThawtePolicyStr); - fake_policy = RegisterOID(pool.get(), kFakePolicyStr); - cab_ev_policy = RegisterOID(pool.get(), kCabEvPolicyStr); - - return verisign_policy != SEC_OID_UNKNOWN && - thawte_policy != SEC_OID_UNKNOWN && fake_policy != SEC_OID_UNKNOWN && - cab_ev_policy != SEC_OID_UNKNOWN; -} +#endif // defined(PLATFORM_USES_CHROMIUM_EV_METADATA) -#elif defined(OS_WIN) +#if defined(OS_WIN) EVOidData::EVOidData() - : verisign_policy(kVerisignPolicyStr), - verisign_policy_bytes(kVerisignPolicyBytes), - thawte_policy(kThawtePolicyStr), - thawte_policy_bytes(kThawtePolicyBytes), - fake_policy(kFakePolicyStr), + : fake_policy(kFakePolicyStr), fake_policy_bytes(kFakePolicyBytes), cab_ev_policy(kCabEvPolicyStr), - cab_ev_policy_bytes(kCabEvPolicyBytes) {} + cab_ev_policy_bytes(kCabEvPolicyBytes), + starfield_policy(kStarfieldPolicyStr), + starfield_policy_bytes(kStarfieldPolicyBytes) {} bool EVOidData::Init() { return true; } -#elif defined(OS_MACOSX) +#elif defined(PLATFORM_USES_CHROMIUM_EV_METADATA) EVOidData::EVOidData() - : verisign_policy(kVerisignPolicyBytes), - verisign_policy_bytes(kVerisignPolicyBytes), - thawte_policy(kThawtePolicyBytes), - thawte_policy_bytes(kThawtePolicyBytes), - fake_policy(kFakePolicyBytes), + : fake_policy(kFakePolicyBytes), fake_policy_bytes(kFakePolicyBytes), cab_ev_policy(kCabEvPolicyBytes), - cab_ev_policy_bytes(kCabEvPolicyBytes) {} + cab_ev_policy_bytes(kCabEvPolicyBytes), + starfield_policy(kStarfieldPolicyBytes), + starfield_policy_bytes(kStarfieldPolicyBytes) {} bool EVOidData::Init() { return true; @@ -143,7 +85,7 @@ bool EVOidData::Init() { #endif -#if defined(USE_NSS_CERTS) || defined(OS_WIN) || defined(OS_MACOSX) +#if defined(PLATFORM_USES_CHROMIUM_EV_METADATA) class EVRootCAMetadataTest : public testing::Test { protected: @@ -155,43 +97,51 @@ class EVRootCAMetadataTest : public testing::Test { TEST_F(EVRootCAMetadataTest, Basic) { EVRootCAMetadata* ev_metadata(EVRootCAMetadata::GetInstance()); - EXPECT_TRUE(ev_metadata->IsEVPolicyOID(ev_oid_data.verisign_policy)); + // Contains an expected policy. + EXPECT_TRUE(ev_metadata->IsEVPolicyOID(ev_oid_data.starfield_policy)); EXPECT_TRUE( - ev_metadata->IsEVPolicyOIDGivenBytes(ev_oid_data.verisign_policy_bytes)); + ev_metadata->IsEVPolicyOIDGivenBytes(ev_oid_data.starfield_policy_bytes)); + // Does not contain an unregistered policy. EXPECT_FALSE(ev_metadata->IsEVPolicyOID(ev_oid_data.fake_policy)); EXPECT_FALSE( ev_metadata->IsEVPolicyOIDGivenBytes(ev_oid_data.fake_policy_bytes)); - EXPECT_TRUE(ev_metadata->HasEVPolicyOID(kVerisignFingerprint, - ev_oid_data.verisign_policy)); + // The policy is correct for the right root. + EXPECT_TRUE(ev_metadata->HasEVPolicyOID(kStarfieldFingerprint, + ev_oid_data.starfield_policy)); EXPECT_TRUE(ev_metadata->HasEVPolicyOIDGivenBytes( - kVerisignFingerprint, ev_oid_data.verisign_policy_bytes)); + kStarfieldFingerprint, ev_oid_data.starfield_policy_bytes)); + // The policy does not match if the root does not match. EXPECT_FALSE(ev_metadata->HasEVPolicyOID(kFakeFingerprint, - ev_oid_data.verisign_policy)); + ev_oid_data.starfield_policy)); EXPECT_FALSE(ev_metadata->HasEVPolicyOIDGivenBytes( - kFakeFingerprint, ev_oid_data.verisign_policy_bytes)); + kFakeFingerprint, ev_oid_data.starfield_policy_bytes)); - EXPECT_FALSE(ev_metadata->HasEVPolicyOID(kVerisignFingerprint, + // The expected root only has the expected policies; it should fail to match + // the root against both unknown policies as well as policies associated + // with other roots. + EXPECT_FALSE(ev_metadata->HasEVPolicyOID(kStarfieldFingerprint, ev_oid_data.fake_policy)); EXPECT_FALSE(ev_metadata->HasEVPolicyOIDGivenBytes( - kVerisignFingerprint, ev_oid_data.fake_policy_bytes)); + kStarfieldFingerprint, ev_oid_data.fake_policy_bytes)); - EXPECT_FALSE(ev_metadata->HasEVPolicyOID(kVerisignFingerprint, - ev_oid_data.thawte_policy)); + EXPECT_FALSE(ev_metadata->HasEVPolicyOID(kStarfieldFingerprint, + ev_oid_data.cab_ev_policy)); EXPECT_FALSE(ev_metadata->HasEVPolicyOIDGivenBytes( - kVerisignFingerprint, ev_oid_data.thawte_policy_bytes)); + kStarfieldFingerprint, ev_oid_data.cab_ev_policy_bytes)); // Test a completely bogus OID given bytes. const uint8_t bad_oid[] = {0}; - EXPECT_FALSE(ev_metadata->HasEVPolicyOIDGivenBytes(kVerisignFingerprint, + EXPECT_FALSE(ev_metadata->HasEVPolicyOIDGivenBytes(kStarfieldFingerprint, der::Input(bad_oid))); } TEST_F(EVRootCAMetadataTest, AddRemove) { EVRootCAMetadata* ev_metadata(EVRootCAMetadata::GetInstance()); + // An unregistered/junk policy should not work. EXPECT_FALSE(ev_metadata->IsEVPolicyOID(ev_oid_data.fake_policy)); EXPECT_FALSE( ev_metadata->IsEVPolicyOIDGivenBytes(ev_oid_data.fake_policy_bytes)); @@ -202,6 +152,8 @@ TEST_F(EVRootCAMetadataTest, AddRemove) { kFakeFingerprint, ev_oid_data.fake_policy_bytes)); { + // However, this unregistered/junk policy can be temporarily registered + // and made to work. ScopedTestEVPolicy test_ev_policy(ev_metadata, kFakeFingerprint, kFakePolicyStr); @@ -215,6 +167,7 @@ TEST_F(EVRootCAMetadataTest, AddRemove) { kFakeFingerprint, ev_oid_data.fake_policy_bytes)); } + // It should go out of scope when the ScopedTestEVPolicy goes out of scope. EXPECT_FALSE(ev_metadata->IsEVPolicyOID(ev_oid_data.fake_policy)); EXPECT_FALSE( ev_metadata->IsEVPolicyOIDGivenBytes(ev_oid_data.fake_policy_bytes)); @@ -232,10 +185,10 @@ TEST_F(EVRootCAMetadataTest, IsCaBrowserForumEvOid) { EXPECT_FALSE( EVRootCAMetadata::IsCaBrowserForumEvOid(ev_oid_data.fake_policy)); EXPECT_FALSE( - EVRootCAMetadata::IsCaBrowserForumEvOid(ev_oid_data.verisign_policy)); + EVRootCAMetadata::IsCaBrowserForumEvOid(ev_oid_data.starfield_policy)); } -#endif // defined(USE_NSS_CERTS) || defined(OS_WIN) || defined(OS_MACOSX) +#endif // defined(PLATFORM_USES_CHROMIUM_EV_METADATA) } // namespace diff --git a/chromium/net/cert/internal/parse_authority_key_identifier_fuzzer.cc b/chromium/net/cert/internal/parse_authority_key_identifier_fuzzer.cc index cb1718673a1..3d3e00ed321 100644 --- a/chromium/net/cert/internal/parse_authority_key_identifier_fuzzer.cc +++ b/chromium/net/cert/internal/parse_authority_key_identifier_fuzzer.cc @@ -5,6 +5,7 @@ #include <stddef.h> #include <stdint.h> +#include "base/macros.h" #include "net/cert/internal/parse_certificate.h" #include "net/der/input.h" diff --git a/chromium/net/cert/internal/parsed_certificate.h b/chromium/net/cert/internal/parsed_certificate.h index c83cebe57c5..a5ad843e001 100644 --- a/chromium/net/cert/internal/parsed_certificate.h +++ b/chromium/net/cert/internal/parsed_certificate.h @@ -9,7 +9,7 @@ #include <memory> #include <vector> -#include "base/logging.h" +#include "base/check.h" #include "base/memory/ref_counted.h" #include "net/base/net_export.h" #include "net/cert/internal/certificate_policies.h" diff --git a/chromium/net/cert/internal/path_builder.cc b/chromium/net/cert/internal/path_builder.cc index ccd89249ab4..568497b7b4a 100644 --- a/chromium/net/cert/internal/path_builder.cc +++ b/chromium/net/cert/internal/path_builder.cc @@ -10,6 +10,7 @@ #include "base/logging.h" #include "base/metrics/histogram_functions.h" +#include "base/notreached.h" #include "base/strings/string_number_conversions.h" #include "crypto/sha2.h" #include "net/base/net_errors.h" diff --git a/chromium/net/cert/internal/path_builder_pkits_unittest.cc b/chromium/net/cert/internal/path_builder_pkits_unittest.cc index dca35a8cb0a..b6daaaf0a17 100644 --- a/chromium/net/cert/internal/path_builder_pkits_unittest.cc +++ b/chromium/net/cert/internal/path_builder_pkits_unittest.cc @@ -114,7 +114,9 @@ class PathBuilderPkitsTestDelegate { public: static void RunTest(std::vector<std::string> cert_ders, std::vector<std::string> crl_ders, - const PkitsTestInfo& info) { + const PkitsTestInfo& orig_info) { + PkitsTestInfo info = orig_info; + ASSERT_FALSE(cert_ders.empty()); ParsedCertificateList certs; for (const std::string& der : cert_ders) { @@ -139,28 +141,71 @@ class PathBuilderPkitsTestDelegate { scoped_refptr<ParsedCertificate> target_cert(certs.back()); + base::Time verify_time; + ASSERT_TRUE(der::GeneralizedTimeToTime(info.time, &verify_time)); + CrlCheckingPathBuilderDelegate path_builder_delegate( + crl_ders, verify_time, /*max_age=*/base::TimeDelta::FromDays(365 * 2), + 1024, SimplePathBuilderDelegate::DigestPolicy::kWeakAllowSha1); + base::StringPiece test_number = info.test_number; - std::unique_ptr<CertPathBuilderDelegate> path_builder_delegate; if (test_number == "4.4.19" || test_number == "4.5.3" || test_number == "4.5.4" || test_number == "4.5.6") { - // TODO(https://crbug.com/749276): extend CRL support: These tests - // require better CRL issuer cert discovery & path building and/or - // issuingDistributionPoint extension handling. Disable CRL checking for - // them for now. Maybe should just run these with CRL checking enabled - // and expect them to fail? - path_builder_delegate = std::make_unique<SimplePathBuilderDelegate>( - 1024, SimplePathBuilderDelegate::DigestPolicy::kWeakAllowSha1); - } else { - base::Time verify_time; - ASSERT_TRUE(der::GeneralizedTimeToTime(info.time, &verify_time)); - path_builder_delegate = std::make_unique<CrlCheckingPathBuilderDelegate>( - crl_ders, verify_time, /*max_age=*/base::TimeDelta::FromDays(365 * 2), - 1024, SimplePathBuilderDelegate::DigestPolicy::kWeakAllowSha1); + // 4.4.19 - fails since CRL is signed by a certificate that is not part + // of the verified chain, which is not supported. + // 4.5.3 - fails since non-URI distribution point names are not supported + // 4.5.4, 4.5.6 - fails since CRL is signed by a certificate that is not + // part of verified chain, and also non-URI distribution + // point names not supported + info.should_validate = false; + } else if (test_number == "4.14.1" || test_number == "4.14.4" || + test_number == "4.14.5" || test_number == "4.14.7" || + test_number == "4.14.18" || test_number == "4.14.19" || + test_number == "4.14.22" || test_number == "4.14.24" || + test_number == "4.14.25" || test_number == "4.14.28" || + test_number == "4.14.29" || test_number == "4.14.30" || + test_number == "4.14.33") { + // 4.14 tests: + // .1 - fails since non-URI distribution point names not supported + // .2, .3 - fails since non-URI distribution point names not supported + // (but test is expected to fail for other reason) + // .4, .5 - fails since non-URI distribution point names not supported, + // also uses nameRelativeToCRLIssuer which is not supported + // .6 - fails since non-URI distribution point names not supported, also + // uses nameRelativeToCRLIssuer which is not supported (but test is + // expected to fail for other reason) + // .7 - fails since relative distributionPointName not supported + // .8, .9 - fails since relative distributionPointName not supported (but + // test is expected to fail for other reason) + // .10, .11, .12, .13, .14, .27, .35 - PASS + // .15, .16, .17, .20, .21 - fails since onlySomeReasons is not supported + // (but test is expected to fail for other + // reason) + // .18, .19 - fails since onlySomeReasons is not supported + // .22, .24, .25, .28, .29, .30, .33 - fails since indirect CRLs are not + // supported + // .23, .26, .31, .32, .34 - fails since indirect CRLs are not supported + // (but test is expected to fail for other + // reason) + info.should_validate = false; + } else if (test_number == "4.15.1" || test_number == "4.15.5") { + // 4.15 tests: + // .1 - fails due to unhandled critical deltaCRLIndicator extension + // .2, .3, .6, .7, .8, .9, .10 - PASS since expected cert status is + // reflected in base CRL and delta CRL is + // ignored + // .5 - fails, cert status is "on hold" in base CRL but the delta CRL + // which removes the cert from CRL is ignored + info.should_validate = false; + } else if (test_number == "4.15.4") { + // 4.15.4 - Invalid delta-CRL Test4 has the target cert marked revoked in + // a delta-CRL. Since delta-CRLs are not supported, the chain validates + // successfully. + info.should_validate = true; } CertPathBuilder path_builder( - std::move(target_cert), &trust_store, path_builder_delegate.get(), - info.time, KeyPurpose::ANY_EKU, info.initial_explicit_policy, + std::move(target_cert), &trust_store, &path_builder_delegate, info.time, + KeyPurpose::ANY_EKU, info.initial_explicit_policy, info.initial_policy_set, info.initial_policy_mapping_inhibit, info.initial_inhibit_any_policy); path_builder.AddCertIssuerSource(&cert_issuer_source); @@ -228,12 +273,13 @@ INSTANTIATE_TYPED_TEST_SUITE_P(PathBuilder, PkitsTest13NameConstraints, PathBuilderPkitsTestDelegate); INSTANTIATE_TYPED_TEST_SUITE_P(PathBuilder, + PkitsTest14DistributionPoints, + PathBuilderPkitsTestDelegate); +INSTANTIATE_TYPED_TEST_SUITE_P(PathBuilder, + PkitsTest15DeltaCRLs, + PathBuilderPkitsTestDelegate); +INSTANTIATE_TYPED_TEST_SUITE_P(PathBuilder, PkitsTest16PrivateCertificateExtensions, PathBuilderPkitsTestDelegate); -// TODO(https://crbug.com/749276): extend CRL support?: -// PkitsTest14DistributionPoints: indirect CRLs and reason codes are not -// supported. -// PkitsTest15DeltaCRLs: Delta CRLs are not supported. - } // namespace net diff --git a/chromium/net/cert/internal/system_trust_store.cc b/chromium/net/cert/internal/system_trust_store.cc index f3737ebd167..0f0d3332b5a 100644 --- a/chromium/net/cert/internal/system_trust_store.cc +++ b/chromium/net/cert/internal/system_trust_store.cc @@ -19,6 +19,7 @@ #include "base/files/file_path.h" #include "base/files/file_util.h" +#include "base/logging.h" #include "base/no_destructor.h" #include "build/build_config.h" #include "net/cert/internal/cert_errors.h" diff --git a/chromium/net/cert/internal/trust_store_mac_unittest.cc b/chromium/net/cert/internal/trust_store_mac_unittest.cc index dd79ef376b5..7c5ff55227e 100644 --- a/chromium/net/cert/internal/trust_store_mac_unittest.cc +++ b/chromium/net/cert/internal/trust_store_mac_unittest.cc @@ -7,6 +7,7 @@ #include "base/base_paths.h" #include "base/files/file_util.h" #include "base/files/scoped_temp_dir.h" +#include "base/logging.h" #include "base/path_service.h" #include "base/process/launch.h" #include "base/strings/string_split.h" diff --git a/chromium/net/cert/internal/trust_store_nss.cc b/chromium/net/cert/internal/trust_store_nss.cc index e4cf9e3a94a..4b0ba6e5457 100644 --- a/chromium/net/cert/internal/trust_store_nss.cc +++ b/chromium/net/cert/internal/trust_store_nss.cc @@ -7,6 +7,7 @@ #include <cert.h> #include <certdb.h> +#include "base/logging.h" #include "crypto/nss_util.h" #include "net/cert/internal/cert_errors.h" #include "net/cert/internal/parsed_certificate.h" diff --git a/chromium/net/cert/known_roots_mac.cc b/chromium/net/cert/known_roots_mac.cc index 72ed07f027a..dfcaecd73d3 100644 --- a/chromium/net/cert/known_roots_mac.cc +++ b/chromium/net/cert/known_roots_mac.cc @@ -10,6 +10,7 @@ #include <vector> #include "base/lazy_instance.h" +#include "base/logging.h" #include "crypto/mac_security_services_lock.h" #include "net/cert/x509_util_mac.h" diff --git a/chromium/net/cert/multi_threaded_cert_verifier.cc b/chromium/net/cert/multi_threaded_cert_verifier.cc index 8b0ff51d732..f2546d9187d 100644 --- a/chromium/net/cert/multi_threaded_cert_verifier.cc +++ b/chromium/net/cert/multi_threaded_cert_verifier.cc @@ -22,6 +22,10 @@ #include "net/log/net_log_source_type.h" #include "net/log/net_log_with_source.h" +#if defined(USE_NSS_CERTS) +#include "net/cert/x509_util_nss.h" +#endif + namespace net { // Allows DoVerifyOnWorkerThread to wait on a base::WaitableEvent. @@ -232,6 +236,21 @@ void MultiThreadedCertVerifier::SetConfig(const CertVerifier::Config& config) { << "Attempted to set a CertVerifier::Config with additional trust " "anchors, but |verify_proc_| does not support additional trust " "anchors."; + +// TODO(https://crbug.com/978854): Pass these into the actual CertVerifyProc +// rather than relying on global side-effects. +#if !defined(USE_NSS_CERTS) + // Not yet implemented. + DCHECK(config.additional_untrusted_authorities.empty()); +#else + for (const auto& cert : config.additional_untrusted_authorities) { + ScopedCERTCertificate x509_cert = + x509_util::CreateCERTCertificateFromX509Certificate(cert.get()); + DCHECK(x509_cert); + temp_certs_.push_back(std::move(x509_cert)); + } +#endif + config_ = config; if (!config_.crl_set) config_.crl_set = CRLSet::BuiltinCRLSet(); diff --git a/chromium/net/cert/multi_threaded_cert_verifier.h b/chromium/net/cert/multi_threaded_cert_verifier.h index ef8225bc878..82b750a42f8 100644 --- a/chromium/net/cert/multi_threaded_cert_verifier.h +++ b/chromium/net/cert/multi_threaded_cert_verifier.h @@ -18,6 +18,10 @@ #include "net/base/net_export.h" #include "net/cert/cert_verifier.h" +#if defined(USE_NSS_CERTS) +#include "net/cert/scoped_nss_types.h" +#endif + namespace net { class CertVerifyProc; @@ -48,6 +52,14 @@ class NET_EXPORT_PRIVATE MultiThreadedCertVerifier : public CertVerifier { base::LinkedList<InternalRequest> request_list_; +#if defined(USE_NSS_CERTS) + // Holds NSS temporary certificates that will be exposed as untrusted + // authorities by SystemCertStoreNSS. + // TODO(https://crbug.com/978854): Pass these into the actual CertVerifyProc + // rather than relying on global side-effects. + net::ScopedCERTCertificateList temp_certs_; +#endif + THREAD_CHECKER(thread_checker_); DISALLOW_COPY_AND_ASSIGN(MultiThreadedCertVerifier); diff --git a/chromium/net/cert/test_keychain_search_list_mac.h b/chromium/net/cert/test_keychain_search_list_mac.h index 4ae25729c93..48edf89d979 100644 --- a/chromium/net/cert/test_keychain_search_list_mac.h +++ b/chromium/net/cert/test_keychain_search_list_mac.h @@ -5,6 +5,8 @@ #ifndef NET_CERT_TEST_KEYCHAIN_SEARCH_LIST_MAC_H_ #define NET_CERT_TEST_KEYCHAIN_SEARCH_LIST_MAC_H_ +#include <memory> + #include <CoreServices/CoreServices.h> #include <Security/Security.h> diff --git a/chromium/net/cert/test_root_certs.h b/chromium/net/cert/test_root_certs.h index c0be7b78328..756379fb9b7 100644 --- a/chromium/net/cert/test_root_certs.h +++ b/chromium/net/cert/test_root_certs.h @@ -12,11 +12,7 @@ #include "net/base/net_export.h" #include "net/cert/internal/trust_store_in_memory.h" -#if defined(USE_NSS_CERTS) -#include <cert.h> -#include <vector> -#include "net/cert/scoped_nss_types.h" -#elif defined(OS_WIN) +#if defined(OS_WIN) #include <windows.h> #include "base/win/wincrypt_shim.h" #elif defined(OS_MACOSX) @@ -62,10 +58,7 @@ class NET_EXPORT TestRootCerts { // Returns true if there are no certificates that have been marked trusted. bool IsEmpty() const; -#if defined(USE_NSS_CERTS) - bool Contains(CERTCertificate* cert) const; - TrustStore* test_trust_store() { return &test_trust_store_; } -#elif defined(OS_MACOSX) +#if defined(OS_MACOSX) CFArrayRef temporary_roots() const { return temporary_roots_; } // Modifies the root certificates of |trust_ref| to include the @@ -82,7 +75,7 @@ class NET_EXPORT TestRootCerts { // engine is appropriate. The caller is responsible for freeing the // returned HCERTCHAINENGINE. HCERTCHAINENGINE GetChainEngine() const; -#elif defined(OS_FUCHSIA) +#elif defined(OS_FUCHSIA) || defined(OS_LINUX) || defined(OS_CHROMEOS) TrustStore* test_trust_store() { return &test_trust_store_; } #endif @@ -95,46 +88,17 @@ class NET_EXPORT TestRootCerts { // Performs platform-dependent initialization. void Init(); -#if defined(USE_NSS_CERTS) - // TrustEntry is used to store the original CERTCertificate and CERTCertTrust - // for a certificate whose trust status has been changed by the - // TestRootCerts. - class TrustEntry { - public: - // Creates a new TrustEntry by incrementing the reference to |certificate| - // and copying |trust|. - TrustEntry(ScopedCERTCertificate certificate, const CERTCertTrust& trust); - ~TrustEntry(); - - CERTCertificate* certificate() const { return certificate_.get(); } - const CERTCertTrust& trust() const { return trust_; } - - private: - // The temporary root certificate. - ScopedCERTCertificate certificate_; - - // The original trust settings, before |certificate_| was manipulated to - // be a temporarily trusted root. - CERTCertTrust trust_; - - DISALLOW_COPY_AND_ASSIGN(TrustEntry); - }; - - // It is necessary to maintain a cache of the original certificate trust - // settings, in order to restore them when Clear() is called. - std::vector<std::unique_ptr<TrustEntry>> trust_cache_; - - TrustStoreInMemory test_trust_store_; -#elif defined(OS_WIN) +#if defined(OS_WIN) HCERTSTORE temporary_roots_; #elif defined(OS_MACOSX) base::ScopedCFTypeRef<CFMutableArrayRef> temporary_roots_; TrustStoreInMemory test_trust_store_; -#elif defined(OS_FUCHSIA) +#elif defined(OS_FUCHSIA) || defined(OS_LINUX) || defined(OS_CHROMEOS) TrustStoreInMemory test_trust_store_; #endif -#if defined(OS_WIN) || defined(OS_ANDROID) || defined(OS_FUCHSIA) +#if defined(OS_WIN) || defined(OS_ANDROID) || defined(OS_FUCHSIA) || \ + defined(OS_LINUX) || defined(OS_CHROMEOS) // True if there are no temporarily trusted root certificates. bool empty_ = true; #endif diff --git a/chromium/net/cert/test_root_certs_fuchsia.cc b/chromium/net/cert/test_root_certs_builtin.cc index 3bf05c8f34b..3bf05c8f34b 100644 --- a/chromium/net/cert/test_root_certs_fuchsia.cc +++ b/chromium/net/cert/test_root_certs_builtin.cc diff --git a/chromium/net/cert/test_root_certs_nss.cc b/chromium/net/cert/test_root_certs_nss.cc deleted file mode 100644 index a04885edbb8..00000000000 --- a/chromium/net/cert/test_root_certs_nss.cc +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/cert/test_root_certs.h" - -#include <cert.h> - -#include "base/logging.h" -#include "base/macros.h" -#include "crypto/nss_util.h" -#include "net/cert/internal/cert_errors.h" -#include "net/cert/x509_certificate.h" -#include "net/cert/x509_util.h" -#include "net/cert/x509_util_nss.h" -#include "third_party/boringssl/src/include/openssl/pool.h" - -namespace net { - -TestRootCerts::TrustEntry::TrustEntry(ScopedCERTCertificate certificate, - const CERTCertTrust& trust) - : certificate_(std::move(certificate)), trust_(trust) {} - -TestRootCerts::TrustEntry::~TrustEntry() = default; - -bool TestRootCerts::Add(X509Certificate* certificate) { - ScopedCERTCertificate cert_handle = - x509_util::CreateCERTCertificateFromX509Certificate(certificate); - if (!cert_handle) - return false; - // Preserve the original trust bits so that they can be restored when - // the certificate is removed. - CERTCertTrust original_trust; - SECStatus rv = CERT_GetCertTrust(cert_handle.get(), &original_trust); - if (rv != SECSuccess) { - // CERT_GetCertTrust will fail if the certificate does not have any - // particular trust settings associated with it, and attempts to use - // |original_trust| later to restore the original trust settings will not - // cause the trust settings to be revoked. If the certificate has no - // particular trust settings associated with it, mark the certificate as - // a valid CA certificate with no specific trust. - rv = CERT_DecodeTrustString(&original_trust, "c,c,c"); - } - - // Change the trust bits to unconditionally trust this certificate. - CERTCertTrust new_trust; - rv = CERT_DecodeTrustString(&new_trust, "TCPu,Cu,Tu"); - if (rv != SECSuccess) { - LOG(ERROR) << "Cannot decode certificate trust string."; - return false; - } - - rv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), cert_handle.get(), - &new_trust); - if (rv != SECSuccess) { - LOG(ERROR) << "Cannot change certificate trust."; - return false; - } - - trust_cache_.push_back( - std::make_unique<TrustEntry>(std::move(cert_handle), original_trust)); - - // Add the certificate to the parallel |test_trust_store_|. TrustStoreNSS - // ignores temporary certs, so it won't see the cert that was added above. - // (See https://crbug.com/951166) - // TODO(https://crbug.com/951479): remove this when the istemp check is - // removed from TrustStoreNSS. - CertErrors errors; - scoped_refptr<ParsedCertificate> parsed = ParsedCertificate::Create( - bssl::UpRef(certificate->cert_buffer()), - x509_util::DefaultParseCertificateOptions(), &errors); - if (!parsed) - return false; - test_trust_store_.AddTrustAnchor(parsed); - - return true; -} - -void TestRootCerts::Clear() { - // Restore the certificate trusts to what they were originally, before - // Add() was called. Work from the rear first, since if a certificate was - // added twice, the second entry's original trust status will be that of - // the first entry, while the first entry contains the desired resultant - // status. - for (auto it = trust_cache_.rbegin(); it != trust_cache_.rend(); ++it) { - CERTCertTrust original_trust = (*it)->trust(); - SECStatus rv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), - (*it)->certificate(), - &original_trust); - // DCHECK(), rather than LOG(), as a failure to restore the original - // trust can cause flake or hard-to-trace errors in any unit tests that - // occur after Clear() has been called. - DCHECK_EQ(SECSuccess, rv) << "Cannot restore certificate trust."; - } - trust_cache_.clear(); - - test_trust_store_.Clear(); -} - -bool TestRootCerts::IsEmpty() const { - return trust_cache_.empty(); -} - -bool TestRootCerts::Contains(CERTCertificate* cert) const { - for (const auto& item : trust_cache_) - if (x509_util::IsSameCertificate(cert, item->certificate())) - return true; - - return false; -} - -TestRootCerts::~TestRootCerts() { - Clear(); -} - -void TestRootCerts::Init() { - crypto::EnsureNSSInit(); -} - -} // namespace net diff --git a/chromium/net/cert/test_root_certs_unittest.cc b/chromium/net/cert/test_root_certs_unittest.cc index f65174ddf68..983c88c3b80 100644 --- a/chromium/net/cert/test_root_certs_unittest.cc +++ b/chromium/net/cert/test_root_certs_unittest.cc @@ -21,12 +21,6 @@ #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" -#if defined(USE_NSS_CERTS) -#include <nss.h> - -#include "net/cert/x509_util_nss.h" -#endif - using net::test::IsOk; namespace net { @@ -147,45 +141,6 @@ TEST(TestRootCertsTest, OverrideTrust) { EXPECT_EQ(bad_verify_result.cert_status, restored_verify_result.cert_status); } -#if defined(USE_NSS_CERTS) -TEST(TestRootCertsTest, Contains) { - // Another test root certificate. - const char kRootCertificateFile2[] = "2048-rsa-root.pem"; - - TestRootCerts* test_roots = TestRootCerts::GetInstance(); - ASSERT_TRUE(test_roots); - - scoped_refptr<X509Certificate> root_cert_1 = - ImportCertFromFile(GetTestCertsDirectory(), kRootCertificateFile); - ASSERT_TRUE(root_cert_1); - ScopedCERTCertificate nss_root_cert_1 = - x509_util::CreateCERTCertificateFromX509Certificate(root_cert_1.get()); - ASSERT_TRUE(nss_root_cert_1); - - scoped_refptr<X509Certificate> root_cert_2 = - ImportCertFromFile(GetTestCertsDirectory(), kRootCertificateFile2); - ASSERT_TRUE(root_cert_2); - ScopedCERTCertificate nss_root_cert_2 = - x509_util::CreateCERTCertificateFromX509Certificate(root_cert_2.get()); - ASSERT_TRUE(nss_root_cert_2); - - EXPECT_FALSE(test_roots->Contains(nss_root_cert_1.get())); - EXPECT_FALSE(test_roots->Contains(nss_root_cert_2.get())); - - EXPECT_TRUE(test_roots->Add(root_cert_1.get())); - EXPECT_TRUE(test_roots->Contains(nss_root_cert_1.get())); - EXPECT_FALSE(test_roots->Contains(nss_root_cert_2.get())); - - EXPECT_TRUE(test_roots->Add(root_cert_2.get())); - EXPECT_TRUE(test_roots->Contains(nss_root_cert_1.get())); - EXPECT_TRUE(test_roots->Contains(nss_root_cert_2.get())); - - test_roots->Clear(); - EXPECT_FALSE(test_roots->Contains(nss_root_cert_1.get())); - EXPECT_FALSE(test_roots->Contains(nss_root_cert_2.get())); -} -#endif - // TODO(rsleevi): Add tests for revocation checking via CRLs, ensuring that // TestRootCerts properly injects itself into the validation process. See // http://crbug.com/63958 diff --git a/chromium/net/cert/x509_cert_types.h b/chromium/net/cert/x509_cert_types.h index 3317d93adfe..b5c42777309 100644 --- a/chromium/net/cert/x509_cert_types.h +++ b/chromium/net/cert/x509_cert_types.h @@ -13,7 +13,6 @@ #include <string> #include <vector> -#include "base/logging.h" #include "base/strings/string_piece.h" #include "build/build_config.h" #include "net/base/hash_value.h" diff --git a/chromium/net/cert/x509_util.cc b/chromium/net/cert/x509_util.cc index 90b848da6ab..4ebef1754b0 100644 --- a/chromium/net/cert/x509_util.cc +++ b/chromium/net/cert/x509_util.cc @@ -10,6 +10,7 @@ #include "base/lazy_instance.h" #include "base/logging.h" +#include "base/notreached.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" #include "base/time/time.h" diff --git a/chromium/net/cert/x509_util_ios_and_mac.cc b/chromium/net/cert/x509_util_ios_and_mac.cc index 8e41cd87cd0..4d503de1414 100644 --- a/chromium/net/cert/x509_util_ios_and_mac.cc +++ b/chromium/net/cert/x509_util_ios_and_mac.cc @@ -4,6 +4,7 @@ #include "net/cert/x509_util_ios_and_mac.h" +#include "base/logging.h" #include "net/cert/x509_certificate.h" #if defined(OS_IOS) #include "net/cert/x509_util_ios.h" diff --git a/chromium/net/cookies/canonical_cookie.cc b/chromium/net/cookies/canonical_cookie.cc index e87937435d9..68fa41779bb 100644 --- a/chromium/net/cookies/canonical_cookie.cc +++ b/chromium/net/cookies/canonical_cookie.cc @@ -105,16 +105,6 @@ void AppendCookieLineEntry(const CanonicalCookie& cookie, *cookie_line += cookie.Value(); } -uint32_t GetExclusionBitmask( - CanonicalCookie::CookieInclusionStatus::ExclusionReason reason) { - return 1u << static_cast<uint32_t>(reason); -} - -uint32_t GetWarningBitmask( - CanonicalCookie::CookieInclusionStatus::WarningReason reason) { - return 1u << static_cast<uint32_t>(reason); -} - // Captures Strict -> Lax context downgrade with Strict cookie bool IsBreakingStrictToLaxDowngrade( CookieOptions::SameSiteCookieContext::ContextType context, @@ -198,13 +188,13 @@ void ApplySameSiteCookieWarningToStatus( CookieEffectiveSameSite effective_samesite, bool is_secure, CookieOptions::SameSiteCookieContext same_site_context, - CanonicalCookie::CookieInclusionStatus* status, + CookieInclusionStatus* status, bool is_cookie_being_set) { if (samesite == CookieSameSite::UNSPECIFIED && same_site_context.GetContextForCookieInclusion() < CookieOptions::SameSiteCookieContext::ContextType::SAME_SITE_LAX) { - status->AddWarningReason(CanonicalCookie::CookieInclusionStatus:: - WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT); + status->AddWarningReason( + CookieInclusionStatus::WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT); } if (effective_samesite == CookieEffectiveSameSite::LAX_MODE_ALLOW_UNSAFE && same_site_context.GetContextForCookieInclusion() == @@ -213,14 +203,13 @@ void ApplySameSiteCookieWarningToStatus( // This warning is more specific so remove the previous, more general, // warning. status->RemoveWarningReason( - CanonicalCookie::CookieInclusionStatus:: - WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT); - status->AddWarningReason(CanonicalCookie::CookieInclusionStatus:: - WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE); + CookieInclusionStatus::WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT); + status->AddWarningReason( + CookieInclusionStatus::WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE); } if (samesite == CookieSameSite::NO_RESTRICTION && !is_secure) { status->AddWarningReason( - CanonicalCookie::CookieInclusionStatus::WARN_SAMESITE_NONE_INSECURE); + CookieInclusionStatus::WARN_SAMESITE_NONE_INSECURE); } // Add a warning if the cookie would be accessible in @@ -229,19 +218,19 @@ void ApplySameSiteCookieWarningToStatus( if (IsBreakingStrictToLaxDowngrade(same_site_context.context(), same_site_context.schemeful_context(), effective_samesite, is_cookie_being_set)) { - status->AddWarningReason(CanonicalCookie::CookieInclusionStatus:: - WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE); + status->AddWarningReason( + CookieInclusionStatus::WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE); } else if (IsBreakingStrictToCrossDowngrade( same_site_context.context(), same_site_context.schemeful_context(), effective_samesite)) { // Which warning to apply depends on the SameSite value. if (effective_samesite == CookieEffectiveSameSite::STRICT_MODE) { - status->AddWarningReason(CanonicalCookie::CookieInclusionStatus:: - WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE); + status->AddWarningReason( + CookieInclusionStatus::WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE); } else { // LAX_MODE or LAX_MODE_ALLOW_UNSAFE. - status->AddWarningReason(CanonicalCookie::CookieInclusionStatus:: - WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE); + status->AddWarningReason( + CookieInclusionStatus::WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE); } } else if (IsBreakingLaxToCrossDowngrade( @@ -250,13 +239,13 @@ void ApplySameSiteCookieWarningToStatus( is_cookie_being_set)) { // Which warning to apply depends on the SameSite value. if (effective_samesite == CookieEffectiveSameSite::STRICT_MODE) { - status->AddWarningReason(CanonicalCookie::CookieInclusionStatus:: - WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE); + status->AddWarningReason( + CookieInclusionStatus::WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE); } else { // LAX_MODE or LAX_MODE_ALLOW_UNSAFE. // This warning applies to both set/send. - status->AddWarningReason(CanonicalCookie::CookieInclusionStatus:: - WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE); + status->AddWarningReason( + CookieInclusionStatus::WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE); } } @@ -581,11 +570,10 @@ bool CanonicalCookie::IsDomainMatch(const std::string& host) const { return cookie_util::IsDomainMatch(domain_, host); } -CanonicalCookie::CookieInclusionStatus CanonicalCookie::IncludeForRequestURL( +CookieAccessResult CanonicalCookie::IncludeForRequestURL( const GURL& url, const CookieOptions& options, CookieAccessSemantics access_semantics) const { - base::TimeDelta cookie_age = base::Time::Now() - CreationDate(); CookieInclusionStatus status; // Filter out HttpOnly cookies, per options. if (options.exclude_httponly() && IsHttpOnly()) @@ -627,17 +615,6 @@ CanonicalCookie::CookieInclusionStatus CanonicalCookie::IncludeForRequestURL( case CookieEffectiveSameSite::LAX_MODE: if (options.same_site_cookie_context().GetContextForCookieInclusion() < CookieOptions::SameSiteCookieContext::ContextType::SAME_SITE_LAX) { - // Log metrics for a cookie that would have been included under the - // "Lax-allow-unsafe" intervention, had it been new enough. - if (SameSite() == CookieSameSite::UNSPECIFIED && - options.same_site_cookie_context().GetContextForCookieInclusion() == - CookieOptions::SameSiteCookieContext::ContextType:: - SAME_SITE_LAX_METHOD_UNSAFE) { - UMA_HISTOGRAM_CUSTOM_TIMES( - "Cookie.SameSiteUnspecifiedTooOldToAllowUnsafe", cookie_age, - base::TimeDelta::FromMinutes(1), base::TimeDelta::FromDays(5), - 100); - } status.AddExclusionReason( (SameSite() == CookieSameSite::UNSPECIFIED) ? CookieInclusionStatus:: @@ -654,15 +631,6 @@ CanonicalCookie::CookieInclusionStatus CanonicalCookie::IncludeForRequestURL( // TODO(chlily): Do we need a separate CookieInclusionStatus for this? status.AddExclusionReason( CookieInclusionStatus::EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX); - } else if (options.same_site_cookie_context() - .GetContextForCookieInclusion() == - CookieOptions::SameSiteCookieContext::ContextType:: - SAME_SITE_LAX_METHOD_UNSAFE) { - // Log metrics for cookies that activate the "Lax-allow-unsafe" - // intervention. This histogram macro allows up to 3 minutes, which is - // enough for the current threshold of 2 minutes. - UMA_HISTOGRAM_MEDIUM_TIMES("Cookie.LaxAllowUnsafeCookieIncludedAge", - cookie_age); } break; default: @@ -700,10 +668,10 @@ CanonicalCookie::CookieInclusionStatus CanonicalCookie::IncludeForRequestURL( } // TODO(chlily): Log metrics. - return status; + return CookieAccessResult(effective_same_site, status); } -CanonicalCookie::CookieInclusionStatus CanonicalCookie::IsSetPermittedInContext( +CookieInclusionStatus CanonicalCookie::IsSetPermittedInContext( const CookieOptions& options, CookieAccessSemantics access_semantics) const { CookieInclusionStatus status; @@ -730,7 +698,7 @@ void CanonicalCookie::IsSetPermittedInContext( DVLOG(net::cookie_util::kVlogSetCookies) << "SetCookie() rejecting insecure cookie with SameSite=None."; status->AddExclusionReason( - CanonicalCookie::CookieInclusionStatus::EXCLUDE_SAMESITE_NONE_INSECURE); + CookieInclusionStatus::EXCLUDE_SAMESITE_NONE_INSECURE); } // Log whether a SameSite=None cookie is Secure or not. if (SameSite() == CookieSameSite::NO_RESTRICTION) { @@ -867,10 +835,10 @@ std::string CanonicalCookie::BuildCookieLine(const CookieList& cookies) { // static std::string CanonicalCookie::BuildCookieLine( - const CookieStatusList& cookie_status_list) { + const CookieAccessResultList& cookie_access_result_list) { std::string cookie_line; - for (const auto& cookie_with_status : cookie_status_list) { - const CanonicalCookie& cookie = cookie_with_status.cookie; + for (const auto& cookie_with_access_result : cookie_access_result_list) { + const CanonicalCookie& cookie = cookie_with_access_result.cookie; AppendCookieLineEntry(cookie, &cookie_line); } return cookie_line; @@ -973,289 +941,12 @@ bool CanonicalCookie::IsRecentlyCreated(base::TimeDelta age_threshold) const { return (base::Time::Now() - creation_date_) <= age_threshold; } -CanonicalCookie::CookieInclusionStatus::CookieInclusionStatus() - : exclusion_reasons_(0u), warning_reasons_(0u) {} - -CanonicalCookie::CookieInclusionStatus::CookieInclusionStatus( - ExclusionReason reason) - : exclusion_reasons_(GetExclusionBitmask(reason)) {} - -CanonicalCookie::CookieInclusionStatus::CookieInclusionStatus( - ExclusionReason reason, - WarningReason warning) - : exclusion_reasons_(GetExclusionBitmask(reason)), - warning_reasons_(GetWarningBitmask(warning)) {} - -bool CanonicalCookie::CookieInclusionStatus::operator==( - const CookieInclusionStatus& other) const { - return exclusion_reasons_ == other.exclusion_reasons_ && - warning_reasons_ == other.warning_reasons_; -} - -bool CanonicalCookie::CookieInclusionStatus::operator!=( - const CookieInclusionStatus& other) const { - return !operator==(other); -} - -bool CanonicalCookie::CookieInclusionStatus::IsInclude() const { - return exclusion_reasons_ == 0u; -} - -bool CanonicalCookie::CookieInclusionStatus::HasExclusionReason( - ExclusionReason reason) const { - return exclusion_reasons_ & GetExclusionBitmask(reason); -} - -void CanonicalCookie::CookieInclusionStatus::AddExclusionReason( - ExclusionReason reason) { - exclusion_reasons_ |= GetExclusionBitmask(reason); - // If the cookie would be excluded for reasons other than the new SameSite - // rules, don't bother warning about it. - MaybeClearSameSiteWarning(); -} - -void CanonicalCookie::CookieInclusionStatus::RemoveExclusionReason( - ExclusionReason reason) { - exclusion_reasons_ &= ~(GetExclusionBitmask(reason)); -} - -void CanonicalCookie::CookieInclusionStatus::MaybeClearSameSiteWarning() { - uint32_t samesite_reasons_mask = - GetExclusionBitmask(EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX) | - GetExclusionBitmask(EXCLUDE_SAMESITE_NONE_INSECURE); - if (exclusion_reasons_ & ~samesite_reasons_mask) { - RemoveWarningReason(CanonicalCookie::CookieInclusionStatus:: - WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT); - RemoveWarningReason( - CanonicalCookie::CookieInclusionStatus::WARN_SAMESITE_NONE_INSECURE); - RemoveWarningReason(CanonicalCookie::CookieInclusionStatus:: - WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE); - } - - uint32_t context_reasons_mask = - GetExclusionBitmask(EXCLUDE_SAMESITE_STRICT) | - GetExclusionBitmask(EXCLUDE_SAMESITE_LAX) | - GetExclusionBitmask(EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX); - if (exclusion_reasons_ & ~context_reasons_mask) { - RemoveWarningReason(CanonicalCookie::CookieInclusionStatus:: - WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE); - RemoveWarningReason(CanonicalCookie::CookieInclusionStatus:: - WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE); - RemoveWarningReason(CanonicalCookie::CookieInclusionStatus:: - WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE); - RemoveWarningReason(CanonicalCookie::CookieInclusionStatus:: - WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE); - RemoveWarningReason(CanonicalCookie::CookieInclusionStatus:: - WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE); - } -} - -bool CanonicalCookie::CookieInclusionStatus::ShouldRecordDowngradeMetrics() - const { - uint32_t context_reasons_mask = - GetExclusionBitmask(EXCLUDE_SAMESITE_STRICT) | - GetExclusionBitmask(EXCLUDE_SAMESITE_LAX) | - GetExclusionBitmask(EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX); - - return (exclusion_reasons_ & ~context_reasons_mask) == 0u; -} - -bool CanonicalCookie::CookieInclusionStatus::ShouldWarn() const { - return warning_reasons_ != 0u; -} - -bool CanonicalCookie::CookieInclusionStatus::HasWarningReason( - WarningReason reason) const { - return warning_reasons_ & GetWarningBitmask(reason); -} - -bool net::CanonicalCookie::CookieInclusionStatus::HasDowngradeWarning( - CookieInclusionStatus::WarningReason* reason) const { - if (!ShouldWarn()) - return false; - - const CookieInclusionStatus::WarningReason kDowngradeWarnings[] = { - WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE, - WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE, - WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE, - WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE, - WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE, - }; - - for (auto warning : kDowngradeWarnings) { - if (!HasWarningReason(warning)) - continue; - - if (reason) - *reason = warning; - - return true; - } - - return false; -} - -void CanonicalCookie::CookieInclusionStatus::AddWarningReason( - WarningReason reason) { - warning_reasons_ |= GetWarningBitmask(reason); -} - -void CanonicalCookie::CookieInclusionStatus::RemoveWarningReason( - WarningReason reason) { - warning_reasons_ &= ~(GetWarningBitmask(reason)); -} - -CanonicalCookie::CookieInclusionStatus::ContextDowngradeMetricValues -CanonicalCookie::CookieInclusionStatus::GetBreakingDowngradeMetricsEnumValue( - const GURL& url) const { - bool url_is_secure = url.SchemeIsCryptographic(); - - // Start the |reason| as something other than the downgrade warnings. - WarningReason reason = WarningReason::NUM_WARNING_REASONS; - - // Don't bother checking the return value because the default switch case - // will handle if no reason was found. - HasDowngradeWarning(&reason); - - switch (reason) { - case WarningReason::WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE: - return url_is_secure - ? ContextDowngradeMetricValues::STRICT_LAX_STRICT_SECURE - : ContextDowngradeMetricValues::STRICT_LAX_STRICT_INSECURE; - case WarningReason::WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE: - return url_is_secure - ? ContextDowngradeMetricValues::STRICT_CROSS_STRICT_SECURE - : ContextDowngradeMetricValues::STRICT_CROSS_STRICT_INSECURE; - case WarningReason::WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE: - return url_is_secure - ? ContextDowngradeMetricValues::STRICT_CROSS_LAX_SECURE - : ContextDowngradeMetricValues::STRICT_CROSS_LAX_INSECURE; - case WarningReason::WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE: - return url_is_secure - ? ContextDowngradeMetricValues::LAX_CROSS_STRICT_SECURE - : ContextDowngradeMetricValues::LAX_CROSS_STRICT_INSECURE; - case WarningReason::WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE: - return url_is_secure - ? ContextDowngradeMetricValues::LAX_CROSS_LAX_SECURE - : ContextDowngradeMetricValues::LAX_CROSS_LAX_INSECURE; - default: - return url_is_secure - ? ContextDowngradeMetricValues::NO_DOWNGRADE_SECURE - : ContextDowngradeMetricValues::NO_DOWNGRADE_INSECURE; - } -} - -std::string CanonicalCookie::CookieInclusionStatus::GetDebugString() const { - std::string out; - - // Inclusion/exclusion - if (IsInclude()) - base::StrAppend(&out, {"INCLUDE, "}); - if (HasExclusionReason(EXCLUDE_UNKNOWN_ERROR)) - base::StrAppend(&out, {"EXCLUDE_UNKNOWN_ERROR, "}); - if (HasExclusionReason(EXCLUDE_HTTP_ONLY)) - base::StrAppend(&out, {"EXCLUDE_HTTP_ONLY, "}); - if (HasExclusionReason(EXCLUDE_SECURE_ONLY)) - base::StrAppend(&out, {"EXCLUDE_SECURE_ONLY, "}); - if (HasExclusionReason(EXCLUDE_DOMAIN_MISMATCH)) - base::StrAppend(&out, {"EXCLUDE_DOMAIN_MISMATCH, "}); - if (HasExclusionReason(EXCLUDE_NOT_ON_PATH)) - base::StrAppend(&out, {"EXCLUDE_NOT_ON_PATH, "}); - if (HasExclusionReason(EXCLUDE_SAMESITE_STRICT)) - base::StrAppend(&out, {"EXCLUDE_SAMESITE_STRICT, "}); - if (HasExclusionReason(EXCLUDE_SAMESITE_LAX)) - base::StrAppend(&out, {"EXCLUDE_SAMESITE_LAX, "}); - if (HasExclusionReason(EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX)) - base::StrAppend(&out, {"EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX, "}); - if (HasExclusionReason(EXCLUDE_SAMESITE_NONE_INSECURE)) - base::StrAppend(&out, {"EXCLUDE_SAMESITE_NONE_INSECURE, "}); - if (HasExclusionReason(EXCLUDE_USER_PREFERENCES)) - base::StrAppend(&out, {"EXCLUDE_USER_PREFERENCES, "}); - if (HasExclusionReason(EXCLUDE_FAILURE_TO_STORE)) - base::StrAppend(&out, {"EXCLUDE_FAILURE_TO_STORE, "}); - if (HasExclusionReason(EXCLUDE_NONCOOKIEABLE_SCHEME)) - base::StrAppend(&out, {"EXCLUDE_NONCOOKIEABLE_SCHEME, "}); - if (HasExclusionReason(EXCLUDE_OVERWRITE_SECURE)) - base::StrAppend(&out, {"EXCLUDE_OVERWRITE_SECURE, "}); - if (HasExclusionReason(EXCLUDE_OVERWRITE_HTTP_ONLY)) - base::StrAppend(&out, {"EXCLUDE_OVERWRITE_HTTP_ONLY, "}); - if (HasExclusionReason(EXCLUDE_INVALID_DOMAIN)) - base::StrAppend(&out, {"EXCLUDE_INVALID_DOMAIN, "}); - if (HasExclusionReason(EXCLUDE_INVALID_PREFIX)) - base::StrAppend(&out, {"EXCLUDE_INVALID_PREFIX, "}); - - // Add warning - if (!ShouldWarn()) { - base::StrAppend(&out, {"DO_NOT_WARN"}); - return out; - } - - if (HasWarningReason(WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT)) - base::StrAppend(&out, {"WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT, "}); - if (HasWarningReason(WARN_SAMESITE_NONE_INSECURE)) - base::StrAppend(&out, {"WARN_SAMESITE_NONE_INSECURE, "}); - if (HasWarningReason(WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE)) - base::StrAppend(&out, {"WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE, "}); - if (HasWarningReason(WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE)) - base::StrAppend(&out, {"WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE, "}); - if (HasWarningReason(WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE)) - base::StrAppend(&out, {"WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE, "}); - if (HasWarningReason(WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE)) - base::StrAppend(&out, {"WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE, "}); - if (HasWarningReason(WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE)) - base::StrAppend(&out, {"WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE, "}); - if (HasWarningReason(WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE)) - base::StrAppend(&out, {"WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE, "}); - - // Strip trailing comma and space. - out.erase(out.end() - 2, out.end()); - - return out; -} - -bool CanonicalCookie::CookieInclusionStatus::IsValid() const { - // Bit positions where there should not be any true bits. - uint32_t exclusion_mask = ~0u << static_cast<int>(NUM_EXCLUSION_REASONS); - uint32_t warning_mask = ~0u << static_cast<int>(NUM_WARNING_REASONS); - return (exclusion_mask & exclusion_reasons_) == 0u && - (warning_mask & warning_reasons_) == 0u; -} - -bool CanonicalCookie::CookieInclusionStatus:: - HasExactlyExclusionReasonsForTesting( - std::vector<CanonicalCookie::CookieInclusionStatus::ExclusionReason> - reasons) const { - CookieInclusionStatus expected = MakeFromReasonsForTesting(reasons); - return expected.exclusion_reasons_ == exclusion_reasons_; -} - -bool CanonicalCookie::CookieInclusionStatus::HasExactlyWarningReasonsForTesting( - std::vector<WarningReason> reasons) const { - CookieInclusionStatus expected = MakeFromReasonsForTesting({}, reasons); - return expected.warning_reasons_ == warning_reasons_; -} - -// static -CanonicalCookie::CookieInclusionStatus -CanonicalCookie::CookieInclusionStatus::MakeFromReasonsForTesting( - std::vector<ExclusionReason> reasons, - std::vector<WarningReason> warnings) { - CookieInclusionStatus status; - for (ExclusionReason reason : reasons) { - status.AddExclusionReason(reason); - } - for (WarningReason warning : warnings) { - status.AddWarningReason(warning); - } - return status; -} - CookieAndLineWithStatus::CookieAndLineWithStatus() = default; CookieAndLineWithStatus::CookieAndLineWithStatus( base::Optional<CanonicalCookie> cookie, std::string cookie_string, - CanonicalCookie::CookieInclusionStatus status) + CookieInclusionStatus status) : cookie(std::move(cookie)), cookie_string(std::move(cookie_string)), status(status) {} diff --git a/chromium/net/cookies/canonical_cookie.h b/chromium/net/cookies/canonical_cookie.h index 10b66c661b2..aa538085ac8 100644 --- a/chromium/net/cookies/canonical_cookie.h +++ b/chromium/net/cookies/canonical_cookie.h @@ -14,7 +14,9 @@ #include "base/optional.h" #include "base/time/time.h" #include "net/base/net_export.h" +#include "net/cookies/cookie_access_result.h" #include "net/cookies/cookie_constants.h" +#include "net/cookies/cookie_inclusion_status.h" #include "net/cookies/cookie_options.h" class GURL; @@ -25,15 +27,16 @@ class ParsedCookie; class CanonicalCookie; struct CookieWithStatus; +struct CookieWithAccessResult; struct CookieAndLineWithStatus; using CookieList = std::vector<CanonicalCookie>; using CookieStatusList = std::vector<CookieWithStatus>; using CookieAndLineStatusList = std::vector<CookieAndLineWithStatus>; +using CookieAccessResultList = std::vector<CookieWithAccessResult>; class NET_EXPORT CanonicalCookie { public: - class CookieInclusionStatus; using UniqueCookieKey = std::tuple<std::string, std::string, std::string>; CanonicalCookie(); @@ -228,7 +231,7 @@ class NET_EXPORT CanonicalCookie { // request |url| using the CookieInclusionStatus enum. HTTP only cookies can // be filter by using appropriate cookie |options|. PLEASE NOTE that this // method does not check whether a cookie is expired or not! - CookieInclusionStatus IncludeForRequestURL( + CookieAccessResult IncludeForRequestURL( const GURL& url, const CookieOptions& options, CookieAccessSemantics access_semantics = @@ -294,8 +297,9 @@ class NET_EXPORT CanonicalCookie { // by |cookies|. The string is built in the same order as the given list. static std::string BuildCookieLine(const CookieList& cookies); - // Same as above but takes a CookieStatusList (ignores the statuses). - static std::string BuildCookieLine(const CookieStatusList& cookies); + // Same as above but takes a CookieAccessResultList + // (ignores the access result). + static std::string BuildCookieLine(const CookieAccessResultList& cookies); private: FRIEND_TEST_ALL_PREFIXES(CanonicalCookieTest, TestPrefixHistograms); @@ -358,250 +362,11 @@ class NET_EXPORT CanonicalCookie { CookieSourceScheme source_scheme_; }; -// This class represents if a cookie was included or excluded in a cookie get or -// set operation, and if excluded why. It holds a vector of reasons for -// exclusion, where cookie inclusion is represented by the absence of any -// exclusion reasons. Also marks whether a cookie should be warned about, e.g. -// for deprecation or intervention reasons. -// TODO(chlily): Rename/move this to just net::CookieInclusionStatus. -class NET_EXPORT CanonicalCookie::CookieInclusionStatus { - public: - // Types of reasons why a cookie might be excluded. - // If adding a ExclusionReason, please also update the GetDebugString() - // method. - enum ExclusionReason { - EXCLUDE_UNKNOWN_ERROR = 0, - - EXCLUDE_HTTP_ONLY = 1, - EXCLUDE_SECURE_ONLY = 2, - EXCLUDE_DOMAIN_MISMATCH = 3, - EXCLUDE_NOT_ON_PATH = 4, - EXCLUDE_SAMESITE_STRICT = 5, - EXCLUDE_SAMESITE_LAX = 6, - - // The following two are used for the SameSiteByDefaultCookies experiment, - // where if the SameSite attribute is not specified, it will be treated as - // SameSite=Lax by default. - EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX = 7, - // This is used if SameSite=None is specified, but the cookie is not - // Secure. - EXCLUDE_SAMESITE_NONE_INSECURE = 8, - EXCLUDE_USER_PREFERENCES = 9, - - // Statuses specific to setting cookies - EXCLUDE_FAILURE_TO_STORE = 10, - EXCLUDE_NONCOOKIEABLE_SCHEME = 11, - EXCLUDE_OVERWRITE_SECURE = 12, - EXCLUDE_OVERWRITE_HTTP_ONLY = 13, - EXCLUDE_INVALID_DOMAIN = 14, - EXCLUDE_INVALID_PREFIX = 15, - - // This should be kept last. - NUM_EXCLUSION_REASONS - }; - - // Reason to warn about a cookie. If you add one, please update - // GetDebugString(). - enum WarningReason { - // Of the following 3 SameSite warnings, there will be, at most, a single - // active one. - - // Warn if a cookie with unspecified SameSite attribute is used in a - // cross-site context. - WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT = 0, - // Warn if a cookie with SameSite=None is not Secure. - WARN_SAMESITE_NONE_INSECURE = 1, - // Warn if a cookie with unspecified SameSite attribute is defaulted into - // Lax and is sent on a request with unsafe method, only because it is new - // enough to activate the Lax-allow-unsafe intervention. - WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE = 2, - - // The following warnings indicate that an included cookie with an effective - // SameSite is experiencing a SameSiteCookieContext::|context| -> - // SameSiteCookieContext::|schemeful_context| downgrade that will prevent - // its access schemefully. - // This situation means that a cookie is accessible when the - // SchemefulSameSite feature is disabled but not when it's enabled, - // indicating changed behavior and potential breakage. - // - // For example, a Strict to Lax downgrade for an effective SameSite=Strict - // cookie: - // This cookie would be accessible in the Strict context as its SameSite - // value is Strict. However its context for schemeful same-site becomes Lax. - // A strict cookie cannot be accessed in a Lax context and therefore the - // behavior has changed. - // As a counterexample, a Strict to Lax downgrade for an effective - // SameSite=Lax cookie: A Lax cookie can be accessed in both Strict and Lax - // contexts so there is no behavior change (and we don't warn about it). - // - // The warnings are in the following format: - // WARN_{context}_{schemeful_context}_DOWNGRADE_{samesite_value}_SAMESITE - // - // Of the following 5 SameSite warnings, there will be, at most, a single - // active one. - - // Strict to Lax downgrade for an effective SameSite=Strict cookie. - // This warning is only applicable for cookies being sent because a Strict - // cookie will be set in both Strict and Lax Contexts so the downgrade will - // not affect it. - WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE = 3, - // Strict to Cross-site downgrade for an effective SameSite=Strict cookie. - // This also applies to Strict to Lax Unsafe downgrades due to Lax Unsafe - // behaving like Cross-site. - WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE = 4, - // Strict to Cross-site downgrade for an effective SameSite=Lax cookie. - // This also applies to Strict to Lax Unsafe downgrades due to Lax Unsafe - // behaving like Cross-site. - WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE = 5, - // Lax to Cross-site downgrade for an effective SameSite=Strict cookie. - // This warning is only applicable for cookies being set because a Strict - // cookie will not be sent in a Lax context so the downgrade would not - // affect it. - WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE = 6, - // Lax to Cross-site downgrade for an effective SameSite=Lax cookie. - WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE = 7, - - // This should be kept last. - NUM_WARNING_REASONS - }; - - // These enums encode the context downgrade warnings + the secureness of the - // url sending/setting the cookie. They're used for metrics only. The format - // is {context}_{schemeful_context}_{samesite_value}_{securness}. - // NO_DOWNGRADE_{securness} indicates that a cookie didn't have a breaking - // context downgrade and was A) included B) excluded only due to insufficient - // same-site context. I.e. the cookie wasn't excluded due to other reasons - // such as third-party cookie blocking. Keep this in line with - // SameSiteCookieContextBreakingDowngradeWithSecureness in enums.xml. - enum ContextDowngradeMetricValues { - NO_DOWNGRADE_INSECURE = 0, - NO_DOWNGRADE_SECURE = 1, - - STRICT_LAX_STRICT_INSECURE = 2, - STRICT_CROSS_STRICT_INSECURE = 3, - STRICT_CROSS_LAX_INSECURE = 4, - LAX_CROSS_STRICT_INSECURE = 5, - LAX_CROSS_LAX_INSECURE = 6, - - STRICT_LAX_STRICT_SECURE = 7, - STRICT_CROSS_STRICT_SECURE = 8, - STRICT_CROSS_LAX_SECURE = 9, - LAX_CROSS_STRICT_SECURE = 10, - LAX_CROSS_LAX_SECURE = 11, - - // Keep last. - kMaxValue = LAX_CROSS_LAX_SECURE - }; - // Makes a status that says include and should not warn. - CookieInclusionStatus(); - - // Make a status that contains the given exclusion reason. - explicit CookieInclusionStatus(ExclusionReason reason); - // Makes a status that contains the given exclusion reason and warning. - CookieInclusionStatus(ExclusionReason reason, WarningReason warning); - - bool operator==(const CookieInclusionStatus& other) const; - bool operator!=(const CookieInclusionStatus& other) const; - - // Whether the status is to include the cookie, and has no other reasons for - // exclusion. - bool IsInclude() const; - - // Whether the given reason for exclusion is present. - bool HasExclusionReason(ExclusionReason status_type) const; - - // Add an exclusion reason. - void AddExclusionReason(ExclusionReason status_type); - - // Remove an exclusion reason. - void RemoveExclusionReason(ExclusionReason reason); - - // If the cookie would have been excluded for reasons other than - // SAMESITE_UNSPECIFIED_TREATED_AS_LAX or SAMESITE_NONE_INSECURE, don't bother - // warning about it (clear the warning). - void MaybeClearSameSiteWarning(); - - // Whether to record the breaking downgrade metrics if the cookie is included - // or if it's only excluded because of insufficient same-site context. - bool ShouldRecordDowngradeMetrics() const; - - // Whether the cookie should be warned about. - bool ShouldWarn() const; - - // Whether the given reason for warning is present. - bool HasWarningReason(WarningReason reason) const; - - // Whether a schemeful downgrade warning is present. - // A schemeful downgrade means that an included cookie with an effective - // SameSite is experiencing a SameSiteCookieContext::|context| -> - // SameSiteCookieContext::|schemeful_context| downgrade that will prevent its - // access schemefully. If the function returns true and |reason| is valid then - // |reason| will contain which warning was found. - bool HasDowngradeWarning( - CookieInclusionStatus::WarningReason* reason = nullptr) const; - - // Add an warning reason. - void AddWarningReason(WarningReason reason); - - // Remove an warning reason. - void RemoveWarningReason(WarningReason reason); - - // Used for serialization/deserialization. - uint32_t exclusion_reasons() const { return exclusion_reasons_; } - void set_exclusion_reasons(uint32_t exclusion_reasons) { - exclusion_reasons_ = exclusion_reasons; - } - - uint32_t warning_reasons() const { return warning_reasons_; } - void set_warning_reasons(uint32_t warning_reasons) { - warning_reasons_ = warning_reasons; - } - - ContextDowngradeMetricValues GetBreakingDowngradeMetricsEnumValue( - const GURL& url) const; - - // Get exclusion reason(s) and warning in string format. - std::string GetDebugString() const; - - // Checks that the underlying bit vector representation doesn't contain any - // extraneous bits that are not mapped to any enum values. Does not check - // for reasons which semantically cannot coexist. - bool IsValid() const; - - // Checks whether the exclusion reasons are exactly the set of exclusion - // reasons in the vector. (Ignores warnings.) - bool HasExactlyExclusionReasonsForTesting( - std::vector<ExclusionReason> reasons) const; - - // Checks whether the warning reasons are exactly the set of warning - // reasons in the vector. (Ignores exclusions.) - bool HasExactlyWarningReasonsForTesting( - std::vector<WarningReason> reasons) const; - - // Makes a status that contains the given exclusion reasons and warning. - static CookieInclusionStatus MakeFromReasonsForTesting( - std::vector<ExclusionReason> reasons, - std::vector<WarningReason> warnings = std::vector<WarningReason>()); - - private: - // A bit vector of the applicable exclusion reasons. - uint32_t exclusion_reasons_ = 0u; - - // A bit vector of the applicable warning reasons. - uint32_t warning_reasons_ = 0u; -}; - -NET_EXPORT inline std::ostream& operator<<( - std::ostream& os, - const CanonicalCookie::CookieInclusionStatus status) { - return os << status.GetDebugString(); -} - // These enable us to pass along a list of excluded cookie with the reason they // were excluded struct CookieWithStatus { CanonicalCookie cookie; - CanonicalCookie::CookieInclusionStatus status; + CookieInclusionStatus status; }; // Used to pass excluded cookie information when it's possible that the @@ -610,7 +375,7 @@ struct NET_EXPORT CookieAndLineWithStatus { CookieAndLineWithStatus(); CookieAndLineWithStatus(base::Optional<CanonicalCookie> cookie, std::string cookie_string, - CanonicalCookie::CookieInclusionStatus status); + CookieInclusionStatus status); CookieAndLineWithStatus( const CookieAndLineWithStatus& cookie_and_line_with_status); @@ -624,7 +389,12 @@ struct NET_EXPORT CookieAndLineWithStatus { base::Optional<CanonicalCookie> cookie; std::string cookie_string; - CanonicalCookie::CookieInclusionStatus status; + CookieInclusionStatus status; +}; + +struct CookieWithAccessResult { + CanonicalCookie cookie; + CookieAccessResult access_result; }; } // namespace net diff --git a/chromium/net/cookies/canonical_cookie_unittest.cc b/chromium/net/cookies/canonical_cookie_unittest.cc index 68548deed97..77465c83b92 100644 --- a/chromium/net/cookies/canonical_cookie_unittest.cc +++ b/chromium/net/cookies/canonical_cookie_unittest.cc @@ -125,7 +125,7 @@ TEST(CanonicalCookieTest, Create) { // Test creating secure cookies. Secure scheme is not checked upon creation, // so a URL of any scheme can create a Secure cookie. - CanonicalCookie::CookieInclusionStatus status; + CookieInclusionStatus status; cookie = CanonicalCookie::Create(url, "A=2; Secure", creation_time, server_time, &status); EXPECT_TRUE(cookie->IsSecure()); @@ -218,7 +218,7 @@ TEST(CanonicalCookieTest, CreateHttpOnly) { GURL url("http://www.example.com/test/foo.html"); base::Time now = base::Time::Now(); base::Optional<base::Time> server_time = base::nullopt; - CanonicalCookie::CookieInclusionStatus status; + CookieInclusionStatus status; // An HttpOnly cookie can be created. std::unique_ptr<CanonicalCookie> cookie = @@ -231,13 +231,13 @@ TEST(CanonicalCookieTest, CreateWithInvalidDomain) { GURL url("http://www.example.com/test/foo.html"); base::Time now = base::Time::Now(); base::Optional<base::Time> server_time = base::nullopt; - CanonicalCookie::CookieInclusionStatus status; + CookieInclusionStatus status; std::unique_ptr<CanonicalCookie> cookie = CanonicalCookie::Create( url, "A=2; Domain=wrongdomain.com", now, server_time, &status); EXPECT_EQ(nullptr, cookie.get()); EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus::EXCLUDE_INVALID_DOMAIN})); + {CookieInclusionStatus::EXCLUDE_INVALID_DOMAIN})); } TEST(CanonicalCookieTest, EmptyExpiry) { @@ -656,50 +656,47 @@ TEST(CanonicalCookieTest, IncludeForRequestURL) { std::unique_ptr<CanonicalCookie> cookie( CanonicalCookie::Create(url, "A=2", creation_time, server_time)); - EXPECT_TRUE(cookie->IncludeForRequestURL(url, options).IsInclude()); + EXPECT_TRUE(cookie->IncludeForRequestURL(url, options).status.IsInclude()); EXPECT_TRUE(cookie ->IncludeForRequestURL(GURL("http://www.example.com/foo/bar"), options) - .IsInclude()); + .status.IsInclude()); EXPECT_TRUE(cookie ->IncludeForRequestURL( GURL("https://www.example.com/foo/bar"), options) - .IsInclude()); + .status.IsInclude()); EXPECT_TRUE( cookie->IncludeForRequestURL(GURL("https://sub.example.com"), options) - .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_DOMAIN_MISMATCH})); + .status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_DOMAIN_MISMATCH})); EXPECT_TRUE( cookie->IncludeForRequestURL(GURL("https://sub.www.example.com"), options) - .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_DOMAIN_MISMATCH})); + .status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_DOMAIN_MISMATCH})); // Test that cookie with a cookie path that does not match the url path are // not included. cookie = CanonicalCookie::Create(url, "A=2; Path=/foo/bar", creation_time, server_time); - EXPECT_TRUE( - cookie->IncludeForRequestURL(url, options) - .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus::EXCLUDE_NOT_ON_PATH})); + EXPECT_TRUE(cookie->IncludeForRequestURL(url, options) + .status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_NOT_ON_PATH})); EXPECT_TRUE( cookie ->IncludeForRequestURL( GURL("http://www.example.com/foo/bar/index.html"), options) - .IsInclude()); + .status.IsInclude()); // Test that a secure cookie is not included for a non secure URL. GURL secure_url("https://www.example.com"); cookie = CanonicalCookie::Create(secure_url, "A=2; Secure", creation_time, server_time); EXPECT_TRUE(cookie->IsSecure()); - EXPECT_TRUE(cookie->IncludeForRequestURL(secure_url, options).IsInclude()); EXPECT_TRUE( - cookie->IncludeForRequestURL(url, options) - .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus::EXCLUDE_SECURE_ONLY})); + cookie->IncludeForRequestURL(secure_url, options).status.IsInclude()); + EXPECT_TRUE(cookie->IncludeForRequestURL(url, options) + .status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_SECURE_ONLY})); // Test that http only cookies are only included if the include httponly flag // is set on the cookie options. @@ -707,12 +704,11 @@ TEST(CanonicalCookieTest, IncludeForRequestURL) { cookie = CanonicalCookie::Create(url, "A=2; HttpOnly", creation_time, server_time); EXPECT_TRUE(cookie->IsHttpOnly()); - EXPECT_TRUE(cookie->IncludeForRequestURL(url, options).IsInclude()); + EXPECT_TRUE(cookie->IncludeForRequestURL(url, options).status.IsInclude()); options.set_exclude_httponly(); - EXPECT_TRUE( - cookie->IncludeForRequestURL(url, options) - .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus::EXCLUDE_HTTP_ONLY})); + EXPECT_TRUE(cookie->IncludeForRequestURL(url, options) + .status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_HTTP_ONLY})); } struct IncludeForRequestURLTestCase { @@ -720,7 +716,7 @@ struct IncludeForRequestURLTestCase { CookieSameSite expected_samesite; CookieEffectiveSameSite expected_effective_samesite; CookieOptions::SameSiteCookieContext request_options_samesite_context; - CanonicalCookie::CookieInclusionStatus expected_inclusion_status; + CookieInclusionStatus expected_inclusion_status; base::TimeDelta creation_time_delta = base::TimeDelta(); }; @@ -742,16 +738,16 @@ void VerifyIncludeForRequestURLTestCases( std::unique_ptr<CanonicalCookie> cookie = CanonicalCookie::Create( url, test.cookie_line, creation_time, base::nullopt /* server_time */); EXPECT_EQ(test.expected_samesite, cookie->SameSite()); - EXPECT_EQ(test.expected_effective_samesite, - cookie->GetEffectiveSameSiteForTesting(access_semantics)); CookieOptions request_options; request_options.set_same_site_cookie_context( test.request_options_samesite_context); + net::CookieAccessResult access_result = + cookie->IncludeForRequestURL(url, request_options, access_semantics); - EXPECT_EQ( - test.expected_inclusion_status, - cookie->IncludeForRequestURL(url, request_options, access_semantics)); + EXPECT_EQ(test.expected_inclusion_status, access_result.status); + EXPECT_EQ(test.expected_effective_samesite, + access_result.effective_same_site); } } @@ -770,131 +766,116 @@ TEST(CanonicalCookieTest, IncludeForRequestURLSameSite) { {"Common=1;SameSite=Strict", CookieSameSite::STRICT_MODE, CookieEffectiveSameSite::STRICT_MODE, SameSiteCookieContext(SameSiteCookieContext::ContextType::CROSS_SITE), - CanonicalCookie::CookieInclusionStatus( - CanonicalCookie::CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT)}, + CookieInclusionStatus(CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT)}, {"Common=2;SameSite=Strict", CookieSameSite::STRICT_MODE, CookieEffectiveSameSite::STRICT_MODE, SameSiteCookieContext( SameSiteCookieContext::ContextType::SAME_SITE_LAX_METHOD_UNSAFE), - CanonicalCookie::CookieInclusionStatus( - CanonicalCookie::CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT)}, + CookieInclusionStatus(CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT)}, {"Common=3;SameSite=Strict", CookieSameSite::STRICT_MODE, CookieEffectiveSameSite::STRICT_MODE, SameSiteCookieContext(SameSiteCookieContext::ContextType::SAME_SITE_LAX), - CanonicalCookie::CookieInclusionStatus( - CanonicalCookie::CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT)}, + CookieInclusionStatus(CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT)}, {"Common=4;SameSite=Strict", CookieSameSite::STRICT_MODE, CookieEffectiveSameSite::STRICT_MODE, SameSiteCookieContext( SameSiteCookieContext::ContextType::SAME_SITE_STRICT), - CanonicalCookie::CookieInclusionStatus()}, + CookieInclusionStatus()}, // Strict cookies with downgrade: {"Common=5;SameSite=Strict", CookieSameSite::STRICT_MODE, CookieEffectiveSameSite::STRICT_MODE, SameSiteCookieContext( SameSiteCookieContext::ContextType::SAME_SITE_STRICT, SameSiteCookieContext::ContextType::SAME_SITE_LAX), - CanonicalCookie::CookieInclusionStatus::MakeFromReasonsForTesting( - std::vector< - CanonicalCookie::CookieInclusionStatus::ExclusionReason>(), - {CanonicalCookie::CookieInclusionStatus:: - WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE})}, + CookieInclusionStatus::MakeFromReasonsForTesting( + std::vector<CookieInclusionStatus::ExclusionReason>(), + {CookieInclusionStatus::WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE})}, {"Common=6;SameSite=Strict", CookieSameSite::STRICT_MODE, CookieEffectiveSameSite::STRICT_MODE, SameSiteCookieContext( SameSiteCookieContext::ContextType::SAME_SITE_STRICT, SameSiteCookieContext::ContextType::SAME_SITE_LAX_METHOD_UNSAFE), - CanonicalCookie::CookieInclusionStatus::MakeFromReasonsForTesting( - std::vector< - CanonicalCookie::CookieInclusionStatus::ExclusionReason>(), - {CanonicalCookie::CookieInclusionStatus:: + CookieInclusionStatus::MakeFromReasonsForTesting( + std::vector<CookieInclusionStatus::ExclusionReason>(), + {CookieInclusionStatus:: WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE})}, {"Common=7;SameSite=Strict", CookieSameSite::STRICT_MODE, CookieEffectiveSameSite::STRICT_MODE, SameSiteCookieContext( SameSiteCookieContext::ContextType::SAME_SITE_STRICT, SameSiteCookieContext::ContextType::CROSS_SITE), - CanonicalCookie::CookieInclusionStatus::MakeFromReasonsForTesting( - std::vector< - CanonicalCookie::CookieInclusionStatus::ExclusionReason>(), - {CanonicalCookie::CookieInclusionStatus:: + CookieInclusionStatus::MakeFromReasonsForTesting( + std::vector<CookieInclusionStatus::ExclusionReason>(), + {CookieInclusionStatus:: WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE})}, // Lax cookies: {"Common=8;SameSite=Lax", CookieSameSite::LAX_MODE, CookieEffectiveSameSite::LAX_MODE, SameSiteCookieContext(SameSiteCookieContext::ContextType::CROSS_SITE), - CanonicalCookie::CookieInclusionStatus( - CanonicalCookie::CookieInclusionStatus::EXCLUDE_SAMESITE_LAX)}, + CookieInclusionStatus(CookieInclusionStatus::EXCLUDE_SAMESITE_LAX)}, {"Common=9;SameSite=Lax", CookieSameSite::LAX_MODE, CookieEffectiveSameSite::LAX_MODE, SameSiteCookieContext( SameSiteCookieContext::ContextType::SAME_SITE_LAX_METHOD_UNSAFE), - CanonicalCookie::CookieInclusionStatus( - CanonicalCookie::CookieInclusionStatus::EXCLUDE_SAMESITE_LAX)}, + CookieInclusionStatus(CookieInclusionStatus::EXCLUDE_SAMESITE_LAX)}, {"Common=10;SameSite=Lax", CookieSameSite::LAX_MODE, CookieEffectiveSameSite::LAX_MODE, SameSiteCookieContext(SameSiteCookieContext::ContextType::SAME_SITE_LAX), - CanonicalCookie::CookieInclusionStatus()}, + CookieInclusionStatus()}, {"Common=11;SameSite=Lax", CookieSameSite::LAX_MODE, CookieEffectiveSameSite::LAX_MODE, SameSiteCookieContext( SameSiteCookieContext::ContextType::SAME_SITE_STRICT), - CanonicalCookie::CookieInclusionStatus()}, + CookieInclusionStatus()}, // Lax cookies with downgrade: {"Common=12;SameSite=Lax", CookieSameSite::LAX_MODE, CookieEffectiveSameSite::LAX_MODE, SameSiteCookieContext( SameSiteCookieContext::ContextType::SAME_SITE_STRICT, SameSiteCookieContext::ContextType::SAME_SITE_LAX), - CanonicalCookie::CookieInclusionStatus()}, + CookieInclusionStatus()}, {"Common=13;SameSite=Lax", CookieSameSite::LAX_MODE, CookieEffectiveSameSite::LAX_MODE, SameSiteCookieContext( SameSiteCookieContext::ContextType::SAME_SITE_STRICT, SameSiteCookieContext::ContextType::SAME_SITE_LAX_METHOD_UNSAFE), - CanonicalCookie::CookieInclusionStatus::MakeFromReasonsForTesting( - std::vector< - CanonicalCookie::CookieInclusionStatus::ExclusionReason>(), - {CanonicalCookie::CookieInclusionStatus:: - WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE})}, + CookieInclusionStatus::MakeFromReasonsForTesting( + std::vector<CookieInclusionStatus::ExclusionReason>(), + {CookieInclusionStatus::WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE})}, {"Common=14;SameSite=Lax", CookieSameSite::LAX_MODE, CookieEffectiveSameSite::LAX_MODE, SameSiteCookieContext( SameSiteCookieContext::ContextType::SAME_SITE_STRICT, SameSiteCookieContext::ContextType::CROSS_SITE), - CanonicalCookie::CookieInclusionStatus::MakeFromReasonsForTesting( - std::vector< - CanonicalCookie::CookieInclusionStatus::ExclusionReason>(), - {CanonicalCookie::CookieInclusionStatus:: - WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE})}, + CookieInclusionStatus::MakeFromReasonsForTesting( + std::vector<CookieInclusionStatus::ExclusionReason>(), + {CookieInclusionStatus::WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE})}, {"Common=15;SameSite=Lax", CookieSameSite::LAX_MODE, CookieEffectiveSameSite::LAX_MODE, SameSiteCookieContext(SameSiteCookieContext::ContextType::SAME_SITE_LAX, SameSiteCookieContext::ContextType::CROSS_SITE), - CanonicalCookie::CookieInclusionStatus::MakeFromReasonsForTesting( - std::vector< - CanonicalCookie::CookieInclusionStatus::ExclusionReason>(), - {CanonicalCookie::CookieInclusionStatus:: - WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE})}, + CookieInclusionStatus::MakeFromReasonsForTesting( + std::vector<CookieInclusionStatus::ExclusionReason>(), + {CookieInclusionStatus::WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE})}, // None and Secure cookies: {"Common=16;SameSite=None;Secure", CookieSameSite::NO_RESTRICTION, CookieEffectiveSameSite::NO_RESTRICTION, SameSiteCookieContext(SameSiteCookieContext::ContextType::CROSS_SITE), - CanonicalCookie::CookieInclusionStatus()}, + CookieInclusionStatus()}, {"Common=17;SameSite=None;Secure", CookieSameSite::NO_RESTRICTION, CookieEffectiveSameSite::NO_RESTRICTION, SameSiteCookieContext( SameSiteCookieContext::ContextType::SAME_SITE_LAX_METHOD_UNSAFE), - CanonicalCookie::CookieInclusionStatus()}, + CookieInclusionStatus()}, {"Common=18;SameSite=None;Secure", CookieSameSite::NO_RESTRICTION, CookieEffectiveSameSite::NO_RESTRICTION, SameSiteCookieContext(SameSiteCookieContext::ContextType::SAME_SITE_LAX), - CanonicalCookie::CookieInclusionStatus()}, + CookieInclusionStatus()}, {"Common=19;SameSite=None;Secure", CookieSameSite::NO_RESTRICTION, CookieEffectiveSameSite::NO_RESTRICTION, SameSiteCookieContext( SameSiteCookieContext::ContextType::SAME_SITE_STRICT), - CanonicalCookie::CookieInclusionStatus()}}; + CookieInclusionStatus()}}; // Test cases where the default is None (either access semantics is LEGACY, or // semantics is UNKNOWN and feature is enabled): @@ -903,29 +884,27 @@ TEST(CanonicalCookieTest, IncludeForRequestURLSameSite) { {"DefaultNone=1", CookieSameSite::UNSPECIFIED, CookieEffectiveSameSite::NO_RESTRICTION, SameSiteCookieContext(SameSiteCookieContext::ContextType::CROSS_SITE), - CanonicalCookie::CookieInclusionStatus::MakeFromReasonsForTesting( - std::vector< - CanonicalCookie::CookieInclusionStatus::ExclusionReason>(), - {CanonicalCookie::CookieInclusionStatus:: + CookieInclusionStatus::MakeFromReasonsForTesting( + std::vector<CookieInclusionStatus::ExclusionReason>(), + {CookieInclusionStatus:: WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT})}, {"DefaultNone=2", CookieSameSite::UNSPECIFIED, CookieEffectiveSameSite::NO_RESTRICTION, SameSiteCookieContext( SameSiteCookieContext::ContextType::SAME_SITE_LAX_METHOD_UNSAFE), - CanonicalCookie::CookieInclusionStatus::MakeFromReasonsForTesting( - std::vector< - CanonicalCookie::CookieInclusionStatus::ExclusionReason>(), - {CanonicalCookie::CookieInclusionStatus:: + CookieInclusionStatus::MakeFromReasonsForTesting( + std::vector<CookieInclusionStatus::ExclusionReason>(), + {CookieInclusionStatus:: WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT})}, {"DefaultNone=3", CookieSameSite::UNSPECIFIED, CookieEffectiveSameSite::NO_RESTRICTION, SameSiteCookieContext(SameSiteCookieContext::ContextType::SAME_SITE_LAX), - CanonicalCookie::CookieInclusionStatus()}, + CookieInclusionStatus()}, {"DefaultNone=4", CookieSameSite::UNSPECIFIED, CookieEffectiveSameSite::NO_RESTRICTION, SameSiteCookieContext( SameSiteCookieContext::ContextType::SAME_SITE_STRICT), - CanonicalCookie::CookieInclusionStatus()}}; + CookieInclusionStatus()}}; // Test cases where the default is Lax (either access semantics is NONLEGACY, // or access semantics is UNKNOWN and feature is enabled): @@ -934,60 +913,52 @@ TEST(CanonicalCookieTest, IncludeForRequestURLSameSite) { {"DefaultLax=1", CookieSameSite::UNSPECIFIED, CookieEffectiveSameSite::LAX_MODE_ALLOW_UNSAFE, SameSiteCookieContext(SameSiteCookieContext::ContextType::CROSS_SITE), - CanonicalCookie::CookieInclusionStatus( - CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX, - CanonicalCookie::CookieInclusionStatus:: - WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT), + CookieInclusionStatus( + CookieInclusionStatus::EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX, + CookieInclusionStatus::WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT), kShortAge}, {"DefaultLax=2", CookieSameSite::UNSPECIFIED, CookieEffectiveSameSite::LAX_MODE_ALLOW_UNSAFE, SameSiteCookieContext( SameSiteCookieContext::ContextType::SAME_SITE_LAX_METHOD_UNSAFE), - CanonicalCookie::CookieInclusionStatus::MakeFromReasonsForTesting( - std::vector< - CanonicalCookie::CookieInclusionStatus::ExclusionReason>(), - {CanonicalCookie::CookieInclusionStatus:: - WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE}), + CookieInclusionStatus::MakeFromReasonsForTesting( + std::vector<CookieInclusionStatus::ExclusionReason>(), + {CookieInclusionStatus::WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE}), kShortAge}, {"DefaultLax=3", CookieSameSite::UNSPECIFIED, CookieEffectiveSameSite::LAX_MODE_ALLOW_UNSAFE, SameSiteCookieContext(SameSiteCookieContext::ContextType::SAME_SITE_LAX), - CanonicalCookie::CookieInclusionStatus(), kShortAge}, + CookieInclusionStatus(), kShortAge}, {"DefaultLax=4", CookieSameSite::UNSPECIFIED, CookieEffectiveSameSite::LAX_MODE_ALLOW_UNSAFE, SameSiteCookieContext( SameSiteCookieContext::ContextType::SAME_SITE_STRICT), - CanonicalCookie::CookieInclusionStatus(), kShortAge}, + CookieInclusionStatus(), kShortAge}, // Unspecified not-recently-created cookies (with SameSite-by-default): {"DefaultLax=5", CookieSameSite::UNSPECIFIED, CookieEffectiveSameSite::LAX_MODE, SameSiteCookieContext(SameSiteCookieContext::ContextType::CROSS_SITE), - CanonicalCookie::CookieInclusionStatus( - CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX, - CanonicalCookie::CookieInclusionStatus:: - WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT), + CookieInclusionStatus( + CookieInclusionStatus::EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX, + CookieInclusionStatus::WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT), kLongAge}, {"DefaultLax=6", CookieSameSite::UNSPECIFIED, CookieEffectiveSameSite::LAX_MODE, SameSiteCookieContext( SameSiteCookieContext::ContextType::SAME_SITE_LAX_METHOD_UNSAFE), - CanonicalCookie::CookieInclusionStatus( - CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX, - CanonicalCookie::CookieInclusionStatus:: - WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT), + CookieInclusionStatus( + CookieInclusionStatus::EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX, + CookieInclusionStatus::WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT), kLongAge}, {"DefaultLax=7", CookieSameSite::UNSPECIFIED, CookieEffectiveSameSite::LAX_MODE, SameSiteCookieContext(SameSiteCookieContext::ContextType::SAME_SITE_LAX), - CanonicalCookie::CookieInclusionStatus(), kLongAge}, + CookieInclusionStatus(), kLongAge}, {"DefaultLax=8", CookieSameSite::UNSPECIFIED, CookieEffectiveSameSite::LAX_MODE, SameSiteCookieContext( SameSiteCookieContext::ContextType::SAME_SITE_STRICT), - CanonicalCookie::CookieInclusionStatus(), kLongAge}, + CookieInclusionStatus(), kLongAge}, }; VerifyIncludeForRequestURLTestCases(true, CookieAccessSemantics::UNKNOWN, @@ -1046,19 +1017,18 @@ TEST(CanonicalCookieTest, IncludeCookiesWithoutSameSiteMustBeSecure) { EXPECT_TRUE( cookie ->IncludeForRequestURL(url, options, CookieAccessSemantics::UNKNOWN) - .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_SAMESITE_NONE_INSECURE})); + .status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_SAMESITE_NONE_INSECURE})); EXPECT_TRUE( cookie ->IncludeForRequestURL(url, options, CookieAccessSemantics::LEGACY) - .IsInclude()); - EXPECT_TRUE(cookie - ->IncludeForRequestURL(url, options, - CookieAccessSemantics::NONLEGACY) - .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_SAMESITE_NONE_INSECURE})); + .status.IsInclude()); + EXPECT_TRUE( + cookie + ->IncludeForRequestURL(url, options, + CookieAccessSemantics::NONLEGACY) + .status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_SAMESITE_NONE_INSECURE})); } // Features off: { @@ -1072,17 +1042,17 @@ TEST(CanonicalCookieTest, IncludeCookiesWithoutSameSiteMustBeSecure) { EXPECT_TRUE( cookie ->IncludeForRequestURL(url, options, CookieAccessSemantics::UNKNOWN) - .IsInclude()); + .status.IsInclude()); EXPECT_TRUE( cookie ->IncludeForRequestURL(url, options, CookieAccessSemantics::LEGACY) - .IsInclude()); + .status.IsInclude()); // If the semantics is Nonlegacy, only reject the cookie if the // SameSite=None-must-be-Secure feature is enabled. EXPECT_TRUE(cookie ->IncludeForRequestURL(url, options, CookieAccessSemantics::NONLEGACY) - .IsInclude()); + .status.IsInclude()); } } @@ -1102,35 +1072,32 @@ TEST(CanonicalCookieTest, MultipleExclusionReasons) { "name", "value", "other-domain.com", "/bar", creation_time, base::Time(), base::Time(), true /* secure */, true /* httponly */, CookieSameSite::STRICT_MODE, COOKIE_PRIORITY_DEFAULT); - EXPECT_TRUE( - cookie1.IncludeForRequestURL(url, options) - .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus::EXCLUDE_HTTP_ONLY, - CanonicalCookie::CookieInclusionStatus::EXCLUDE_SECURE_ONLY, - CanonicalCookie::CookieInclusionStatus::EXCLUDE_DOMAIN_MISMATCH, - CanonicalCookie::CookieInclusionStatus::EXCLUDE_NOT_ON_PATH, - CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_SAMESITE_STRICT})); + EXPECT_TRUE(cookie1.IncludeForRequestURL(url, options) + .status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_HTTP_ONLY, + CookieInclusionStatus::EXCLUDE_SECURE_ONLY, + CookieInclusionStatus::EXCLUDE_DOMAIN_MISMATCH, + CookieInclusionStatus::EXCLUDE_NOT_ON_PATH, + CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT})); // Test Create() - CanonicalCookie::CookieInclusionStatus create_status; + CookieInclusionStatus create_status; auto cookie2 = CanonicalCookie::Create( url, "__Secure-notactuallysecure=value;Domain=some-other-domain.com", creation_time, server_time, &create_status); ASSERT_FALSE(cookie2); EXPECT_TRUE(create_status.HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX, - CanonicalCookie::CookieInclusionStatus::EXCLUDE_INVALID_DOMAIN})); + {CookieInclusionStatus::EXCLUDE_INVALID_PREFIX, + CookieInclusionStatus::EXCLUDE_INVALID_DOMAIN})); // Test IsSetPermittedInContext() auto cookie3 = CanonicalCookie::Create( url, "name=value;HttpOnly;SameSite=Lax", creation_time, server_time); ASSERT_TRUE(cookie3); - EXPECT_TRUE( - cookie3->IsSetPermittedInContext(options) - .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus::EXCLUDE_HTTP_ONLY, - CanonicalCookie::CookieInclusionStatus::EXCLUDE_SAMESITE_LAX})); + EXPECT_TRUE(cookie3->IsSetPermittedInContext(options) + .HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_HTTP_ONLY, + CookieInclusionStatus::EXCLUDE_SAMESITE_LAX})); } TEST(CanonicalCookieTest, PartialCompare) { @@ -1166,18 +1133,18 @@ TEST(CanonicalCookieTest, SecureCookiePrefix) { GURL http_url("http://www.example.test"); base::Time creation_time = base::Time::Now(); base::Optional<base::Time> server_time = base::nullopt; - CanonicalCookie::CookieInclusionStatus status; + CookieInclusionStatus status; // A __Secure- cookie must be Secure. EXPECT_FALSE(CanonicalCookie::Create(https_url, "__Secure-A=B", creation_time, server_time, &status)); EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX})); + {CookieInclusionStatus::EXCLUDE_INVALID_PREFIX})); EXPECT_FALSE(CanonicalCookie::Create(https_url, "__Secure-A=B; httponly", creation_time, server_time, &status)); // (EXCLUDE_HTTP_ONLY would be fine, too) EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX})); + {CookieInclusionStatus::EXCLUDE_INVALID_PREFIX})); // A typoed prefix does not have to be Secure. EXPECT_TRUE(CanonicalCookie::Create(https_url, "__secure-A=B; Secure", @@ -1193,7 +1160,7 @@ TEST(CanonicalCookieTest, SecureCookiePrefix) { EXPECT_FALSE(CanonicalCookie::Create(http_url, "__Secure-A=B; Secure", creation_time, server_time, &status)); EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX})); + {CookieInclusionStatus::EXCLUDE_INVALID_PREFIX})); } TEST(CanonicalCookieTest, HostCookiePrefix) { @@ -1202,18 +1169,18 @@ TEST(CanonicalCookieTest, HostCookiePrefix) { base::Time creation_time = base::Time::Now(); base::Optional<base::Time> server_time = base::nullopt; std::string domain = https_url.host(); - CanonicalCookie::CookieInclusionStatus status; + CookieInclusionStatus status; // A __Host- cookie must be Secure. EXPECT_FALSE(CanonicalCookie::Create(https_url, "__Host-A=B;", creation_time, server_time, &status)); EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX})); + {CookieInclusionStatus::EXCLUDE_INVALID_PREFIX})); EXPECT_FALSE(CanonicalCookie::Create( https_url, "__Host-A=B; Domain=" + domain + "; Path=/;", creation_time, server_time, &status)); EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX})); + {CookieInclusionStatus::EXCLUDE_INVALID_PREFIX})); EXPECT_TRUE(CanonicalCookie::Create(https_url, "__Host-A=B; Path=/; Secure;", creation_time, server_time)); @@ -1222,7 +1189,7 @@ TEST(CanonicalCookieTest, HostCookiePrefix) { http_url, "__Host-A=B; Domain=" + domain + "; Path=/; Secure;", creation_time, server_time, &status)); EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX})); + {CookieInclusionStatus::EXCLUDE_INVALID_PREFIX})); EXPECT_TRUE(CanonicalCookie::Create(https_url, "__Host-A=B; Path=/; Secure;", creation_time, server_time)); @@ -1231,12 +1198,12 @@ TEST(CanonicalCookieTest, HostCookiePrefix) { https_url, "__Host-A=B; Domain=" + domain + "; Path=/; Secure;", creation_time, server_time, &status)); EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX})); + {CookieInclusionStatus::EXCLUDE_INVALID_PREFIX})); EXPECT_FALSE(CanonicalCookie::Create( https_url, "__Host-A=B; Domain=" + domain + "; Secure;", creation_time, server_time, &status)); EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX})); + {CookieInclusionStatus::EXCLUDE_INVALID_PREFIX})); // A __Host- cookie may have a domain if it's an IP address that matches the // URL. @@ -1255,11 +1222,11 @@ TEST(CanonicalCookieTest, HostCookiePrefix) { "__Host-A=B; Path=/foo; Secure;", creation_time, server_time, &status)); EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX})); + {CookieInclusionStatus::EXCLUDE_INVALID_PREFIX})); EXPECT_FALSE(CanonicalCookie::Create(https_url, "__Host-A=B; Secure;", creation_time, server_time, &status)); EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX})); + {CookieInclusionStatus::EXCLUDE_INVALID_PREFIX})); EXPECT_TRUE(CanonicalCookie::Create(https_url, "__Host-A=B; Secure; Path=/;", creation_time, server_time)); @@ -2030,10 +1997,9 @@ TEST(CanonicalCookieTest, IsSetPermittedInContext) { EXPECT_TRUE( cookie_httponly.IsSetPermittedInContext(context_network).IsInclude()); - EXPECT_TRUE( - cookie_httponly.IsSetPermittedInContext(context_script) - .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus::EXCLUDE_HTTP_ONLY})); + EXPECT_TRUE(cookie_httponly.IsSetPermittedInContext(context_script) + .HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_HTTP_ONLY})); CookieOptions context_cross_site; CookieOptions context_same_site_lax; @@ -2079,17 +2045,17 @@ TEST(CanonicalCookieTest, IsSetPermittedInContext) { .IsSetPermittedInContext(context_same_site_strict) .IsInclude()); - CanonicalCookie::CookieInclusionStatus status_strict_to_lax = + CookieInclusionStatus status_strict_to_lax = cookie_same_site_unrestricted.IsSetPermittedInContext( context_same_site_strict_to_lax); EXPECT_TRUE(status_strict_to_lax.IsInclude()); EXPECT_FALSE(status_strict_to_lax.HasDowngradeWarning()); - CanonicalCookie::CookieInclusionStatus status_strict_to_cross = + CookieInclusionStatus status_strict_to_cross = cookie_same_site_unrestricted.IsSetPermittedInContext( context_same_site_strict_to_cross); EXPECT_TRUE(status_strict_to_cross.IsInclude()); EXPECT_FALSE(status_strict_to_cross.HasDowngradeWarning()); - CanonicalCookie::CookieInclusionStatus status_lax_to_cross = + CookieInclusionStatus status_lax_to_cross = cookie_same_site_unrestricted.IsSetPermittedInContext( context_same_site_lax_to_cross); EXPECT_TRUE(status_lax_to_cross.IsInclude()); @@ -2104,8 +2070,7 @@ TEST(CanonicalCookieTest, IsSetPermittedInContext) { EXPECT_TRUE(cookie_same_site_lax.IsSetPermittedInContext(context_cross_site) .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_SAMESITE_LAX})); + {CookieInclusionStatus::EXCLUDE_SAMESITE_LAX})); EXPECT_TRUE( cookie_same_site_lax.IsSetPermittedInContext(context_same_site_lax) .IsInclude()); @@ -2113,25 +2078,23 @@ TEST(CanonicalCookieTest, IsSetPermittedInContext) { cookie_same_site_lax.IsSetPermittedInContext(context_same_site_strict) .IsInclude()); - CanonicalCookie::CookieInclusionStatus status_strict_to_lax = + CookieInclusionStatus status_strict_to_lax = cookie_same_site_lax.IsSetPermittedInContext( context_same_site_strict_to_lax); EXPECT_TRUE(status_strict_to_lax.IsInclude()); EXPECT_FALSE(status_strict_to_lax.HasDowngradeWarning()); - CanonicalCookie::CookieInclusionStatus status_strict_to_cross = + CookieInclusionStatus status_strict_to_cross = cookie_same_site_lax.IsSetPermittedInContext( context_same_site_strict_to_cross); EXPECT_TRUE(status_strict_to_cross.IsInclude()); EXPECT_TRUE(status_strict_to_cross.HasWarningReason( - CanonicalCookie::CookieInclusionStatus:: - WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE)); - CanonicalCookie::CookieInclusionStatus status_lax_to_cross = + CookieInclusionStatus::WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE)); + CookieInclusionStatus status_lax_to_cross = cookie_same_site_lax.IsSetPermittedInContext( context_same_site_lax_to_cross); EXPECT_TRUE(status_lax_to_cross.IsInclude()); EXPECT_TRUE(status_lax_to_cross.HasWarningReason( - CanonicalCookie::CookieInclusionStatus:: - WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE)); + CookieInclusionStatus::WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE)); } { @@ -2145,8 +2108,7 @@ TEST(CanonicalCookieTest, IsSetPermittedInContext) { EXPECT_TRUE( cookie_same_site_strict.IsSetPermittedInContext(context_cross_site) .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_SAMESITE_STRICT})); + {CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT})); EXPECT_TRUE( cookie_same_site_strict.IsSetPermittedInContext(context_same_site_lax) .IsInclude()); @@ -2154,25 +2116,23 @@ TEST(CanonicalCookieTest, IsSetPermittedInContext) { .IsSetPermittedInContext(context_same_site_strict) .IsInclude()); - CanonicalCookie::CookieInclusionStatus status_strict_to_lax = + CookieInclusionStatus status_strict_to_lax = cookie_same_site_strict.IsSetPermittedInContext( context_same_site_strict_to_lax); EXPECT_TRUE(status_strict_to_lax.IsInclude()); EXPECT_FALSE(status_strict_to_lax.HasDowngradeWarning()); - CanonicalCookie::CookieInclusionStatus status_strict_to_cross = + CookieInclusionStatus status_strict_to_cross = cookie_same_site_strict.IsSetPermittedInContext( context_same_site_strict_to_cross); EXPECT_TRUE(status_strict_to_cross.IsInclude()); EXPECT_TRUE(status_strict_to_cross.HasWarningReason( - CanonicalCookie::CookieInclusionStatus:: - WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE)); - CanonicalCookie::CookieInclusionStatus status_lax_to_cross = + CookieInclusionStatus::WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE)); + CookieInclusionStatus status_lax_to_cross = cookie_same_site_strict.IsSetPermittedInContext( context_same_site_lax_to_cross); EXPECT_TRUE(status_lax_to_cross.IsInclude()); EXPECT_TRUE(status_lax_to_cross.HasWarningReason( - CanonicalCookie::CookieInclusionStatus:: - WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE)); + CookieInclusionStatus::WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE)); } // Behavior of UNSPECIFIED depends on an experiment and CookieAccessSemantics. @@ -2213,7 +2173,7 @@ TEST(CanonicalCookieTest, IsSetPermittedInContext) { .IsSetPermittedInContext(context_cross_site, CookieAccessSemantics::NONLEGACY) .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: + {CookieInclusionStatus:: EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX})); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_same_site_lax, @@ -2233,7 +2193,7 @@ TEST(CanonicalCookieTest, IsSetPermittedInContext) { .IsSetPermittedInContext(context_cross_site, CookieAccessSemantics::UNKNOWN) .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: + {CookieInclusionStatus:: EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX})); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_same_site_lax, @@ -2259,7 +2219,7 @@ TEST(CanonicalCookieTest, IsSetPermittedInContext) { .IsSetPermittedInContext(context_cross_site, CookieAccessSemantics::NONLEGACY) .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: + {CookieInclusionStatus:: EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX})); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_same_site_lax, @@ -2272,213 +2232,4 @@ TEST(CanonicalCookieTest, IsSetPermittedInContext) { } } -TEST(CookieInclusionStatusTest, IncludeStatus) { - int num_exclusion_reasons = static_cast<int>( - CanonicalCookie::CookieInclusionStatus::NUM_EXCLUSION_REASONS); - int num_warning_reasons = static_cast<int>( - CanonicalCookie::CookieInclusionStatus::NUM_WARNING_REASONS); - // Zero-argument constructor - CanonicalCookie::CookieInclusionStatus status; - EXPECT_TRUE(status.IsValid()); - EXPECT_TRUE(status.IsInclude()); - for (int i = 0; i < num_exclusion_reasons; ++i) { - EXPECT_FALSE(status.HasExclusionReason( - static_cast<CanonicalCookie::CookieInclusionStatus::ExclusionReason>( - i))); - } - for (int i = 0; i < num_warning_reasons; ++i) { - EXPECT_FALSE(status.HasWarningReason( - static_cast<CanonicalCookie::CookieInclusionStatus::WarningReason>(i))); - } - EXPECT_FALSE(status.HasExclusionReason( - CanonicalCookie::CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR)); -} - -TEST(CookieInclusionStatusTest, ExcludeStatus) { - int num_exclusion_reasons = static_cast<int>( - CanonicalCookie::CookieInclusionStatus::NUM_EXCLUSION_REASONS); - for (int i = 0; i < num_exclusion_reasons; ++i) { - auto reason = - static_cast<CanonicalCookie::CookieInclusionStatus::ExclusionReason>(i); - CanonicalCookie::CookieInclusionStatus status(reason); - EXPECT_TRUE(status.IsValid()); - EXPECT_FALSE(status.IsInclude()); - EXPECT_TRUE(status.HasExclusionReason(reason)); - for (int j = 0; j < num_exclusion_reasons; ++j) { - if (i == j) - continue; - EXPECT_FALSE(status.HasExclusionReason( - static_cast<CanonicalCookie::CookieInclusionStatus::ExclusionReason>( - j))); - } - } -} - -TEST(CookieInclusionStatusTest, NotValid) { - CanonicalCookie::CookieInclusionStatus status; - int num_exclusion_reasons = static_cast<int>( - CanonicalCookie::CookieInclusionStatus::NUM_EXCLUSION_REASONS); - int num_warning_reasons = static_cast<int>( - CanonicalCookie::CookieInclusionStatus::NUM_WARNING_REASONS); - status.set_exclusion_reasons(1 << num_exclusion_reasons); - EXPECT_FALSE(status.IsInclude()); - EXPECT_FALSE(status.IsValid()); - - status.set_exclusion_reasons(~0u); - EXPECT_FALSE(status.IsInclude()); - EXPECT_FALSE(status.IsValid()); - - status.set_warning_reasons(1 << num_warning_reasons); - EXPECT_FALSE(status.IsInclude()); - EXPECT_FALSE(status.IsValid()); - - status.set_warning_reasons(~0u); - EXPECT_FALSE(status.IsInclude()); - EXPECT_FALSE(status.IsValid()); - - status.set_exclusion_reasons(1 << num_exclusion_reasons); - status.set_warning_reasons(1 << num_warning_reasons); - EXPECT_FALSE(status.IsInclude()); - EXPECT_FALSE(status.IsValid()); -} - -TEST(CookieInclusionStatusTest, AddExclusionReason) { - CanonicalCookie::CookieInclusionStatus status; - status.AddWarningReason(CanonicalCookie::CookieInclusionStatus:: - WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE); - status.AddExclusionReason( - CanonicalCookie::CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR); - EXPECT_TRUE(status.IsValid()); - EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR})); - // Adding an exclusion reason other than - // EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX or - // EXCLUDE_SAMESITE_NONE_INSECURE should clear any SameSite warning. - EXPECT_FALSE(status.ShouldWarn()); - - status = CanonicalCookie::CookieInclusionStatus(); - status.AddWarningReason(CanonicalCookie::CookieInclusionStatus:: - WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT); - status.AddExclusionReason(CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX); - EXPECT_TRUE(status.IsValid()); - EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX})); - EXPECT_TRUE(status.HasExactlyWarningReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT})); -} - -TEST(CookieInclusionStatusTest, CheckEachWarningReason) { - CanonicalCookie::CookieInclusionStatus status; - - int num_warning_reasons = static_cast<int>( - CanonicalCookie::CookieInclusionStatus::NUM_WARNING_REASONS); - EXPECT_FALSE(status.ShouldWarn()); - for (int i = 0; i < num_warning_reasons; ++i) { - auto reason = - static_cast<CanonicalCookie::CookieInclusionStatus::WarningReason>(i); - status.AddWarningReason(reason); - EXPECT_TRUE(status.IsValid()); - EXPECT_TRUE(status.IsInclude()); - EXPECT_TRUE(status.ShouldWarn()); - EXPECT_TRUE(status.HasWarningReason(reason)); - for (int j = 0; j < num_warning_reasons; ++j) { - if (i == j) - continue; - EXPECT_FALSE(status.HasWarningReason( - static_cast<CanonicalCookie::CookieInclusionStatus::WarningReason>( - j))); - } - status.RemoveWarningReason(reason); - EXPECT_FALSE(status.ShouldWarn()); - } -} - -TEST(CookieInclusionStatusTest, RemoveExclusionReason) { - CanonicalCookie::CookieInclusionStatus status( - CanonicalCookie::CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR); - EXPECT_TRUE(status.IsValid()); - ASSERT_TRUE(status.HasExclusionReason( - CanonicalCookie::CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR)); - - status.RemoveExclusionReason( - CanonicalCookie::CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR); - EXPECT_TRUE(status.IsValid()); - EXPECT_FALSE(status.HasExclusionReason( - CanonicalCookie::CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR)); - - // Removing a nonexistent exclusion reason doesn't do anything. - ASSERT_FALSE(status.HasExclusionReason( - CanonicalCookie::CookieInclusionStatus::NUM_EXCLUSION_REASONS)); - status.RemoveExclusionReason( - CanonicalCookie::CookieInclusionStatus::NUM_EXCLUSION_REASONS); - EXPECT_TRUE(status.IsValid()); - EXPECT_FALSE(status.HasExclusionReason( - CanonicalCookie::CookieInclusionStatus::NUM_EXCLUSION_REASONS)); -} - -TEST(CookieInclusionStatusTest, RemoveWarningReason) { - CanonicalCookie::CookieInclusionStatus status( - CanonicalCookie::CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR, - CanonicalCookie::CookieInclusionStatus::WARN_SAMESITE_NONE_INSECURE); - EXPECT_TRUE(status.IsValid()); - EXPECT_TRUE(status.ShouldWarn()); - ASSERT_TRUE(status.HasWarningReason( - CanonicalCookie::CookieInclusionStatus::WARN_SAMESITE_NONE_INSECURE)); - - status.RemoveWarningReason( - CanonicalCookie::CookieInclusionStatus::WARN_SAMESITE_NONE_INSECURE); - EXPECT_TRUE(status.IsValid()); - EXPECT_FALSE(status.ShouldWarn()); - EXPECT_FALSE(status.HasWarningReason( - CanonicalCookie::CookieInclusionStatus::WARN_SAMESITE_NONE_INSECURE)); - - // Removing a nonexistent warning reason doesn't do anything. - ASSERT_FALSE(status.HasWarningReason( - CanonicalCookie::CookieInclusionStatus:: - WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT)); - status.RemoveWarningReason(CanonicalCookie::CookieInclusionStatus:: - WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT); - EXPECT_TRUE(status.IsValid()); - EXPECT_FALSE(status.ShouldWarn()); - EXPECT_FALSE(status.HasWarningReason( - CanonicalCookie::CookieInclusionStatus:: - WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT)); -} - -TEST(CookieInclusionStatusTest, HasDowngradeWarning) { - std::vector<CanonicalCookie::CookieInclusionStatus::WarningReason> - downgrade_warnings = { - CanonicalCookie::CookieInclusionStatus:: - WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE, - CanonicalCookie::CookieInclusionStatus:: - WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE, - CanonicalCookie::CookieInclusionStatus:: - WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE, - CanonicalCookie::CookieInclusionStatus:: - WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE, - CanonicalCookie::CookieInclusionStatus:: - WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE, - }; - - CanonicalCookie::CookieInclusionStatus empty_status; - EXPECT_FALSE(empty_status.HasDowngradeWarning()); - - CanonicalCookie::CookieInclusionStatus not_downgrade; - not_downgrade.AddWarningReason( - CanonicalCookie::CookieInclusionStatus:: - WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT); - EXPECT_FALSE(not_downgrade.HasDowngradeWarning()); - - for (auto warning : downgrade_warnings) { - CanonicalCookie::CookieInclusionStatus status; - status.AddWarningReason(warning); - CanonicalCookie::CookieInclusionStatus::WarningReason reason; - - EXPECT_TRUE(status.HasDowngradeWarning(&reason)); - EXPECT_EQ(warning, reason); - } -} } // namespace net diff --git a/chromium/net/cookies/cookie_access_result.cc b/chromium/net/cookies/cookie_access_result.cc new file mode 100644 index 00000000000..182dc53f704 --- /dev/null +++ b/chromium/net/cookies/cookie_access_result.cc @@ -0,0 +1,25 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/cookies/cookie_access_result.h" + +namespace net { + +CookieAccessResult::CookieAccessResult() = default; + +CookieAccessResult::CookieAccessResult( + CookieEffectiveSameSite effective_same_site, + CookieInclusionStatus status) + : effective_same_site(effective_same_site), status(status) {} + +CookieAccessResult::CookieAccessResult(const CookieAccessResult&) = default; + +CookieAccessResult& CookieAccessResult::operator=( + const CookieAccessResult& cookie_access_result) = default; + +CookieAccessResult::CookieAccessResult(CookieAccessResult&&) = default; + +CookieAccessResult::~CookieAccessResult() = default; + +} // namespace net diff --git a/chromium/net/cookies/cookie_access_result.h b/chromium/net/cookies/cookie_access_result.h new file mode 100644 index 00000000000..a21305bfe11 --- /dev/null +++ b/chromium/net/cookies/cookie_access_result.h @@ -0,0 +1,34 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NET_COOKIES_COOKIE_ACCESS_RESULT_H_ +#define NET_COOKIES_COOKIE_ACCESS_RESULT_H_ + +#include "net/base/net_export.h" +#include "net/cookies/cookie_constants.h" +#include "net/cookies/cookie_inclusion_status.h" + +namespace net { + +struct NET_EXPORT CookieAccessResult { + CookieAccessResult(); + CookieAccessResult(CookieEffectiveSameSite effective_same_site, + CookieInclusionStatus status); + + CookieAccessResult(const CookieAccessResult& cookie_access_result); + + CookieAccessResult& operator=(const CookieAccessResult& cookie_access_result); + + CookieAccessResult(CookieAccessResult&& cookie_access_result); + + ~CookieAccessResult(); + + CookieEffectiveSameSite effective_same_site = + CookieEffectiveSameSite::LAX_MODE; + CookieInclusionStatus status; +}; + +} // namespace net + +#endif // NET_COOKIES_COOKIE_ACCESS_RESULT_H_ diff --git a/chromium/net/cookies/cookie_deletion_info.cc b/chromium/net/cookies/cookie_deletion_info.cc index b451dc2350f..6429510e83f 100644 --- a/chromium/net/cookies/cookie_deletion_info.cc +++ b/chromium/net/cookies/cookie_deletion_info.cc @@ -116,7 +116,7 @@ bool CookieDeletionInfo::Matches(const CanonicalCookie& cookie, !cookie .IncludeForRequestURL(url.value(), CookieOptions::MakeAllInclusive(), access_semantics) - .IsInclude()) { + .status.IsInclude()) { return false; } diff --git a/chromium/net/cookies/cookie_inclusion_status.cc b/chromium/net/cookies/cookie_inclusion_status.cc new file mode 100644 index 00000000000..8e13916ba13 --- /dev/null +++ b/chromium/net/cookies/cookie_inclusion_status.cc @@ -0,0 +1,290 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/cookies/cookie_inclusion_status.h" + +#include "base/strings/strcat.h" +#include "url/gurl.h" + +namespace net { + +namespace { + +uint32_t GetExclusionBitmask(CookieInclusionStatus::ExclusionReason reason) { + return 1u << static_cast<uint32_t>(reason); +} + +uint32_t GetWarningBitmask(CookieInclusionStatus::WarningReason reason) { + return 1u << static_cast<uint32_t>(reason); +} + +} // namespace + +CookieInclusionStatus::CookieInclusionStatus() + : exclusion_reasons_(0u), warning_reasons_(0u) {} + +CookieInclusionStatus::CookieInclusionStatus(ExclusionReason reason) + : exclusion_reasons_(GetExclusionBitmask(reason)) {} + +CookieInclusionStatus::CookieInclusionStatus(ExclusionReason reason, + WarningReason warning) + : exclusion_reasons_(GetExclusionBitmask(reason)), + warning_reasons_(GetWarningBitmask(warning)) {} + +bool CookieInclusionStatus::operator==( + const CookieInclusionStatus& other) const { + return exclusion_reasons_ == other.exclusion_reasons_ && + warning_reasons_ == other.warning_reasons_; +} + +bool CookieInclusionStatus::operator!=( + const CookieInclusionStatus& other) const { + return !operator==(other); +} + +bool CookieInclusionStatus::IsInclude() const { + return exclusion_reasons_ == 0u; +} + +bool CookieInclusionStatus::HasExclusionReason(ExclusionReason reason) const { + return exclusion_reasons_ & GetExclusionBitmask(reason); +} + +void CookieInclusionStatus::AddExclusionReason(ExclusionReason reason) { + exclusion_reasons_ |= GetExclusionBitmask(reason); + // If the cookie would be excluded for reasons other than the new SameSite + // rules, don't bother warning about it. + MaybeClearSameSiteWarning(); +} + +void CookieInclusionStatus::RemoveExclusionReason(ExclusionReason reason) { + exclusion_reasons_ &= ~(GetExclusionBitmask(reason)); +} + +void CookieInclusionStatus::MaybeClearSameSiteWarning() { + uint32_t samesite_reasons_mask = + GetExclusionBitmask(EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX) | + GetExclusionBitmask(EXCLUDE_SAMESITE_NONE_INSECURE); + if (exclusion_reasons_ & ~samesite_reasons_mask) { + RemoveWarningReason( + CookieInclusionStatus::WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT); + RemoveWarningReason(CookieInclusionStatus::WARN_SAMESITE_NONE_INSECURE); + RemoveWarningReason( + CookieInclusionStatus::WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE); + } + + uint32_t context_reasons_mask = + GetExclusionBitmask(EXCLUDE_SAMESITE_STRICT) | + GetExclusionBitmask(EXCLUDE_SAMESITE_LAX) | + GetExclusionBitmask(EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX); + if (exclusion_reasons_ & ~context_reasons_mask) { + RemoveWarningReason( + CookieInclusionStatus::WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE); + RemoveWarningReason( + CookieInclusionStatus::WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE); + RemoveWarningReason( + CookieInclusionStatus::WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE); + RemoveWarningReason( + CookieInclusionStatus::WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE); + RemoveWarningReason( + CookieInclusionStatus::WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE); + } +} + +bool CookieInclusionStatus::ShouldRecordDowngradeMetrics() const { + uint32_t context_reasons_mask = + GetExclusionBitmask(EXCLUDE_SAMESITE_STRICT) | + GetExclusionBitmask(EXCLUDE_SAMESITE_LAX) | + GetExclusionBitmask(EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX); + + return (exclusion_reasons_ & ~context_reasons_mask) == 0u; +} + +bool CookieInclusionStatus::ShouldWarn() const { + return warning_reasons_ != 0u; +} + +bool CookieInclusionStatus::HasWarningReason(WarningReason reason) const { + return warning_reasons_ & GetWarningBitmask(reason); +} + +bool CookieInclusionStatus::HasDowngradeWarning( + CookieInclusionStatus::WarningReason* reason) const { + if (!ShouldWarn()) + return false; + + const CookieInclusionStatus::WarningReason kDowngradeWarnings[] = { + WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE, + WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE, + WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE, + WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE, + WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE, + }; + + for (auto warning : kDowngradeWarnings) { + if (!HasWarningReason(warning)) + continue; + + if (reason) + *reason = warning; + + return true; + } + + return false; +} + +void CookieInclusionStatus::AddWarningReason(WarningReason reason) { + warning_reasons_ |= GetWarningBitmask(reason); +} + +void CookieInclusionStatus::RemoveWarningReason(WarningReason reason) { + warning_reasons_ &= ~(GetWarningBitmask(reason)); +} + +CookieInclusionStatus::ContextDowngradeMetricValues +CookieInclusionStatus::GetBreakingDowngradeMetricsEnumValue( + const GURL& url) const { + bool url_is_secure = url.SchemeIsCryptographic(); + + // Start the |reason| as something other than the downgrade warnings. + WarningReason reason = WarningReason::NUM_WARNING_REASONS; + + // Don't bother checking the return value because the default switch case + // will handle if no reason was found. + HasDowngradeWarning(&reason); + + switch (reason) { + case WarningReason::WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE: + return url_is_secure + ? ContextDowngradeMetricValues::STRICT_LAX_STRICT_SECURE + : ContextDowngradeMetricValues::STRICT_LAX_STRICT_INSECURE; + case WarningReason::WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE: + return url_is_secure + ? ContextDowngradeMetricValues::STRICT_CROSS_STRICT_SECURE + : ContextDowngradeMetricValues::STRICT_CROSS_STRICT_INSECURE; + case WarningReason::WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE: + return url_is_secure + ? ContextDowngradeMetricValues::STRICT_CROSS_LAX_SECURE + : ContextDowngradeMetricValues::STRICT_CROSS_LAX_INSECURE; + case WarningReason::WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE: + return url_is_secure + ? ContextDowngradeMetricValues::LAX_CROSS_STRICT_SECURE + : ContextDowngradeMetricValues::LAX_CROSS_STRICT_INSECURE; + case WarningReason::WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE: + return url_is_secure + ? ContextDowngradeMetricValues::LAX_CROSS_LAX_SECURE + : ContextDowngradeMetricValues::LAX_CROSS_LAX_INSECURE; + default: + return url_is_secure + ? ContextDowngradeMetricValues::NO_DOWNGRADE_SECURE + : ContextDowngradeMetricValues::NO_DOWNGRADE_INSECURE; + } +} + +std::string CookieInclusionStatus::GetDebugString() const { + std::string out; + + // Inclusion/exclusion + if (IsInclude()) + base::StrAppend(&out, {"INCLUDE, "}); + if (HasExclusionReason(EXCLUDE_UNKNOWN_ERROR)) + base::StrAppend(&out, {"EXCLUDE_UNKNOWN_ERROR, "}); + if (HasExclusionReason(EXCLUDE_HTTP_ONLY)) + base::StrAppend(&out, {"EXCLUDE_HTTP_ONLY, "}); + if (HasExclusionReason(EXCLUDE_SECURE_ONLY)) + base::StrAppend(&out, {"EXCLUDE_SECURE_ONLY, "}); + if (HasExclusionReason(EXCLUDE_DOMAIN_MISMATCH)) + base::StrAppend(&out, {"EXCLUDE_DOMAIN_MISMATCH, "}); + if (HasExclusionReason(EXCLUDE_NOT_ON_PATH)) + base::StrAppend(&out, {"EXCLUDE_NOT_ON_PATH, "}); + if (HasExclusionReason(EXCLUDE_SAMESITE_STRICT)) + base::StrAppend(&out, {"EXCLUDE_SAMESITE_STRICT, "}); + if (HasExclusionReason(EXCLUDE_SAMESITE_LAX)) + base::StrAppend(&out, {"EXCLUDE_SAMESITE_LAX, "}); + if (HasExclusionReason(EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX)) + base::StrAppend(&out, {"EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX, "}); + if (HasExclusionReason(EXCLUDE_SAMESITE_NONE_INSECURE)) + base::StrAppend(&out, {"EXCLUDE_SAMESITE_NONE_INSECURE, "}); + if (HasExclusionReason(EXCLUDE_USER_PREFERENCES)) + base::StrAppend(&out, {"EXCLUDE_USER_PREFERENCES, "}); + if (HasExclusionReason(EXCLUDE_FAILURE_TO_STORE)) + base::StrAppend(&out, {"EXCLUDE_FAILURE_TO_STORE, "}); + if (HasExclusionReason(EXCLUDE_NONCOOKIEABLE_SCHEME)) + base::StrAppend(&out, {"EXCLUDE_NONCOOKIEABLE_SCHEME, "}); + if (HasExclusionReason(EXCLUDE_OVERWRITE_SECURE)) + base::StrAppend(&out, {"EXCLUDE_OVERWRITE_SECURE, "}); + if (HasExclusionReason(EXCLUDE_OVERWRITE_HTTP_ONLY)) + base::StrAppend(&out, {"EXCLUDE_OVERWRITE_HTTP_ONLY, "}); + if (HasExclusionReason(EXCLUDE_INVALID_DOMAIN)) + base::StrAppend(&out, {"EXCLUDE_INVALID_DOMAIN, "}); + if (HasExclusionReason(EXCLUDE_INVALID_PREFIX)) + base::StrAppend(&out, {"EXCLUDE_INVALID_PREFIX, "}); + + // Add warning + if (!ShouldWarn()) { + base::StrAppend(&out, {"DO_NOT_WARN"}); + return out; + } + + if (HasWarningReason(WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT)) + base::StrAppend(&out, {"WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT, "}); + if (HasWarningReason(WARN_SAMESITE_NONE_INSECURE)) + base::StrAppend(&out, {"WARN_SAMESITE_NONE_INSECURE, "}); + if (HasWarningReason(WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE)) + base::StrAppend(&out, {"WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE, "}); + if (HasWarningReason(WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE)) + base::StrAppend(&out, {"WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE, "}); + if (HasWarningReason(WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE)) + base::StrAppend(&out, {"WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE, "}); + if (HasWarningReason(WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE)) + base::StrAppend(&out, {"WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE, "}); + if (HasWarningReason(WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE)) + base::StrAppend(&out, {"WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE, "}); + if (HasWarningReason(WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE)) + base::StrAppend(&out, {"WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE, "}); + if (HasWarningReason(WARN_SAMESITE_COMPAT_PAIR)) + base::StrAppend(&out, {"WARN_SAMESITE_COMPAT_PAIR, "}); + + // Strip trailing comma and space. + out.erase(out.end() - 2, out.end()); + + return out; +} + +bool CookieInclusionStatus::IsValid() const { + // Bit positions where there should not be any true bits. + uint32_t exclusion_mask = ~0u << static_cast<int>(NUM_EXCLUSION_REASONS); + uint32_t warning_mask = ~0u << static_cast<int>(NUM_WARNING_REASONS); + return (exclusion_mask & exclusion_reasons_) == 0u && + (warning_mask & warning_reasons_) == 0u; +} + +bool CookieInclusionStatus::HasExactlyExclusionReasonsForTesting( + std::vector<CookieInclusionStatus::ExclusionReason> reasons) const { + CookieInclusionStatus expected = MakeFromReasonsForTesting(reasons); + return expected.exclusion_reasons_ == exclusion_reasons_; +} + +bool CookieInclusionStatus::HasExactlyWarningReasonsForTesting( + std::vector<WarningReason> reasons) const { + CookieInclusionStatus expected = MakeFromReasonsForTesting({}, reasons); + return expected.warning_reasons_ == warning_reasons_; +} + +// static +CookieInclusionStatus CookieInclusionStatus::MakeFromReasonsForTesting( + std::vector<ExclusionReason> reasons, + std::vector<WarningReason> warnings) { + CookieInclusionStatus status; + for (ExclusionReason reason : reasons) { + status.AddExclusionReason(reason); + } + for (WarningReason warning : warnings) { + status.AddWarningReason(warning); + } + return status; +} + +} // namespace net diff --git a/chromium/net/cookies/cookie_inclusion_status.h b/chromium/net/cookies/cookie_inclusion_status.h new file mode 100644 index 00000000000..3f38eddb39b --- /dev/null +++ b/chromium/net/cookies/cookie_inclusion_status.h @@ -0,0 +1,275 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NET_COOKIES_COOKIE_INCLUSION_STATUS_H_ +#define NET_COOKIES_COOKIE_INCLUSION_STATUS_H_ + +#include <string> +#include <vector> + +#include "net/base/net_export.h" + +class GURL; + +namespace net { + +// This class represents if a cookie was included or excluded in a cookie get or +// set operation, and if excluded why. It holds a vector of reasons for +// exclusion, where cookie inclusion is represented by the absence of any +// exclusion reasons. Also marks whether a cookie should be warned about, e.g. +// for deprecation or intervention reasons. +class NET_EXPORT CookieInclusionStatus { + public: + // Types of reasons why a cookie might be excluded. + // If adding a ExclusionReason, please also update the GetDebugString() + // method. + enum ExclusionReason { + EXCLUDE_UNKNOWN_ERROR = 0, + + EXCLUDE_HTTP_ONLY = 1, + EXCLUDE_SECURE_ONLY = 2, + EXCLUDE_DOMAIN_MISMATCH = 3, + EXCLUDE_NOT_ON_PATH = 4, + EXCLUDE_SAMESITE_STRICT = 5, + EXCLUDE_SAMESITE_LAX = 6, + + // The following two are used for the SameSiteByDefaultCookies experiment, + // where if the SameSite attribute is not specified, it will be treated as + // SameSite=Lax by default. + EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX = 7, + // This is used if SameSite=None is specified, but the cookie is not + // Secure. + EXCLUDE_SAMESITE_NONE_INSECURE = 8, + EXCLUDE_USER_PREFERENCES = 9, + + // Statuses specific to setting cookies + EXCLUDE_FAILURE_TO_STORE = 10, + EXCLUDE_NONCOOKIEABLE_SCHEME = 11, + EXCLUDE_OVERWRITE_SECURE = 12, + EXCLUDE_OVERWRITE_HTTP_ONLY = 13, + EXCLUDE_INVALID_DOMAIN = 14, + EXCLUDE_INVALID_PREFIX = 15, + + // This should be kept last. + NUM_EXCLUSION_REASONS + }; + + // Reason to warn about a cookie. Any information contained in WarningReason + // of an included cookie may be passed to an untrusted renderer. + // If you add one, please update GetDebugString(). + enum WarningReason { + // Of the following 3 SameSite warnings, there will be, at most, a single + // active one. + + // Warn if a cookie with unspecified SameSite attribute is used in a + // cross-site context. + WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT = 0, + // Warn if a cookie with SameSite=None is not Secure. + WARN_SAMESITE_NONE_INSECURE = 1, + // Warn if a cookie with unspecified SameSite attribute is defaulted into + // Lax and is sent on a request with unsafe method, only because it is new + // enough to activate the Lax-allow-unsafe intervention. + WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE = 2, + + // The following warnings indicate that an included cookie with an effective + // SameSite is experiencing a SameSiteCookieContext::|context| -> + // SameSiteCookieContext::|schemeful_context| downgrade that will prevent + // its access schemefully. + // This situation means that a cookie is accessible when the + // SchemefulSameSite feature is disabled but not when it's enabled, + // indicating changed behavior and potential breakage. + // + // For example, a Strict to Lax downgrade for an effective SameSite=Strict + // cookie: + // This cookie would be accessible in the Strict context as its SameSite + // value is Strict. However its context for schemeful same-site becomes Lax. + // A strict cookie cannot be accessed in a Lax context and therefore the + // behavior has changed. + // As a counterexample, a Strict to Lax downgrade for an effective + // SameSite=Lax cookie: A Lax cookie can be accessed in both Strict and Lax + // contexts so there is no behavior change (and we don't warn about it). + // + // The warnings are in the following format: + // WARN_{context}_{schemeful_context}_DOWNGRADE_{samesite_value}_SAMESITE + // + // Of the following 5 SameSite warnings, there will be, at most, a single + // active one. + + // Strict to Lax downgrade for an effective SameSite=Strict cookie. + // This warning is only applicable for cookies being sent because a Strict + // cookie will be set in both Strict and Lax Contexts so the downgrade will + // not affect it. + WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE = 3, + // Strict to Cross-site downgrade for an effective SameSite=Strict cookie. + // This also applies to Strict to Lax Unsafe downgrades due to Lax Unsafe + // behaving like Cross-site. + WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE = 4, + // Strict to Cross-site downgrade for an effective SameSite=Lax cookie. + // This also applies to Strict to Lax Unsafe downgrades due to Lax Unsafe + // behaving like Cross-site. + WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE = 5, + // Lax to Cross-site downgrade for an effective SameSite=Strict cookie. + // This warning is only applicable for cookies being set because a Strict + // cookie will not be sent in a Lax context so the downgrade would not + // affect it. + WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE = 6, + // Lax to Cross-site downgrade for an effective SameSite=Lax cookie. + WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE = 7, + + // This is applied to a cookie that may be part of a "double cookie" pair + // used for compatibility reasons. These pairs consist of one cookie that + // has "SameSite=None; Secure" and a duplicate cookie that leaves SameSite + // unspecified to maintain compatibility with browsers that do not support + // the "SameSite=None" attribute. This warning is applied to both + // members of the pair. See cookie_util::IsSameSiteCompatPair(). + // + // If computing this for a cookie access attempt from a non-network context + // (i.e. script), this should not be applied if either member of the pair is + // HttpOnly, to avoid leaking information about the name and value of + // HttpOnly cookies to an untrusted renderer. + // + // This is only relevant if WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT is + // present on the same status or a status for a cookie accessed at the same + // time, so it may not be applied at other times (e.g. when the context is + // same-site). + WARN_SAMESITE_COMPAT_PAIR = 8, + + // This should be kept last. + NUM_WARNING_REASONS + }; + + // These enums encode the context downgrade warnings + the secureness of the + // url sending/setting the cookie. They're used for metrics only. The format + // is {context}_{schemeful_context}_{samesite_value}_{securness}. + // NO_DOWNGRADE_{securness} indicates that a cookie didn't have a breaking + // context downgrade and was A) included B) excluded only due to insufficient + // same-site context. I.e. the cookie wasn't excluded due to other reasons + // such as third-party cookie blocking. Keep this in line with + // SameSiteCookieContextBreakingDowngradeWithSecureness in enums.xml. + enum ContextDowngradeMetricValues { + NO_DOWNGRADE_INSECURE = 0, + NO_DOWNGRADE_SECURE = 1, + + STRICT_LAX_STRICT_INSECURE = 2, + STRICT_CROSS_STRICT_INSECURE = 3, + STRICT_CROSS_LAX_INSECURE = 4, + LAX_CROSS_STRICT_INSECURE = 5, + LAX_CROSS_LAX_INSECURE = 6, + + STRICT_LAX_STRICT_SECURE = 7, + STRICT_CROSS_STRICT_SECURE = 8, + STRICT_CROSS_LAX_SECURE = 9, + LAX_CROSS_STRICT_SECURE = 10, + LAX_CROSS_LAX_SECURE = 11, + + // Keep last. + kMaxValue = LAX_CROSS_LAX_SECURE + }; + // Makes a status that says include and should not warn. + CookieInclusionStatus(); + + // Make a status that contains the given exclusion reason. + explicit CookieInclusionStatus(ExclusionReason reason); + // Makes a status that contains the given exclusion reason and warning. + CookieInclusionStatus(ExclusionReason reason, WarningReason warning); + + bool operator==(const CookieInclusionStatus& other) const; + bool operator!=(const CookieInclusionStatus& other) const; + + // Whether the status is to include the cookie, and has no other reasons for + // exclusion. + bool IsInclude() const; + + // Whether the given reason for exclusion is present. + bool HasExclusionReason(ExclusionReason status_type) const; + + // Add an exclusion reason. + void AddExclusionReason(ExclusionReason status_type); + + // Remove an exclusion reason. + void RemoveExclusionReason(ExclusionReason reason); + + // If the cookie would have been excluded for reasons other than + // SAMESITE_UNSPECIFIED_TREATED_AS_LAX or SAMESITE_NONE_INSECURE, don't bother + // warning about it (clear the warning). + void MaybeClearSameSiteWarning(); + + // Whether to record the breaking downgrade metrics if the cookie is included + // or if it's only excluded because of insufficient same-site context. + bool ShouldRecordDowngradeMetrics() const; + + // Whether the cookie should be warned about. + bool ShouldWarn() const; + + // Whether the given reason for warning is present. + bool HasWarningReason(WarningReason reason) const; + + // Whether a schemeful downgrade warning is present. + // A schemeful downgrade means that an included cookie with an effective + // SameSite is experiencing a SameSiteCookieContext::|context| -> + // SameSiteCookieContext::|schemeful_context| downgrade that will prevent its + // access schemefully. If the function returns true and |reason| is valid then + // |reason| will contain which warning was found. + bool HasDowngradeWarning( + CookieInclusionStatus::WarningReason* reason = nullptr) const; + + // Add an warning reason. + void AddWarningReason(WarningReason reason); + + // Remove an warning reason. + void RemoveWarningReason(WarningReason reason); + + // Used for serialization/deserialization. + uint32_t exclusion_reasons() const { return exclusion_reasons_; } + void set_exclusion_reasons(uint32_t exclusion_reasons) { + exclusion_reasons_ = exclusion_reasons; + } + + uint32_t warning_reasons() const { return warning_reasons_; } + void set_warning_reasons(uint32_t warning_reasons) { + warning_reasons_ = warning_reasons; + } + + ContextDowngradeMetricValues GetBreakingDowngradeMetricsEnumValue( + const GURL& url) const; + + // Get exclusion reason(s) and warning in string format. + std::string GetDebugString() const; + + // Checks that the underlying bit vector representation doesn't contain any + // extraneous bits that are not mapped to any enum values. Does not check + // for reasons which semantically cannot coexist. + bool IsValid() const; + + // Checks whether the exclusion reasons are exactly the set of exclusion + // reasons in the vector. (Ignores warnings.) + bool HasExactlyExclusionReasonsForTesting( + std::vector<ExclusionReason> reasons) const; + + // Checks whether the warning reasons are exactly the set of warning + // reasons in the vector. (Ignores exclusions.) + bool HasExactlyWarningReasonsForTesting( + std::vector<WarningReason> reasons) const; + + // Makes a status that contains the given exclusion reasons and warning. + static CookieInclusionStatus MakeFromReasonsForTesting( + std::vector<ExclusionReason> reasons, + std::vector<WarningReason> warnings = std::vector<WarningReason>()); + + private: + // A bit vector of the applicable exclusion reasons. + uint32_t exclusion_reasons_ = 0u; + + // A bit vector of the applicable warning reasons. + uint32_t warning_reasons_ = 0u; +}; + +NET_EXPORT inline std::ostream& operator<<(std::ostream& os, + const CookieInclusionStatus status) { + return os << status.GetDebugString(); +} + +} // namespace net + +#endif // NET_COOKIES_COOKIE_INCLUSION_STATUS_H_ diff --git a/chromium/net/cookies/cookie_inclusion_status_unittest.cc b/chromium/net/cookies/cookie_inclusion_status_unittest.cc new file mode 100644 index 00000000000..bc5c7edaa39 --- /dev/null +++ b/chromium/net/cookies/cookie_inclusion_status_unittest.cc @@ -0,0 +1,200 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/cookies/cookie_inclusion_status.h" + +#include "testing/gtest/include/gtest/gtest.h" + +namespace net { + +TEST(CookieInclusionStatusTest, IncludeStatus) { + int num_exclusion_reasons = + static_cast<int>(CookieInclusionStatus::NUM_EXCLUSION_REASONS); + int num_warning_reasons = + static_cast<int>(CookieInclusionStatus::NUM_WARNING_REASONS); + // Zero-argument constructor + CookieInclusionStatus status; + EXPECT_TRUE(status.IsValid()); + EXPECT_TRUE(status.IsInclude()); + for (int i = 0; i < num_exclusion_reasons; ++i) { + EXPECT_FALSE(status.HasExclusionReason( + static_cast<CookieInclusionStatus::ExclusionReason>(i))); + } + for (int i = 0; i < num_warning_reasons; ++i) { + EXPECT_FALSE(status.HasWarningReason( + static_cast<CookieInclusionStatus::WarningReason>(i))); + } + EXPECT_FALSE( + status.HasExclusionReason(CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR)); +} + +TEST(CookieInclusionStatusTest, ExcludeStatus) { + int num_exclusion_reasons = + static_cast<int>(CookieInclusionStatus::NUM_EXCLUSION_REASONS); + for (int i = 0; i < num_exclusion_reasons; ++i) { + auto reason = static_cast<CookieInclusionStatus::ExclusionReason>(i); + CookieInclusionStatus status(reason); + EXPECT_TRUE(status.IsValid()); + EXPECT_FALSE(status.IsInclude()); + EXPECT_TRUE(status.HasExclusionReason(reason)); + for (int j = 0; j < num_exclusion_reasons; ++j) { + if (i == j) + continue; + EXPECT_FALSE(status.HasExclusionReason( + static_cast<CookieInclusionStatus::ExclusionReason>(j))); + } + } +} + +TEST(CookieInclusionStatusTest, NotValid) { + CookieInclusionStatus status; + int num_exclusion_reasons = + static_cast<int>(CookieInclusionStatus::NUM_EXCLUSION_REASONS); + int num_warning_reasons = + static_cast<int>(CookieInclusionStatus::NUM_WARNING_REASONS); + status.set_exclusion_reasons(1 << num_exclusion_reasons); + EXPECT_FALSE(status.IsInclude()); + EXPECT_FALSE(status.IsValid()); + + status.set_exclusion_reasons(~0u); + EXPECT_FALSE(status.IsInclude()); + EXPECT_FALSE(status.IsValid()); + + status.set_warning_reasons(1 << num_warning_reasons); + EXPECT_FALSE(status.IsInclude()); + EXPECT_FALSE(status.IsValid()); + + status.set_warning_reasons(~0u); + EXPECT_FALSE(status.IsInclude()); + EXPECT_FALSE(status.IsValid()); + + status.set_exclusion_reasons(1 << num_exclusion_reasons); + status.set_warning_reasons(1 << num_warning_reasons); + EXPECT_FALSE(status.IsInclude()); + EXPECT_FALSE(status.IsValid()); +} + +TEST(CookieInclusionStatusTest, AddExclusionReason) { + CookieInclusionStatus status; + status.AddWarningReason( + CookieInclusionStatus::WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE); + status.AddExclusionReason(CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR); + EXPECT_TRUE(status.IsValid()); + EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR})); + // Adding an exclusion reason other than + // EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX or + // EXCLUDE_SAMESITE_NONE_INSECURE should clear any SameSite warning. + EXPECT_FALSE(status.ShouldWarn()); + + status = CookieInclusionStatus(); + status.AddWarningReason( + CookieInclusionStatus::WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT); + status.AddExclusionReason( + CookieInclusionStatus::EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX); + EXPECT_TRUE(status.IsValid()); + EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX})); + EXPECT_TRUE(status.HasExactlyWarningReasonsForTesting( + {CookieInclusionStatus::WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT})); +} + +TEST(CookieInclusionStatusTest, CheckEachWarningReason) { + CookieInclusionStatus status; + + int num_warning_reasons = + static_cast<int>(CookieInclusionStatus::NUM_WARNING_REASONS); + EXPECT_FALSE(status.ShouldWarn()); + for (int i = 0; i < num_warning_reasons; ++i) { + auto reason = static_cast<CookieInclusionStatus::WarningReason>(i); + status.AddWarningReason(reason); + EXPECT_TRUE(status.IsValid()); + EXPECT_TRUE(status.IsInclude()); + EXPECT_TRUE(status.ShouldWarn()); + EXPECT_TRUE(status.HasWarningReason(reason)); + for (int j = 0; j < num_warning_reasons; ++j) { + if (i == j) + continue; + EXPECT_FALSE(status.HasWarningReason( + static_cast<CookieInclusionStatus::WarningReason>(j))); + } + status.RemoveWarningReason(reason); + EXPECT_FALSE(status.ShouldWarn()); + } +} + +TEST(CookieInclusionStatusTest, RemoveExclusionReason) { + CookieInclusionStatus status(CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR); + EXPECT_TRUE(status.IsValid()); + ASSERT_TRUE( + status.HasExclusionReason(CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR)); + + status.RemoveExclusionReason(CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR); + EXPECT_TRUE(status.IsValid()); + EXPECT_FALSE( + status.HasExclusionReason(CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR)); + + // Removing a nonexistent exclusion reason doesn't do anything. + ASSERT_FALSE( + status.HasExclusionReason(CookieInclusionStatus::NUM_EXCLUSION_REASONS)); + status.RemoveExclusionReason(CookieInclusionStatus::NUM_EXCLUSION_REASONS); + EXPECT_TRUE(status.IsValid()); + EXPECT_FALSE( + status.HasExclusionReason(CookieInclusionStatus::NUM_EXCLUSION_REASONS)); +} + +TEST(CookieInclusionStatusTest, RemoveWarningReason) { + CookieInclusionStatus status( + CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR, + CookieInclusionStatus::WARN_SAMESITE_NONE_INSECURE); + EXPECT_TRUE(status.IsValid()); + EXPECT_TRUE(status.ShouldWarn()); + ASSERT_TRUE(status.HasWarningReason( + CookieInclusionStatus::WARN_SAMESITE_NONE_INSECURE)); + + status.RemoveWarningReason( + CookieInclusionStatus::WARN_SAMESITE_NONE_INSECURE); + EXPECT_TRUE(status.IsValid()); + EXPECT_FALSE(status.ShouldWarn()); + EXPECT_FALSE(status.HasWarningReason( + CookieInclusionStatus::WARN_SAMESITE_NONE_INSECURE)); + + // Removing a nonexistent warning reason doesn't do anything. + ASSERT_FALSE(status.HasWarningReason( + CookieInclusionStatus::WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT)); + status.RemoveWarningReason( + CookieInclusionStatus::WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT); + EXPECT_TRUE(status.IsValid()); + EXPECT_FALSE(status.ShouldWarn()); + EXPECT_FALSE(status.HasWarningReason( + CookieInclusionStatus::WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT)); +} + +TEST(CookieInclusionStatusTest, HasDowngradeWarning) { + std::vector<CookieInclusionStatus::WarningReason> downgrade_warnings = { + CookieInclusionStatus::WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE, + CookieInclusionStatus::WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE, + CookieInclusionStatus::WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE, + CookieInclusionStatus::WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE, + CookieInclusionStatus::WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE, + }; + + CookieInclusionStatus empty_status; + EXPECT_FALSE(empty_status.HasDowngradeWarning()); + + CookieInclusionStatus not_downgrade; + not_downgrade.AddWarningReason( + CookieInclusionStatus::WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT); + EXPECT_FALSE(not_downgrade.HasDowngradeWarning()); + + for (auto warning : downgrade_warnings) { + CookieInclusionStatus status; + status.AddWarningReason(warning); + CookieInclusionStatus::WarningReason reason; + + EXPECT_TRUE(status.HasDowngradeWarning(&reason)); + EXPECT_EQ(warning, reason); + } +} +} // namespace net diff --git a/chromium/net/cookies/cookie_monster.cc b/chromium/net/cookies/cookie_monster.cc index 533cc97ba71..477b47a7721 100644 --- a/chromium/net/cookies/cookie_monster.cc +++ b/chromium/net/cookies/cookie_monster.cc @@ -142,6 +142,8 @@ const size_t CookieMonster::kDomainPurgeCookies = 30; const size_t CookieMonster::kMaxCookies = 3300; const size_t CookieMonster::kPurgeCookies = 300; +const size_t CookieMonster::kMaxDomainPurgedKeys = 100; + const size_t CookieMonster::kDomainCookiesQuotaLow = 30; const size_t CookieMonster::kDomainCookiesQuotaMedium = 50; const size_t CookieMonster::kDomainCookiesQuotaHigh = @@ -319,7 +321,8 @@ CookieMonster::CookieMonster(scoped_refptr<PersistentCookieStore> store, CookieMonster::CookieMonster(scoped_refptr<PersistentCookieStore> store, base::TimeDelta last_access_threshold, NetLog* net_log) - : initialized_(false), + : num_keys_(0u), + initialized_(false), started_fetching_all_cookies_(false), finished_fetching_all_cookies_(false), seen_global_task_(false), @@ -578,8 +581,8 @@ void CookieMonster::GetCookieListWithOptions(const GURL& url, GetCookieListCallback callback) { DCHECK(thread_checker_.CalledOnValidThread()); - CookieStatusList included_cookies; - CookieStatusList excluded_cookies; + CookieAccessResultList included_cookies; + CookieAccessResultList excluded_cookies; if (HasCookieableScheme(url)) { std::vector<CanonicalCookie*> cookie_ptrs; FindCookiesForRegistryControlledHost(url, &cookie_ptrs); @@ -950,8 +953,8 @@ void CookieMonster::FilterCookiesWithOptions( const GURL url, const CookieOptions options, std::vector<CanonicalCookie*>* cookie_ptrs, - CookieStatusList* included_cookies, - CookieStatusList* excluded_cookies) { + CookieAccessResultList* included_cookies, + CookieAccessResultList* excluded_cookies) { DCHECK(thread_checker_.CalledOnValidThread()); // Probe to save statistics relatively frequently. We do it here rather @@ -965,12 +968,12 @@ void CookieMonster::FilterCookiesWithOptions( // Filter out cookies that should not be included for a request to the // given |url|. HTTP only cookies are filtered depending on the passed // cookie |options|. - CanonicalCookie::CookieInclusionStatus status = (*it)->IncludeForRequestURL( + CookieAccessResult access_result = (*it)->IncludeForRequestURL( url, options, GetAccessSemanticsForCookieGet(**it)); - if (!status.IsInclude()) { + if (!access_result.status.IsInclude()) { if (options.return_excluded_cookies()) - excluded_cookies->push_back({**it, status}); + excluded_cookies->push_back({**it, access_result}); continue; } @@ -979,7 +982,7 @@ void CookieMonster::FilterCookiesWithOptions( MaybeRecordCookieAccessWithOptions(**it, options, false); - included_cookies->push_back({**it, status}); + included_cookies->push_back({**it, access_result}); } } @@ -990,12 +993,12 @@ void CookieMonster::MaybeDeleteEquivalentCookieAndUpdateStatus( bool skip_httponly, bool already_expired, base::Time* creation_date_to_inherit, - CanonicalCookie::CookieInclusionStatus* status) { + CookieInclusionStatus* status) { DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(!status->HasExclusionReason( - CanonicalCookie::CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE)); + CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE)); DCHECK(!status->HasExclusionReason( - CanonicalCookie::CookieInclusionStatus::EXCLUDE_OVERWRITE_HTTP_ONLY)); + CookieInclusionStatus::EXCLUDE_OVERWRITE_HTTP_ONLY)); bool found_equivalent_cookie = false; CookieMap::iterator deletion_candidate_it = cookies_.end(); @@ -1030,7 +1033,7 @@ void CookieMonster::MaybeDeleteEquivalentCookieAndUpdateStatus( capture_mode); }); status->AddExclusionReason( - CanonicalCookie::CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE); + CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE); } if (cookie_being_set.IsEquivalent(*cur_existing_cookie)) { @@ -1050,8 +1053,8 @@ void CookieMonster::MaybeDeleteEquivalentCookieAndUpdateStatus( return NetLogCookieMonsterCookieRejectedHttponly( cur_existing_cookie, &cookie_being_set, capture_mode); }); - status->AddExclusionReason(CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_OVERWRITE_HTTP_ONLY); + status->AddExclusionReason( + CookieInclusionStatus::EXCLUDE_OVERWRITE_HTTP_ONLY); } else { deletion_candidate_it = cur_it; } @@ -1067,8 +1070,7 @@ void CookieMonster::MaybeDeleteEquivalentCookieAndUpdateStatus( already_expired ? DELETE_COOKIE_EXPIRED_OVERWRITE : DELETE_COOKIE_OVERWRITE); } else if (status->HasExclusionReason( - CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_OVERWRITE_SECURE)) { + CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE)) { // Log that we preserved a cookie that would have been deleted due to // Leave Secure Cookies Alone. This arbitrarily only logs the last // |skipped_secure_cookie| that we were left with after the for loop, even @@ -1145,6 +1147,15 @@ CookieMonster::CookieMap::iterator CookieMonster::InternalInsertCookie( CookieChangeCause::INSERTED), true); + // If this is the first cookie in |cookies_| with this key, increment the + // |num_keys_| counter. + bool different_prev = + inserted == cookies_.begin() || std::prev(inserted)->first != key; + bool different_next = + inserted == cookies_.end() || std::next(inserted)->first != key; + if (different_prev && different_next) + ++num_keys_; + return inserted; } @@ -1154,19 +1165,18 @@ void CookieMonster::SetCanonicalCookie(std::unique_ptr<CanonicalCookie> cc, SetCookiesCallback callback) { DCHECK(thread_checker_.CalledOnValidThread()); - CanonicalCookie::CookieInclusionStatus status; + CookieInclusionStatus status; bool secure_source = source_url.SchemeIsCryptographic(); cc->SetSourceScheme(secure_source ? CookieSourceScheme::kSecure : CookieSourceScheme::kNonSecure); if ((cc->IsSecure() && !secure_source)) { - status.AddExclusionReason( - CanonicalCookie::CookieInclusionStatus::EXCLUDE_SECURE_ONLY); + status.AddExclusionReason(CookieInclusionStatus::EXCLUDE_SECURE_ONLY); } if (!IsCookieableScheme(source_url.scheme())) { status.AddExclusionReason( - CanonicalCookie::CookieInclusionStatus::EXCLUDE_NONCOOKIEABLE_SCHEME); + CookieInclusionStatus::EXCLUDE_NONCOOKIEABLE_SCHEME); } const std::string key(GetKey(cc->Domain())); @@ -1194,9 +1204,9 @@ void CookieMonster::SetCanonicalCookie(std::unique_ptr<CanonicalCookie> cc, &creation_date_to_inherit, &status); if (status.HasExclusionReason( - CanonicalCookie::CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE) || - status.HasExclusionReason(CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_OVERWRITE_HTTP_ONLY)) { + CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE) || + status.HasExclusionReason( + CookieInclusionStatus::EXCLUDE_OVERWRITE_HTTP_ONLY)) { DVLOG(net::cookie_util::kVlogSetCookies) << "SetCookie() not clobbering httponly cookie or secure cookie for " "insecure scheme"; @@ -1293,8 +1303,7 @@ void CookieMonster::SetAllCookies(CookieList list, // shouldn't have a return value. But it should also be deleted (see // https://codereview.chromium.org/2882063002/#msg64), which would // solve the return value problem. - MaybeRunCookieCallback(std::move(callback), - CanonicalCookie::CookieInclusionStatus()); + MaybeRunCookieCallback(std::move(callback), CookieInclusionStatus()); } void CookieMonster::InternalUpdateCookieAccessTime(CanonicalCookie* cc, @@ -1358,6 +1367,16 @@ void CookieMonster::InternalDeleteCookie(CookieMap::iterator it, GetAccessSemanticsForCookie(*cc, false /* legacy_access_granted */), mapping.cause), mapping.notify); + + // If this is the last cookie in |cookies_| with this key, decrement the + // |num_keys_| counter. + bool different_prev = + it == cookies_.begin() || std::prev(it)->first != it->first; + bool different_next = + it == cookies_.end() || std::next(it)->first != it->first; + if (different_prev && different_next) + --num_keys_; + cookies_.erase(it); } @@ -1385,6 +1404,10 @@ size_t CookieMonster::GarbageCollect(const Time& current, if (cookie_its->size() > kDomainMaxCookies) { DVLOG(net::cookie_util::kVlogGarbageCollection) << "Deep Garbage Collect domain."; + + if (domain_purged_keys_.size() < kMaxDomainPurgedKeys) + domain_purged_keys_.insert(key); + size_t purge_goal = cookie_its->size() - (kDomainMaxCookies - kDomainPurgeCookies); DCHECK(purge_goal > kDomainPurgeCookies); @@ -1801,11 +1824,25 @@ void CookieMonster::RecordPeriodicStats(const base::Time& current_time) { return; } + if (DoRecordPeriodicStats()) + last_statistic_record_time_ = current_time; +} + +bool CookieMonster::DoRecordPeriodicStats() { + // These values are all bogus if we have only partially loaded the cookies. + if (started_fetching_all_cookies_ && !finished_fetching_all_cookies_) + return false; + // See InitializeHistograms() for details. histogram_count_->Add(cookies_.size()); - // More detailed statistics on cookie counts at different granularities. - last_statistic_record_time_ = current_time; + // Can be up to kMaxDomainPurgedKeys. + UMA_HISTOGRAM_COUNTS_100("Cookie.NumDomainPurgedKeys", + domain_purged_keys_.size()); + // Can be up to kMaxCookies. + UMA_HISTOGRAM_COUNTS_10000("Cookie.NumKeys", num_keys_); + + return true; } // Initialize all histogram counter variables used in this class. diff --git a/chromium/net/cookies/cookie_monster.h b/chromium/net/cookies/cookie_monster.h index 46001bd4e4e..9908e6f8e7e 100644 --- a/chromium/net/cookies/cookie_monster.h +++ b/chromium/net/cookies/cookie_monster.h @@ -31,6 +31,7 @@ #include "net/cookies/canonical_cookie.h" #include "net/cookies/cookie_access_delegate.h" #include "net/cookies/cookie_constants.h" +#include "net/cookies/cookie_inclusion_status.h" #include "net/cookies/cookie_monster_change_dispatcher.h" #include "net/cookies/cookie_store.h" #include "net/log/net_log_with_source.h" @@ -123,6 +124,9 @@ class NET_EXPORT CookieMonster : public CookieStore { static const size_t kMaxCookies; static const size_t kPurgeCookies; + // Max number of keys to store for domains that have been purged. + static const size_t kMaxDomainPurgedKeys; + // Quota for cookies with {low, medium, high} priorities within a domain. static const size_t kDomainCookiesQuotaLow; static const size_t kDomainCookiesQuotaMedium; @@ -203,6 +207,10 @@ class NET_EXPORT CookieMonster : public CookieStore { // before the CookieMap typedef. static std::string GetKey(base::StringPiece domain); + // Triggers immediate recording of stats that are typically reported + // periodically. + bool DoRecordPeriodicStatsForTesting() { return DoRecordPeriodicStats(); } + private: // For garbage collection constants. FRIEND_TEST_ALL_PREFIXES(CookieMonsterTest, TestHostGarbageCollection); @@ -394,8 +402,8 @@ class NET_EXPORT CookieMonster : public CookieStore { void FilterCookiesWithOptions(const GURL url, const CookieOptions options, std::vector<CanonicalCookie*>* cookie_ptrs, - CookieStatusList* included_cookies, - CookieStatusList* excluded_cookies); + CookieAccessResultList* included_cookies, + CookieAccessResultList* excluded_cookies); // Possibly delete an existing cookie equivalent to |cookie_being_set| (same // path, domain, and name). @@ -428,7 +436,7 @@ class NET_EXPORT CookieMonster : public CookieStore { bool skip_httponly, bool already_expired, base::Time* creation_date_to_inherit, - CanonicalCookie::CookieInclusionStatus* status); + CookieInclusionStatus* status); // This is only used if the RecentCreationTimeGrantsLegacyCookieSemantics // feature is enabled. It finds an equivalent cookie (based on name, domain, @@ -562,7 +570,11 @@ class NET_EXPORT CookieMonster : public CookieStore { // statistics if a sufficient time period has passed. void RecordPeriodicStats(const base::Time& current_time); - // Initialize the above variables; should only be called from + // Records the aforementioned stats if we have already finished loading all + // cookies. Returns whether stats were recorded. + bool DoRecordPeriodicStats(); + + // Initialize the histogram_* variables below; should only be called from // the constructor. void InitializeHistograms(); @@ -588,6 +600,15 @@ class NET_EXPORT CookieMonster : public CookieStore { base::HistogramBase* histogram_cookie_source_scheme_; base::HistogramBase* histogram_time_blocked_on_load_; + // Set of keys (eTLD+1's) for which non-expired cookies have + // been evicted for hitting the per-domain max. The size of this set is + // histogrammed periodically. The size is limited to |kMaxDomainPurgedKeys|. + std::set<std::string> domain_purged_keys_; + + // The number of distinct keys (eTLD+1's) currently present in the |cookies_| + // multimap. This is histogrammed periodically. + size_t num_keys_; + CookieMap cookies_; CookieMonsterChangeDispatcher change_dispatcher_; diff --git a/chromium/net/cookies/cookie_monster_change_dispatcher.cc b/chromium/net/cookies/cookie_monster_change_dispatcher.cc index 28cfe347c58..6bd731f47ca 100644 --- a/chromium/net/cookies/cookie_monster_change_dispatcher.cc +++ b/chromium/net/cookies/cookie_monster_change_dispatcher.cc @@ -61,7 +61,7 @@ void CookieMonsterChangeDispatcher::Subscription::DispatchChange( !cookie .IncludeForRequestURL(url_, CookieOptions::MakeAllInclusive(), change.access_semantics) - .IsInclude()) { + .status.IsInclude()) { return; } diff --git a/chromium/net/cookies/cookie_monster_perftest.cc b/chromium/net/cookies/cookie_monster_perftest.cc index 6966a8a9e4b..96d16f545a6 100644 --- a/chromium/net/cookies/cookie_monster_perftest.cc +++ b/chromium/net/cookies/cookie_monster_perftest.cc @@ -105,7 +105,7 @@ class SetCookieCallback : public CookieTestCallback { } private: - void Run(CanonicalCookie::CookieInclusionStatus status) { + void Run(CookieInclusionStatus status) { EXPECT_TRUE(status.IsInclude()); CookieTestCallback::Run(); } @@ -123,9 +123,9 @@ class GetCookieListCallback : public CookieTestCallback { } private: - void Run(const CookieStatusList& cookie_list, - const CookieStatusList& excluded_cookies) { - cookie_list_ = cookie_util::StripStatuses(cookie_list); + void Run(const CookieAccessResultList& cookie_list, + const CookieAccessResultList& excluded_cookies) { + cookie_list_ = cookie_util::StripAccessResults(cookie_list); CookieTestCallback::Run(); } CookieList cookie_list_; diff --git a/chromium/net/cookies/cookie_monster_unittest.cc b/chromium/net/cookies/cookie_monster_unittest.cc index 82877bcb54b..fc83d6a6211 100644 --- a/chromium/net/cookies/cookie_monster_unittest.cc +++ b/chromium/net/cookies/cookie_monster_unittest.cc @@ -135,7 +135,7 @@ class CookieMonsterTestBase : public CookieStoreTest<T> { return callback.cookies(); } - CookieStatusList GetExcludedCookiesForURLWithOptions( + CookieAccessResultList GetExcludedCookiesForURLWithOptions( CookieMonster* cm, const GURL& url, const CookieOptions& options) { @@ -148,7 +148,7 @@ class CookieMonsterTestBase : public CookieStoreTest<T> { bool SetAllCookies(CookieMonster* cm, const CookieList& list) { DCHECK(cm); - ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus> callback; + ResultSavingCookieCallback<CookieInclusionStatus> callback; cm->SetAllCookiesAsync(list, callback.MakeCallback()); callback.WaitUntilDone(); return callback.result().IsInclude(); @@ -160,7 +160,7 @@ class CookieMonsterTestBase : public CookieStoreTest<T> { base::Time creation_time) { DCHECK(cm); DCHECK(!creation_time.is_null()); - ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus> callback; + ResultSavingCookieCallback<CookieInclusionStatus> callback; cm->SetCanonicalCookieAsync( CanonicalCookie::Create(url, cookie_line, creation_time, base::nullopt /* server_time */), @@ -310,10 +310,10 @@ class CookieMonsterTestBase : public CookieStoreTest<T> { } void TestHostGarbageCollectHelper() { + const char kHistogramName[] = "Cookie.NumDomainPurgedKeys"; int domain_max_cookies = CookieMonster::kDomainMaxCookies; int domain_purge_cookies = CookieMonster::kDomainPurgeCookies; - const int more_than_enough_cookies = - (domain_max_cookies + domain_purge_cookies) * 2; + const int more_than_enough_cookies = domain_max_cookies + 10; // Add a bunch of cookies on a single host, should purge them. { auto cm = std::make_unique<CookieMonster>(nullptr, &net_log_); @@ -326,6 +326,10 @@ class CookieMonsterTestBase : public CookieStoreTest<T> { // Count the number of cookies. EXPECT_LE(CountInString(cookies, '='), domain_max_cookies); } + base::HistogramTester histogram_tester; + EXPECT_TRUE(cm->DoRecordPeriodicStatsForTesting()); + histogram_tester.ExpectUniqueSample(kHistogramName, 1 /* sample */, + 1 /* count */); } // Add a bunch of cookies on multiple hosts within a single eTLD. @@ -359,6 +363,51 @@ class CookieMonsterTestBase : public CookieStoreTest<T> { CountInString(cookies_specific, '=')); EXPECT_GE(total_cookies, domain_max_cookies - domain_purge_cookies); EXPECT_LE(total_cookies, domain_max_cookies); + + base::HistogramTester histogram_tester; + EXPECT_TRUE(cm->DoRecordPeriodicStatsForTesting()); + histogram_tester.ExpectUniqueSample(kHistogramName, 1 /* sample */, + 1 /* count */); + } + + // Test histogram for the number of registrable domains affected by domain + // purge. + { + auto cm = std::make_unique<CookieMonster>(nullptr, &net_log_); + GURL url; + for (int domain_num = 0; domain_num < 3; ++domain_num) { + url = GURL(base::StringPrintf("http://domain%d.test", domain_num)); + for (int i = 0; i < more_than_enough_cookies; ++i) { + std::string cookie = base::StringPrintf("a%03d=b", i); + EXPECT_TRUE(SetCookie(cm.get(), url, cookie)); + std::string cookies = this->GetCookies(cm.get(), url); + // Make sure we find it in the cookies. + EXPECT_NE(cookies.find(cookie), std::string::npos); + // Count the number of cookies. + EXPECT_LE(CountInString(cookies, '='), domain_max_cookies); + } + base::HistogramTester histogram_tester; + EXPECT_TRUE(cm->DoRecordPeriodicStatsForTesting()); + histogram_tester.ExpectUniqueSample( + kHistogramName, domain_num + 1 /* sample */, 1 /* count */); + } + + // Triggering eviction again for a previously affected registrable domain + // does not increment the histogram. + for (int i = 0; i < domain_purge_cookies * 2; ++i) { + // Add some extra cookies (different names than before). + std::string cookie = base::StringPrintf("b%03d=b", i); + EXPECT_TRUE(SetCookie(cm.get(), url, cookie)); + std::string cookies = this->GetCookies(cm.get(), url); + // Make sure we find it in the cookies. + EXPECT_NE(cookies.find(cookie), std::string::npos); + // Count the number of cookies. + EXPECT_LE(CountInString(cookies, '='), domain_max_cookies); + } + base::HistogramTester histogram_tester; + EXPECT_TRUE(cm->DoRecordPeriodicStatsForTesting()); + histogram_tester.ExpectUniqueSample(kHistogramName, 3 /* sample */, + 1 /* count */); } } @@ -932,7 +981,7 @@ TEST_F(DeferredCookieTaskTest, DeferredSetCookie) { // Generate puts to store w/o needing a proper expiration. cookie_monster_->SetPersistSessionCookies(true); - ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus> call1; + ResultSavingCookieCallback<CookieInclusionStatus> call1; cookie_monster_->SetCanonicalCookieAsync( CanonicalCookie::Create(http_www_foo_.url(), "A=B", base::Time::Now(), base::nullopt /* server_time */), @@ -946,7 +995,7 @@ TEST_F(DeferredCookieTaskTest, DeferredSetCookie) { EXPECT_TRUE(call1.result().IsInclude()); EXPECT_EQ("LOAD; LOAD_FOR_KEY:foo.com; ADD; ", TakeCommandSummary()); - ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus> call2; + ResultSavingCookieCallback<CookieInclusionStatus> call2; cookie_monster_->SetCanonicalCookieAsync( CanonicalCookie::Create(http_www_foo_.url(), "X=Y", base::Time::Now(), base::nullopt /* server_time */), @@ -971,7 +1020,7 @@ TEST_F(DeferredCookieTaskTest, DeferredSetAllCookies) { false, true, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT)); - ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus> call1; + ResultSavingCookieCallback<CookieInclusionStatus> call1; cookie_monster_->SetAllCookiesAsync(list, call1.MakeCallback()); base::RunLoop().RunUntilIdle(); EXPECT_FALSE(call1.was_run()); @@ -982,7 +1031,7 @@ TEST_F(DeferredCookieTaskTest, DeferredSetAllCookies) { EXPECT_EQ("LOAD; ADD; ADD; ", TakeCommandSummary()); // 2nd set doesn't need to read from store. It erases the old cookies, though. - ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus> call2; + ResultSavingCookieCallback<CookieInclusionStatus> call2; cookie_monster_->SetAllCookiesAsync(list, call2.MakeCallback()); ASSERT_TRUE(call2.was_run()); EXPECT_TRUE(call2.result().IsInclude()); @@ -1183,30 +1232,30 @@ TEST_F(DeferredCookieTaskTest, DeferredTaskOrder) { bool get_cookie_list_callback_was_run = false; GetCookieListCallback get_cookie_list_callback_deferred; - ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus> - set_cookies_callback; + ResultSavingCookieCallback<CookieInclusionStatus> set_cookies_callback; base::RunLoop run_loop; cookie_monster_->GetCookieListWithOptionsAsync( http_www_foo_.url(), CookieOptions::MakeAllInclusive(), - base::BindLambdaForTesting([&](const CookieStatusList& cookies, - const CookieStatusList& excluded_list) { - // This should complete before the set. - get_cookie_list_callback_was_run = true; - EXPECT_FALSE(set_cookies_callback.was_run()); - EXPECT_THAT(cookies, MatchesCookieLine("X=1")); - // Can't use TakeCommandSummary here since ExecuteLoads is walking - // through the data it takes. - EXPECT_EQ("LOAD; LOAD_FOR_KEY:foo.com; ", - CommandSummary(persistent_store_->commands())); - - // Queue up a second get. It should see the result of the set queued - // before it. - cookie_monster_->GetCookieListWithOptionsAsync( - http_www_foo_.url(), CookieOptions::MakeAllInclusive(), - get_cookie_list_callback_deferred.MakeCallback()); - - run_loop.Quit(); - })); + base::BindLambdaForTesting( + [&](const CookieAccessResultList& cookies, + const CookieAccessResultList& excluded_list) { + // This should complete before the set. + get_cookie_list_callback_was_run = true; + EXPECT_FALSE(set_cookies_callback.was_run()); + EXPECT_THAT(cookies, MatchesCookieLine("X=1")); + // Can't use TakeCommandSummary here since ExecuteLoads is walking + // through the data it takes. + EXPECT_EQ("LOAD; LOAD_FOR_KEY:foo.com; ", + CommandSummary(persistent_store_->commands())); + + // Queue up a second get. It should see the result of the set queued + // before it. + cookie_monster_->GetCookieListWithOptionsAsync( + http_www_foo_.url(), CookieOptions::MakeAllInclusive(), + get_cookie_list_callback_deferred.MakeCallback()); + + run_loop.Quit(); + })); cookie_monster_->SetCanonicalCookieAsync( CanonicalCookie::Create(http_www_foo_.url(), "A=B", base::Time::Now(), @@ -1446,15 +1495,13 @@ TEST_F(CookieMonsterTest, SetCookieableSchemes) { EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), foo_url, "x=1") .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_NONCOOKIEABLE_SCHEME})); + {CookieInclusionStatus::EXCLUDE_NONCOOKIEABLE_SCHEME})); EXPECT_TRUE(SetCanonicalCookieReturnStatus( cm.get(), CanonicalCookie::Create(foo_url, "y=1", now, server_time), foo_url, false /*modify_httponly*/) .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_NONCOOKIEABLE_SCHEME})); + {CookieInclusionStatus::EXCLUDE_NONCOOKIEABLE_SCHEME})); EXPECT_TRUE( CreateAndSetCookieReturnStatus(cm_foo.get(), foo_url, "x=1").IsInclude()); @@ -1466,15 +1513,13 @@ TEST_F(CookieMonsterTest, SetCookieableSchemes) { EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm_foo.get(), http_url, "x=1") .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_NONCOOKIEABLE_SCHEME})); + {CookieInclusionStatus::EXCLUDE_NONCOOKIEABLE_SCHEME})); EXPECT_TRUE(SetCanonicalCookieReturnStatus( cm_foo.get(), CanonicalCookie::Create(http_url, "y=1", now, server_time), http_url, false /*modify_httponly*/) .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_NONCOOKIEABLE_SCHEME})); + {CookieInclusionStatus::EXCLUDE_NONCOOKIEABLE_SCHEME})); } TEST_F(CookieMonsterTest, GetAllCookiesForURL) { @@ -1573,7 +1618,7 @@ TEST_F(CookieMonsterTest, GetExcludedCookiesForURL) { CookieOptions do_not_return_excluded; do_not_return_excluded.unset_return_excluded_cookies(); - CookieStatusList excluded_cookies = GetExcludedCookiesForURLWithOptions( + CookieAccessResultList excluded_cookies = GetExcludedCookiesForURLWithOptions( cm.get(), http_www_foo_.url(), do_not_return_excluded); auto iter = excluded_cookies.begin(); @@ -1587,8 +1632,8 @@ TEST_F(CookieMonsterTest, GetExcludedCookiesForURL) { ASSERT_TRUE(iter != excluded_cookies.end()); EXPECT_EQ(http_www_foo_.Format(".%D"), iter->cookie.Domain()); EXPECT_EQ("E", iter->cookie.Name()); - EXPECT_TRUE(iter->status.HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus::EXCLUDE_SECURE_ONLY})); + EXPECT_TRUE(iter->access_result.status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_SECURE_ONLY})); ASSERT_TRUE(++iter == excluded_cookies.end()); @@ -1607,14 +1652,14 @@ TEST_F(CookieMonsterTest, GetExcludedCookiesForURL) { ASSERT_TRUE(iter != excluded_cookies.end()); EXPECT_EQ(http_www_foo_.host(), iter->cookie.Domain()); EXPECT_EQ("A", iter->cookie.Name()); - EXPECT_TRUE(iter->status.HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus::EXCLUDE_HTTP_ONLY})); + EXPECT_TRUE(iter->access_result.status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_HTTP_ONLY})); ASSERT_TRUE(++iter != excluded_cookies.end()); EXPECT_EQ(http_www_foo_.Format(".%D"), iter->cookie.Domain()); EXPECT_EQ("E", iter->cookie.Name()); - EXPECT_TRUE(iter->status.HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus::EXCLUDE_SECURE_ONLY})); + EXPECT_TRUE(iter->access_result.status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_SECURE_ONLY})); ASSERT_TRUE(++iter == excluded_cookies.end()); @@ -1674,15 +1719,15 @@ TEST_F(CookieMonsterTest, GetExcludedCookiesForURLPathMatching) { EXPECT_TRUE( CreateAndSetCookie(cm.get(), http_www_foo_.url(), "E=F;", options)); - CookieStatusList excluded_cookies = + CookieAccessResultList excluded_cookies = GetExcludedCookiesForURL(cm.get(), www_foo_foo_.url()); auto it = excluded_cookies.begin(); ASSERT_TRUE(it != excluded_cookies.end()); EXPECT_EQ("C", it->cookie.Name()); EXPECT_EQ("/bar", it->cookie.Path()); - EXPECT_TRUE(it->status.HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus::EXCLUDE_NOT_ON_PATH})); + EXPECT_TRUE(it->access_result.status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_NOT_ON_PATH})); ASSERT_TRUE(++it == excluded_cookies.end()); @@ -1692,8 +1737,8 @@ TEST_F(CookieMonsterTest, GetExcludedCookiesForURLPathMatching) { ASSERT_TRUE(it != excluded_cookies.end()); EXPECT_EQ("A", it->cookie.Name()); EXPECT_EQ("/foo", it->cookie.Path()); - EXPECT_TRUE(it->status.HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus::EXCLUDE_NOT_ON_PATH})); + EXPECT_TRUE(it->access_result.status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_NOT_ON_PATH})); ASSERT_TRUE(++it == excluded_cookies.end()); } @@ -2189,8 +2234,7 @@ TEST_F(CookieMonsterTest, WhileLoadingLoadCompletesBeforeKeyLoadCompletes) { auto cookie = CanonicalCookie::Create(kUrl, "a=b", base::Time::Now(), base::nullopt /* server_time */); - ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus> - set_cookie_callback; + ResultSavingCookieCallback<CookieInclusionStatus> set_cookie_callback; cm->SetCanonicalCookieAsync(std::move(cookie), kUrl, CookieOptions::MakeAllInclusive(), set_cookie_callback.MakeCallback()); @@ -2278,8 +2322,7 @@ TEST_F(CookieMonsterTest, WhileLoadingGetAllSetGetAll) { auto cookie = CanonicalCookie::Create(kUrl, "a=b", base::Time::Now(), base::nullopt /* server_time */); - ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus> - set_cookie_callback; + ResultSavingCookieCallback<CookieInclusionStatus> set_cookie_callback; cm->SetCanonicalCookieAsync(std::move(cookie), kUrl, CookieOptions::MakeAllInclusive(), set_cookie_callback.MakeCallback()); @@ -2326,8 +2369,7 @@ TEST_F(CookieMonsterTest, CheckOrderOfCookieTaskQueueWhenLoadingCompletes) { // Get all cookies task that queues a task to set a cookie when executed. auto cookie = CanonicalCookie::Create(kUrl, "a=b", base::Time::Now(), base::nullopt /* server_time */); - ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus> - set_cookie_callback; + ResultSavingCookieCallback<CookieInclusionStatus> set_cookie_callback; cm->GetAllCookiesAsync(base::BindOnce( &RunClosureOnAllCookiesReceived, base::BindOnce(&CookieStore::SetCanonicalCookieAsync, @@ -2720,6 +2762,95 @@ TEST_F(CookieMonsterTest, CookieSourceHistogram) { CookieMonster::COOKIE_SOURCE_NONSECURE_COOKIE_NONCRYPTOGRAPHIC_SCHEME, 1); } +// Test that inserting the first cookie for a key and deleting the last cookie +// for a key correctly reflected in the Cookie.NumKeys histogram. +TEST_F(CookieMonsterTest, NumKeysHistogram) { + const char kHistogramName[] = "Cookie.NumKeys"; + + // Test loading cookies from store. + scoped_refptr<MockPersistentCookieStore> store(new MockPersistentCookieStore); + std::vector<std::unique_ptr<CanonicalCookie>> initial_cookies; + initial_cookies.push_back(CanonicalCookie::Create( + GURL("http://domain1.test"), "A=1", base::Time::Now(), base::nullopt)); + initial_cookies.push_back(CanonicalCookie::Create( + GURL("http://domain2.test"), "A=1", base::Time::Now(), base::nullopt)); + initial_cookies.push_back( + CanonicalCookie::Create(GURL("http://sub.domain2.test"), "A=1", + base::Time::Now(), base::nullopt)); + initial_cookies.push_back(CanonicalCookie::Create( + GURL("http://domain3.test"), "A=1", base::Time::Now(), base::nullopt)); + initial_cookies.push_back(CanonicalCookie::Create( + GURL("http://domain3.test"), "B=1", base::Time::Now(), base::nullopt)); + store->SetLoadExpectation(true /* return_value */, + std::move(initial_cookies)); + auto cm = std::make_unique<CookieMonster>(store.get(), &net_log_); + { + base::HistogramTester histogram_tester; + // Access the cookies to trigger loading from the persistent store. + EXPECT_EQ(5u, this->GetAllCookies(cm.get()).size()); + EXPECT_TRUE(cm->DoRecordPeriodicStatsForTesting()); + // There should be 3 keys: "domain1.test", "domain2.test", and + // "domain3.test". + histogram_tester.ExpectUniqueSample(kHistogramName, 3 /* sample */, + 1 /* count */); + } + + // Test adding cookies for already existing key. + { + base::HistogramTester histogram_tester; + EXPECT_TRUE(CreateAndSetCookie(cm.get(), GURL("https://domain1.test"), + "B=1", CookieOptions::MakeAllInclusive())); + EXPECT_TRUE(CreateAndSetCookie(cm.get(), GURL("http://sub.domain1.test"), + "B=1", CookieOptions::MakeAllInclusive())); + EXPECT_TRUE(cm->DoRecordPeriodicStatsForTesting()); + histogram_tester.ExpectUniqueSample(kHistogramName, 3 /* sample */, + 1 /* count */); + } + + // Test adding a cookie for a new key. + { + base::HistogramTester histogram_tester; + EXPECT_TRUE(CreateAndSetCookie(cm.get(), GURL("https://domain4.test"), + "A=1", CookieOptions::MakeAllInclusive())); + EXPECT_TRUE(cm->DoRecordPeriodicStatsForTesting()); + histogram_tester.ExpectUniqueSample(kHistogramName, 4 /* sample */, + 1 /* count */); + } + + // Test overwriting the only cookie for a key. (Deletes and inserts, so the + // total doesn't change.) + { + base::HistogramTester histogram_tester; + EXPECT_TRUE(CreateAndSetCookie(cm.get(), GURL("https://domain4.test"), + "A=2", CookieOptions::MakeAllInclusive())); + EXPECT_TRUE(cm->DoRecordPeriodicStatsForTesting()); + histogram_tester.ExpectUniqueSample(kHistogramName, 4 /* sample */, + 1 /* count */); + } + + // Test deleting cookie for a key with more than one cookie. + { + base::HistogramTester histogram_tester; + EXPECT_TRUE(CreateAndSetCookie(cm.get(), GURL("https://domain2.test"), + "A=1; Max-Age=0", + CookieOptions::MakeAllInclusive())); + EXPECT_TRUE(cm->DoRecordPeriodicStatsForTesting()); + histogram_tester.ExpectUniqueSample(kHistogramName, 4 /* sample */, + 1 /* count */); + } + + // Test deleting cookie for a key with only one cookie. + { + base::HistogramTester histogram_tester; + EXPECT_TRUE(CreateAndSetCookie(cm.get(), GURL("https://domain4.test"), + "A=1; Max-Age=0", + CookieOptions::MakeAllInclusive())); + EXPECT_TRUE(cm->DoRecordPeriodicStatsForTesting()); + histogram_tester.ExpectUniqueSample(kHistogramName, 3 /* sample */, + 1 /* count */); + } +} + TEST_F(CookieMonsterTest, MaybeDeleteEquivalentCookieAndUpdateStatus) { scoped_refptr<MockPersistentCookieStore> store(new MockPersistentCookieStore); std::unique_ptr<CookieMonster> cm(new CookieMonster(store.get(), &net_log_)); @@ -2728,10 +2859,9 @@ TEST_F(CookieMonsterTest, MaybeDeleteEquivalentCookieAndUpdateStatus) { auto preexisting_cookie = CanonicalCookie::Create( https_www_foo_.url(), "A=B;Secure;HttpOnly", base::Time::Now(), base::nullopt /* server_time */); - CanonicalCookie::CookieInclusionStatus status = - SetCanonicalCookieReturnStatus(cm.get(), std::move(preexisting_cookie), - https_www_foo_.url(), - true /* can_modify_httponly */); + CookieInclusionStatus status = SetCanonicalCookieReturnStatus( + cm.get(), std::move(preexisting_cookie), https_www_foo_.url(), + true /* can_modify_httponly */); ASSERT_TRUE(status.IsInclude()); // Set a new cookie with a different name. Should work because cookies with @@ -2753,7 +2883,7 @@ TEST_F(CookieMonsterTest, MaybeDeleteEquivalentCookieAndUpdateStatus) { http_www_foo_.url(), true /* can_modify_httponly */); EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE})); + {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE})); // The preexisting cookie should still be there. EXPECT_THAT(GetCookiesWithOptions(cm.get(), https_www_foo_.url(), CookieOptions::MakeAllInclusive()), @@ -2784,7 +2914,7 @@ TEST_F(CookieMonsterTest, MaybeDeleteEquivalentCookieAndUpdateStatus) { http_www_foo_.url(), true /* can_modify_httponly */); EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE})); + {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE})); // The preexisting cookie should still be there. EXPECT_THAT(GetCookiesWithOptions(cm.get(), https_www_foo_.url(), CookieOptions::MakeAllInclusive()), @@ -2812,7 +2942,7 @@ TEST_F(CookieMonsterTest, MaybeDeleteEquivalentCookieAndUpdateStatus) { https_www_foo_.url(), false /* can_modify_httponly */); EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus::EXCLUDE_OVERWRITE_HTTP_ONLY})); + {CookieInclusionStatus::EXCLUDE_OVERWRITE_HTTP_ONLY})); entries = net_log_.GetEntries(); ExpectLogContainsSomewhere( @@ -2832,10 +2962,9 @@ TEST_F(CookieMonsterTest, SkipDontOverwriteForMultipleReasons) { auto preexisting_cookie = CanonicalCookie::Create( https_www_foo_.url(), "A=B;Secure;HttpOnly", base::Time::Now(), base::nullopt /* server_time */); - CanonicalCookie::CookieInclusionStatus status = - SetCanonicalCookieReturnStatus(cm.get(), std::move(preexisting_cookie), - https_www_foo_.url(), - true /* can_modify_httponly */); + CookieInclusionStatus status = SetCanonicalCookieReturnStatus( + cm.get(), std::move(preexisting_cookie), https_www_foo_.url(), + true /* can_modify_httponly */); ASSERT_TRUE(status.IsInclude()); // Attempt to set a new cookie with the same name that is not Secure or @@ -2847,8 +2976,8 @@ TEST_F(CookieMonsterTest, SkipDontOverwriteForMultipleReasons) { http_www_foo_.url(), false /* can_modify_httponly */); EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE, - CanonicalCookie::CookieInclusionStatus::EXCLUDE_OVERWRITE_HTTP_ONLY})); + {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE, + CookieInclusionStatus::EXCLUDE_OVERWRITE_HTTP_ONLY})); auto entries = net_log_.GetEntries(); ExpectLogContainsSomewhere( @@ -2868,21 +2997,19 @@ TEST_F(CookieMonsterTest, DontDeleteEquivalentCookieIfSetIsRejected) { auto preexisting_cookie = CanonicalCookie::Create( http_www_foo_.url(), "cookie=foo", base::Time::Now(), base::nullopt /* server_time */); - CanonicalCookie::CookieInclusionStatus status = - SetCanonicalCookieReturnStatus(cm.get(), std::move(preexisting_cookie), - http_www_foo_.url(), - false /* can_modify_httponly */); + CookieInclusionStatus status = SetCanonicalCookieReturnStatus( + cm.get(), std::move(preexisting_cookie), http_www_foo_.url(), + false /* can_modify_httponly */); ASSERT_TRUE(status.IsInclude()); auto bad_cookie = CanonicalCookie::Create( http_www_foo_.url(), "cookie=bar;secure", base::Time::Now(), base::nullopt /* server_time */); - CanonicalCookie::CookieInclusionStatus status2 = - SetCanonicalCookieReturnStatus(cm.get(), std::move(bad_cookie), - http_www_foo_.url(), - false /* can_modify_httponly */); + CookieInclusionStatus status2 = SetCanonicalCookieReturnStatus( + cm.get(), std::move(bad_cookie), http_www_foo_.url(), + false /* can_modify_httponly */); EXPECT_TRUE(status2.HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus::EXCLUDE_SECURE_ONLY})); + {CookieInclusionStatus::EXCLUDE_SECURE_ONLY})); // Check that the original cookie is still there. EXPECT_EQ("cookie=foo", GetCookies(cm.get(), https_www_foo_.url())); @@ -2904,10 +3031,9 @@ TEST_F(CookieMonsterTest, SetSecureCookies) { CreateAndSetCookieReturnStatus(cm.get(), https_url, "A=B;").IsInclude()); // A secure cookie cannot be set from a URL with an insecure scheme. - EXPECT_TRUE( - CreateAndSetCookieReturnStatus(cm.get(), http_url, "A=B; Secure") - .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus::EXCLUDE_SECURE_ONLY})); + EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), http_url, "A=B; Secure") + .HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_SECURE_ONLY})); // A secure cookie can be set from a URL with a secure scheme. EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), https_url, "A=B; Secure") @@ -2919,8 +3045,7 @@ TEST_F(CookieMonsterTest, SetSecureCookies) { .IsInclude()); EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), http_url, "A=C;") .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_OVERWRITE_SECURE})); + {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE})); // If a non-secure cookie is created from a URL with an secure scheme, and a // secure cookie with the same name already exists, update the cookie. @@ -2939,13 +3064,11 @@ TEST_F(CookieMonsterTest, SetSecureCookies) { .IsInclude()); EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), http_url, "A=C; path=/") .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_OVERWRITE_SECURE})); + {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE})); EXPECT_TRUE( CreateAndSetCookieReturnStatus(cm.get(), http_url, "A=C; path=/my/path") .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_OVERWRITE_SECURE})); + {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE})); // But if the existing cookie has a path somewhere under the root, cookies // with the same name may be set for paths which don't overlap the existing @@ -2963,13 +3086,11 @@ TEST_F(CookieMonsterTest, SetSecureCookies) { EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), http_url, "WITH_PATH=C; path=/my/path") .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_OVERWRITE_SECURE})); + {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE})); EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), http_url, "WITH_PATH=C; path=/my/path/sub") .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_OVERWRITE_SECURE})); + {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE})); DeleteAll(cm.get()); @@ -2994,12 +3115,10 @@ TEST_F(CookieMonsterTest, SetSecureCookies) { EXPECT_TRUE( CreateAndSetCookieReturnStatus(cm.get(), http_url, "A=D; path=/foo") .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_OVERWRITE_SECURE})); + {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE})); EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), http_url, "A=D; path=/") .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_OVERWRITE_SECURE})); + {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE})); EXPECT_THAT(GetCookies(cm.get(), https_foo_url), testing::HasSubstr("A=C")); // ...but the original insecure cookie is still retained. @@ -3022,13 +3141,11 @@ TEST_F(CookieMonsterTest, SetSecureCookies) { EXPECT_TRUE( CreateAndSetCookieReturnStatus(cm.get(), http_url, "A=C; domain=foo.com") .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_OVERWRITE_SECURE})); + {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE})); EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), http_url, "A=C; domain=www.foo.com") .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_OVERWRITE_SECURE})); + {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE})); // Since A=B was set above with no domain string, set a different cookie here // so the insecure examples aren't trying to overwrite the one above. @@ -3038,17 +3155,14 @@ TEST_F(CookieMonsterTest, SetSecureCookies) { EXPECT_TRUE( CreateAndSetCookieReturnStatus(cm.get(), http_url, "B=D; domain=foo.com") .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_OVERWRITE_SECURE})); + {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE})); EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), http_url, "B=D") .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_OVERWRITE_SECURE})); + {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE})); EXPECT_TRUE( CreateAndSetCookieReturnStatus(cm.get(), http_superdomain_url, "B=D") .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_OVERWRITE_SECURE})); + {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE})); // Verify that if an httponly version of the cookie exists, adding a Secure // version of the cookie still does not overwrite it. @@ -3059,8 +3173,7 @@ TEST_F(CookieMonsterTest, SetSecureCookies) { // which in this case includes "exclude_httponly = true". EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), https_url, "C=E; Secure") .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_OVERWRITE_HTTP_ONLY})); + {CookieInclusionStatus::EXCLUDE_OVERWRITE_HTTP_ONLY})); auto entries = net_log_.GetEntries(); ExpectLogContainsSomewhere( @@ -3109,8 +3222,7 @@ TEST_F(CookieMonsterTest, LeaveSecureCookiesAlone_DomainMatch) { // cookie exists. EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), http_url, "A=1") .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_OVERWRITE_SECURE})) + {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE})) << "Insecure host cookie from " << http_url << " should not be set if equivalent secure host cookie from " << preexisting_cookie_url << " exists."; @@ -3118,15 +3230,13 @@ TEST_F(CookieMonsterTest, LeaveSecureCookiesAlone_DomainMatch) { cm.get(), http_url, base::StrCat({"A=2; Domain=", new_cookie_host})) .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_OVERWRITE_SECURE})) + {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE})) << "Insecure domain cookie from " << http_url << " should not be set if equivalent secure host cookie from " << preexisting_cookie_url << " exists."; EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), http_url, "B=1") .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_OVERWRITE_SECURE})) + {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE})) << "Insecure host cookie from " << http_url << " should not be set if equivalent secure domain cookie from " << preexisting_cookie_url << " exists."; @@ -3134,8 +3244,7 @@ TEST_F(CookieMonsterTest, LeaveSecureCookiesAlone_DomainMatch) { cm.get(), http_url, base::StrCat({"B=2; Domain=", new_cookie_host})) .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_OVERWRITE_SECURE})) + {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE})) << "Insecure domain cookie from " << http_url << " should not be set if equivalent secure domain cookie from " << preexisting_cookie_url << " exists."; @@ -3282,14 +3391,11 @@ TEST_F(CookieMonsterTest, LeaveSecureCookiesAlone_PathMatch) { // Don't set insecure cookie from an insecure URL if equivalent secure // cookie exists. - CanonicalCookie::CookieInclusionStatus set = - CreateAndSetCookieReturnStatus( - cm.get(), http_url, - base::StrCat({"A=1; Path=", new_cookie_path})); + CookieInclusionStatus set = CreateAndSetCookieReturnStatus( + cm.get(), http_url, base::StrCat({"A=1; Path=", new_cookie_path})); EXPECT_TRUE(should_path_match ? set.HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_OVERWRITE_SECURE}) + {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE}) : set.IsInclude()) << "Insecure cookie from " << http_url << " should " << (should_path_match ? "not " : "") @@ -3507,8 +3613,7 @@ TEST_F(CookieMonsterTest, SetCanonicalCookieDoesNotBlockForLoadAll) { CookieMonster cm(persistent_store.get(), nullptr); // Start of a canonical cookie set. - ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus> - callback_set; + ResultSavingCookieCallback<CookieInclusionStatus> callback_set; GURL cookie_url("http://a.com/"); cm.SetCanonicalCookieAsync( CanonicalCookie::Create(cookie_url, "A=B", base::Time::Now(), @@ -3594,16 +3699,14 @@ TEST_F(CookieMonsterTest, DeleteCookieWithInheritedTimestamps) { // Write a cookie created at |t1|. auto cookie = CanonicalCookie::Create(url, cookie_line, t1, server_time); - ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus> - set_callback_1; + ResultSavingCookieCallback<CookieInclusionStatus> set_callback_1; cm.SetCanonicalCookieAsync(std::move(cookie), url, options, set_callback_1.MakeCallback()); set_callback_1.WaitUntilDone(); // Overwrite the cookie at |t2|. cookie = CanonicalCookie::Create(url, cookie_line, t2, server_time); - ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus> - set_callback_2; + ResultSavingCookieCallback<CookieInclusionStatus> set_callback_2; cm.SetCanonicalCookieAsync(std::move(cookie), url, options, set_callback_2.MakeCallback()); set_callback_2.WaitUntilDone(); @@ -3627,7 +3730,7 @@ TEST_F(CookieMonsterTest, RejectCreatedSameSiteCookieOnSet) { CookieOptions::SameSiteCookieContext( CookieOptions::SameSiteCookieContext::ContextType::CROSS_SITE)); - CanonicalCookie::CookieInclusionStatus status; + CookieInclusionStatus status; // Cookie can be created successfully; SameSite is not checked on Creation. auto cookie = CanonicalCookie::Create(url, cookie_line, base::Time::Now(), @@ -3636,12 +3739,12 @@ TEST_F(CookieMonsterTest, RejectCreatedSameSiteCookieOnSet) { ASSERT_TRUE(status.IsInclude()); // ... but the environment is checked on set, so this may be rejected then. - ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus> callback; + ResultSavingCookieCallback<CookieInclusionStatus> callback; cm.SetCanonicalCookieAsync(std::move(cookie), url, env_cross_site, callback.MakeCallback()); callback.WaitUntilDone(); EXPECT_TRUE(callback.result().HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus::EXCLUDE_SAMESITE_LAX})); + {CookieInclusionStatus::EXCLUDE_SAMESITE_LAX})); } TEST_F(CookieMonsterTest, RejectCreatedSecureCookieOnSet) { @@ -3649,7 +3752,7 @@ TEST_F(CookieMonsterTest, RejectCreatedSecureCookieOnSet) { std::string cookie_line = "foo=bar; Secure"; CookieMonster cm(nullptr, nullptr); - CanonicalCookie::CookieInclusionStatus status; + CookieInclusionStatus status; // Cookie can be created successfully from an any url. Secure is not checked // on Create. auto cookie = @@ -3660,13 +3763,13 @@ TEST_F(CookieMonsterTest, RejectCreatedSecureCookieOnSet) { ASSERT_TRUE(status.IsInclude()); // Cookie is rejected when attempting to set from a non-secure scheme. - ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus> callback; + ResultSavingCookieCallback<CookieInclusionStatus> callback; cm.SetCanonicalCookieAsync(std::move(cookie), http_url, CookieOptions::MakeAllInclusive(), callback.MakeCallback()); callback.WaitUntilDone(); EXPECT_TRUE(callback.result().HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus::EXCLUDE_SECURE_ONLY})); + {CookieInclusionStatus::EXCLUDE_SECURE_ONLY})); } TEST_F(CookieMonsterTest, RejectCreatedHttpOnlyCookieOnSet) { @@ -3674,7 +3777,7 @@ TEST_F(CookieMonsterTest, RejectCreatedHttpOnlyCookieOnSet) { std::string cookie_line = "foo=bar; HttpOnly"; CookieMonster cm(nullptr, nullptr); - CanonicalCookie::CookieInclusionStatus status; + CookieInclusionStatus status; // Cookie can be created successfully; HttpOnly is not checked on Create. auto cookie = CanonicalCookie::Create(url, cookie_line, base::Time::Now(), @@ -3690,12 +3793,12 @@ TEST_F(CookieMonsterTest, RejectCreatedHttpOnlyCookieOnSet) { CookieOptions::SameSiteCookieContext( CookieOptions::SameSiteCookieContext::ContextType::SAME_SITE_STRICT)); options_no_httponly.set_exclude_httponly(); // Default, but make it explicit. - ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus> callback; + ResultSavingCookieCallback<CookieInclusionStatus> callback; cm.SetCanonicalCookieAsync(std::move(cookie), url, options_no_httponly, callback.MakeCallback()); callback.WaitUntilDone(); EXPECT_TRUE(callback.result().HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus::EXCLUDE_HTTP_ONLY})); + {CookieInclusionStatus::EXCLUDE_HTTP_ONLY})); } // Test the CookiesWithoutSameSiteMustBeSecure experimental option (in @@ -3708,7 +3811,7 @@ TEST_F(CookieMonsterTest, CookiesWithoutSameSiteMustBeSecure) { bool is_cookies_without_samesite_must_be_secure_enabled; bool is_url_secure; std::string cookie_line; - CanonicalCookie::CookieInclusionStatus expected_set_cookie_result; + CookieInclusionStatus expected_set_cookie_result; // Only makes sense to check if result is INCLUDE: CookieEffectiveSameSite expected_effective_samesite = CookieEffectiveSameSite::NO_RESTRICTION; @@ -3716,80 +3819,67 @@ TEST_F(CookieMonsterTest, CookiesWithoutSameSiteMustBeSecure) { } test_cases[] = { // Feature enabled: // Cookie set from a secure URL with SameSite enabled is not rejected. - {true, true, "A=B; SameSite=Lax", - CanonicalCookie::CookieInclusionStatus(), + {true, true, "A=B; SameSite=Lax", CookieInclusionStatus(), CookieEffectiveSameSite::LAX_MODE}, // Cookie set from a secure URL which is defaulted into Lax is not // rejected. {true, true, "A=B", // recently-set session cookie. - CanonicalCookie::CookieInclusionStatus(), - CookieEffectiveSameSite::LAX_MODE_ALLOW_UNSAFE, kShortAge}, + CookieInclusionStatus(), CookieEffectiveSameSite::LAX_MODE_ALLOW_UNSAFE, + kShortAge}, {true, true, "A=B", // not-recently-set session cookie. - CanonicalCookie::CookieInclusionStatus(), - CookieEffectiveSameSite::LAX_MODE, kLongAge}, + CookieInclusionStatus(), CookieEffectiveSameSite::LAX_MODE, kLongAge}, // Cookie set from a secure URL with SameSite=None and Secure is set. - {true, true, "A=B; SameSite=None; Secure", - CanonicalCookie::CookieInclusionStatus(), + {true, true, "A=B; SameSite=None; Secure", CookieInclusionStatus(), CookieEffectiveSameSite::NO_RESTRICTION}, // Cookie set from a secure URL with SameSite=None but not specifying // Secure is rejected. {true, true, "A=B; SameSite=None", - CanonicalCookie::CookieInclusionStatus( - CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_SAMESITE_NONE_INSECURE, - CanonicalCookie::CookieInclusionStatus:: - WARN_SAMESITE_NONE_INSECURE)}, + CookieInclusionStatus( + CookieInclusionStatus::EXCLUDE_SAMESITE_NONE_INSECURE, + CookieInclusionStatus::WARN_SAMESITE_NONE_INSECURE)}, // Cookie set from an insecure URL which defaults into LAX_MODE is not // rejected. {true, false, "A=B", // recently-set session cookie. - CanonicalCookie::CookieInclusionStatus(), - CookieEffectiveSameSite::LAX_MODE_ALLOW_UNSAFE, kShortAge}, + CookieInclusionStatus(), CookieEffectiveSameSite::LAX_MODE_ALLOW_UNSAFE, + kShortAge}, {true, false, "A=B", // not-recently-set session cookie. - CanonicalCookie::CookieInclusionStatus(), - CookieEffectiveSameSite::LAX_MODE, kLongAge}, + CookieInclusionStatus(), CookieEffectiveSameSite::LAX_MODE, kLongAge}, {true, false, "A=B; Max-Age=1000000", // recently-set persistent cookie. - CanonicalCookie::CookieInclusionStatus(), - CookieEffectiveSameSite::LAX_MODE_ALLOW_UNSAFE, kShortAge}, + CookieInclusionStatus(), CookieEffectiveSameSite::LAX_MODE_ALLOW_UNSAFE, + kShortAge}, {true, false, "A=B; Max-Age=1000000", // not-recently-set persistent cookie. - CanonicalCookie::CookieInclusionStatus(), - CookieEffectiveSameSite::LAX_MODE, kLongAge}, + CookieInclusionStatus(), CookieEffectiveSameSite::LAX_MODE, kLongAge}, // Feature not enabled (but SameSiteByDefaultCookies is still enabled): // Cookie set from a secure URL with SameSite enabled is not rejected. - {false, true, "A=B; SameSite=Lax", - CanonicalCookie::CookieInclusionStatus(), + {false, true, "A=B; SameSite=Lax", CookieInclusionStatus(), CookieEffectiveSameSite::LAX_MODE}, // Cookie set from a secure URL which is defaulted into Lax is not // rejected. {false, true, "A=B", // recently-set session cookie. - CanonicalCookie::CookieInclusionStatus(), - CookieEffectiveSameSite::LAX_MODE_ALLOW_UNSAFE, kShortAge}, + CookieInclusionStatus(), CookieEffectiveSameSite::LAX_MODE_ALLOW_UNSAFE, + kShortAge}, {false, true, "A=B", // not-recently-set session cookie. - CanonicalCookie::CookieInclusionStatus(), - CookieEffectiveSameSite::LAX_MODE, kLongAge}, + CookieInclusionStatus(), CookieEffectiveSameSite::LAX_MODE, kLongAge}, // Cookie set from a secure URL with SameSite=None and Secure is set. - {false, true, "A=B; SameSite=None; Secure", - CanonicalCookie::CookieInclusionStatus(), + {false, true, "A=B; SameSite=None; Secure", CookieInclusionStatus(), CookieEffectiveSameSite::NO_RESTRICTION}, // Cookie set from an insecure URL with SameSite=None (which can't ever be // secure because it's an insecure URL) is NOT rejected, because // CookiesWithoutSameSiteMustBeSecure is not enabled. {false, false, "A=B; SameSite=None", - CanonicalCookie::CookieInclusionStatus::MakeFromReasonsForTesting( - std::vector< - CanonicalCookie::CookieInclusionStatus::ExclusionReason>(), - {CanonicalCookie::CookieInclusionStatus:: - WARN_SAMESITE_NONE_INSECURE}), + CookieInclusionStatus::MakeFromReasonsForTesting( + std::vector<CookieInclusionStatus::ExclusionReason>(), + {CookieInclusionStatus::WARN_SAMESITE_NONE_INSECURE}), CookieEffectiveSameSite::NO_RESTRICTION}, // Cookie set from an insecure URL which is defaulted into Lax is not // rejected. {false, false, "A=B", // recently-set session cookie. - CanonicalCookie::CookieInclusionStatus(), - CookieEffectiveSameSite::LAX_MODE_ALLOW_UNSAFE, kShortAge}, + CookieInclusionStatus(), CookieEffectiveSameSite::LAX_MODE_ALLOW_UNSAFE, + kShortAge}, {false, false, "A=B", // not-recently-set session cookie. - CanonicalCookie::CookieInclusionStatus(), - CookieEffectiveSameSite::LAX_MODE, kLongAge}, + CookieInclusionStatus(), CookieEffectiveSameSite::LAX_MODE, kLongAge}, }; auto cm = std::make_unique<CookieMonster>(nullptr, nullptr); @@ -3820,10 +3910,9 @@ TEST_F(CookieMonsterTest, CookiesWithoutSameSiteMustBeSecure) { base::nullopt /* server_time */); // Make a copy so we can delete it after the test. CanonicalCookie cookie_copy = *cookie; - CanonicalCookie::CookieInclusionStatus result = - SetCanonicalCookieReturnStatus( - cm.get(), std::move(cookie), url, - true /* can_modify_httponly (irrelevant) */); + CookieInclusionStatus result = SetCanonicalCookieReturnStatus( + cm.get(), std::move(cookie), url, + true /* can_modify_httponly (irrelevant) */); EXPECT_EQ(test.expected_set_cookie_result, result) << "Test case " << i << " failed."; if (result.IsInclude()) { diff --git a/chromium/net/cookies/cookie_store.h b/chromium/net/cookies/cookie_store.h index 4157f0ce83a..47f2942cd32 100644 --- a/chromium/net/cookies/cookie_store.h +++ b/chromium/net/cookies/cookie_store.h @@ -20,6 +20,7 @@ #include "net/cookies/canonical_cookie.h" #include "net/cookies/cookie_access_delegate.h" #include "net/cookies/cookie_deletion_info.h" +#include "net/cookies/cookie_inclusion_status.h" #include "net/cookies/cookie_options.h" class GURL; @@ -45,8 +46,8 @@ class NET_EXPORT CookieStore { public: // Callback definitions. using GetCookieListCallback = - base::OnceCallback<void(const CookieStatusList& included_cookies, - const CookieStatusList& excluded_list)>; + base::OnceCallback<void(const CookieAccessResultList& included_cookies, + const CookieAccessResultList& excluded_list)>; using GetAllCookiesCallback = base::OnceCallback<void(const CookieList& cookies)>; // |access_semantics_list| is guaranteed to the same length as |cookies|. @@ -54,7 +55,7 @@ class NET_EXPORT CookieStore { const CookieList& cookies, const std::vector<CookieAccessSemantics>& access_semantics_list)>; using SetCookiesCallback = - base::OnceCallback<void(CanonicalCookie::CookieInclusionStatus status)>; + base::OnceCallback<void(CookieInclusionStatus status)>; using DeleteCallback = base::OnceCallback<void(uint32_t num_deleted)>; using SetCookieableSchemesCallback = base::OnceCallback<void(bool success)>; diff --git a/chromium/net/cookies/cookie_store_test_callbacks.cc b/chromium/net/cookies/cookie_store_test_callbacks.cc index a582a6eb8d2..67461b50bf0 100644 --- a/chromium/net/cookies/cookie_store_test_callbacks.cc +++ b/chromium/net/cookies/cookie_store_test_callbacks.cc @@ -60,10 +60,11 @@ GetCookieListCallback::GetCookieListCallback(base::Thread* run_in_thread) GetCookieListCallback::~GetCookieListCallback() = default; -void GetCookieListCallback::Run(const CookieStatusList& cookies, - const CookieStatusList& excluded_cookies) { - cookies_with_statuses_ = cookies; - cookies_ = cookie_util::StripStatuses(cookies); +void GetCookieListCallback::Run( + const CookieAccessResultList& cookies, + const CookieAccessResultList& excluded_cookies) { + cookies_with_access_results_ = cookies; + cookies_ = cookie_util::StripAccessResults(cookies); excluded_cookies_ = excluded_cookies; CallbackEpilogue(); } diff --git a/chromium/net/cookies/cookie_store_test_callbacks.h b/chromium/net/cookies/cookie_store_test_callbacks.h index 54b00b565d7..b3195c20aca 100644 --- a/chromium/net/cookies/cookie_store_test_callbacks.h +++ b/chromium/net/cookies/cookie_store_test_callbacks.h @@ -109,26 +109,27 @@ class GetCookieListCallback : public CookieCallback { ~GetCookieListCallback(); - void Run(const CookieStatusList& cookies, - const CookieStatusList& excluded_cookies); + void Run(const CookieAccessResultList& cookies, + const CookieAccessResultList& excluded_cookies); // Makes a callback that will invoke Run. Assumes that |this| will be kept // alive till the time the callback is used. - base::OnceCallback<void(const CookieStatusList&, const CookieStatusList&)> + base::OnceCallback<void(const CookieAccessResultList&, + const CookieAccessResultList&)> MakeCallback() { return base::BindOnce(&GetCookieListCallback::Run, base::Unretained(this)); } const CookieList& cookies() { return cookies_; } - const CookieStatusList& cookies_with_statuses() { - return cookies_with_statuses_; + const CookieAccessResultList& cookies_with_access_results() { + return cookies_with_access_results_; } - const CookieStatusList& excluded_cookies() { return excluded_cookies_; } + const CookieAccessResultList& excluded_cookies() { return excluded_cookies_; } private: CookieList cookies_; - CookieStatusList cookies_with_statuses_; - CookieStatusList excluded_cookies_; + CookieAccessResultList cookies_with_access_results_; + CookieAccessResultList excluded_cookies_; }; class GetAllCookiesCallback : public CookieCallback { diff --git a/chromium/net/cookies/cookie_store_test_helpers.cc b/chromium/net/cookies/cookie_store_test_helpers.cc index a709c84f134..aae0c873540 100644 --- a/chromium/net/cookies/cookie_store_test_helpers.cc +++ b/chromium/net/cookies/cookie_store_test_helpers.cc @@ -65,25 +65,24 @@ DelayedCookieMonsterChangeDispatcher::AddCallbackForAllChanges( } DelayedCookieMonster::DelayedCookieMonster() - : cookie_monster_(new CookieMonster(nullptr /* store */, - nullptr /* netlog */)), + : cookie_monster_( + new CookieMonster(nullptr /* store */, nullptr /* netlog */)), did_run_(false), - result_( - CanonicalCookie::CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE) {} + result_(CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE) {} DelayedCookieMonster::~DelayedCookieMonster() = default; void DelayedCookieMonster::SetCookiesInternalCallback( - CanonicalCookie::CookieInclusionStatus result) { + CookieInclusionStatus result) { result_ = result; did_run_ = true; } void DelayedCookieMonster::GetCookieListWithOptionsInternalCallback( - const CookieStatusList& cookie_list, - const CookieStatusList& excluded_cookies) { - cookie_status_list_ = cookie_list; - cookie_list_ = cookie_util::StripStatuses(cookie_status_list_); + const CookieAccessResultList& cookie_list, + const CookieAccessResultList& excluded_cookies) { + cookie_access_result_list_ = cookie_list; + cookie_list_ = cookie_util::StripAccessResults(cookie_access_result_list_); did_run_ = true; } @@ -136,7 +135,8 @@ void DelayedCookieMonster::InvokeSetCookiesCallback( void DelayedCookieMonster::InvokeGetCookieListCallback( CookieMonster::GetCookieListCallback callback) { if (!callback.is_null()) - std::move(callback).Run(cookie_status_list_, CookieStatusList()); + std::move(callback).Run(cookie_access_result_list_, + CookieAccessResultList()); } void DelayedCookieMonster::DeleteCanonicalCookieAsync( diff --git a/chromium/net/cookies/cookie_store_test_helpers.h b/chromium/net/cookies/cookie_store_test_helpers.h index ae6a152b7f2..5f9f03d15d4 100644 --- a/chromium/net/cookies/cookie_store_test_helpers.h +++ b/chromium/net/cookies/cookie_store_test_helpers.h @@ -86,13 +86,12 @@ class DelayedCookieMonster : public CookieStore { private: // Be called immediately from CookieMonster. - void SetCookiesInternalCallback( - CanonicalCookie::CookieInclusionStatus result); + void SetCookiesInternalCallback(CookieInclusionStatus result); void GetCookiesWithOptionsInternalCallback(const std::string& cookie); void GetCookieListWithOptionsInternalCallback( - const CookieStatusList& cookie, - const CookieStatusList& excluded_cookies); + const CookieAccessResultList& cookie, + const CookieAccessResultList& excluded_cookies); // Invoke the original callbacks. @@ -107,10 +106,10 @@ class DelayedCookieMonster : public CookieStore { DelayedCookieMonsterChangeDispatcher change_dispatcher_; bool did_run_; - CanonicalCookie::CookieInclusionStatus result_; + CookieInclusionStatus result_; std::string cookie_; std::string cookie_line_; - CookieStatusList cookie_status_list_; + CookieAccessResultList cookie_access_result_list_; CookieList cookie_list_; DISALLOW_COPY_AND_ASSIGN(DelayedCookieMonster); diff --git a/chromium/net/cookies/cookie_store_unittest.h b/chromium/net/cookies/cookie_store_unittest.h index ee8e46f9b1d..026ed96ba11 100644 --- a/chromium/net/cookies/cookie_store_unittest.h +++ b/chromium/net/cookies/cookie_store_unittest.h @@ -171,7 +171,8 @@ class CookieStoreTest : public testing::Test { } // This does not update the access time on the cookies. - CookieStatusList GetExcludedCookiesForURL(CookieStore* cs, const GURL& url) { + CookieAccessResultList GetExcludedCookiesForURL(CookieStore* cs, + const GURL& url) { DCHECK(cs); GetCookieListCallback callback; CookieOptions options = CookieOptions::MakeAllInclusive(); @@ -200,7 +201,7 @@ class CookieStoreTest : public testing::Test { if (!cookie) return false; DCHECK(cs); - ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus> callback; + ResultSavingCookieCallback<CookieInclusionStatus> callback; cs->SetCanonicalCookieAsync(std::move(cookie), url, options, callback.MakeCallback()); callback.WaitUntilDone(); @@ -212,7 +213,7 @@ class CookieStoreTest : public testing::Test { const GURL& source_url, bool can_modify_httponly) { DCHECK(cs); - ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus> callback; + ResultSavingCookieCallback<CookieInclusionStatus> callback; CookieOptions options; if (can_modify_httponly) options.set_include_httponly(); @@ -248,11 +249,11 @@ class CookieStoreTest : public testing::Test { return CreateAndSetCookie(cs, url, cookie_line, options); } - CanonicalCookie::CookieInclusionStatus CreateAndSetCookieReturnStatus( + CookieInclusionStatus CreateAndSetCookieReturnStatus( CookieStore* cs, const GURL& url, const std::string& cookie_line) { - CanonicalCookie::CookieInclusionStatus create_status; + CookieInclusionStatus create_status; auto cookie = CanonicalCookie::Create(url, cookie_line, base::Time::Now(), base::nullopt /* server_time */, &create_status); @@ -267,20 +268,20 @@ class CookieStoreTest : public testing::Test { net::CookieOptions::SameSiteCookieContext::MakeInclusive()); DCHECK(cs); - ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus> callback; + ResultSavingCookieCallback<CookieInclusionStatus> callback; cs->SetCanonicalCookieAsync(std::move(cookie), url, options, callback.MakeCallback()); callback.WaitUntilDone(); return callback.result(); } - CanonicalCookie::CookieInclusionStatus SetCanonicalCookieReturnStatus( + CookieInclusionStatus SetCanonicalCookieReturnStatus( CookieStore* cs, std::unique_ptr<CanonicalCookie> cookie, const GURL& source_url, bool can_modify_httponly) { DCHECK(cs); - ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus> callback; + ResultSavingCookieCallback<CookieInclusionStatus> callback; CookieOptions options; if (can_modify_httponly) options.set_include_httponly(); @@ -568,12 +569,11 @@ TYPED_TEST_P(CookieStoreTest, SetCanonicalCookieTest) { base::Time(), true, false, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT), this->http_www_foo_.url(), true) - .HasExclusionReason( - CanonicalCookie::CookieInclusionStatus::EXCLUDE_SECURE_ONLY)); + .HasExclusionReason(CookieInclusionStatus::EXCLUDE_SECURE_ONLY)); // A Secure cookie can be created from an insecure URL, but is rejected upon // setting. - CanonicalCookie::CookieInclusionStatus status; + CookieInclusionStatus status; auto cookie = CanonicalCookie::Create( this->http_www_foo_.url(), "foo=1; Secure", base::Time::Now(), base::nullopt /* server_time */, &status); @@ -582,8 +582,7 @@ TYPED_TEST_P(CookieStoreTest, SetCanonicalCookieTest) { EXPECT_TRUE( this->SetCanonicalCookieReturnStatus(cs, std::move(cookie), this->http_www_foo_.url(), true) - .HasExclusionReason( - CanonicalCookie::CookieInclusionStatus::EXCLUDE_SECURE_ONLY)); + .HasExclusionReason(CookieInclusionStatus::EXCLUDE_SECURE_ONLY)); // A secure source is also required for overwriting secure cookies. Writing // a secure cookie then overwriting it from a non-secure source should fail. @@ -603,8 +602,7 @@ TYPED_TEST_P(CookieStoreTest, SetCanonicalCookieTest) { base::Time(), true /* secure */, false /* httponly */, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT), this->http_www_foo_.url(), true /* modify_http_only */) - .HasExclusionReason( - CanonicalCookie::CookieInclusionStatus::EXCLUDE_SECURE_ONLY)); + .HasExclusionReason(CookieInclusionStatus::EXCLUDE_SECURE_ONLY)); if (TypeParam::supports_http_only) { // Permission to modify http only cookies is required to set an @@ -618,12 +616,11 @@ TYPED_TEST_P(CookieStoreTest, SetCanonicalCookieTest) { true /* httponly */, CookieSameSite::LAX_MODE, COOKIE_PRIORITY_DEFAULT), this->http_www_foo_.url(), false /* modify_http_only */) - .HasExclusionReason( - CanonicalCookie::CookieInclusionStatus::EXCLUDE_HTTP_ONLY)); + .HasExclusionReason(CookieInclusionStatus::EXCLUDE_HTTP_ONLY)); // A HttpOnly cookie can be created, but is rejected // upon setting if the options do not specify include_httponly. - CanonicalCookie::CookieInclusionStatus create_status; + CookieInclusionStatus create_status; auto c = CanonicalCookie::Create( this->http_www_foo_.url(), "bar=1; HttpOnly", base::Time::Now(), base::nullopt /* server_time */, &create_status); @@ -633,8 +630,7 @@ TYPED_TEST_P(CookieStoreTest, SetCanonicalCookieTest) { this->SetCanonicalCookieReturnStatus(cs, std::move(c), this->http_www_foo_.url(), false /* can_modify_httponly */) - .HasExclusionReason( - CanonicalCookie::CookieInclusionStatus::EXCLUDE_HTTP_ONLY)); + .HasExclusionReason(CookieInclusionStatus::EXCLUDE_HTTP_ONLY)); // Permission to modify httponly cookies is also required to overwrite // an httponly cookie. @@ -655,8 +651,7 @@ TYPED_TEST_P(CookieStoreTest, SetCanonicalCookieTest) { true /* httponly */, CookieSameSite::LAX_MODE, COOKIE_PRIORITY_DEFAULT), this->http_www_foo_.url(), false /* modify_http_only */) - .HasExclusionReason( - CanonicalCookie::CookieInclusionStatus::EXCLUDE_HTTP_ONLY)); + .HasExclusionReason(CookieInclusionStatus::EXCLUDE_HTTP_ONLY)); } else { // Leave store in same state as if the above tests had been run. EXPECT_TRUE(this->SetCanonicalCookie( diff --git a/chromium/net/cookies/cookie_util.cc b/chromium/net/cookies/cookie_util.cc index 7f3afe4e178..99859d89606 100644 --- a/chromium/net/cookies/cookie_util.cc +++ b/chromium/net/cookies/cookie_util.cc @@ -11,6 +11,7 @@ #include "base/callback.h" #include "base/check.h" #include "base/feature_list.h" +#include "base/metrics/histogram_macros.h" #include "base/notreached.h" #include "base/stl_util.h" #include "base/strings/string_piece.h" @@ -121,6 +122,10 @@ CookieOptions::SameSiteCookieContext ComputeSameSiteContextForSet( } // namespace +void FireStorageAccessHistogram(StorageAccessResult result) { + UMA_HISTOGRAM_ENUMERATION("API.StorageAccess.AllowedRequests", result); +} + bool DomainIsHostOnly(const std::string& domain_string) { return (domain_string.empty() || domain_string[0] != '.'); } @@ -551,6 +556,48 @@ CookieOptions::SameSiteCookieContext ComputeSameSiteContextForSubresource( return CookieOptions::SameSiteCookieContext::MakeInclusive(); } +bool IsSameSiteCompatPair(const CanonicalCookie& c1, + const CanonicalCookie& c2, + const CookieOptions& options) { + if (options.exclude_httponly() && (c1.IsHttpOnly() || c2.IsHttpOnly())) + return false; + + if (c1.IsEquivalent(c2)) + return false; + + // One of them is SameSite=None and Secure; the other one has unspecified + // SameSite. + bool same_site_attributes_ok = + c1.SameSite() == CookieSameSite::NO_RESTRICTION && c1.IsSecure() && + c2.SameSite() == CookieSameSite::UNSPECIFIED; + same_site_attributes_ok = + same_site_attributes_ok || + (c2.SameSite() == CookieSameSite::NO_RESTRICTION && c2.IsSecure() && + c1.SameSite() == CookieSameSite::UNSPECIFIED); + if (!same_site_attributes_ok) + return false; + + if (c1.Domain() != c2.Domain() || c1.Path() != c2.Path() || + c1.Value() != c2.Value()) { + return false; + } + + DCHECK(c1.Name() != c2.Name()); + std::string shorter, longer; + std::tie(shorter, longer) = (c1.Name().length() < c2.Name().length()) + ? std::tie(c1.Name(), c2.Name()) + : std::tie(c2.Name(), c1.Name()); + // One of them has a name that is a prefix or suffix of the other and has + // length at least 3 characters. + if (shorter.length() < kMinCompatPairNameLength) + return false; + if (base::StartsWith(longer, shorter, base::CompareCase::SENSITIVE) || + base::EndsWith(longer, shorter, base::CompareCase::SENSITIVE)) { + return true; + } + return false; +} + bool IsSameSiteByDefaultCookiesEnabled() { return base::FeatureList::IsEnabled(features::kSameSiteByDefaultCookies); } @@ -610,21 +657,23 @@ bool DoesCreationTimeGrantLegacySemantics(base::Time creation_date) { return (base::Time::Now() - creation_date) < recency_threshold; } -base::OnceCallback<void(net::CanonicalCookie::CookieInclusionStatus)> +base::OnceCallback<void(CookieInclusionStatus)> AdaptCookieInclusionStatusToBool(base::OnceCallback<void(bool)> callback) { return base::BindOnce( [](base::OnceCallback<void(bool)> inner_callback, - const net::CanonicalCookie::CookieInclusionStatus status) { + const CookieInclusionStatus status) { bool success = status.IsInclude(); std::move(inner_callback).Run(success); }, std::move(callback)); } -CookieList StripStatuses(const CookieStatusList& cookie_status_list) { +CookieList StripAccessResults( + const CookieAccessResultList& cookie_access_results_list) { CookieList cookies; - for (const CookieWithStatus& cookie_with_status : cookie_status_list) { - cookies.push_back(cookie_with_status.cookie); + for (const CookieWithAccessResult& cookie_with_access_result : + cookie_access_results_list) { + cookies.push_back(cookie_with_access_result.cookie); } return cookies; } diff --git a/chromium/net/cookies/cookie_util.h b/chromium/net/cookies/cookie_util.h index 3634058c1b0..be3cd3f458d 100644 --- a/chromium/net/cookies/cookie_util.h +++ b/chromium/net/cookies/cookie_util.h @@ -13,6 +13,7 @@ #include "base/time/time.h" #include "net/base/net_export.h" #include "net/cookies/canonical_cookie.h" +#include "net/cookies/cookie_inclusion_status.h" #include "net/cookies/cookie_options.h" #include "net/cookies/site_for_cookies.h" #include "url/origin.h" @@ -27,6 +28,23 @@ const int kVlogPerCookieMonster = 1; const int kVlogSetCookies = 7; const int kVlogGarbageCollection = 5; +// Minimum name length for SameSite compatibility pair heuristic (see +// IsSameSiteCompatPair() below.) +const int kMinCompatPairNameLength = 3; + +// This enum must match the numbering for StorageAccessResult in +// histograms/enums.xml. Do not reorder or remove items, only add new items +// at the end. +enum class StorageAccessResult { + ACCESS_BLOCKED = 0, + ACCESS_ALLOWED = 1, + ACCESS_ALLOWED_STORAGE_ACCESS_GRANT = 2, + kMaxValue = ACCESS_ALLOWED_STORAGE_ACCESS_GRANT, +}; +// Helper to fire telemetry indicating if a given request for storage was +// allowed or not by the provided |result|. +NET_EXPORT void FireStorageAccessHistogram(StorageAccessResult result); + // Returns the effective TLD+1 for a given host. This only makes sense for http // and https schemes. For other schemes, the host will be returned unchanged // (minus any leading period). @@ -172,6 +190,26 @@ ComputeSameSiteContextForSubresource(const GURL& url, const SiteForCookies& site_for_cookies, bool force_ignore_site_for_cookies); +// Evaluates a heuristic to determine whether |c1| and |c2| are likely to be a +// "double cookie" pair used for SameSite=None compatibility reasons. +// +// This returns true if all of the following are true: +// 1. The cookies are not equivalent (i.e. same name, domain, and path). +// 2. One of them is SameSite=None and Secure; the other one has unspecified +// SameSite. +// 3. Their domains are equal. +// 4. Their paths are equal. +// 5. Their values are equal. +// 6. One of them has a name that is a prefix or suffix of the other and has +// length at least 3 characters. +// +// |options| is the CookieOptions object used to access (get/set) the cookies. +// If the CookieOptions indicate that HttpOnly cookies are not allowed, this +// will return false if either of |c1| or |c2| is HttpOnly. +NET_EXPORT bool IsSameSiteCompatPair(const CanonicalCookie& c1, + const CanonicalCookie& c2, + const CookieOptions& options); + // Returns whether the respective SameSite feature is enabled. NET_EXPORT bool IsSameSiteByDefaultCookiesEnabled(); NET_EXPORT bool IsCookiesWithoutSameSiteMustBeSecureEnabled(); @@ -198,12 +236,13 @@ bool DoesCreationTimeGrantLegacySemantics(base::Time creation_date); // // Can be used with SetCanonicalCookie when you don't need to know why a cookie // was blocked, only whether it was blocked. -NET_EXPORT base::OnceCallback<void(CanonicalCookie::CookieInclusionStatus)> +NET_EXPORT base::OnceCallback<void(CookieInclusionStatus)> AdaptCookieInclusionStatusToBool(base::OnceCallback<void(bool)> callback); -// Turn a CookieStatusList into a CookieList by stripping out the statuses -// (for callers who don't care about the statuses). -NET_EXPORT CookieList StripStatuses(const CookieStatusList& cookie_status_list); +// Turn a CookieAccessResultList into a CookieList by stripping out access +// results (for callers who only care about cookies). +NET_EXPORT CookieList +StripAccessResults(const CookieAccessResultList& cookie_access_result_list); } // namespace cookie_util } // namespace net diff --git a/chromium/net/cookies/cookie_util_unittest.cc b/chromium/net/cookies/cookie_util_unittest.cc index b95e1d6da26..14f8edf50f7 100644 --- a/chromium/net/cookies/cookie_util_unittest.cc +++ b/chromium/net/cookies/cookie_util_unittest.cc @@ -1216,13 +1216,11 @@ TEST(CookieUtilTest, AdaptCookieInclusionStatusToBool) { base::OnceCallback<void(bool)> callback = base::BindLambdaForTesting( [&result_out](bool result) { result_out = result; }); - base::OnceCallback<void(CanonicalCookie::CookieInclusionStatus)> - adapted_callback = - cookie_util::AdaptCookieInclusionStatusToBool(std::move(callback)); + base::OnceCallback<void(CookieInclusionStatus)> adapted_callback = + cookie_util::AdaptCookieInclusionStatusToBool(std::move(callback)); std::move(adapted_callback) - .Run(CanonicalCookie::CookieInclusionStatus( - CanonicalCookie::CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR)); + .Run(CookieInclusionStatus(CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR)); EXPECT_FALSE(result_out); @@ -1233,11 +1231,144 @@ TEST(CookieUtilTest, AdaptCookieInclusionStatusToBool) { adapted_callback = cookie_util::AdaptCookieInclusionStatusToBool(std::move(callback)); - std::move(adapted_callback).Run(CanonicalCookie::CookieInclusionStatus()); + std::move(adapted_callback).Run(CookieInclusionStatus()); EXPECT_TRUE(result_out); } +TEST(CookieUtilTest, IsSameSiteCompatPair) { + ASSERT_EQ(3, cookie_util::kMinCompatPairNameLength) + << "This test assumes that SameSite compatibility pairs have cookie name " + "length at least 3."; + GURL url("https://www.site.example/path"); + + struct { + const char* cookie_line_1; + const char* cookie_line_2; + bool expected_is_same_site_compat_pair; + } kTestCases[] = { + // Matching cases + {"name=value; SameSite=None; Secure", "name_legacy=value", true}, + {"uid=value; SameSite=None; Secure", "uid_old=value", true}, + {"name=value; SameSite=None; Secure", "name2=value; Secure", true}, + {"name_samesite=value; SameSite=None; Secure", "name=value", true}, + {"__Secure-name=value; SameSite=None; Secure", "name=value", true}, + {"__Secure-3Pname=value; SameSite=None; Secure", "name=value", true}, + {"name=value; SameSite=None; Secure; HttpOnly", "name_legacy=value", + true}, + {"name=value; SameSite=None; Secure; Domain=site.example", + "name_legacy=value; Secure; Domain=site.example", true}, + // Fails because cookies are equivalent + {"name=value; SameSite=None; Secure", "name=value", false}, + // Fails SameSite criterion + {"name=value", "name_legacy=value", false}, + {"name=value; SameSite=None", "name_legacy=value", false}, + {"name=value; SameSite=None; Secure", "name_legacy=value; SameSite=None", + false}, + {"name=value; SameSite=None; Secure", + "name_legacy=value; SameSite=None; Secure", false}, + // Fails Domain criterion + {"name=value; SameSite=None; Secure; Domain=site.example", + "name_legacy=value", false}, + {"name=value; SameSite=None; Secure; Domain=www.site.example", + "name_legacy=value", false}, + {"name=value; SameSite=None; Secure", + "name_legacy=value; Domain=site.example", false}, + {"name=value; SameSite=None; Secure", + "name_legacy=value; Domain=www.site.example", false}, + // Fails Path criterion + {"name=value; SameSite=None; Secure; Path=/path", "name_legacy=value", + false}, + {"name=value; SameSite=None; Secure; Path=/path", + "name_legacy=value; Path=/", false}, + {"name=value; SameSite=None; Secure; Path=/", + "name_legacy=value; Path=/path", false}, + {"name=value; SameSite=None; Secure", "name_legacy=value; Path=/path", + false}, + // Fails value criterion + {"name=value; SameSite=None; Secure", "name_legacy=foobar", false}, + {"name=value; SameSite=None; Secure", "name_legacy=value2", false}, + // Fails name length criterion + {"id=value; SameSite=None; Secure", "id_legacy=value", false}, + {"id_samesite=value; SameSite=None; Secure", "id=value", false}, + {"value; SameSite=None; Secure", "legacy=value", false}, + // Fails suffix/prefix criterion + {"name_samesite=value; SameSite=None; Secure", "name_legacy=value", + false}, + {"name1=value; SameSite=None; Secure", "name2=value", false}, + }; + + for (const auto& test_case : kTestCases) { + auto cookie1 = CanonicalCookie::Create(url, test_case.cookie_line_1, + base::Time::Now(), base::nullopt); + auto cookie2 = CanonicalCookie::Create(url, test_case.cookie_line_2, + base::Time::Now(), base::nullopt); + + ASSERT_TRUE(cookie1); + ASSERT_TRUE(cookie2); + EXPECT_EQ(test_case.expected_is_same_site_compat_pair, + cookie_util::IsSameSiteCompatPair( + *cookie1, *cookie2, CookieOptions::MakeAllInclusive())); + EXPECT_EQ(test_case.expected_is_same_site_compat_pair, + cookie_util::IsSameSiteCompatPair( + *cookie2, *cookie1, CookieOptions::MakeAllInclusive())); + } +} + +TEST(CookieUtilTest, IsSameSiteCompatPair_HttpOnly) { + GURL url("https://www.site.example/path"); + auto new_cookie = + CanonicalCookie::Create(url, "name=value; SameSite=None; Secure", + base::Time::Now(), base::nullopt); + auto legacy_cookie = CanonicalCookie::Create( + url, "name_legacy=value", base::Time::Now(), base::nullopt); + auto http_only_new_cookie = CanonicalCookie::Create( + url, "name=value; SameSite=None; Secure; HttpOnly", base::Time::Now(), + base::nullopt); + auto http_only_legacy_cookie = CanonicalCookie::Create( + url, "name_legacy=value; HttpOnly", base::Time::Now(), base::nullopt); + ASSERT_TRUE(new_cookie); + ASSERT_TRUE(legacy_cookie); + ASSERT_TRUE(http_only_new_cookie); + ASSERT_TRUE(http_only_legacy_cookie); + + // Allows HttpOnly access. + CookieOptions inclusive_options = CookieOptions::MakeAllInclusive(); + // Disallows HttpOnly access. + CookieOptions restrictive_options; + // Allows SameSite but not HttpOnly access. (SameSite shouldn't matter.) + CookieOptions same_site_options; + same_site_options.set_same_site_cookie_context( + CookieOptions::SameSiteCookieContext::MakeInclusive()); + + EXPECT_TRUE(cookie_util::IsSameSiteCompatPair(*new_cookie, *legacy_cookie, + inclusive_options)); + EXPECT_TRUE(cookie_util::IsSameSiteCompatPair( + *http_only_new_cookie, *legacy_cookie, inclusive_options)); + EXPECT_TRUE(cookie_util::IsSameSiteCompatPair( + *new_cookie, *http_only_legacy_cookie, inclusive_options)); + EXPECT_TRUE(cookie_util::IsSameSiteCompatPair( + *http_only_new_cookie, *http_only_legacy_cookie, inclusive_options)); + + EXPECT_TRUE(cookie_util::IsSameSiteCompatPair(*new_cookie, *legacy_cookie, + restrictive_options)); + EXPECT_FALSE(cookie_util::IsSameSiteCompatPair( + *http_only_new_cookie, *legacy_cookie, restrictive_options)); + EXPECT_FALSE(cookie_util::IsSameSiteCompatPair( + *new_cookie, *http_only_legacy_cookie, restrictive_options)); + EXPECT_FALSE(cookie_util::IsSameSiteCompatPair( + *http_only_new_cookie, *http_only_legacy_cookie, restrictive_options)); + + EXPECT_TRUE(cookie_util::IsSameSiteCompatPair(*new_cookie, *legacy_cookie, + same_site_options)); + EXPECT_FALSE(cookie_util::IsSameSiteCompatPair( + *http_only_new_cookie, *legacy_cookie, same_site_options)); + EXPECT_FALSE(cookie_util::IsSameSiteCompatPair( + *new_cookie, *http_only_legacy_cookie, same_site_options)); + EXPECT_FALSE(cookie_util::IsSameSiteCompatPair( + *http_only_new_cookie, *http_only_legacy_cookie, same_site_options)); +} + } // namespace } // namespace net diff --git a/chromium/net/data/ssl/certificates/398_days_1_second_after_2020_09_01.pem b/chromium/net/data/ssl/certificates/398_days_1_second_after_2020_09_01.pem new file mode 100644 index 00000000000..de02b968499 --- /dev/null +++ b/chromium/net/data/ssl/certificates/398_days_1_second_after_2020_09_01.pem @@ -0,0 +1,85 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + ef:2f:0a:6a:75:56:1e:b1:0b:03:50:df:7c:9a:63:bb + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, ST=California, L=Mountain View, O=Test CA, CN=Test Root CA + Validity + Not Before: Sep 2 00:00:00 2020 GMT + Not After : Oct 5 00:00:01 2021 GMT + Subject: C=US, ST=California, L=Mountain View, O=Test CA, CN=127.0.0.1 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:a0:5a:8e:f1:48:37:d4:3a:96:e6:c1:b5:20:88: + 16:f4:a5:80:cb:72:18:0c:db:c0:26:9f:75:8a:c1: + 58:3a:a9:9c:05:fe:f4:9c:92:7f:2e:59:ec:97:77: + ca:87:43:0a:05:4a:d3:a6:af:67:f7:c1:9a:f3:7e: + 92:86:ed:c9:3e:89:b4:fa:be:c8:a7:6c:b5:02:a0: + b5:02:f1:83:41:18:d6:86:29:c8:b1:be:16:e0:15: + 49:2e:bf:d0:a0:65:b9:05:4b:52:f0:be:88:a4:30: + b1:73:f3:aa:69:65:80:99:ad:14:62:13:bc:7b:52: + 93:fe:91:4f:8a:b1:4c:d3:52:ac:77:7c:92:02:fc: + 34:c7:15:10:a8:70:f1:77:ec:0d:c7:5b:53:df:49: + 1f:be:59:a0:93:45:4b:eb:71:c2:ba:8f:0c:43:73: + 96:5c:f4:96:bd:ed:cd:8c:18:79:db:18:ef:29:5e: + d9:78:80:c4:92:ec:6b:e1:19:19:83:c3:4e:bb:08: + 1c:5d:8e:a4:10:24:48:fe:69:f5:d2:01:ef:a5:59: + ce:de:2f:b4:20:f4:83:b3:ef:e0:e8:af:09:69:dc: + 09:70:79:9b:3b:60:f6:6f:32:71:93:7a:29:9a:f3: + e1:54:5f:9c:5a:41:33:2a:f9:29:ec:db:83:45:9d: + 4f:59 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:FALSE + X509v3 Subject Key Identifier: + 70:97:92:9D:2A:18:0D:AD:5F:DE:86:29:A0:44:DF:0B:3E:41:A4:D5 + X509v3 Authority Key Identifier: + keyid:9B:26:0B:8A:98:A9:BB:1D:B9:1F:1C:E3:1A:40:33:ED:8E:17:88:AB + + X509v3 Extended Key Usage: + TLS Web Server Authentication, TLS Web Client Authentication + X509v3 Subject Alternative Name: + IP Address:127.0.0.1 + Signature Algorithm: sha256WithRSAEncryption + 80:fe:bc:f5:9a:97:cf:a2:26:63:e5:4a:4a:53:71:bc:40:e2: + a5:30:21:28:f8:0e:12:b1:00:bc:ab:c8:50:8b:a7:fc:15:ef: + 3c:57:ef:92:90:ff:89:42:42:34:6d:00:ff:d6:0a:a8:89:0b: + c9:cf:fb:15:6a:6c:ab:c0:18:05:68:e5:a1:ef:d4:20:55:0c: + 4f:84:da:f7:df:29:4a:69:c9:8f:1c:c8:a6:c9:ca:a0:86:bc: + c4:4d:96:0f:62:63:4b:ea:85:8d:fa:5a:2b:7e:4e:1f:4a:60: + ed:8a:cc:f4:0f:6d:56:2f:ce:18:56:54:c3:1f:09:39:d2:62: + 63:75:11:3f:70:6f:cc:af:cb:c4:52:c7:1f:19:5f:ce:24:5b: + f8:54:c8:25:78:a8:51:eb:f9:26:41:e1:f0:a1:29:ec:fc:8c: + aa:ed:2c:fd:49:28:ff:ad:2a:ea:87:83:cf:02:ac:1b:2d:a1: + e7:0e:51:59:8f:62:ab:95:f1:b4:f2:9f:62:a7:04:b2:13:a8: + ae:41:88:b5:1c:0c:cf:5a:f3:a7:41:d2:9c:88:4d:50:54:14: + c3:58:c1:10:93:49:33:21:ff:00:41:0c:71:7e:00:ab:44:35: + ea:c1:c4:1c:76:a1:3a:09:21:35:8b:45:13:ba:9a:58:a0:e6: + 8f:1e:55:94 +-----BEGIN CERTIFICATE----- +MIIDzzCCAregAwIBAgIRAO8vCmp1Vh6xCwNQ33yaY7swDQYJKoZIhvcNAQELBQAw +YzELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDU1v +dW50YWluIFZpZXcxEDAOBgNVBAoMB1Rlc3QgQ0ExFTATBgNVBAMMDFRlc3QgUm9v +dCBDQTAeFw0yMDA5MDIwMDAwMDBaFw0yMTEwMDUwMDAwMDFaMGAxCzAJBgNVBAYT +AlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3 +MRAwDgYDVQQKDAdUZXN0IENBMRIwEAYDVQQDDAkxMjcuMC4wLjEwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCgWo7xSDfUOpbmwbUgiBb0pYDLchgM28Am +n3WKwVg6qZwF/vSckn8uWeyXd8qHQwoFStOmr2f3wZrzfpKG7ck+ibT6vsinbLUC +oLUC8YNBGNaGKcixvhbgFUkuv9CgZbkFS1LwvoikMLFz86ppZYCZrRRiE7x7UpP+ +kU+KsUzTUqx3fJIC/DTHFRCocPF37A3HW1PfSR++WaCTRUvrccK6jwxDc5Zc9Ja9 +7c2MGHnbGO8pXtl4gMSS7GvhGRmDw067CBxdjqQQJEj+afXSAe+lWc7eL7Qg9IOz +7+Dorwlp3AlweZs7YPZvMnGTeima8+FUX5xaQTMq+Sns24NFnU9ZAgMBAAGjgYAw +fjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBRwl5KdKhgNrV/ehimgRN8LPkGk1TAf +BgNVHSMEGDAWgBSbJguKmKm7HbkfHOMaQDPtjheIqzAdBgNVHSUEFjAUBggrBgEF +BQcDAQYIKwYBBQUHAwIwDwYDVR0RBAgwBocEfwAAATANBgkqhkiG9w0BAQsFAAOC +AQEAgP689ZqXz6ImY+VKSlNxvEDipTAhKPgOErEAvKvIUIun/BXvPFfvkpD/iUJC +NG0A/9YKqIkLyc/7FWpsq8AYBWjloe/UIFUMT4Ta998pSmnJjxzIpsnKoIa8xE2W +D2JjS+qFjfpaK35OH0pg7YrM9A9tVi/OGFZUwx8JOdJiY3URP3BvzK/LxFLHHxlf +ziRb+FTIJXioUev5JkHh8KEp7PyMqu0s/Uko/60q6oeDzwKsGy2h5w5RWY9iq5Xx +tPKfYqcEshOorkGItRwMz1rzp0HSnIhNUFQUw1jBEJNJMyH/AEEMcX4Aq0Q16sHE +HHahOgkhNYtFE7qaWKDmjx5VlA== +-----END CERTIFICATE----- diff --git a/chromium/net/data/ssl/certificates/398_days_after_2020_09_01.pem b/chromium/net/data/ssl/certificates/398_days_after_2020_09_01.pem new file mode 100644 index 00000000000..475fa9e71ea --- /dev/null +++ b/chromium/net/data/ssl/certificates/398_days_after_2020_09_01.pem @@ -0,0 +1,85 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + ef:2f:0a:6a:75:56:1e:b1:0b:03:50:df:7c:9a:63:ba + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, ST=California, L=Mountain View, O=Test CA, CN=Test Root CA + Validity + Not Before: Sep 2 00:00:00 2020 GMT + Not After : Oct 5 00:00:00 2021 GMT + Subject: C=US, ST=California, L=Mountain View, O=Test CA, CN=127.0.0.1 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:d3:41:3d:2b:88:60:a1:04:75:8f:26:22:b0:55: + 52:26:fd:78:db:f4:f8:c4:89:d7:f2:b2:77:85:02: + 25:4a:48:08:1d:e0:1c:df:90:29:9a:fa:94:ca:c5: + 51:ee:49:72:35:70:e0:40:f8:4f:7f:e3:97:68:9f: + 2d:1f:68:b6:1c:e6:29:02:cc:3d:ca:31:3f:e1:a5: + 70:30:40:f0:b0:4f:ed:21:5f:17:b8:49:30:bc:aa: + d4:0a:11:d5:85:b6:2d:91:f4:19:f5:1d:29:94:83: + 08:ec:fc:03:fc:b1:f1:24:87:35:14:ab:9c:57:ae: + f5:a2:f5:74:24:23:93:2d:aa:10:4d:8b:3d:7f:26: + 66:88:3a:a0:a3:7f:d6:e8:35:d5:6f:9c:46:5f:77: + d5:e2:6f:59:cf:d0:ac:d2:09:b1:11:5f:62:83:c7: + f7:57:22:37:20:68:eb:29:ec:da:d2:d9:2a:99:a9: + 56:c3:f7:62:89:f2:43:b4:e8:48:4b:ba:af:2e:81: + 29:5b:e0:1c:a4:b0:11:f9:8a:38:3e:8a:02:5d:6e: + 0a:01:c7:ee:da:db:25:b7:b2:49:ad:b3:63:42:7c: + a6:d3:0d:3c:bb:4b:86:ba:be:45:fc:03:18:2a:8d: + 57:81:57:0c:21:14:c3:cb:4c:db:8b:ee:d5:ce:7a: + 5c:a7 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:FALSE + X509v3 Subject Key Identifier: + 13:0F:2C:60:16:93:D8:1D:23:A3:72:5F:53:88:02:23:C9:2A:6B:CF + X509v3 Authority Key Identifier: + keyid:9B:26:0B:8A:98:A9:BB:1D:B9:1F:1C:E3:1A:40:33:ED:8E:17:88:AB + + X509v3 Extended Key Usage: + TLS Web Server Authentication, TLS Web Client Authentication + X509v3 Subject Alternative Name: + IP Address:127.0.0.1 + Signature Algorithm: sha256WithRSAEncryption + bf:48:b6:5d:1e:6e:bb:ff:65:33:c3:39:ab:82:8e:54:b1:ff: + b5:58:41:fb:91:27:a5:61:d8:0c:cc:97:62:31:4f:f7:61:a2: + 91:ba:16:ed:73:08:7f:75:be:b5:6e:50:79:c3:a0:73:1b:4d: + a1:85:cc:48:54:5c:27:1e:03:96:a8:1e:65:2e:0f:7c:9d:78: + 30:84:db:46:ec:48:53:26:b8:8f:ee:89:9c:c9:f2:c1:92:ce: + f6:fc:0f:c8:bc:6f:e0:ce:83:a8:85:7d:19:c3:07:f1:31:c0: + 5f:f9:d0:4c:90:89:59:69:3e:54:69:eb:15:52:3d:9e:b9:71: + 14:d4:a6:20:e0:d6:de:2b:b7:04:43:85:54:a7:42:d6:ca:00: + b4:57:68:93:65:6c:36:90:3f:5c:23:23:e3:7a:62:36:92:8f: + e7:37:0e:65:0b:71:fe:72:ed:8c:d3:da:bd:98:66:01:e6:4d: + 91:11:ab:e5:f1:c8:79:66:8e:27:f9:e0:60:49:fc:86:ed:95: + 36:9a:15:ca:84:d4:d4:69:1c:c2:d5:c7:30:ac:7e:f1:97:49: + ec:8e:39:ab:3c:58:2e:2f:21:13:f8:ee:a5:00:49:ca:88:7a: + 8b:e7:b9:5d:37:92:5c:b8:8d:8e:27:84:01:1f:14:6c:33:11: + 4b:cd:9a:e0 +-----BEGIN CERTIFICATE----- +MIIDzzCCAregAwIBAgIRAO8vCmp1Vh6xCwNQ33yaY7owDQYJKoZIhvcNAQELBQAw +YzELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDU1v +dW50YWluIFZpZXcxEDAOBgNVBAoMB1Rlc3QgQ0ExFTATBgNVBAMMDFRlc3QgUm9v +dCBDQTAeFw0yMDA5MDIwMDAwMDBaFw0yMTEwMDUwMDAwMDBaMGAxCzAJBgNVBAYT +AlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3 +MRAwDgYDVQQKDAdUZXN0IENBMRIwEAYDVQQDDAkxMjcuMC4wLjEwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDTQT0riGChBHWPJiKwVVIm/Xjb9PjEidfy +sneFAiVKSAgd4BzfkCma+pTKxVHuSXI1cOBA+E9/45dony0faLYc5ikCzD3KMT/h +pXAwQPCwT+0hXxe4STC8qtQKEdWFti2R9Bn1HSmUgwjs/AP8sfEkhzUUq5xXrvWi +9XQkI5MtqhBNiz1/JmaIOqCjf9boNdVvnEZfd9Xib1nP0KzSCbERX2KDx/dXIjcg +aOsp7NrS2SqZqVbD92KJ8kO06EhLuq8ugSlb4ByksBH5ijg+igJdbgoBx+7a2yW3 +skmts2NCfKbTDTy7S4a6vkX8AxgqjVeBVwwhFMPLTNuL7tXOelynAgMBAAGjgYAw +fjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBQTDyxgFpPYHSOjcl9TiAIjySprzzAf +BgNVHSMEGDAWgBSbJguKmKm7HbkfHOMaQDPtjheIqzAdBgNVHSUEFjAUBggrBgEF +BQcDAQYIKwYBBQUHAwIwDwYDVR0RBAgwBocEfwAAATANBgkqhkiG9w0BAQsFAAOC +AQEAv0i2XR5uu/9lM8M5q4KOVLH/tVhB+5EnpWHYDMyXYjFP92GikboW7XMIf3W+ +tW5QecOgcxtNoYXMSFRcJx4DlqgeZS4PfJ14MITbRuxIUya4j+6JnMnywZLO9vwP +yLxv4M6DqIV9GcMH8THAX/nQTJCJWWk+VGnrFVI9nrlxFNSmIODW3iu3BEOFVKdC +1soAtFdok2VsNpA/XCMj43piNpKP5zcOZQtx/nLtjNPavZhmAeZNkRGr5fHIeWaO +J/ngYEn8hu2VNpoVyoTU1GkcwtXHMKx+8ZdJ7I45qzxYLi8hE/jupQBJyoh6i+e5 +XTeSXLiNjieEAR8UbDMRS82a4A== +-----END CERTIFICATE----- diff --git a/chromium/net/data/ssl/certificates/399_days_after_2020_09_01.pem b/chromium/net/data/ssl/certificates/399_days_after_2020_09_01.pem new file mode 100644 index 00000000000..6f101151d7b --- /dev/null +++ b/chromium/net/data/ssl/certificates/399_days_after_2020_09_01.pem @@ -0,0 +1,85 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + ef:2f:0a:6a:75:56:1e:b1:0b:03:50:df:7c:9a:63:b9 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, ST=California, L=Mountain View, O=Test CA, CN=Test Root CA + Validity + Not Before: Sep 2 00:00:00 2020 GMT + Not After : Oct 6 00:00:00 2021 GMT + Subject: C=US, ST=California, L=Mountain View, O=Test CA, CN=127.0.0.1 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:c5:26:15:5a:01:bc:a6:ca:fe:e3:aa:f1:02:b3: + 0d:f9:2f:0c:53:18:0b:b2:e1:8e:3b:e4:eb:bf:ff: + d3:90:40:7f:3c:f2:9c:c7:4d:c0:e5:7f:b2:8d:79: + e8:d9:c6:79:f4:2b:29:40:a7:5d:27:52:b7:d0:ed: + b6:aa:21:32:fd:57:27:6a:30:bb:bc:11:46:38:83: + 5c:f4:ec:db:6c:99:29:5d:38:e0:41:e3:ae:fe:81: + 5c:1e:53:51:95:55:e9:e6:e3:e6:20:52:40:c5:c7: + c7:18:96:08:96:66:fb:a6:3b:8a:8a:c1:b6:88:c9: + 90:1b:42:fd:b2:1d:68:10:8f:f9:4e:94:df:31:4c: + 36:b9:70:ff:82:7c:5a:84:9e:51:91:1e:8d:e7:23: + 3a:7a:a3:65:6d:f8:b7:0a:87:1e:a5:78:04:2c:a8: + 1c:f7:ed:a8:fd:f4:36:52:97:6c:f1:de:59:66:6e: + 97:52:30:c8:60:59:ed:1a:5a:51:23:bc:83:9e:72: + b1:50:35:cd:a6:66:bf:ef:07:d4:f0:f4:ef:38:e5: + 0d:5d:d4:74:51:ca:5c:96:2f:e4:24:59:61:f6:cd: + ac:f9:1b:bd:62:2b:f3:7d:3e:db:6d:04:49:a4:e1: + c1:72:59:3c:95:49:36:87:ba:57:ac:de:cd:f6:90: + 49:09 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:FALSE + X509v3 Subject Key Identifier: + 1A:11:83:6D:87:2A:09:79:38:65:B2:89:81:B1:F5:26:46:33:82:62 + X509v3 Authority Key Identifier: + keyid:9B:26:0B:8A:98:A9:BB:1D:B9:1F:1C:E3:1A:40:33:ED:8E:17:88:AB + + X509v3 Extended Key Usage: + TLS Web Server Authentication, TLS Web Client Authentication + X509v3 Subject Alternative Name: + IP Address:127.0.0.1 + Signature Algorithm: sha256WithRSAEncryption + 15:c0:67:79:e4:03:8d:38:8b:ca:57:ff:1e:fd:d6:2b:1e:0e: + ed:9d:6a:c7:16:53:36:f7:ce:eb:8d:36:79:a1:b6:59:d8:d0: + bb:35:96:53:57:59:ad:91:39:f9:70:36:ac:37:9f:75:40:a3: + 3b:be:59:ed:32:4e:c4:a7:a9:3b:79:4d:8c:0c:3d:ba:6f:98: + 3e:3a:ff:28:19:fd:a2:d2:12:41:75:4a:1f:b0:22:0b:51:28: + 4d:9e:bd:e9:f3:67:b3:11:ef:9b:01:cb:c1:01:b1:6b:71:d2: + 68:a7:29:33:41:9a:3f:7b:ae:45:67:8f:a8:97:65:21:85:93: + b9:db:1b:46:bd:c9:46:23:71:27:1b:9a:aa:58:b7:7b:a1:2d: + 8c:27:65:75:9b:be:56:c5:bb:50:0c:62:ce:93:47:90:aa:db: + 47:c4:80:c5:43:f7:89:6b:b0:ea:a1:91:d5:2f:89:f8:d7:05: + 56:60:18:3c:c1:4a:bf:93:df:76:0a:ff:9f:b5:30:da:10:1a: + 15:94:f0:5a:82:11:ef:26:27:1c:50:1d:8b:c6:19:01:e4:01: + 48:22:c0:b9:97:12:58:4b:f1:61:7d:a9:69:d8:70:83:54:af: + 39:9e:fc:9b:17:f5:b1:69:cd:3e:b5:ba:13:df:e6:fd:71:9d: + d2:ef:95:1c +-----BEGIN CERTIFICATE----- +MIIDzzCCAregAwIBAgIRAO8vCmp1Vh6xCwNQ33yaY7kwDQYJKoZIhvcNAQELBQAw +YzELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDU1v +dW50YWluIFZpZXcxEDAOBgNVBAoMB1Rlc3QgQ0ExFTATBgNVBAMMDFRlc3QgUm9v +dCBDQTAeFw0yMDA5MDIwMDAwMDBaFw0yMTEwMDYwMDAwMDBaMGAxCzAJBgNVBAYT +AlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3 +MRAwDgYDVQQKDAdUZXN0IENBMRIwEAYDVQQDDAkxMjcuMC4wLjEwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDFJhVaAbymyv7jqvECsw35LwxTGAuy4Y47 +5Ou//9OQQH888pzHTcDlf7KNeejZxnn0KylAp10nUrfQ7baqITL9VydqMLu8EUY4 +g1z07NtsmSldOOBB467+gVweU1GVVenm4+YgUkDFx8cYlgiWZvumO4qKwbaIyZAb +Qv2yHWgQj/lOlN8xTDa5cP+CfFqEnlGRHo3nIzp6o2Vt+LcKhx6leAQsqBz37aj9 +9DZSl2zx3llmbpdSMMhgWe0aWlEjvIOecrFQNc2mZr/vB9Tw9O845Q1d1HRRylyW +L+QkWWH2zaz5G71iK/N9PtttBEmk4cFyWTyVSTaHules3s32kEkJAgMBAAGjgYAw +fjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBQaEYNthyoJeThlsomBsfUmRjOCYjAf +BgNVHSMEGDAWgBSbJguKmKm7HbkfHOMaQDPtjheIqzAdBgNVHSUEFjAUBggrBgEF +BQcDAQYIKwYBBQUHAwIwDwYDVR0RBAgwBocEfwAAATANBgkqhkiG9w0BAQsFAAOC +AQEAFcBneeQDjTiLylf/Hv3WKx4O7Z1qxxZTNvfO6402eaG2WdjQuzWWU1dZrZE5 ++XA2rDefdUCjO75Z7TJOxKepO3lNjAw9um+YPjr/KBn9otISQXVKH7AiC1EoTZ69 +6fNnsxHvmwHLwQGxa3HSaKcpM0GaP3uuRWePqJdlIYWTudsbRr3JRiNxJxuaqli3 +e6EtjCdldZu+VsW7UAxizpNHkKrbR8SAxUP3iWuw6qGR1S+J+NcFVmAYPMFKv5Pf +dgr/n7Uw2hAaFZTwWoIR7yYnHFAdi8YZAeQBSCLAuZcSWEvxYX2padhwg1SvOZ78 +mxf1sWnNPrW6E9/m/XGd0u+VHA== +-----END CERTIFICATE----- diff --git a/chromium/net/data/ssl/certificates/quic-short-lived.pem b/chromium/net/data/ssl/certificates/quic-short-lived.pem new file mode 100644 index 00000000000..36422406f9a --- /dev/null +++ b/chromium/net/data/ssl/certificates/quic-short-lived.pem @@ -0,0 +1,80 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 02:10:43:05:54:18:1c:69:17:b8:d7:dd:1c:87:89:d3:d3:f9:8d:c7 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C = US, CN = Short-lived Certificate + Validity + Not Before: Jun 5 19:49:12 2020 GMT + Not After : Jun 19 19:49:12 2020 GMT + Subject: C = US, CN = Short-lived Certificate + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:b2:56:6f:7e:d4:b4:b6:4e:e3:15:8e:8a:e9:46: + 06:15:63:4c:6d:3a:32:67:c7:14:a4:17:fc:b7:04: + 98:fb:b5:11:ae:93:1c:20:73:15:cd:b3:bc:ee:61: + 82:8e:cb:b8:78:ca:6d:e6:57:73:f3:45:6e:1e:c3: + 27:5d:af:5e:52:6d:12:47:44:72:3d:7d:8a:c1:47: + 50:19:4a:21:a4:08:b4:cc:2e:9c:a2:2a:ce:1b:87: + 82:ae:3a:23:b0:dd:d2:3e:64:fe:ce:a6:35:34:93: + 07:f8:88:6e:c8:be:b2:0b:5f:9c:96:0e:79:1c:a3: + 2b:c9:23:5a:8a:1f:1e:17:e2:a9:d4:3c:49:22:29: + 43:fa:63:55:3c:72:62:4a:d1:72:5a:ae:75:a8:14: + 67:eb:58:88:ce:11:0c:bf:09:67:f2:bb:c8:80:3e: + 4a:f0:35:ad:d2:dc:43:a3:2f:da:c6:3b:1c:6e:76: + 70:31:73:cc:33:5b:4f:36:dc:f3:8f:9f:a6:07:6d: + 61:e0:66:6f:2c:76:bd:85:a3:8b:d0:8a:ce:c4:bc: + 97:e0:ed:e1:29:df:a1:62:b9:ad:d8:0f:1a:f8:ae: + 44:fe:a6:28:95:c4:cc:df:b5:f7:6d:46:ae:ef:9b: + af:73:50:1d:9f:f0:c7:a0:ef:37:4b:13:73:96:24: + 95:0f + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + 9A:4F:94:3E:9D:8E:6D:5A:9B:9B:8B:88:97:B6:D4:FF:10:AE:47:76 + X509v3 Authority Key Identifier: + keyid:9A:4F:94:3E:9D:8E:6D:5A:9B:9B:8B:88:97:B6:D4:FF:10:AE:47:76 + + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Alternative Name: + DNS:example.org + Signature Algorithm: sha256WithRSAEncryption + 7b:10:40:c9:9b:ad:b1:3d:03:c3:b6:f3:d7:3f:75:56:2b:80: + ff:c4:e5:88:3a:b4:0b:c2:4a:cd:ae:0a:b3:d4:1f:d3:ec:ec: + 81:85:0b:96:47:2d:78:d1:9c:45:c3:cd:7c:ba:a0:f8:b0:56: + 83:2f:e9:8a:06:05:fa:06:65:85:fd:60:99:6e:29:5c:b8:22: + 6f:1b:24:63:ce:95:f6:bc:a1:76:69:15:b7:33:b4:e1:c4:e4: + e1:8d:2b:71:5f:af:8d:0e:17:be:ea:b1:b7:75:66:29:8d:4d: + 92:bc:fe:7e:12:b3:46:ab:fb:7f:01:46:77:c1:6a:1b:9b:65: + 79:cb:aa:64:24:1a:ee:99:85:8e:b8:51:33:c7:8d:88:40:ae: + 0b:e2:cf:b1:57:f1:c9:a7:08:d7:8d:3d:da:9c:f4:79:28:a3: + 39:0e:e6:2f:16:71:89:4c:8b:cc:62:6c:13:b2:f0:38:1d:7b: + 04:4b:21:01:c9:52:09:6e:0f:7a:13:a7:62:07:08:7a:0e:90: + a8:fd:13:2b:2c:39:37:3b:0f:fa:36:f7:64:76:d3:b5:9b:7a: + ab:49:b3:52:0f:cf:d2:c6:02:c9:05:30:3f:60:c7:c5:f3:4b: + fa:c3:e6:fd:de:3f:2b:d6:a5:1a:ff:6c:8e:75:d0:c9:ff:f2: + 65:d8:07:d1 +-----BEGIN CERTIFICATE----- +MIIDVzCCAj+gAwIBAgIUAhBDBVQYHGkXuNfdHIeJ09P5jccwDQYJKoZIhvcNAQEL +BQAwLzELMAkGA1UEBhMCVVMxIDAeBgNVBAMMF1Nob3J0LWxpdmVkIENlcnRpZmlj +YXRlMB4XDTIwMDYwNTE5NDkxMloXDTIwMDYxOTE5NDkxMlowLzELMAkGA1UEBhMC +VVMxIDAeBgNVBAMMF1Nob3J0LWxpdmVkIENlcnRpZmljYXRlMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEAslZvftS0tk7jFY6K6UYGFWNMbToyZ8cUpBf8 +twSY+7URrpMcIHMVzbO87mGCjsu4eMpt5ldz80VuHsMnXa9eUm0SR0RyPX2KwUdQ +GUohpAi0zC6coirOG4eCrjojsN3SPmT+zqY1NJMH+IhuyL6yC1+clg55HKMrySNa +ih8eF+Kp1DxJIilD+mNVPHJiStFyWq51qBRn61iIzhEMvwln8rvIgD5K8DWt0txD +oy/axjscbnZwMXPMM1tPNtzzj5+mB21h4GZvLHa9haOL0IrOxLyX4O3hKd+hYrmt +2A8a+K5E/qYolcTM37X3bUau75uvc1Adn/DHoO83SxNzliSVDwIDAQABo2swaTAd +BgNVHQ4EFgQUmk+UPp2ObVqbm4uIl7bU/xCuR3YwHwYDVR0jBBgwFoAUmk+UPp2O +bVqbm4uIl7bU/xCuR3YwDwYDVR0TAQH/BAUwAwEB/zAWBgNVHREEDzANggtleGFt +cGxlLm9yZzANBgkqhkiG9w0BAQsFAAOCAQEAexBAyZutsT0Dw7bz1z91ViuA/8Tl +iDq0C8JKza4Ks9Qf0+zsgYULlkcteNGcRcPNfLqg+LBWgy/pigYF+gZlhf1gmW4p +XLgibxskY86V9ryhdmkVtzO04cTk4Y0rcV+vjQ4Xvuqxt3VmKY1Nkrz+fhKzRqv7 +fwFGd8FqG5tlecuqZCQa7pmFjrhRM8eNiECuC+LPsVfxyacI14092pz0eSijOQ7m +LxZxiUyLzGJsE7LwOB17BEshAclSCW4PehOnYgcIeg6QqP0TKyw5NzsP+jb3ZHbT +tZt6q0mzUg/P0sYCyQUwP2DHxfNL+sPm/d4/K9alGv9sjnXQyf/yZdgH0Q== +-----END CERTIFICATE----- diff --git a/chromium/net/data/ssl/ev_roots/08297a4047dba23680c731db6e317653ca7848e1bebd3a0b0179a707f92cf178.pem b/chromium/net/data/ssl/ev_roots/08297a4047dba23680c731db6e317653ca7848e1bebd3a0b0179a707f92cf178.pem deleted file mode 100644 index 6cd05f10420..00000000000 --- a/chromium/net/data/ssl/ev_roots/08297a4047dba23680c731db6e317653ca7848e1bebd3a0b0179a707f92cf178.pem +++ /dev/null @@ -1,71 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: 903804111 (0x35def4cf) - Signature Algorithm: sha1WithRSAEncryption - Issuer: C=US, O=Equifax, OU=Equifax Secure Certificate Authority - Validity - Not Before: Aug 22 16:41:51 1998 GMT - Not After : Aug 22 16:41:51 2018 GMT - Subject: C=US, O=Equifax, OU=Equifax Secure Certificate Authority - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (1024 bit) - Modulus: - 00:c1:5d:b1:58:67:08:62:ee:a0:9a:2d:1f:08:6d: - 91:14:68:98:0a:1e:fe:da:04:6f:13:84:62:21:c3: - d1:7c:ce:9f:05:e0:b8:01:f0:4e:34:ec:e2:8a:95: - 04:64:ac:f1:6b:53:5f:05:b3:cb:67:80:bf:42:02: - 8e:fe:dd:01:09:ec:e1:00:14:4f:fc:fb:f0:0c:dd: - 43:ba:5b:2b:e1:1f:80:70:99:15:57:93:16:f1:0f: - 97:6a:b7:c2:68:23:1c:cc:4d:59:30:ac:51:1e:3b: - af:2b:d6:ee:63:45:7b:c5:d9:5f:50:d2:e3:50:0f: - 3a:88:e7:bf:14:fd:e0:c7:b9 - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 CRL Distribution Points: - - Full Name: - DirName: C = US, O = Equifax, OU = Equifax Secure Certificate Authority, CN = CRL1 - - X509v3 Private Key Usage Period: - Not After: Aug 22 16:41:51 2018 GMT - X509v3 Key Usage: - Certificate Sign, CRL Sign - X509v3 Authority Key Identifier: - keyid:48:E6:68:F9:2B:D2:B2:95:D7:47:D8:23:20:10:4F:33:98:90:9F:D4 - - X509v3 Subject Key Identifier: - 48:E6:68:F9:2B:D2:B2:95:D7:47:D8:23:20:10:4F:33:98:90:9F:D4 - X509v3 Basic Constraints: - CA:TRUE - 1.2.840.113533.7.65.0: - 0...V3.0c.... - Signature Algorithm: sha1WithRSAEncryption - 58:ce:29:ea:fc:f7:de:b5:ce:02:b9:17:b5:85:d1:b9:e3:e0: - 95:cc:25:31:0d:00:a6:92:6e:7f:b6:92:63:9e:50:95:d1:9a: - 6f:e4:11:de:63:85:6e:98:ee:a8:ff:5a:c8:d3:55:b2:66:71: - 57:de:c0:21:eb:3d:2a:a7:23:49:01:04:86:42:7b:fc:ee:7f: - a2:16:52:b5:67:67:d3:40:db:3b:26:58:b2:28:77:3d:ae:14: - 77:61:d6:fa:2a:66:27:a0:0d:fa:a7:73:5c:ea:70:f1:94:21: - 65:44:5f:fa:fc:ef:29:68:a9:a2:87:79:ef:79:ef:4f:ac:07: - 77:38 ------BEGIN CERTIFICATE----- -MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV -UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy -dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1 -MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx -dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B -AQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPRfM6f -BeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+A -cJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kC -AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQ -MA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlm -aWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgw -ODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gj -IBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQF -MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA -A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y -7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh -1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4 ------END CERTIFICATE----- diff --git a/chromium/net/data/ssl/ev_roots/0f993c8aef97baaf5687140ed59ad1821bb4afacf0aa9a58b5d57a338a3afbcb.pem b/chromium/net/data/ssl/ev_roots/0f993c8aef97baaf5687140ed59ad1821bb4afacf0aa9a58b5d57a338a3afbcb.pem deleted file mode 100644 index 58656022a93..00000000000 --- a/chromium/net/data/ssl/ev_roots/0f993c8aef97baaf5687140ed59ad1821bb4afacf0aa9a58b5d57a338a3afbcb.pem +++ /dev/null @@ -1,86 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 85:bd:4b:f3:d8:da:e3:69:f6:94:d7:5f:c3:a5:44:23 - Signature Algorithm: sha1WithRSAEncryption - Issuer: C=FR, O=Certplus, CN=Class 2 Primary CA - Validity - Not Before: Jul 7 17:05:00 1999 GMT - Not After : Jul 6 23:59:59 2019 GMT - Subject: C=FR, O=Certplus, CN=Class 2 Primary CA - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (2048 bit) - Modulus: - 00:dc:50:96:d0:12:f8:35:d2:08:78:7a:b6:52:70: - fd:6f:ee:cf:b9:11:cb:5d:77:e1:ec:e9:7e:04:8d: - d6:cc:6f:73:43:57:60:ac:33:0a:44:ec:03:5f:1c: - 80:24:91:e5:a8:91:56:12:82:f7:e0:2b:f4:db:ae: - 61:2e:89:10:8d:6b:6c:ba:b3:02:bd:d5:36:c5:48: - 37:23:e2:f0:5a:37:52:33:17:12:e2:d1:60:4d:be: - 2f:41:11:e3:f6:17:25:0c:8b:91:c0:1b:99:7b:99: - 56:0d:af:ee:d2:bc:47:57:e3:79:49:7b:34:89:27: - 24:84:de:b1:ec:e9:58:4e:fe:4e:df:5a:be:41:ad: - ac:08:c5:18:0e:ef:d2:53:ee:6c:d0:9d:12:01:13: - 8d:dc:80:62:f7:95:a9:44:88:4a:71:4e:60:55:9e: - db:23:19:79:56:07:0c:3f:63:0b:5c:b0:e2:be:7e: - 15:fc:94:33:58:41:38:74:c4:e1:8f:8b:df:26:ac: - 1f:b5:8b:3b:b7:43:59:6b:b0:24:a6:6d:90:8b:c4: - 72:ea:5d:33:98:b7:cb:de:5e:7b:ef:94:f1:1b:3e: - ca:c9:21:c1:c5:98:02:aa:a2:f6:5b:77:9b:f5:7e: - 96:55:34:1c:67:69:c0:f1:42:e3:47:ac:fc:28:1c: - 66:55 - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Basic Constraints: - CA:TRUE, pathlen:10 - X509v3 Key Usage: - Certificate Sign, CRL Sign - X509v3 Subject Key Identifier: - E3:73:2D:DF:CB:0E:28:0C:DE:DD:B3:A4:CA:79:B8:8E:BB:E8:30:89 - Netscape Cert Type: - SSL CA, S/MIME CA - X509v3 CRL Distribution Points: - - Full Name: - URI:http://www.certplus.com/CRL/class2.crl - - Signature Algorithm: sha1WithRSAEncryption - a7:54:cf:88:44:19:cb:df:d4:7f:00:df:56:33:62:b5:f7:51: - 01:90:eb:c3:3f:d1:88:44:e9:24:5d:ef:e7:14:bd:20:b7:9a: - 3c:00:fe:6d:9f:db:90:dc:d7:f4:62:d6:8b:70:5d:e7:e5:04: - 48:a9:68:7c:c9:f1:42:f3:6c:7f:c5:7a:7c:1d:51:88:ba:d2: - 0a:3e:27:5d:de:2d:51:4e:d3:13:64:69:e4:2e:e3:d3:e7:9b: - 09:99:a6:e0:95:9b:ce:1a:d7:7f:be:3c:ce:52:b3:11:15:c1: - 0f:17:cd:03:bb:9c:25:15:ba:a2:76:89:fc:06:f1:18:d0:93: - 4b:0e:7c:82:b7:a5:f4:f6:5f:fe:ed:40:a6:9d:84:74:39:b9: - dc:1e:85:16:da:29:1b:86:23:00:c9:bb:89:7e:6e:80:88:1e: - 2f:14:b4:03:24:a8:32:6f:03:9a:47:2c:30:be:56:c6:a7:42: - 02:70:1b:ea:40:d8:ba:05:03:70:07:a4:96:ff:fd:48:33:0a: - e1:dc:a5:81:90:9b:4d:dd:7d:e7:e7:b2:cd:5c:c8:6a:95:f8: - a5:f6:8d:c4:5d:78:08:be:7b:06:d6:49:cf:19:36:50:23:2e: - 08:e6:9e:05:4d:47:18:d5:16:e9:b1:d6:b6:10:d5:bb:97:bf: - a2:8e:b4:54 ------BEGIN CERTIFICATE----- -MIIDkjCCAnqgAwIBAgIRAIW9S/PY2uNp9pTXX8OlRCMwDQYJKoZIhvcNAQEFBQAw -PTELMAkGA1UEBhMCRlIxETAPBgNVBAoTCENlcnRwbHVzMRswGQYDVQQDExJDbGFz -cyAyIFByaW1hcnkgQ0EwHhcNOTkwNzA3MTcwNTAwWhcNMTkwNzA2MjM1OTU5WjA9 -MQswCQYDVQQGEwJGUjERMA8GA1UEChMIQ2VydHBsdXMxGzAZBgNVBAMTEkNsYXNz -IDIgUHJpbWFyeSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANxQ -ltAS+DXSCHh6tlJw/W/uz7kRy1134ezpfgSN1sxvc0NXYKwzCkTsA18cgCSR5aiR -VhKC9+Ar9NuuYS6JEI1rbLqzAr3VNsVINyPi8Fo3UjMXEuLRYE2+L0ER4/YXJQyL -kcAbmXuZVg2v7tK8R1fjeUl7NIknJITesezpWE7+Tt9avkGtrAjFGA7v0lPubNCd -EgETjdyAYveVqUSISnFOYFWe2yMZeVYHDD9jC1yw4r5+FfyUM1hBOHTE4Y+L3yas -H7WLO7dDWWuwJKZtkIvEcupdM5i3y95ee++U8Rs+yskhwcWYAqqi9lt3m/V+llU0 -HGdpwPFC40es/CgcZlUCAwEAAaOBjDCBiTAPBgNVHRMECDAGAQH/AgEKMAsGA1Ud -DwQEAwIBBjAdBgNVHQ4EFgQU43Mt38sOKAze3bOkynm4jrvoMIkwEQYJYIZIAYb4 -QgEBBAQDAgEGMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly93d3cuY2VydHBsdXMu -Y29tL0NSTC9jbGFzczIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCnVM+IRBnL39R/ -AN9WM2K191EBkOvDP9GIROkkXe/nFL0gt5o8AP5tn9uQ3Nf0YtaLcF3n5QRIqWh8 -yfFC82x/xXp8HVGIutIKPidd3i1RTtMTZGnkLuPT55sJmabglZvOGtd/vjzOUrMR -FcEPF80Du5wlFbqidon8BvEY0JNLDnyCt6X09l/+7UCmnYR0ObncHoUW2ikbhiMA -ybuJfm6AiB4vFLQDJKgybwOaRywwvlbGp0ICcBvqQNi6BQNwB6SW//1IMwrh3KWB -kJtN3X3n57LNXMhqlfil9o3EXXgIvnsG1knPGTZQIy4I5p4FTUcY1Rbpsda2ENW7 -l7+ijrRU ------END CERTIFICATE----- diff --git a/chromium/net/data/ssl/ev_roots/136335439334a7698016a0d324de72284e079d7b5220bb8fbd747816eebebaca.pem b/chromium/net/data/ssl/ev_roots/136335439334a7698016a0d324de72284e079d7b5220bb8fbd747816eebebaca.pem deleted file mode 100644 index 7e4f933d417..00000000000 --- a/chromium/net/data/ssl/ev_roots/136335439334a7698016a0d324de72284e079d7b5220bb8fbd747816eebebaca.pem +++ /dev/null @@ -1,137 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: 14541511773111788494 (0xc9cdd3e9d57d23ce) - Signature Algorithm: sha1WithRSAEncryption - Issuer: C=EU, L=Madrid (see current address at www.camerfirma.com/address)/serialNumber=A82743287, O=AC Camerfirma S.A., CN=Global Chambersign Root - 2008 - Validity - Not Before: Aug 1 12:31:40 2008 GMT - Not After : Jul 31 12:31:40 2038 GMT - Subject: C=EU, L=Madrid (see current address at www.camerfirma.com/address)/serialNumber=A82743287, O=AC Camerfirma S.A., CN=Global Chambersign Root - 2008 - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (4096 bit) - Modulus: - 00:c0:df:56:d3:e4:3a:9b:76:45:b4:13:db:ff:c1: - b6:19:8b:37:41:18:95:52:47:eb:17:9d:29:88:8e: - 35:6c:06:32:2e:47:62:f3:49:04:bf:7d:44:36:b1: - 71:cc:bd:5a:09:73:d5:d9:85:44:ff:91:57:25:df: - 5e:36:8e:70:d1:5c:71:43:1d:d9:da:ef:5c:d2:fb: - 1b:bd:3a:b5:cb:ad:a3:cc:44:a7:0d:ae:21:15:3f: - b9:7a:5b:92:75:d8:a4:12:38:89:19:8a:b7:80:d2: - e2:32:6f:56:9c:91:d6:88:10:0b:b3:74:64:92:74: - 60:f3:f6:cf:18:4f:60:b2:23:d0:c7:3b:ce:61:4b: - 99:8f:c2:0c:d0:40:b2:98:dc:0d:a8:4e:a3:b9:0a: - ae:60:a0:ad:45:52:63:ba:66:bd:68:e0:f9:be:1a: - a8:81:bb:1e:41:78:75:d3:c1:fe:00:55:b0:87:54: - e8:27:90:35:1d:4c:33:ad:97:fc:97:2e:98:84:bf: - 2c:c9:a3:bf:d1:98:11:14:ed:63:f8:ca:98:88:58: - 17:99:ed:45:03:97:7e:3c:86:1e:88:8c:be:f2:91: - 84:8f:65:34:d8:00:4c:7d:b7:31:17:5a:29:7a:0a: - 18:24:30:a3:37:b5:7a:a9:01:7d:26:d6:f9:0e:8e: - 59:f1:fd:1b:33:b5:29:3b:17:3b:41:b6:21:dd:d4: - c0:3d:a5:9f:9f:1f:43:50:c9:bb:bc:6c:7a:97:98: - ee:cd:8c:1f:fb:9c:51:ae:8b:70:bd:27:9f:71:c0: - 6b:ac:7d:90:66:e8:d7:5d:3a:0d:b0:d5:c2:8d:d5: - c8:9d:9d:c1:6d:d0:d0:bf:51:e4:e3:f8:c3:38:36: - ae:d6:a7:75:e6:af:84:43:5d:93:92:0c:6a:07:de: - 3b:1d:98:22:d6:ac:c1:35:db:a3:a0:25:ff:72:b5: - 76:1d:de:6d:e9:2c:66:2c:52:84:d0:45:92:ce:1c: - e5:e5:33:1d:dc:07:53:54:a3:aa:82:3b:9a:37:2f: - dc:dd:a0:64:e9:e6:dd:bd:ae:fc:64:85:1d:3c:a7: - c9:06:de:84:ff:6b:e8:6b:1a:3c:c5:a2:b3:42:fb: - 8b:09:3e:5f:08:52:c7:62:c4:d4:05:71:bf:c4:64: - e4:f8:a1:83:e8:3e:12:9b:a8:1e:d4:36:4d:2f:71: - f6:8d:28:f6:83:a9:13:d2:61:c1:91:bb:48:c0:34: - 8f:41:8c:4b:4c:db:69:12:ff:50:94:9c:20:83:59: - 73:ed:7c:a1:f2:f1:fd:dd:f7:49:d3:43:58:a0:56: - 63:ca:3d:3d:e5:35:56:59:e9:0e:ca:20:cc:2b:4b: - 93:29:0f - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Basic Constraints: critical - CA:TRUE, pathlen:12 - X509v3 Subject Key Identifier: - B9:09:CA:9C:1E:DB:D3:6C:3A:6B:AE:ED:54:F1:5B:93:06:35:2E:5E - X509v3 Authority Key Identifier: - keyid:B9:09:CA:9C:1E:DB:D3:6C:3A:6B:AE:ED:54:F1:5B:93:06:35:2E:5E - DirName:/C=EU/L=Madrid (see current address at www.camerfirma.com/address)/serialNumber=A82743287/O=AC Camerfirma S.A./CN=Global Chambersign Root - 2008 - serial:C9:CD:D3:E9:D5:7D:23:CE - - X509v3 Key Usage: critical - Certificate Sign, CRL Sign - X509v3 Certificate Policies: - Policy: X509v3 Any Policy - CPS: http://policy.camerfirma.com - - Signature Algorithm: sha1WithRSAEncryption - 80:88:7f:70:de:92:28:d9:05:94:46:ff:90:57:a9:f1:2f:df: - 1a:0d:6b:fa:7c:0e:1c:49:24:79:27:d8:46:aa:6f:29:59:52: - 88:70:12:ea:dd:3d:f5:9b:53:54:6f:e1:60:a2:a8:09:b9:ec: - eb:59:7c:c6:35:f1:dc:18:e9:f1:67:e5:af:ba:45:e0:09:de: - ca:44:0f:c2:17:0e:77:91:45:7a:33:5f:5f:96:2c:68:8b:c1: - 47:8f:98:9b:3d:c0:ec:cb:f5:d5:82:92:84:35:d1:be:36:38: - 56:72:31:5b:47:2d:aa:17:a4:63:51:eb:0a:01:ad:7f:ec:75: - 9e:cb:a1:1f:f1:7f:12:b1:b9:e4:64:7f:67:d6:23:2a:f4:b8: - 39:5d:98:e8:21:a7:e1:bd:3d:42:1a:74:9a:70:af:68:6c:50: - 5d:49:cf:ff:fb:0e:5d:e6:2c:47:d7:81:3a:59:00:b5:73:6b: - 63:20:f6:31:45:08:39:0e:f4:70:7e:40:70:5a:3f:d0:6b:42: - a9:74:3d:28:2f:02:6d:75:72:95:09:8d:48:63:c6:c6:23:57: - 92:93:5e:35:c1:8d:f9:0a:f7:2c:9d:62:1c:f6:ad:7c:dd:a6: - 31:1e:b6:b1:c7:7e:85:26:fa:a4:6a:b5:da:63:30:d1:ef:93: - 37:b2:66:2f:7d:05:f7:e7:b7:4b:98:94:35:c0:d9:3a:29:c1: - 9d:b2:50:33:1d:4a:a9:5a:a6:c9:03:ef:ed:f4:e7:a8:6e:8a: - b4:57:84:eb:a4:3f:d0:ee:aa:aa:87:5b:63:e8:93:e2:6b:a8: - d4:b8:72:78:6b:1b:ed:39:e4:5d:cb:9b:aa:87:d5:4f:4e:00: - fe:d9:6a:9f:3c:31:0f:28:02:01:7d:98:e8:a7:b0:a2:64:9e: - 79:f8:48:f2:15:a9:cc:e6:c8:44:eb:3f:78:99:f2:7b:71:3e: - 3c:f1:98:a7:c5:18:12:3f:e6:bb:28:33:42:e9:45:0a:7c:6d: - f2:86:79:2f:c5:82:19:7d:09:89:7c:b2:54:76:88:ae:de:c1: - f3:cc:e1:6e:db:31:d6:93:ae:99:a0:ef:25:6a:73:98:89:5b: - 3a:2e:13:88:1e:bf:c0:92:94:34:1b:e3:27:b7:8b:1e:6f:42: - ff:e7:e9:37:9b:50:1d:2d:a2:f9:02:ee:cb:58:58:3a:71:bc: - 68:e3:aa:c1:af:1c:28:1f:a2:dc:23:65:3f:81:ea:ae:99:d3: - d8:30:cf:13:0d:4f:15:c9:84:bc:a7:48:2d:f8:30:23:77:d8: - 46:4b:79:6d:f6:8c:ed:3a:7f:60:11:78:f4:e9:9b:ae:d5:54: - c0:74:80:d1:0b:42:9f:c1 ------BEGIN CERTIFICATE----- -MIIHSTCCBTGgAwIBAgIJAMnN0+nVfSPOMA0GCSqGSIb3DQEBBQUAMIGsMQswCQYD -VQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0 -IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3 -MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAlBgNVBAMTHkdsb2JhbCBD -aGFtYmVyc2lnbiBSb290IC0gMjAwODAeFw0wODA4MDExMjMxNDBaFw0zODA3MzEx -MjMxNDBaMIGsMQswCQYDVQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3Vy -cmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAG -A1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAl -BgNVBAMTHkdsb2JhbCBDaGFtYmVyc2lnbiBSb290IC0gMjAwODCCAiIwDQYJKoZI -hvcNAQEBBQADggIPADCCAgoCggIBAMDfVtPkOpt2RbQT2//BthmLN0EYlVJH6xed -KYiONWwGMi5HYvNJBL99RDaxccy9Wglz1dmFRP+RVyXfXjaOcNFccUMd2drvXNL7 -G706tcuto8xEpw2uIRU/uXpbknXYpBI4iRmKt4DS4jJvVpyR1ogQC7N0ZJJ0YPP2 -zxhPYLIj0Mc7zmFLmY/CDNBAspjcDahOo7kKrmCgrUVSY7pmvWjg+b4aqIG7HkF4 -ddPB/gBVsIdU6CeQNR1MM62X/JcumIS/LMmjv9GYERTtY/jKmIhYF5ntRQOXfjyG -HoiMvvKRhI9lNNgATH23MRdaKXoKGCQwoze1eqkBfSbW+Q6OWfH9GzO1KTsXO0G2 -Id3UwD2ln58fQ1DJu7xsepeY7s2MH/ucUa6LcL0nn3HAa6x9kGbo1106DbDVwo3V -yJ2dwW3Q0L9R5OP4wzg2rtandeavhENdk5IMagfeOx2YItaswTXbo6Al/3K1dh3e -beksZixShNBFks4c5eUzHdwHU1SjqoI7mjcv3N2gZOnm3b2u/GSFHTynyQbehP9r -6GsaPMWis0L7iwk+XwhSx2LE1AVxv8Rk5Pihg+g+EpuoHtQ2TS9x9o0o9oOpE9Jh -wZG7SMA0j0GMS0zbaRL/UJScIINZc+18ofLx/d33SdNDWKBWY8o9PeU1VlnpDsog -zCtLkykPAgMBAAGjggFqMIIBZjASBgNVHRMBAf8ECDAGAQH/AgEMMB0GA1UdDgQW -BBS5CcqcHtvTbDprru1U8VuTBjUuXjCB4QYDVR0jBIHZMIHWgBS5CcqcHtvTbDpr -ru1U8VuTBjUuXqGBsqSBrzCBrDELMAkGA1UEBhMCRVUxQzBBBgNVBAcTOk1hZHJp -ZCAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cuY2FtZXJmaXJtYS5jb20vYWRk -cmVzcykxEjAQBgNVBAUTCUE4Mjc0MzI4NzEbMBkGA1UEChMSQUMgQ2FtZXJmaXJt -YSBTLkEuMScwJQYDVQQDEx5HbG9iYWwgQ2hhbWJlcnNpZ24gUm9vdCAtIDIwMDiC -CQDJzdPp1X0jzjAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCow -KAYIKwYBBQUHAgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZI -hvcNAQEFBQADggIBAICIf3DekijZBZRG/5BXqfEv3xoNa/p8DhxJJHkn2EaqbylZ -UohwEurdPfWbU1Rv4WCiqAm57OtZfMY18dwY6fFn5a+6ReAJ3spED8IXDneRRXoz -X1+WLGiLwUePmJs9wOzL9dWCkoQ10b42OFZyMVtHLaoXpGNR6woBrX/sdZ7LoR/x -fxKxueRkf2fWIyr0uDldmOghp+G9PUIadJpwr2hsUF1Jz//7Dl3mLEfXgTpZALVz -a2Mg9jFFCDkO9HB+QHBaP9BrQql0PSgvAm11cpUJjUhjxsYjV5KTXjXBjfkK9yyd -Yhz2rXzdpjEetrHHfoUm+qRqtdpjMNHvkzeyZi99Bffnt0uYlDXA2TopwZ2yUDMd -SqlapskD7+3056huirRXhOukP9DuqqqHW2Pok+JrqNS4cnhrG+055F3Lm6qH1U9O -AP7Zap88MQ8oAgF9mOinsKJknnn4SPIVqczmyETrP3iZ8ntxPjzxmKfFGBI/5rso -M0LpRQp8bfKGeS/Fghl9CYl8slR2iK7ewfPM4W7bMdaTrpmg7yVqc5iJWzouE4ge -v8CSlDQb4ye3ix5vQv/n6TebUB0tovkC7stYWDpxvGjjqsGvHCgfotwjZT+B6q6Z -09gwzxMNTxXJhLynSC34MCN32EZLeW32jO06f2ARePTpm67VVMB0gNELQp/B ------END CERTIFICATE----- diff --git a/chromium/net/data/ssl/ev_roots/1c01c6f4dbb2fefc22558b2bca32563f49844acfc32b7be4b0ff599f9e8c7af7.pem b/chromium/net/data/ssl/ev_roots/1c01c6f4dbb2fefc22558b2bca32563f49844acfc32b7be4b0ff599f9e8c7af7.pem deleted file mode 100644 index 03178d483e9..00000000000 --- a/chromium/net/data/ssl/ev_roots/1c01c6f4dbb2fefc22558b2bca32563f49844acfc32b7be4b0ff599f9e8c7af7.pem +++ /dev/null @@ -1,83 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: 1218379777 (0x489f0001) - Signature Algorithm: sha1WithRSAEncryption - Issuer: C=CN, O=China Internet Network Information Center, CN=China Internet Network Information Center EV Certificates Root - Validity - Not Before: Aug 31 07:11:25 2010 GMT - Not After : Aug 31 07:11:25 2030 GMT - Subject: C=CN, O=China Internet Network Information Center, CN=China Internet Network Information Center EV Certificates Root - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (2048 bit) - Modulus: - 00:9b:7e:73:ee:bd:3b:78:aa:64:43:41:f5:50:df: - 94:f2:2e:b2:8d:4a:8e:46:54:d2:21:12:c8:39:32: - 42:06:e9:83:d5:9f:52:ed:e5:67:03:3b:54:c1:8c: - 99:99:cc:e9:c0:0f:ff:0d:d9:84:11:b2:b8:d1:cb: - 5b:dc:1e:f9:68:31:64:e1:9b:fa:74:eb:68:b9:20: - 95:f7:c6:0f:8d:47:ac:5a:06:dd:61:ab:e2:ec:d8: - 9f:17:2d:9c:ca:3c:35:97:55:71:cd:43:85:b1:47: - 16:f5:2c:53:80:76:cf:d3:00:64:bd:40:99:dd:cc: - d8:db:c4:9f:d6:13:5f:41:83:8b:f9:0d:87:92:56: - 34:6c:1a:10:0b:17:d5:5a:1c:97:58:84:3c:84:1a: - 2e:5c:91:34:6e:19:5f:7f:17:69:c5:65:ef:6b:21: - c6:d5:50:3a:bf:61:b9:05:8d:ef:6f:34:3a:b2:6f: - 14:63:bf:16:3b:9b:a9:2a:fd:b7:2b:38:66:06:c5: - 2c:e2:aa:67:1e:45:a7:8d:04:66:42:f6:8f:2b:ef: - 88:20:69:8f:32:8c:14:73:da:2b:86:91:63:22:9a: - f2:a7:db:ce:89:8b:ab:5d:c7:14:c1:5b:30:6a:1f: - b1:b7:9e:2e:81:01:02:ed:cf:96:5e:63:db:a8:e6: - 38:b7 - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Authority Key Identifier: - keyid:7C:72:4B:39:C7:C0:DB:62:A5:4F:9B:AA:18:34:92:A2:CA:83:82:59 - - X509v3 Basic Constraints: critical - CA:TRUE - X509v3 Key Usage: critical - Certificate Sign, CRL Sign - X509v3 Subject Key Identifier: - 7C:72:4B:39:C7:C0:DB:62:A5:4F:9B:AA:18:34:92:A2:CA:83:82:59 - Signature Algorithm: sha1WithRSAEncryption - 2a:c3:c7:43:37:8f:dd:ad:a4:b2:0c:ee:dc:14:6d:8f:28:a4: - 98:49:cb:0c:80:ea:f3:ed:23:66:75:7d:c5:d3:21:67:79:d1: - 73:c5:b5:03:b7:58:ac:0c:54:2f:c6:56:13:0f:31:da:06:e7: - 65:3b:1d:6f:36:db:c8:1d:f9:fd:80:06:ca:a3:3d:66:16:a8: - 9d:4c:16:7d:c0:95:46:b5:51:e4:e2:1f:d7:ea:06:4d:63:8d: - 96:8c:ef:e7:33:57:42:3a:eb:8c:c1:79:c8:4d:76:7d:de:f6: - b1:b7:81:e0:a0:f9:a1:78:46:17:1a:56:98:f0:4e:3d:ab:1c: - ed:ec:39:dc:07:48:f7:63:fe:06:ae:c2:a4:5c:6a:5b:32:88: - c5:c7:33:85:ac:66:42:47:c2:58:24:99:e1:e5:3e:e5:75:2c: - 8e:43:d6:5d:3c:78:1e:a8:95:82:29:50:d1:d1:16:ba:ef:c1: - be:7a:d9:b4:d8:cc:1e:4c:46:e1:77:b1:31:ab:bd:2a:c8:ce: - 8f:6e:a1:5d:7f:03:75:34:e4:ad:89:45:54:5e:be:ae:28:a5: - bb:3f:78:79:eb:73:b3:0a:0d:fd:be:c9:f7:56:ac:f6:b7:ed: - 2f:9b:21:29:c7:38:b6:95:c4:04:f2:c3:2d:fd:14:2a:90:99: - b9:07:cc:9f ------BEGIN CERTIFICATE----- -MIID9zCCAt+gAwIBAgIESJ8AATANBgkqhkiG9w0BAQUFADCBijELMAkGA1UEBhMC -Q04xMjAwBgNVBAoMKUNoaW5hIEludGVybmV0IE5ldHdvcmsgSW5mb3JtYXRpb24g -Q2VudGVyMUcwRQYDVQQDDD5DaGluYSBJbnRlcm5ldCBOZXR3b3JrIEluZm9ybWF0 -aW9uIENlbnRlciBFViBDZXJ0aWZpY2F0ZXMgUm9vdDAeFw0xMDA4MzEwNzExMjVa -Fw0zMDA4MzEwNzExMjVaMIGKMQswCQYDVQQGEwJDTjEyMDAGA1UECgwpQ2hpbmEg -SW50ZXJuZXQgTmV0d29yayBJbmZvcm1hdGlvbiBDZW50ZXIxRzBFBgNVBAMMPkNo -aW5hIEludGVybmV0IE5ldHdvcmsgSW5mb3JtYXRpb24gQ2VudGVyIEVWIENlcnRp -ZmljYXRlcyBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm35z -7r07eKpkQ0H1UN+U8i6yjUqORlTSIRLIOTJCBumD1Z9S7eVnAztUwYyZmczpwA// -DdmEEbK40ctb3B75aDFk4Zv6dOtouSCV98YPjUesWgbdYavi7NifFy2cyjw1l1Vx -zUOFsUcW9SxTgHbP0wBkvUCZ3czY28Sf1hNfQYOL+Q2HklY0bBoQCxfVWhyXWIQ8 -hBouXJE0bhlffxdpxWXvayHG1VA6v2G5BY3vbzQ6sm8UY78WO5upKv23KzhmBsUs -4qpnHkWnjQRmQvaPK++IIGmPMowUc9orhpFjIpryp9vOiYurXccUwVswah+xt54u -gQEC7c+WXmPbqOY4twIDAQABo2MwYTAfBgNVHSMEGDAWgBR8cks5x8DbYqVPm6oY -NJKiyoOCWTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4E -FgQUfHJLOcfA22KlT5uqGDSSosqDglkwDQYJKoZIhvcNAQEFBQADggEBACrDx0M3 -j92tpLIM7twUbY8opJhJywyA6vPtI2Z1fcXTIWd50XPFtQO3WKwMVC/GVhMPMdoG -52U7HW8228gd+f2ABsqjPWYWqJ1MFn3AlUa1UeTiH9fqBk1jjZaM7+czV0I664zB -echNdn3e9rG3geCg+aF4RhcaVpjwTj2rHO3sOdwHSPdj/gauwqRcalsyiMXHM4Ws -ZkJHwlgkmeHlPuV1LI5D1l08eB6olYIpUNHRFrrvwb562bTYzB5MRuF3sTGrvSrI -zo9uoV1/A3U05K2JRVRevq4opbs/eHnrc7MKDf2+yfdWrPa37S+bISnHOLaVxATy -wy39FCqQmbkHzJ8= ------END CERTIFICATE----- diff --git a/chromium/net/data/ssl/ev_roots/22a2c1f7bded704cc1e701b5f408c310880fe956b5de2a4a44f99c873a25a7c8.pem b/chromium/net/data/ssl/ev_roots/22a2c1f7bded704cc1e701b5f408c310880fe956b5de2a4a44f99c873a25a7c8.pem new file mode 100644 index 00000000000..17ec3a9d91f --- /dev/null +++ b/chromium/net/data/ssl/ev_roots/22a2c1f7bded704cc1e701b5f408c310880fe956b5de2a4a44f99c873a25a7c8.pem @@ -0,0 +1,56 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 3182246526754555285 (0x2c299c5b16ed0595) + Signature Algorithm: ecdsa-with-SHA256 + Issuer: C = US, ST = Texas, L = Houston, O = SSL Corporation, CN = SSL.com EV Root Certification Authority ECC + Validity + Not Before: Feb 12 18:15:23 2016 GMT + Not After : Feb 12 18:15:23 2041 GMT + Subject: C = US, ST = Texas, L = Houston, O = SSL Corporation, CN = SSL.com EV Root Certification Authority ECC + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (384 bit) + pub: + 04:aa:12:47:90:98:1b:fb:ef:c3:40:07:83:20:4e: + f1:30:82:a2:06:d1:f2:92:86:61:f2:f6:21:68:ca: + 00:c4:c7:ea:43:00:54:86:dc:fd:1f:df:00:b8:41: + 62:5c:dc:70:16:32:de:1f:99:d4:cc:c5:07:c8:08: + 1f:61:16:07:51:3d:7d:5c:07:53:e3:35:38:8c:df: + cd:9f:d9:2e:0d:4a:b6:19:2e:5a:70:5a:06:ed:be: + f0:a1:b0:ca:d0:09:29 + ASN1 OID: secp384r1 + NIST CURVE: P-384 + X509v3 extensions: + X509v3 Subject Key Identifier: + 5B:CA:5E:E5:DE:D2:81:AA:CD:A8:2D:64:51:B6:D9:72:9B:97:E6:4F + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Authority Key Identifier: + keyid:5B:CA:5E:E5:DE:D2:81:AA:CD:A8:2D:64:51:B6:D9:72:9B:97:E6:4F + + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + Signature Algorithm: ecdsa-with-SHA256 + 30:65:02:31:00:8a:e6:40:89:37:eb:e9:d5:13:d9:ca:d4:6b: + 24:f3:b0:3d:87:46:58:1a:ec:b1:df:6f:fb:56:ba:70:6b:c7: + 38:cc:e8:b1:8c:4f:0f:f7:f1:67:76:0e:83:d0:1e:51:8f:02: + 30:3d:f6:23:28:26:4c:c6:60:87:93:26:9b:b2:35:1e:ba:d6: + f7:3c:d1:1c:ce:fa:25:3c:a6:1a:81:15:5b:f3:12:0f:6c:ee: + 65:8a:c9:87:a8:f9:07:e0:62:9a:8c:5c:4a +-----BEGIN CERTIFICATE----- +MIIClDCCAhqgAwIBAgIILCmcWxbtBZUwCgYIKoZIzj0EAwIwfzELMAkGA1UEBhMC +VVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9T +U0wgQ29ycG9yYXRpb24xNDAyBgNVBAMMK1NTTC5jb20gRVYgUm9vdCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEyMTgxNTIzWhcNNDEwMjEyMTgx +NTIzWjB/MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hv +dXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjE0MDIGA1UEAwwrU1NMLmNv +bSBFViBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49 +AgEGBSuBBAAiA2IABKoSR5CYG/vvw0AHgyBO8TCCogbR8pKGYfL2IWjKAMTH6kMA +VIbc/R/fALhBYlzccBYy3h+Z1MzFB8gIH2EWB1E9fVwHU+M1OIzfzZ/ZLg1Kthku +WnBaBu2+8KGwytAJKaNjMGEwHQYDVR0OBBYEFFvKXuXe0oGqzagtZFG22XKbl+ZP +MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUW8pe5d7SgarNqC1kUbbZcpuX +5k8wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2gAMGUCMQCK5kCJN+vp1RPZ +ytRrJPOwPYdGWBrssd9v+1a6cGvHOMzosYxPD/fxZ3YOg9AeUY8CMD32IygmTMZg +h5Mmm7I1HrrW9zzRHM76JTymGoEVW/MSD2zuZYrJh6j5B+BimoxcSg== +-----END CERTIFICATE----- diff --git a/chromium/net/data/ssl/ev_roots/2399561127a57125de8cefea610ddf2fa078b5c8067f4e828290bfb860e84b3c.pem b/chromium/net/data/ssl/ev_roots/2399561127a57125de8cefea610ddf2fa078b5c8067f4e828290bfb860e84b3c.pem deleted file mode 100644 index 36b2c073f64..00000000000 --- a/chromium/net/data/ssl/ev_roots/2399561127a57125de8cefea610ddf2fa078b5c8067f4e828290bfb860e84b3c.pem +++ /dev/null @@ -1,87 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 40:1a:c4:64:21:b3:13:21:03:0e:bb:e4:12:1a:c5:1d - Signature Algorithm: sha256WithRSAEncryption - Issuer: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 2008 VeriSign, Inc. - For authorized use only, CN=VeriSign Universal Root Certification Authority - Validity - Not Before: Apr 2 00:00:00 2008 GMT - Not After : Dec 1 23:59:59 2037 GMT - Subject: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 2008 VeriSign, Inc. - For authorized use only, CN=VeriSign Universal Root Certification Authority - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (2048 bit) - Modulus: - 00:c7:61:37:5e:b1:01:34:db:62:d7:15:9b:ff:58: - 5a:8c:23:23:d6:60:8e:91:d7:90:98:83:7a:e6:58: - 19:38:8c:c5:f6:e5:64:85:b4:a2:71:fb:ed:bd:b9: - da:cd:4d:00:b4:c8:2d:73:a5:c7:69:71:95:1f:39: - 3c:b2:44:07:9c:e8:0e:fa:4d:4a:c4:21:df:29:61: - 8f:32:22:61:82:c5:87:1f:6e:8c:7c:5f:16:20:51: - 44:d1:70:4f:57:ea:e3:1c:e3:cc:79:ee:58:d8:0e: - c2:b3:45:93:c0:2c:e7:9a:17:2b:7b:00:37:7a:41: - 33:78:e1:33:e2:f3:10:1a:7f:87:2c:be:f6:f5:f7: - 42:e2:e5:bf:87:62:89:5f:00:4b:df:c5:dd:e4:75: - 44:32:41:3a:1e:71:6e:69:cb:0b:75:46:08:d1:ca: - d2:2b:95:d0:cf:fb:b9:40:6b:64:8c:57:4d:fc:13: - 11:79:84:ed:5e:54:f6:34:9f:08:01:f3:10:25:06: - 17:4a:da:f1:1d:7a:66:6b:98:60:66:a4:d9:ef:d2: - 2e:82:f1:f0:ef:09:ea:44:c9:15:6a:e2:03:6e:33: - d3:ac:9f:55:00:c7:f6:08:6a:94:b9:5f:dc:e0:33: - f1:84:60:f9:5b:27:11:b4:fc:16:f2:bb:56:6a:80: - 25:8d - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Basic Constraints: critical - CA:TRUE - X509v3 Key Usage: critical - Certificate Sign, CRL Sign - 1.3.6.1.5.5.7.1.12: - 0_.].[0Y0W0U..image/gif0!0.0...+..............k...j.H.,{..0%.#http://logo.verisign.com/vslogo.gif - X509v3 Subject Key Identifier: - B6:77:FA:69:48:47:9F:53:12:D5:C2:EA:07:32:76:07:D1:97:07:19 - Signature Algorithm: sha256WithRSAEncryption - 4a:f8:f8:b0:03:e6:2c:67:7b:e4:94:77:63:cc:6e:4c:f9:7d: - 0e:0d:dc:c8:b9:35:b9:70:4f:63:fa:24:fa:6c:83:8c:47:9d: - 3b:63:f3:9a:f9:76:32:95:91:b1:77:bc:ac:9a:be:b1:e4:31: - 21:c6:81:95:56:5a:0e:b1:c2:d4:b1:a6:59:ac:f1:63:cb:b8: - 4c:1d:59:90:4a:ef:90:16:28:1f:5a:ae:10:fb:81:50:38:0c: - 6c:cc:f1:3d:c3:f5:63:e3:b3:e3:21:c9:24:39:e9:fd:15:66: - 46:f4:1b:11:d0:4d:73:a3:7d:46:f9:3d:ed:a8:5f:62:d4:f1: - 3f:f8:e0:74:57:2b:18:9d:81:b4:c4:28:da:94:97:a5:70:eb: - ac:1d:be:07:11:f0:d5:db:dd:e5:8c:f0:d5:32:b0:83:e6:57: - e2:8f:bf:be:a1:aa:bf:3d:1d:b5:d4:38:ea:d7:b0:5c:3a:4f: - 6a:3f:8f:c0:66:6c:63:aa:e9:d9:a4:16:f4:81:d1:95:14:0e: - 7d:cd:95:34:d9:d2:8f:70:73:81:7b:9c:7e:bd:98:61:d8:45: - 87:98:90:c5:eb:86:30:c6:35:bf:f0:ff:c3:55:88:83:4b:ef: - 05:92:06:71:f2:b8:98:93:b7:ec:cd:82:61:f1:38:e6:4f:97: - 98:2a:5a:8d ------BEGIN CERTIFICATE----- -MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCB -vTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL -ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJp -U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MTgwNgYDVQQDEy9W -ZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe -Fw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJVUzEX -MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0 -IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9y -IGF1dGhvcml6ZWQgdXNlIG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNh -bCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF -AAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj1mCOkdeQmIN65lgZOIzF -9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGPMiJhgsWH -H26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+H -LL729fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN -/BMReYTtXlT2NJ8IAfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPT -rJ9VAMf2CGqUuV/c4DPxhGD5WycRtPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1Ud -EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0GCCsGAQUFBwEMBGEwX6FdoFsw -WTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2Oa8PPgGrUSBgs -exkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud -DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4 -sAPmLGd75JR3Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+ -seQxIcaBlVZaDrHC1LGmWazxY8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz -4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTxP/jgdFcrGJ2BtMQo2pSXpXDrrB2+ -BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+PwGZsY6rp2aQW9IHR -lRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4mJO3 -7M2CYfE45k+XmCpajQ== ------END CERTIFICATE----- diff --git a/chromium/net/data/ssl/ev_roots/2e7bf16cc22485a7bbe2aa8696750761b0ae39be3b2fe9d0cc6d4ef73491425c.pem b/chromium/net/data/ssl/ev_roots/2e7bf16cc22485a7bbe2aa8696750761b0ae39be3b2fe9d0cc6d4ef73491425c.pem new file mode 100644 index 00000000000..fb4614a611d --- /dev/null +++ b/chromium/net/data/ssl/ev_roots/2e7bf16cc22485a7bbe2aa8696750761b0ae39be3b2fe9d0cc6d4ef73491425c.pem @@ -0,0 +1,124 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 6248227494352943350 (0x56b629cd34bc78f6) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C = US, ST = Texas, L = Houston, O = SSL Corporation, CN = SSL.com EV Root Certification Authority RSA R2 + Validity + Not Before: May 31 18:14:37 2017 GMT + Not After : May 30 18:14:37 2042 GMT + Subject: C = US, ST = Texas, L = Houston, O = SSL Corporation, CN = SSL.com EV Root Certification Authority RSA R2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (4096 bit) + Modulus: + 00:8f:36:65:40:e1:d6:4d:c0:d7:b4:e9:46:da:6b: + ea:33:47:cd:4c:f9:7d:7d:be:bd:2d:3d:f0:db:78: + e1:86:a5:d9:ba:09:57:68:ed:57:3e:a0:d0:08:41: + 83:e7:28:41:24:1f:e3:72:15:d0:01:1a:fb:5e:70: + 23:b2:cb:9f:39:e3:cf:c5:4e:c6:92:6d:26:c6:7b: + bb:b3:da:27:9d:0a:86:e9:81:37:05:fe:f0:71:71: + ec:c3:1c:e9:63:a2:17:14:9d:ef:1b:67:d3:85:55: + 02:02:d6:49:c9:cc:5a:e1:b1:f7:6f:32:9f:c9:d4: + 3b:88:41:a8:9c:bd:cb:ab:db:6d:7b:09:1f:a2:4c: + 72:90:da:2b:08:fc:cf:3c:54:ce:67:0f:a8:cf:5d: + 96:19:0b:c4:e3:72:eb:ad:d1:7d:1d:27:ef:92:eb: + 10:bf:5b:eb:3b:af:cf:80:dd:c1:d2:96:04:5b:7a: + 7e:a4:a9:3c:38:76:a4:62:8e:a0:39:5e:ea:77:cf: + 5d:00:59:8f:66:2c:3e:07:a2:a3:05:26:11:69:97: + ea:85:b7:0f:96:0b:4b:c8:40:e1:50:ba:2e:8a:cb: + f7:0f:9a:22:e7:7f:9a:37:13:cd:f2:4d:13:6b:21: + d1:c0:cc:22:f2:a1:46:f6:44:69:9c:ca:61:35:07: + 00:6f:d6:61:08:11:ea:ba:b8:f6:e9:b3:60:e5:4d: + b9:ec:9f:14:66:c9:57:58:db:cd:87:69:f8:8a:86: + 12:03:47:bf:66:13:76:ac:77:7d:34:24:85:83:cd: + d7:aa:9c:90:1a:9f:21:2c:7f:78:b7:64:b8:d8:e8: + a6:f4:78:b3:55:cb:84:d2:32:c4:78:ae:a3:8f:61: + dd:ce:08:53:ad:ec:88:fc:15:e4:9a:0d:e6:9f:1a: + 77:ce:4c:8f:b8:14:15:3d:62:9c:86:38:06:00:66: + 12:e4:59:76:5a:53:c0:02:98:a2:10:2b:68:44:7b: + 8e:79:ce:33:4a:76:aa:5b:81:16:1b:b5:8a:d8:d0: + 00:7b:5e:62:b4:09:d6:86:63:0e:a6:05:95:49:ba: + 28:8b:88:93:b2:34:1c:d8:a4:55:6e:b7:1c:d0:de: + 99:55:3b:23:f4:22:e0:f9:29:66:26:ec:20:50:77: + db:4a:0b:8f:be:e5:02:60:70:41:5e:d4:ae:50:39: + 22:14:26:cb:b2:3b:73:74:55:47:07:79:81:39:a8: + 30:13:44:e5:04:8a:ae:96:13:25:42:0f:b9:53:c4: + 9b:fc:cd:e4:1c:de:3c:fa:ab:d6:06:4a:1f:67:a6: + 98:30:1c:dd:2c:db:dc:18:95:57:66:c6:ff:5c:8b: + 56:f5:77 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Authority Key Identifier: + keyid:F9:60:BB:D4:E3:D5:34:F6:B8:F5:06:80:25:A7:73:DB:46:69:A8:9E + + X509v3 Subject Key Identifier: + F9:60:BB:D4:E3:D5:34:F6:B8:F5:06:80:25:A7:73:DB:46:69:A8:9E + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + Signature Algorithm: sha256WithRSAEncryption + 56:b3:8e:cb:0a:9d:49:8e:bf:a4:c4:91:bb:66:17:05:51:98: + 75:fb:e5:50:2c:7a:9e:f1:14:fa:ab:d3:8a:3e:ff:91:29:8f: + 63:8b:d8:b4:a9:54:01:0d:be:93:86:2f:f9:4a:6d:c7:5e:f5: + 57:f9:ca:55:1c:12:be:47:0f:36:c5:df:6a:b7:db:75:c2:47: + 25:7f:b9:f1:63:f8:68:2d:55:04:d1:f2:8d:b0:a4:cf:bc:3c: + 5e:1f:78:e7:a5:a0:20:70:b0:04:c5:b7:f7:72:a7:de:22:0d: + bd:33:25:46:8c:64:92:26:e3:3e:2e:63:96:da:9b:8c:3d:f8: + 18:09:d7:03:cc:7d:86:82:e0:ca:04:07:51:50:d7:ff:92:d5: + 0c:ef:da:86:9f:99:d7:eb:b7:af:68:e2:39:26:94:ba:68:b7: + bf:83:d3:ea:7a:67:3d:62:67:ae:25:e5:72:e8:e2:e4:ec:ae: + 12:f6:4b:2b:3c:9f:e9:b0:40:f3:38:54:b3:fd:b7:68:c8:da: + c6:8f:51:3c:b2:fb:91:dc:1c:e7:9b:9d:e1:b7:0d:72:8f:e2: + a4:c4:a9:78:f9:eb:14:ac:c6:43:05:c2:65:39:28:18:02:c3: + 82:b2:9d:05:be:65:ed:96:5f:65:74:3c:fb:09:35:2e:7b:9c: + 13:fd:1b:0f:5d:c7:6d:81:3a:56:0f:cc:3b:e1:af:02:2f:22: + ac:46:ca:46:3c:a0:1c:4c:d6:44:b4:5e:2e:5c:15:66:09:e1: + 26:29:fe:c6:52:61:ba:b1:73:ff:c3:0c:9c:e5:6c:6a:94:3f: + 14:ca:40:16:95:84:f3:59:a9:ac:5f:4c:61:93:6d:d1:3b:cc: + a2:95:0c:22:a6:67:67:44:2e:b9:d9:d2:8a:41:b3:66:0b:5a: + fb:7d:23:a5:f2:1a:b0:ff:de:9b:83:94:2e:d1:3f:df:92:b7: + 91:af:05:3b:65:c7:a0:6c:b1:cd:62:12:c3:90:1b:e3:25:ce: + 34:bc:6f:77:76:b1:10:c3:f7:05:1a:c0:d6:af:74:62:48:17: + 77:92:69:90:61:1c:de:95:80:74:54:8f:18:1c:c3:f3:03:d0: + bf:a4:43:75:86:53:18:7a:0a:2e:09:1c:36:9f:91:fd:82:8a: + 22:4b:d1:0e:50:25:dd:cb:03:0c:17:c9:83:00:08:4e:35:4d: + 8a:8b:ed:f0:02:94:66:2c:44:7f:cb:95:27:96:17:ad:09:30: + ac:b6:71:17:6e:8b:17:f6:1c:09:d4:2d:3b:98:a5:71:d3:54: + 13:d9:60:f3:f5:4b:66:4f:fa:f1:ee:20:12:8d:b4:ac:57:b1: + 45:63:a1:ac:76:a9:c2:fb +-----BEGIN CERTIFICATE----- +MIIF6zCCA9OgAwIBAgIIVrYpzTS8ePYwDQYJKoZIhvcNAQELBQAwgYIxCzAJBgNV +BAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UE +CgwPU1NMIENvcnBvcmF0aW9uMTcwNQYDVQQDDC5TU0wuY29tIEVWIFJvb3QgQ2Vy +dGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIyMB4XDTE3MDUzMTE4MTQzN1oXDTQy +MDUzMDE4MTQzN1owgYIxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4G +A1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMTcwNQYDVQQD +DC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIy +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjzZlQOHWTcDXtOlG2mvq +M0fNTPl9fb69LT3w23jhhqXZuglXaO1XPqDQCEGD5yhBJB/jchXQARr7XnAjssuf +OePPxU7Gkm0mxnu7s9onnQqG6YE3Bf7wcXHswxzpY6IXFJ3vG2fThVUCAtZJycxa +4bH3bzKfydQ7iEGonL3Lq9ttewkfokxykNorCPzPPFTOZw+oz12WGQvE43LrrdF9 +HSfvkusQv1vrO6/PgN3B0pYEW3p+pKk8OHakYo6gOV7qd89dAFmPZiw+B6KjBSYR +aZfqhbcPlgtLyEDhULouisv3D5oi53+aNxPN8k0TayHRwMwi8qFG9kRpnMphNQcA +b9ZhCBHqurj26bNg5U257J8UZslXWNvNh2n4ioYSA0e/ZhN2rHd9NCSFg83XqpyQ +Gp8hLH94t2S42Oim9HizVcuE0jLEeK6jj2HdzghTreyI/BXkmg3mnxp3zkyPuBQV +PWKchjgGAGYS5Fl2WlPAApiiECtoRHuOec4zSnaqW4EWG7WK2NAAe15itAnWhmMO +pgWVSbooi4iTsjQc2KRVbrcc0N6ZVTsj9CLg+SlmJuwgUHfbSguPvuUCYHBBXtSu +UDkiFCbLsjtzdFVHB3mBOagwE0TlBIqulhMlQg+5U8Sb/M3kHN48+qvWBkofZ6aY +MBzdLNvcGJVXZsb/XItW9XcCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNV +HSMEGDAWgBT5YLvU49U09rj1BoAlp3PbRmmonjAdBgNVHQ4EFgQU+WC71OPVNPa4 +9QaAJadz20ZpqJ4wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBW +s47LCp1Jjr+kxJG7ZhcFUZh1++VQLHqe8RT6q9OKPv+RKY9ji9i0qVQBDb6Thi/5 +Sm3HXvVX+cpVHBK+Rw82xd9qt9t1wkclf7nxY/hoLVUE0fKNsKTPvDxeH3jnpaAg +cLAExbf3cqfeIg29MyVGjGSSJuM+LmOW2puMPfgYCdcDzH2GguDKBAdRUNf/ktUM +79qGn5nX67evaOI5JpS6aLe/g9Pqemc9YmeuJeVy6OLk7K4S9ksrPJ/psEDzOFSz +/bdoyNrGj1E8svuR3Bznm53htw1yj+KkxKl4+esUrMZDBcJlOSgYAsOCsp0FvmXt +ll9ldDz7CTUue5wT/RsPXcdtgTpWD8w74a8CLyKsRspGPKAcTNZEtF4uXBVmCeEm +Kf7GUmG6sXP/wwyc5WxqlD8UykAWlYTzWamsX0xhk23RO8yilQwipmdnRC652dKK +QbNmC1r7fSOl8hqw/96bg5Qu0T/fkreRrwU7ZcegbLHNYhLDkBvjJc40vG93drEQ +w/cFGsDWr3RiSBd3kmmQYRzelYB0VI8YHMPzA9C/pEN1hlMYegouCRw2n5H9gooi +S9EOUCXdywMMF8mDAAhONU2Ki+3wApRmLER/y5UnlhetCTCstnEXbosX9hwJ1C07 +mKVx01QT2WDz9UtmT/rx7iASjbSsV7FFY6GsdqnC+w== +-----END CERTIFICATE----- diff --git a/chromium/net/data/ssl/ev_roots/37d51006c512eaab626421f1ec8c92013fc5f82ae98ee533eb4619b8deb4d06c.pem b/chromium/net/data/ssl/ev_roots/37d51006c512eaab626421f1ec8c92013fc5f82ae98ee533eb4619b8deb4d06c.pem deleted file mode 100644 index 6f784f046aa..00000000000 --- a/chromium/net/data/ssl/ev_roots/37d51006c512eaab626421f1ec8c92013fc5f82ae98ee533eb4619b8deb4d06c.pem +++ /dev/null @@ -1,78 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 18:ac:b5:6a:fd:69:b6:15:3a:63:6c:af:da:fa:c4:a1 - Signature Algorithm: sha1WithRSAEncryption - Issuer: C=US, O=GeoTrust Inc., CN=GeoTrust Primary Certification Authority - Validity - Not Before: Nov 27 00:00:00 2006 GMT - Not After : Jul 16 23:59:59 2036 GMT - Subject: C=US, O=GeoTrust Inc., CN=GeoTrust Primary Certification Authority - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (2048 bit) - Modulus: - 00:be:b8:15:7b:ff:d4:7c:7d:67:ad:83:64:7b:c8: - 42:53:2d:df:f6:84:08:20:61:d6:01:59:6a:9c:44: - 11:af:ef:76:fd:95:7e:ce:61:30:bb:7a:83:5f:02: - bd:01:66:ca:ee:15:8d:6f:a1:30:9c:bd:a1:85:9e: - 94:3a:f3:56:88:00:31:cf:d8:ee:6a:96:02:d9:ed: - 03:8c:fb:75:6d:e7:ea:b8:55:16:05:16:9a:f4:e0: - 5e:b1:88:c0:64:85:5c:15:4d:88:c7:b7:ba:e0:75: - e9:ad:05:3d:9d:c7:89:48:e0:bb:28:c8:03:e1:30: - 93:64:5e:52:c0:59:70:22:35:57:88:8a:f1:95:0a: - 83:d7:bc:31:73:01:34:ed:ef:46:71:e0:6b:02:a8: - 35:72:6b:97:9b:66:e0:cb:1c:79:5f:d8:1a:04:68: - 1e:47:02:e6:9d:60:e2:36:97:01:df:ce:35:92:df: - be:67:c7:6d:77:59:3b:8f:9d:d6:90:15:94:bc:42: - 34:10:c1:39:f9:b1:27:3e:7e:d6:8a:75:c5:b2:af: - 96:d3:a2:de:9b:e4:98:be:7d:e1:e9:81:ad:b6:6f: - fc:d7:0e:da:e0:34:b0:0d:1a:77:e7:e3:08:98:ef: - 58:fa:9c:84:b7:36:af:c2:df:ac:d2:f4:10:06:70: - 71:35 - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Basic Constraints: critical - CA:TRUE - X509v3 Key Usage: critical - Certificate Sign, CRL Sign - X509v3 Subject Key Identifier: - 2C:D5:50:41:97:15:8B:F0:8F:36:61:5B:4A:FB:6B:D9:99:C9:33:92 - Signature Algorithm: sha1WithRSAEncryption - 5a:70:7f:2c:dd:b7:34:4f:f5:86:51:a9:26:be:4b:b8:aa:f1: - 71:0d:dc:61:c7:a0:ea:34:1e:7a:77:0f:04:35:e8:27:8f:6c: - 90:bf:91:16:24:46:3e:4a:4e:ce:2b:16:d5:0b:52:1d:fc:1f: - 67:a2:02:45:31:4f:ce:f3:fa:03:a7:79:9d:53:6a:d9:da:63: - 3a:f8:80:d7:d3:99:e1:a5:e1:be:d4:55:71:98:35:3a:be:93: - ea:ae:ad:42:b2:90:6f:e0:fc:21:4d:35:63:33:89:49:d6:9b: - 4e:ca:c7:e7:4e:09:00:f7:da:c7:ef:99:62:99:77:b6:95:22: - 5e:8a:a0:ab:f4:b8:78:98:ca:38:19:99:c9:72:9e:78:cd:4b: - ac:af:19:a0:73:12:2d:fc:c2:41:ba:81:91:da:16:5a:31:b7: - f9:b4:71:80:12:48:99:72:73:5a:59:53:c1:63:52:33:ed:a7: - c9:d2:39:02:70:fa:e0:b1:42:66:29:aa:9b:51:ed:30:54:22: - 14:5f:d9:ab:1d:c1:e4:94:f0:f8:f5:2b:f7:ea:ca:78:46:d6: - b8:91:fd:a6:0d:2b:1a:14:01:3e:80:f0:42:a0:95:07:5e:6d: - cd:cc:4b:a4:45:8d:ab:12:e8:b3:de:5a:e5:a0:7c:e8:0f:22: - 1d:5a:e9:59 ------BEGIN CERTIFICATE----- -MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBY -MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMo -R2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEx -MjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgxCzAJBgNVBAYTAlVTMRYwFAYDVQQK -Ew1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQcmltYXJ5IENlcnRp -ZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC -AQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9 -AWbK7hWNb6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjA -ZIVcFU2Ix7e64HXprQU9nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE0 -7e9GceBrAqg1cmuXm2bgyxx5X9gaBGgeRwLmnWDiNpcB3841kt++Z8dtd1k7j53W -kBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGttm/81w7a4DSwDRp35+MI -mO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4G -A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJ -KoZIhvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ1 -6CePbJC/kRYkRj5KTs4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl -4b7UVXGYNTq+k+qurUKykG/g/CFNNWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6K -oKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHaFloxt/m0cYASSJlyc1pZU8Fj -UjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG1riR/aYNKxoU -AT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk= ------END CERTIFICATE----- diff --git a/chromium/net/data/ssl/ev_roots/40f6af0346a99aa1cd1d555a4e9cce62c7f9634603ee406615833dc8c8d00367.pem b/chromium/net/data/ssl/ev_roots/40f6af0346a99aa1cd1d555a4e9cce62c7f9634603ee406615833dc8c8d00367.pem new file mode 100644 index 00000000000..cf78be92339 --- /dev/null +++ b/chromium/net/data/ssl/ev_roots/40f6af0346a99aa1cd1d555a4e9cce62c7f9634603ee406615833dc8c8d00367.pem @@ -0,0 +1,79 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 31:f5:e4:62:0c:6c:58:ed:d6:d8 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C = IN, OU = emSign PKI, O = eMudhra Technologies Limited, CN = emSign Root CA - G1 + Validity + Not Before: Feb 18 18:30:00 2018 GMT + Not After : Feb 18 18:30:00 2043 GMT + Subject: C = IN, OU = emSign PKI, O = eMudhra Technologies Limited, CN = emSign Root CA - G1 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:93:4b:bb:e9:66:8a:ee:9d:5b:d5:34:93:d0:1b: + 1e:c3:e7:9e:b8:64:33:7f:63:78:68:b4:cd:2e:71: + 75:d7:9b:20:c6:4d:29:bc:b6:68:60:8a:f7:21:9a: + 56:35:5a:f3:76:bd:d8:cd:9a:ff:93:56:4b:a5:59: + 06:a1:93:34:29:dd:16:34:75:4e:f2:81:b4:c7:96: + 4e:ad:19:15:52:4a:fe:3c:70:75:70:cd:af:2b:ab: + 15:9a:33:3c:aa:b3:8b:aa:cd:43:fd:f5:ea:70:ff: + ed:cf:11:3b:94:ce:4e:32:16:d3:23:40:2a:77:b3: + af:3c:01:2c:6c:ed:99:2c:8b:d9:4e:69:98:b2:f7: + 8f:41:b0:32:78:61:d6:0d:5f:c3:fa:a2:40:92:1d: + 5c:17:e6:70:3e:35:e7:a2:b7:c2:62:e2:ab:a4:38: + 4c:b5:39:35:6f:ea:03:69:fa:3a:54:68:85:6d:d6: + f2:2f:43:55:1e:91:0d:0e:d8:d5:6a:a4:96:d1:13: + 3c:2c:78:50:e8:3a:92:d2:17:56:e5:35:1a:40:1c: + 3e:8d:2c:ed:39:df:42:e0:83:41:74:df:a3:cd:c2: + 86:60:48:68:e3:69:0b:54:00:8b:e4:76:69:21:0d: + 79:4e:34:08:5e:14:c2:cc:b1:b7:ad:d7:7c:70:8a: + c7:85 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + FB:EF:0D:86:9E:B0:E3:DD:A9:B9:F1:21:17:7F:3E:FC:F0:77:2B:1A + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + Signature Algorithm: sha256WithRSAEncryption + 59:ff:f2:8c:f5:87:7d:71:3d:a3:9f:1b:5b:d1:da:f8:d3:9c: + 6b:36:bd:9b:a9:61:eb:de:16:2c:74:3d:9e:e6:75:da:d7:ba: + a7:bc:42:17:e7:3d:91:eb:e5:7d:dd:3e:9c:f1:cf:92:ac:6c: + 48:cc:c2:22:3f:69:3b:c5:b6:15:2f:a3:35:c6:68:2a:1c:57: + af:39:ef:8d:d0:35:c3:18:0c:7b:00:56:1c:cd:8b:19:74:de: + be:0f:12:e0:d0:aa:a1:3f:02:34:b1:70:ce:9d:18:d6:08:03: + 09:46:ee:60:e0:7e:b6:c4:49:04:51:7d:70:60:bc:aa:b2:ff: + 79:72:7a:a6:1d:3d:5f:2a:f8:ca:e2:fd:39:b7:47:b9:eb:7e: + df:04:23:af:fa:9c:06:07:e9:fb:63:93:80:40:b5:c6:6c:0a: + 31:28:ce:0c:9f:cf:b3:23:35:80:41:8d:6c:c4:37:7b:81:2f: + 80:a1:40:42:85:e9:d9:38:8d:e8:a1:53:cd:01:bf:69:e8:5a: + 06:f2:45:0b:90:fa:ae:e1:bf:9d:f2:ae:57:3c:a5:ae:b2:56: + f4:8b:65:40:e9:fd:31:81:2c:f4:39:09:d8:ee:6b:a7:b4:a6: + 1d:15:a5:98:f7:01:81:d8:85:7d:f3:51:5c:71:88:de:ba:cc: + 1f:80:7e:4a +-----BEGIN CERTIFICATE----- +MIIDlDCCAnygAwIBAgIKMfXkYgxsWO3W2DANBgkqhkiG9w0BAQsFADBnMQswCQYD +VQQGEwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBU +ZWNobm9sb2dpZXMgTGltaXRlZDEcMBoGA1UEAxMTZW1TaWduIFJvb3QgQ0EgLSBH +MTAeFw0xODAyMTgxODMwMDBaFw00MzAyMTgxODMwMDBaMGcxCzAJBgNVBAYTAklO +MRMwEQYDVQQLEwplbVNpZ24gUEtJMSUwIwYDVQQKExxlTXVkaHJhIFRlY2hub2xv +Z2llcyBMaW1pdGVkMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEcxMIIBIjAN +BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk0u76WaK7p1b1TST0Bsew+eeuGQz +f2N4aLTNLnF115sgxk0pvLZoYIr3IZpWNVrzdr3YzZr/k1ZLpVkGoZM0Kd0WNHVO +8oG0x5ZOrRkVUkr+PHB1cM2vK6sVmjM8qrOLqs1D/fXqcP/tzxE7lM5OMhbTI0Aq +d7OvPAEsbO2ZLIvZTmmYsvePQbAyeGHWDV/D+qJAkh1cF+ZwPjXnorfCYuKrpDhM +tTk1b+oDafo6VGiFbdbyL0NVHpENDtjVaqSW0RM8LHhQ6DqS0hdW5TUaQBw+jSzt +Od9C4INBdN+jzcKGYEho42kLVACL5HZpIQ15TjQIXhTCzLG3rdd8cIrHhQIDAQAB +o0IwQDAdBgNVHQ4EFgQU++8Nhp6w492pufEhF38+/PB3KxowDgYDVR0PAQH/BAQD +AgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFn/8oz1h31x +PaOfG1vR2vjTnGs2vZupYeveFix0PZ7mddrXuqe8QhfnPZHr5X3dPpzxz5KsbEjM +wiI/aTvFthUvozXGaCocV685743QNcMYDHsAVhzNixl03r4PEuDQqqE/AjSxcM6d +GNYIAwlG7mDgfrbESQRRfXBgvKqy/3lyeqYdPV8q+Mri/Tm3R7nrft8EI6/6nAYH +6ftjk4BAtcZsCjEozgyfz7MjNYBBjWzEN3uBL4ChQEKF6dk4jeihU80Bv2noWgby +RQuQ+q7hv53yrlc8pa6yVvSLZUDp/TGBLPQ5Cdjua6e0ph0VpZj3AYHYhX3zUVxx +iN66zB+Afko= +-----END CERTIFICATE----- diff --git a/chromium/net/data/ssl/ev_roots/4b03f45807ad70f21bfc2cae71c9fde4604c064cf5ffb686bae5dbaad7fdd34c.pem b/chromium/net/data/ssl/ev_roots/4b03f45807ad70f21bfc2cae71c9fde4604c064cf5ffb686bae5dbaad7fdd34c.pem deleted file mode 100644 index 901e6ae1a5b..00000000000 --- a/chromium/net/data/ssl/ev_roots/4b03f45807ad70f21bfc2cae71c9fde4604c064cf5ffb686bae5dbaad7fdd34c.pem +++ /dev/null @@ -1,82 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 60:01:97:b7:46:a7:ea:b4:b4:9a:d6:4b:2f:f7:90:fb - Signature Algorithm: sha256WithRSAEncryption - Issuer: C=US, O=thawte, Inc., OU=Certification Services Division, OU=(c) 2008 thawte, Inc. - For authorized use only, CN=thawte Primary Root CA - G3 - Validity - Not Before: Apr 2 00:00:00 2008 GMT - Not After : Dec 1 23:59:59 2037 GMT - Subject: C=US, O=thawte, Inc., OU=Certification Services Division, OU=(c) 2008 thawte, Inc. - For authorized use only, CN=thawte Primary Root CA - G3 - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (2048 bit) - Modulus: - 00:b2:bf:27:2c:fb:db:d8:5b:dd:78:7b:1b:9e:77: - 66:81:cb:3e:bc:7c:ae:f3:a6:27:9a:34:a3:68:31: - 71:38:33:62:e4:f3:71:66:79:b1:a9:65:a3:a5:8b: - d5:8f:60:2d:3f:42:cc:aa:6b:32:c0:23:cb:2c:41: - dd:e4:df:fc:61:9c:e2:73:b2:22:95:11:43:18:5f: - c4:b6:1f:57:6c:0a:05:58:22:c8:36:4c:3a:7c:a5: - d1:cf:86:af:88:a7:44:02:13:74:71:73:0a:42:59: - 02:f8:1b:14:6b:42:df:6f:5f:ba:6b:82:a2:9d:5b: - e7:4a:bd:1e:01:72:db:4b:74:e8:3b:7f:7f:7d:1f: - 04:b4:26:9b:e0:b4:5a:ac:47:3d:55:b8:d7:b0:26: - 52:28:01:31:40:66:d8:d9:24:bd:f6:2a:d8:ec:21: - 49:5c:9b:f6:7a:e9:7f:55:35:7e:96:6b:8d:93:93: - 27:cb:92:bb:ea:ac:40:c0:9f:c2:f8:80:cf:5d:f4: - 5a:dc:ce:74:86:a6:3e:6c:0b:53:ca:bd:92:ce:19: - 06:72:e6:0c:5c:38:69:c7:04:d6:bc:6c:ce:5b:f6: - f7:68:9c:dc:25:15:48:88:a1:e9:a9:f8:98:9c:e0: - f3:d5:31:28:61:11:6c:67:96:8d:39:99:cb:c2:45: - 24:39 - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Basic Constraints: critical - CA:TRUE - X509v3 Key Usage: critical - Certificate Sign, CRL Sign - X509v3 Subject Key Identifier: - AD:6C:AA:94:60:9C:ED:E4:FF:FA:3E:0A:74:2B:63:03:F7:B6:59:BF - Signature Algorithm: sha256WithRSAEncryption - 1a:40:d8:95:65:ac:09:92:89:c6:39:f4:10:e5:a9:0e:66:53: - 5d:78:de:fa:24:91:bb:e7:44:51:df:c6:16:34:0a:ef:6a:44: - 51:ea:2b:07:8a:03:7a:c3:eb:3f:0a:2c:52:16:a0:2b:43:b9: - 25:90:3f:70:a9:33:25:6d:45:1a:28:3b:27:cf:aa:c3:29:42: - 1b:df:3b:4c:c0:33:34:5b:41:88:bf:6b:2b:65:af:28:ef:b2: - f5:c3:aa:66:ce:7b:56:ee:b7:c8:cb:67:c1:c9:9c:1a:18:b8: - c4:c3:49:03:f1:60:0e:50:cd:46:c5:f3:77:79:f7:b6:15:e0: - 38:db:c7:2f:28:a0:0c:3f:77:26:74:d9:25:12:da:31:da:1a: - 1e:dc:29:41:91:22:3c:69:a7:bb:02:f2:b6:5c:27:03:89:f4: - 06:ea:9b:e4:72:82:e3:a1:09:c1:e9:00:19:d3:3e:d4:70:6b: - ba:71:a6:aa:58:ae:f4:bb:e9:6c:b6:ef:87:cc:9b:bb:ff:39: - e6:56:61:d3:0a:a7:c4:5c:4c:60:7b:05:77:26:7a:bf:d8:07: - 52:2c:62:f7:70:63:d9:39:bc:6f:1c:c2:79:dc:76:29:af:ce: - c5:2c:64:04:5e:88:36:6e:31:d4:40:1a:62:34:36:3f:35:01: - ae:ac:63:a0 ------BEGIN CERTIFICATE----- -MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCB -rjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf -Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw -MDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNV -BAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0wODA0MDIwMDAwMDBa -Fw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhhd3Rl -LCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9u -MTgwNgYDVQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXpl -ZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEcz -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsr8nLPvb2FvdeHsbnndm -gcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2AtP0LMqmsywCPLLEHd5N/8 -YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC+BsUa0Lf -b1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS9 -9irY7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2S -zhkGcuYMXDhpxwTWvGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUk -OQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNV -HQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJKoZIhvcNAQELBQADggEBABpA -2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweKA3rD6z8KLFIW -oCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu -t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7c -KUGRIjxpp7sC8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fM -m7v/OeZWYdMKp8RcTGB7BXcmer/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZu -MdRAGmI0Nj81Aa6sY6A= ------END CERTIFICATE----- diff --git a/chromium/net/data/ssl/ev_roots/58d017279cd4dc63abddb196a6c9906c30c4e08783eae8c1609954d69355596b.pem b/chromium/net/data/ssl/ev_roots/58d017279cd4dc63abddb196a6c9906c30c4e08783eae8c1609954d69355596b.pem deleted file mode 100644 index 0900e0140aa..00000000000 --- a/chromium/net/data/ssl/ev_roots/58d017279cd4dc63abddb196a6c9906c30c4e08783eae8c1609954d69355596b.pem +++ /dev/null @@ -1,51 +0,0 @@ -Certificate: - Data: - Version: 1 (0x0) - Serial Number: 1 (0x1) - Signature Algorithm: sha1WithRSAEncryption - Issuer: L=ValiCert Validation Network, O=ValiCert, Inc., OU=ValiCert Class 2 Policy Validation Authority, CN=http://www.valicert.com//emailAddress=info@valicert.com - Validity - Not Before: Jun 26 00:19:54 1999 GMT - Not After : Jun 26 00:19:54 2019 GMT - Subject: L=ValiCert Validation Network, O=ValiCert, Inc., OU=ValiCert Class 2 Policy Validation Authority, CN=http://www.valicert.com//emailAddress=info@valicert.com - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (1024 bit) - Modulus: - 00:ce:3a:71:ca:e5:ab:c8:59:92:55:d7:ab:d8:74: - 0e:f9:ee:d9:f6:55:47:59:65:47:0e:05:55:dc:eb: - 98:36:3c:5c:53:5d:d3:30:cf:38:ec:bd:41:89:ed: - 25:42:09:24:6b:0a:5e:b3:7c:dd:52:2d:4c:e6:d4: - d6:7d:5a:59:a9:65:d4:49:13:2d:24:4d:1c:50:6f: - b5:c1:85:54:3b:fe:71:e4:d3:5c:42:f9:80:e0:91: - 1a:0a:5b:39:36:67:f3:3f:55:7c:1b:3f:b4:5f:64: - 73:34:e3:b4:12:bf:87:64:f8:da:12:ff:37:27:c1: - b3:43:bb:ef:7b:6e:2e:69:f7 - Exponent: 65537 (0x10001) - Signature Algorithm: sha1WithRSAEncryption - 3b:7f:50:6f:6f:50:94:99:49:62:38:38:1f:4b:f8:a5:c8:3e: - a7:82:81:f6:2b:c7:e8:c5:ce:e8:3a:10:82:cb:18:00:8e:4d: - bd:a8:58:7f:a1:79:00:b5:bb:e9:8d:af:41:d9:0f:34:ee:21: - 81:19:a0:32:49:28:f4:c4:8e:56:d5:52:33:fd:50:d5:7e:99: - 6c:03:e4:c9:4c:fc:cb:6c:ab:66:b3:4a:21:8c:e5:b5:0c:32: - 3e:10:b2:cc:6c:a1:dc:9a:98:4c:02:5b:f3:ce:b9:9e:a5:72: - 0e:4a:b7:3f:3c:e6:16:68:f8:be:ed:74:4c:bc:5b:d5:62:1f: - 43:dd ------BEGIN CERTIFICATE----- -MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0 -IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz -BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y -aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG -9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMTk1NFoXDTE5MDYy -NjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y -azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs -YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw -Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl -cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vY -dA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9 -WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QS -v4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9v -UJSZSWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTu -IYEZoDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwC -W/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd ------END CERTIFICATE----- diff --git a/chromium/net/data/ssl/ev_roots/5a2fc03f0c83b090bbfa40604b0988446c7636183df9846e17101a447fb8efd6.pem b/chromium/net/data/ssl/ev_roots/5a2fc03f0c83b090bbfa40604b0988446c7636183df9846e17101a447fb8efd6.pem new file mode 100644 index 00000000000..43021ef5202 --- /dev/null +++ b/chromium/net/data/ssl/ev_roots/5a2fc03f0c83b090bbfa40604b0988446c7636183df9846e17101a447fb8efd6.pem @@ -0,0 +1,125 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 08:16:5f:8a:4c:a5:ec:00:c9:93:40:df:c4:c6:ae:23:b8:1c:5a:a4 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C = HK, ST = Hong Kong, L = Hong Kong, O = Hongkong Post, CN = Hongkong Post Root CA 3 + Validity + Not Before: Jun 3 02:29:46 2017 GMT + Not After : Jun 3 02:29:46 2042 GMT + Subject: C = HK, ST = Hong Kong, L = Hong Kong, O = Hongkong Post, CN = Hongkong Post Root CA 3 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (4096 bit) + Modulus: + 00:b3:88:d7:ea:ce:0f:20:4e:be:e6:d6:03:6d:ee: + 59:fc:c2:57:df:29:68:a1:83:0e:3e:68:c7:68:58: + 9c:1c:60:4b:89:43:0c:b9:d4:15:b2:ee:c1:4e:75: + e9:b5:a7:ef:e5:e9:35:99:e4:cc:1c:e7:4b:5f:8d: + 33:30:20:33:53:d9:a6:bb:d5:3e:13:8e:e9:1f:87: + 49:ad:50:2d:50:ca:18:be:01:58:a2:13:70:96:bb: + 89:88:56:80:5c:f8:bd:2c:3c:e1:4c:57:88:bb:d3: + b9:95:ef:cb:c7:f6:da:31:74:28:a6:e6:54:89:f5: + 41:31:ca:e5:26:1a:cd:82:e0:70:da:3b:29:bb:d5: + 03:f5:99:ba:55:f5:64:d1:60:0e:b3:89:49:b8:8a: + 2f:05:d2:84:45:28:7c:8f:68:50:12:78:fc:0b:b5: + 53:cb:c2:98:1c:84:a3:9e:b0:be:23:a4:da:dc:c8: + 2b:1e:da:6e:45:1e:89:98:da:f9:00:2e:06:e9:0c: + 3b:70:d5:50:25:88:99:cb:cd:73:60:f7:d5:ff:35: + 67:c5:a1:bc:5e:ab:cd:4a:b8:45:eb:c8:68:1e:0d: + 0d:14:46:12:e3:d2:64:62:8a:42:98:bc:b4:c6:08: + 08:f8:fd:a8:4c:64:9c:76:01:bd:2f:a9:6c:33:0f: + d8:3f:28:b8:3c:69:01:42:86:7e:69:c1:c9:06:ca: + e5:7a:46:65:e9:c2:d6:50:41:2e:3f:b7:e4:ed:6c: + d7:bf:26:01:11:a2:16:29:4a:6b:34:06:90:ec:13: + d2:b6:fb:6a:76:d2:3c:ed:f0:d6:2d:dd:e1:15:ec: + a3:9b:2f:2c:c9:3e:2b:e4:69:3b:ff:72:25:b1:36: + 86:5b:c7:7f:6b:8b:55:1b:4a:c5:20:61:3d:ae:cb: + 50:e1:08:3a:be:b0:8f:63:41:53:30:08:59:3c:98: + 1d:77:ba:63:91:7a:ca:10:50:60:bf:f0:d7:bc:95: + 87:8f:97:c5:fe:97:6a:01:94:a3:7c:5b:85:1d:2a: + 39:3a:d0:54:a1:d1:39:71:9d:fd:21:f9:b5:7b:f0: + e2:e0:02:8f:6e:96:24:25:2c:a0:1e:2c:a8:c4:89: + a7:ef:ed:99:06:2f:b6:0a:4c:4f:db:a2:cc:37:1a: + af:47:85:2d:8a:5f:c4:34:34:4c:00:fd:18:93:67: + 13:d1:37:e6:48:b4:8b:06:c5:57:7b:19:86:0a:79: + cb:00:c9:52:af:42:ff:37:8f:e1:a3:1e:7a:3d:50: + ab:63:06:e7:15:b5:3f:b6:45:37:94:37:b1:7e:f2: + 48:c3:7f:c5:75:fe:97:8d:45:8f:1a:a7:1a:72:28: + 1a:40:0f + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Authority Key Identifier: + keyid:17:9D:CD:1E:8B:D6:39:2B:70:D3:5C:D4:A0:B8:1F:B0:00:FC:C5:61 + + X509v3 Subject Key Identifier: + 17:9D:CD:1E:8B:D6:39:2B:70:D3:5C:D4:A0:B8:1F:B0:00:FC:C5:61 + Signature Algorithm: sha256WithRSAEncryption + 56:d5:7b:6e:e6:22:01:d2:42:9b:18:d5:0e:d7:66:23:5c:e3: + fe:a0:c7:92:d2:e9:94:ad:4b:a2:c6:ec:12:7c:74:d5:48:d2: + 59:14:99:c0:eb:b9:d1:eb:f4:48:30:5b:ad:a7:57:73:99:a9: + d3:e5:b7:d1:2e:59:24:58:dc:68:2e:2e:62:d8:6a:e4:70:0b: + 2d:20:50:20:a4:32:95:d1:00:98:bb:d3:fd:f7:32:f2:49:ae: + c6:7a:e0:47:be:6e:ce:cb:a3:72:3a:2d:69:5d:cb:c8:e8:45: + 39:d4:fa:42:c1:11:4c:77:5d:92:fb:6a:ff:58:44:e5:eb:81: + 9e:af:a0:99:ad:be:a9:01:66:cb:38:1d:3c:df:43:1f:f4:4d: + 6e:b4:ba:17:46:fc:7d:fd:87:81:79:6a:0d:33:0f:fa:2f:f8: + 14:b9:80:b3:5d:4d:aa:97:e1:f9:e4:18:c5:f8:d5:38:8c:26: + 3c:fd:f2:28:e2:ee:5a:49:88:2c:df:79:3d:8e:9e:90:3c:bd: + 41:4a:3a:dd:5b:f6:9a:b4:ce:3f:25:30:7f:32:7d:a2:03:94: + d0:dc:7a:a1:52:de:6e:93:8d:18:26:fd:55:ac:bd:8f:9b:d2: + cf:af:e7:86:2c:cb:1f:09:6f:a3:6f:a9:84:d4:73:bf:4d:a1: + 74:1b:4e:23:60:f2:cc:0e:aa:7f:a4:9c:4c:25:a8:b2:66:3b: + 38:ff:d9:94:30:f6:72:84:be:68:55:10:0f:c6:73:2c:16:69: + 93:07:fe:b1:45:ed:bb:a2:55:6a:b0:da:b5:4a:02:25:27:85: + d7:b7:b7:86:44:16:89:6c:80:2b:3e:97:a9:9c:d5:7e:55:4c: + c6:de:45:10:1c:ea:e9:3b:9f:03:53:ee:ee:7a:01:02:16:78: + d4:e8:c2:be:46:76:88:13:3f:22:bb:48:12:1d:52:00:b4:02: + 7e:21:1a:1e:9c:25:f4:f3:3d:5e:1e:d2:1c:f9:b3:2d:b6:f7: + 37:5c:c6:cb:21:4e:b0:f7:99:47:18:85:c1:2b:ba:55:ae:06: + ea:d0:07:b2:dc:ab:d0:82:96:75:ce:d2:50:fe:99:e7:cf:2f: + 9f:e7:76:d1:61:2a:fb:21:bb:31:d0:aa:9f:47:a4:b2:22:ca: + 16:3a:50:57:c4:5b:43:67:c5:65:62:03:49:01:eb:43:d9:d8: + f8:9e:ad:cf:b1:63:0e:45:f4:a0:5a:2c:9b:2d:c5:a6:c0:ad: + a8:47:f4:27:4c:38:0d:2e:1b:49:3b:52:f4:e8:88:83:2b:54: + 28:d4:f2:35:52:b4:32:83:62:69:64:0c:91:9c:9f:97:ea:74: + 16:fd:1f:11:06:9a:9b:f4 +-----BEGIN CERTIFICATE----- +MIIFzzCCA7egAwIBAgIUCBZfikyl7ADJk0DfxMauI7gcWqQwDQYJKoZIhvcNAQEL +BQAwbzELMAkGA1UEBhMCSEsxEjAQBgNVBAgTCUhvbmcgS29uZzESMBAGA1UEBxMJ +SG9uZyBLb25nMRYwFAYDVQQKEw1Ib25na29uZyBQb3N0MSAwHgYDVQQDExdIb25n +a29uZyBQb3N0IFJvb3QgQ0EgMzAeFw0xNzA2MDMwMjI5NDZaFw00MjA2MDMwMjI5 +NDZaMG8xCzAJBgNVBAYTAkhLMRIwEAYDVQQIEwlIb25nIEtvbmcxEjAQBgNVBAcT +CUhvbmcgS29uZzEWMBQGA1UEChMNSG9uZ2tvbmcgUG9zdDEgMB4GA1UEAxMXSG9u +Z2tvbmcgUG9zdCBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK +AoICAQCziNfqzg8gTr7m1gNt7ln8wlffKWihgw4+aMdoWJwcYEuJQwy51BWy7sFO +dem1p+/l6TWZ5Mwc50tfjTMwIDNT2aa71T4Tjukfh0mtUC1Qyhi+AViiE3CWu4mI +VoBc+L0sPOFMV4i707mV78vH9toxdCim5lSJ9UExyuUmGs2C4HDaOym71QP1mbpV +9WTRYA6ziUm4ii8F0oRFKHyPaFASePwLtVPLwpgchKOesL4jpNrcyCse2m5FHomY +2vkALgbpDDtw1VAliJnLzXNg99X/NWfFobxeq81KuEXryGgeDQ0URhLj0mRiikKY +vLTGCAj4/ahMZJx2Ab0vqWwzD9g/KLg8aQFChn5pwckGyuV6RmXpwtZQQS4/t+Tt +bNe/JgERohYpSms0BpDsE9K2+2p20jzt8NYt3eEV7KObLyzJPivkaTv/ciWxNoZb +x39ri1UbSsUgYT2uy1DhCDq+sI9jQVMwCFk8mB13umOResoQUGC/8Ne8lYePl8X+ +l2oBlKN8W4UdKjk60FSh0Tlxnf0h+bV78OLgAo9uliQlLKAeLKjEiafv7ZkGL7YK +TE/bosw3Gq9HhS2KX8Q0NEwA/RiTZxPRN+ZItIsGxVd7GYYKecsAyVKvQv83j+Gj +Hno9UKtjBucVtT+2RTeUN7F+8kjDf8V1/peNRY8apxpyKBpADwIDAQABo2MwYTAP +BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBQXnc0e +i9Y5K3DTXNSguB+wAPzFYTAdBgNVHQ4EFgQUF53NHovWOStw01zUoLgfsAD8xWEw +DQYJKoZIhvcNAQELBQADggIBAFbVe27mIgHSQpsY1Q7XZiNc4/6gx5LS6ZStS6LG +7BJ8dNVI0lkUmcDrudHr9EgwW62nV3OZqdPlt9EuWSRY3GguLmLYauRwCy0gUCCk +MpXRAJi70/33MvJJrsZ64Ee+bs7Lo3I6LWldy8joRTnU+kLBEUx3XZL7av9YROXr +gZ6voJmtvqkBZss4HTzfQx/0TW60uhdG/H39h4F5ag0zD/ov+BS5gLNdTaqX4fnk +GMX41TiMJjz98iji7lpJiCzfeT2OnpA8vUFKOt1b9pq0zj8lMH8yfaIDlNDceqFS +3m6TjRgm/VWsvY+b0s+v54Ysyx8Jb6NvqYTUc79NoXQbTiNg8swOqn+knEwlqLJm +Ozj/2ZQw9nKEvmhVEA/GcywWaZMH/rFF7buiVWqw2rVKAiUnhde3t4ZEFolsgCs+ +l6mc1X5VTMbeRRAc6uk7nwNT7u56AQIWeNTowr5GdogTPyK7SBIdUgC0An4hGh6c +JfTzPV4e0hz5sy229zdcxsshTrD3mUcYhcErulWuBurQB7Lcq9CClnXO0lD+mefP +L5/ndtFhKvshuzHQqp9HpLIiyhY6UFfEW0NnxWViA0kB60PZ2Pierc+xYw5F9KBa +LJstxabArahH9CdMOA0uG0k7UvToiIMrVCjU8jVStDKDYmlkDJGcn5fqdBb9HxEG +mpv0 +-----END CERTIFICATE----- diff --git a/chromium/net/data/ssl/ev_roots/5edb7ac43b82a06a8761e8d7be4979ebf2611f7dd79bf91c1c6b566a219ed766.pem b/chromium/net/data/ssl/ev_roots/5edb7ac43b82a06a8761e8d7be4979ebf2611f7dd79bf91c1c6b566a219ed766.pem deleted file mode 100644 index ad1ace9c9da..00000000000 --- a/chromium/net/data/ssl/ev_roots/5edb7ac43b82a06a8761e8d7be4979ebf2611f7dd79bf91c1c6b566a219ed766.pem +++ /dev/null @@ -1,54 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 3c:b2:f4:48:0a:00:e2:fe:eb:24:3b:5e:60:3e:c3:6b - Signature Algorithm: ecdsa-with-SHA384 - Issuer: C=US, O=GeoTrust Inc., OU=(c) 2007 GeoTrust Inc. - For authorized use only, CN=GeoTrust Primary Certification Authority - G2 - Validity - Not Before: Nov 5 00:00:00 2007 GMT - Not After : Jan 18 23:59:59 2038 GMT - Subject: C=US, O=GeoTrust Inc., OU=(c) 2007 GeoTrust Inc. - For authorized use only, CN=GeoTrust Primary Certification Authority - G2 - Subject Public Key Info: - Public Key Algorithm: id-ecPublicKey - Public-Key: (384 bit) - pub: - 04:15:b1:e8:fd:03:15:43:e5:ac:eb:87:37:11:62: - ef:d2:83:36:52:7d:45:57:0b:4a:8d:7b:54:3b:3a: - 6e:5f:15:02:c0:50:a6:cf:25:2f:7d:ca:48:b8:c7: - 50:63:1c:2a:21:08:7c:9a:36:d8:0b:fe:d1:26:c5: - 58:31:30:28:25:f3:5d:5d:a3:b8:b6:a5:b4:92:ed: - 6c:2c:9f:eb:dd:43:89:a2:3c:4b:48:91:1d:50:ec: - 26:df:d6:60:2e:bd:21 - ASN1 OID: secp384r1 - X509v3 extensions: - X509v3 Basic Constraints: critical - CA:TRUE - X509v3 Key Usage: critical - Certificate Sign, CRL Sign - X509v3 Subject Key Identifier: - 15:5F:35:57:51:55:FB:25:B2:AD:03:69:FC:01:A3:FA:BE:11:55:D5 - Signature Algorithm: ecdsa-with-SHA384 - 30:64:02:30:64:96:59:a6:e8:09:de:8b:ba:fa:5a:88:88:f0: - 1f:91:d3:46:a8:f2:4a:4c:02:63:fb:6c:5f:38:db:2e:41:93: - a9:0e:e6:9d:dc:31:1c:b2:a0:a7:18:1c:79:e1:c7:36:02:30: - 3a:56:af:9a:74:6c:f6:fb:83:e0:33:d3:08:5f:a1:9c:c2:5b: - 9f:46:d6:b6:cb:91:06:63:a2:06:e7:33:ac:3e:a8:81:12:d0: - cb:ba:d0:92:0b:b6:9e:96:aa:04:0f:8a ------BEGIN CERTIFICATE----- -MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDEL -MAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChj -KSAyMDA3IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2 -MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 -eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1OVowgZgxCzAJBgNV -BAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykgMjAw -NyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNV -BAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBH -MjB2MBAGByqGSM49AgEGBSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcL -So17VDs6bl8VAsBQps8lL33KSLjHUGMcKiEIfJo22Av+0SbFWDEwKCXzXV2juLal -tJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO -BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+EVXVMAoG -CCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGT -qQ7mndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBucz -rD6ogRLQy7rQkgu2npaqBA+K ------END CERTIFICATE----- diff --git a/chromium/net/data/ssl/ev_roots/62f240278c564c4dd8bf7d9d4f6f366ea894d22f5f34d989a983acec2fffed50.pem b/chromium/net/data/ssl/ev_roots/62f240278c564c4dd8bf7d9d4f6f366ea894d22f5f34d989a983acec2fffed50.pem deleted file mode 100644 index d989575f69f..00000000000 --- a/chromium/net/data/ssl/ev_roots/62f240278c564c4dd8bf7d9d4f6f366ea894d22f5f34d989a983acec2fffed50.pem +++ /dev/null @@ -1,86 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: 927650371 (0x374ad243) - Signature Algorithm: sha1WithRSAEncryption - Issuer: C=US, O=Entrust.net, OU=www.entrust.net/CPS incorp. by ref. (limits liab.), OU=(c) 1999 Entrust.net Limited, CN=Entrust.net Secure Server Certification Authority - Validity - Not Before: May 25 16:09:40 1999 GMT - Not After : May 25 16:39:40 2019 GMT - Subject: C=US, O=Entrust.net, OU=www.entrust.net/CPS incorp. by ref. (limits liab.), OU=(c) 1999 Entrust.net Limited, CN=Entrust.net Secure Server Certification Authority - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (1024 bit) - Modulus: - 00:cd:28:83:34:54:1b:89:f3:0f:af:37:91:31:ff: - af:31:60:c9:a8:e8:b2:10:68:ed:9f:e7:93:36:f1: - 0a:64:bb:47:f5:04:17:3f:23:47:4d:c5:27:19:81: - 26:0c:54:72:0d:88:2d:d9:1f:9a:12:9f:bc:b3:71: - d3:80:19:3f:47:66:7b:8c:35:28:d2:b9:0a:df:24: - da:9c:d6:50:79:81:7a:5a:d3:37:f7:c2:4a:d8:29: - 92:26:64:d1:e4:98:6c:3a:00:8a:f5:34:9b:65:f8: - ed:e3:10:ff:fd:b8:49:58:dc:a0:de:82:39:6b:81: - b1:16:19:61:b9:54:b6:e6:43 - Exponent: 3 (0x3) - X509v3 extensions: - Netscape Cert Type: - SSL CA, S/MIME CA, Object Signing CA - X509v3 CRL Distribution Points: - - Full Name: - DirName: C = US, O = Entrust.net, OU = www.entrust.net/CPS incorp. by ref. (limits liab.), OU = (c) 1999 Entrust.net Limited, CN = Entrust.net Secure Server Certification Authority, CN = CRL1 - - Full Name: - URI:http://www.entrust.net/CRL/net1.crl - - X509v3 Private Key Usage Period: - Not Before: May 25 16:09:40 1999 GMT, Not After: May 25 16:09:40 2019 GMT - X509v3 Key Usage: - Certificate Sign, CRL Sign - X509v3 Authority Key Identifier: - keyid:F0:17:62:13:55:3D:B3:FF:0A:00:6B:FB:50:84:97:F3:ED:62:D0:1A - - X509v3 Subject Key Identifier: - F0:17:62:13:55:3D:B3:FF:0A:00:6B:FB:50:84:97:F3:ED:62:D0:1A - X509v3 Basic Constraints: - CA:TRUE - 1.2.840.113533.7.65.0: - 0 -..V4.0.... - Signature Algorithm: sha1WithRSAEncryption - 90:dc:30:02:fa:64:74:c2:a7:0a:a5:7c:21:8d:34:17:a8:fb: - 47:0e:ff:25:7c:8d:13:0a:fb:e4:98:b5:ef:8c:f8:c5:10:0d: - f7:92:be:f1:c3:d5:d5:95:6a:04:bb:2c:ce:26:36:65:c8:31: - c6:e7:ee:3f:e3:57:75:84:7a:11:ef:46:4f:18:f4:d3:98:bb: - a8:87:32:ba:72:f6:3c:e2:3d:9f:d7:1d:d9:c3:60:43:8c:58: - 0e:22:96:2f:62:a3:2c:1f:ba:ad:05:ef:ab:32:78:87:a0:54: - 73:19:b5:5c:05:f9:52:3e:6d:2d:45:0b:f7:0a:93:ea:ed:06: - f9:b2 ------BEGIN CERTIFICATE----- -MIIE2DCCBEGgAwIBAgIEN0rSQzANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UEBhMC -VVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50cnVzdC5u -ZXQvQ1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMc -KGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UEAxMxRW50cnVzdC5u -ZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05OTA1 -MjUxNjA5NDBaFw0xOTA1MjUxNjM5NDBaMIHDMQswCQYDVQQGEwJVUzEUMBIGA1UE -ChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5j -b3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBF -bnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUg -U2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUA -A4GLADCBhwKBgQDNKIM0VBuJ8w+vN5Ex/68xYMmo6LIQaO2f55M28Qpku0f1BBc/ -I0dNxScZgSYMVHINiC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc1lB5gXpa0zf3 -wkrYKZImZNHkmGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQwIBA6OC -AdcwggHTMBEGCWCGSAGG+EIBAQQEAwIABzCCARkGA1UdHwSCARAwggEMMIHeoIHb -oIHYpIHVMIHSMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5 -BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1p -dHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1pdGVk -MTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRp -b24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCmgJ6AlhiNodHRwOi8vd3d3LmVu -dHJ1c3QubmV0L0NSTC9uZXQxLmNybDArBgNVHRAEJDAigA8xOTk5MDUyNTE2MDk0 -MFqBDzIwMTkwNTI1MTYwOTQwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAU8Bdi -E1U9s/8KAGv7UISX8+1i0BowHQYDVR0OBBYEFPAXYhNVPbP/CgBr+1CEl/PtYtAa -MAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EABAwwChsEVjQuMAMCBJAwDQYJKoZI -hvcNAQEFBQADgYEAkNwwAvpkdMKnCqV8IY00F6j7Rw7/JXyNEwr75Ji174z4xRAN -95K+8cPV1ZVqBLssziY2ZcgxxufuP+NXdYR6Ee9GTxj005i7qIcyunL2POI9n9cd -2cNgQ4xYDiKWL2KjLB+6rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G+bI= ------END CERTIFICATE----- diff --git a/chromium/net/data/ssl/ev_roots/69ddd7ea90bb57c93e135dc85ea6fcd5480b603239bdc454fc758b2a26cf7f79.pem b/chromium/net/data/ssl/ev_roots/69ddd7ea90bb57c93e135dc85ea6fcd5480b603239bdc454fc758b2a26cf7f79.pem deleted file mode 100644 index ef1dd9e5d18..00000000000 --- a/chromium/net/data/ssl/ev_roots/69ddd7ea90bb57c93e135dc85ea6fcd5480b603239bdc454fc758b2a26cf7f79.pem +++ /dev/null @@ -1,60 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 2f:80:fe:23:8c:0e:22:0f:48:67:12:28:91:87:ac:b3 - Signature Algorithm: ecdsa-with-SHA384 - Issuer: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 2007 VeriSign, Inc. - For authorized use only, CN=VeriSign Class 3 Public Primary Certification Authority - G4 - Validity - Not Before: Nov 5 00:00:00 2007 GMT - Not After : Jan 18 23:59:59 2038 GMT - Subject: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 2007 VeriSign, Inc. - For authorized use only, CN=VeriSign Class 3 Public Primary Certification Authority - G4 - Subject Public Key Info: - Public Key Algorithm: id-ecPublicKey - Public-Key: (384 bit) - pub: - 04:a7:56:7a:7c:52:da:64:9b:0e:2d:5c:d8:5e:ac: - 92:3d:fe:01:e6:19:4a:3d:14:03:4b:fa:60:27:20: - d9:83:89:69:fa:54:c6:9a:18:5e:55:2a:64:de:06: - f6:8d:4a:3b:ad:10:3c:65:3d:90:88:04:89:e0:30: - 61:b3:ae:5d:01:a7:7b:de:7c:b2:be:ca:65:61:00: - 86:ae:da:8f:7b:d0:89:ad:4d:1d:59:9a:41:b1:bc: - 47:80:dc:9e:62:c3:f9 - ASN1 OID: secp384r1 - X509v3 extensions: - X509v3 Basic Constraints: critical - CA:TRUE - X509v3 Key Usage: critical - Certificate Sign, CRL Sign - 1.3.6.1.5.5.7.1.12: - 0_.].[0Y0W0U..image/gif0!0.0...+..............k...j.H.,{..0%.#http://logo.verisign.com/vslogo.gif - X509v3 Subject Key Identifier: - B3:16:91:FD:EE:A6:6E:E4:B5:2E:49:8F:87:78:81:80:EC:E5:B1:B5 - Signature Algorithm: ecdsa-with-SHA384 - 30:65:02:30:66:21:0c:18:26:60:5a:38:7b:56:42:e0:a7:fc: - 36:84:51:91:20:2c:76:4d:43:3d:c4:1d:84:23:d0:ac:d6:7c: - 35:06:ce:cd:69:bd:90:0d:db:6c:48:42:1d:0e:aa:42:02:31: - 00:9c:3d:48:39:23:39:58:1a:15:12:59:6a:9e:ef:d5:59:b2: - 1d:52:2c:99:71:cd:c7:29:df:1b:2a:61:7b:71:d1:de:f3:c0: - e5:0d:3a:4a:aa:2d:a7:d8:86:2a:dd:2e:10 ------BEGIN CERTIFICATE----- -MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjEL -MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW -ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2ln -biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp -U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y -aXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjELMAkG -A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJp -U2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwg -SW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2ln -biBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 -IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8Utpkmw4tXNherJI9/gHm -GUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGzrl0Bp3ve -fLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUw -AwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJ -aW1hZ2UvZ2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYj -aHR0cDovL2xvZ28udmVyaXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMW -kf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMDA2gAMGUCMGYhDBgmYFo4e1ZC -4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIxAJw9SDkjOVga -FRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA== ------END CERTIFICATE----- diff --git a/chromium/net/data/ssl/ev_roots/6ea54741d004667eed1b4816634aa3a79e6e4b96950f8279dafc8d9bd8812137.pem b/chromium/net/data/ssl/ev_roots/6ea54741d004667eed1b4816634aa3a79e6e4b96950f8279dafc8d9bd8812137.pem deleted file mode 100644 index 129e75163af..00000000000 --- a/chromium/net/data/ssl/ev_roots/6ea54741d004667eed1b4816634aa3a79e6e4b96950f8279dafc8d9bd8812137.pem +++ /dev/null @@ -1,90 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 44:be:0c:8b:50:00:24:b4:11:d3:36:2a:fe:65:0a:fd - Signature Algorithm: sha1WithRSAEncryption - Issuer: C=US, ST=UT, L=Salt Lake City, O=The USERTRUST Network, OU=http://www.usertrust.com, CN=UTN-USERFirst-Hardware - Validity - Not Before: Jul 9 18:10:42 1999 GMT - Not After : Jul 9 18:19:22 2019 GMT - Subject: C=US, ST=UT, L=Salt Lake City, O=The USERTRUST Network, OU=http://www.usertrust.com, CN=UTN-USERFirst-Hardware - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (2048 bit) - Modulus: - 00:b1:f7:c3:38:3f:b4:a8:7f:cf:39:82:51:67:d0: - 6d:9f:d2:ff:58:f3:e7:9f:2b:ec:0d:89:54:99:b9: - 38:99:16:f7:e0:21:79:48:c2:bb:61:74:12:96:1d: - 3c:6a:72:d5:3c:10:67:3a:39:ed:2b:13:cd:66:eb: - 95:09:33:a4:6c:97:b1:e8:c6:ec:c1:75:79:9c:46: - 5e:8d:ab:d0:6a:fd:b9:2a:55:17:10:54:b3:19:f0: - 9a:f6:f1:b1:5d:b6:a7:6d:fb:e0:71:17:6b:a2:88: - fb:00:df:fe:1a:31:77:0c:9a:01:7a:b1:32:e3:2b: - 01:07:38:6e:c3:a5:5e:23:bc:45:9b:7b:50:c1:c9: - 30:8f:db:e5:2b:7a:d3:5b:fb:33:40:1e:a0:d5:98: - 17:bc:8b:87:c3:89:d3:5d:a0:8e:b2:aa:aa:f6:8e: - 69:88:06:c5:fa:89:21:f3:08:9d:69:2e:09:33:9b: - 29:0d:46:0f:8c:cc:49:34:b0:69:51:bd:f9:06:cd: - 68:ad:66:4c:bc:3e:ac:61:bd:0a:88:0e:c8:df:3d: - ee:7c:04:4c:9d:0a:5e:6b:91:d6:ee:c7:ed:28:8d: - ab:4d:87:89:73:d0:6e:a4:d0:1e:16:8b:14:e1:76: - 44:03:7f:63:ac:e4:cd:49:9c:c5:92:f4:ab:32:a1: - 48:5b - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Key Usage: - Digital Signature, Non Repudiation, Certificate Sign, CRL Sign - X509v3 Basic Constraints: critical - CA:TRUE - X509v3 Subject Key Identifier: - A1:72:5F:26:1B:28:98:43:95:5D:07:37:D5:85:96:9D:4B:D2:C3:45 - X509v3 CRL Distribution Points: - - Full Name: - URI:http://crl.usertrust.com/UTN-USERFirst-Hardware.crl - - X509v3 Extended Key Usage: - TLS Web Server Authentication, IPSec End System, IPSec Tunnel, IPSec User - Signature Algorithm: sha1WithRSAEncryption - 47:19:0f:de:74:c6:99:97:af:fc:ad:28:5e:75:8e:eb:2d:67: - ee:4e:7b:2b:d7:0c:ff:f6:de:cb:55:a2:0a:e1:4c:54:65:93: - 60:6b:9f:12:9c:ad:5e:83:2c:eb:5a:ae:c0:e4:2d:f4:00:63: - 1d:b8:c0:6c:f2:cf:49:bb:4d:93:6f:06:a6:0a:22:b2:49:62: - 08:4e:ff:c8:c8:14:b2:88:16:5d:e7:01:e4:12:95:e5:45:34: - b3:8b:69:bd:cf:b4:85:8f:75:51:9e:7d:3a:38:3a:14:48:12: - c6:fb:a7:3b:1a:8d:0d:82:40:07:e8:04:08:90:a1:89:cb:19: - 50:df:ca:1c:01:bc:1d:04:19:7b:10:76:97:3b:ee:90:90:ca: - c4:0e:1f:16:6e:75:ef:33:f8:d3:6f:5b:1e:96:e3:e0:74:77: - 74:7b:8a:a2:6e:2d:dd:76:d6:39:30:82:f0:ab:9c:52:f2:2a: - c7:af:49:5e:7e:c7:68:e5:82:81:c8:6a:27:f9:27:88:2a:d5: - 58:50:95:1f:f0:3b:1c:57:bb:7d:14:39:62:2b:9a:c9:94:92: - 2a:a3:22:0c:ff:89:26:7d:5f:23:2b:47:d7:15:1d:a9:6a:9e: - 51:0d:2a:51:9e:81:f9:d4:3b:5e:70:12:7f:10:32:9c:1e:bb: - 9d:f8:66:a8 ------BEGIN CERTIFICATE----- -MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCB -lzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug -Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho -dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3Qt -SGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgxOTIyWjCBlzELMAkG -A1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEe -MBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8v -d3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdh -cmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn -0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlIwrthdBKWHTxqctU8EGc6Oe0rE81m65UJ -M6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFdtqdt++BxF2uiiPsA3/4a -MXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8i4fDidNd -oI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqI -DsjfPe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9Ksy -oUhbAgMBAAGjgbkwgbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYD -VR0OBBYEFKFyXyYbKJhDlV0HN9WFlp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0 -dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNFUkZpcnN0LUhhcmR3YXJlLmNy -bDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEF -BQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM -//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28Gpgoiskli -CE7/yMgUsogWXecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gE -CJChicsZUN/KHAG8HQQZexB2lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t -3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kniCrVWFCVH/A7HFe7fRQ5YiuayZSS -KqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67nfhmqA== ------END CERTIFICATE----- diff --git a/chromium/net/data/ssl/ev_roots/7d05ebb682339f8c9451ee094eebfefa7953a114edb2f44949452fab7d2fc185.pem b/chromium/net/data/ssl/ev_roots/7d05ebb682339f8c9451ee094eebfefa7953a114edb2f44949452fab7d2fc185.pem new file mode 100644 index 00000000000..41bdf8673d6 --- /dev/null +++ b/chromium/net/data/ssl/ev_roots/7d05ebb682339f8c9451ee094eebfefa7953a114edb2f44949452fab7d2fc185.pem @@ -0,0 +1,79 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 0b:93:1c:3a:d6:39:67:ea:67:23:bf:c3:af:9a:f4:4b + Signature Algorithm: sha256WithRSAEncryption + Issuer: C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert Assured ID Root G2 + Validity + Not Before: Aug 1 12:00:00 2013 GMT + Not After : Jan 15 12:00:00 2038 GMT + Subject: C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert Assured ID Root G2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:d9:e7:28:2f:52:3f:36:72:49:88:93:34:f3:f8: + 6a:1e:31:54:80:9f:ad:54:41:b5:47:df:96:a8:d4: + af:80:2d:b9:0a:cf:75:fd:89:a5:7d:24:fa:e3:22: + 0c:2b:bc:95:17:0b:33:bf:19:4d:41:06:90:00:bd: + 0c:4d:10:fe:07:b5:e7:1c:6e:22:55:31:65:97:bd: + d3:17:d2:1e:62:f3:db:ea:6c:50:8c:3f:84:0c:96: + cf:b7:cb:03:e0:ca:6d:a1:14:4c:1b:89:dd:ed:00: + b0:52:7c:af:91:6c:b1:38:13:d1:e9:12:08:c0:00: + b0:1c:2b:11:da:77:70:36:9b:ae:ce:79:87:dc:82: + 70:e6:09:74:70:55:69:af:a3:68:9f:bf:dd:b6:79: + b3:f2:9d:70:29:55:f4:ab:ff:95:61:f3:c9:40:6f: + 1d:d1:be:93:bb:d3:88:2a:bb:9d:bf:72:5a:56:71: + 3b:3f:d4:f3:d1:0a:fe:28:ef:a3:ee:d9:99:af:03: + d3:8f:60:b7:f2:92:a1:b1:bd:89:89:1f:30:cd:c3: + a6:2e:62:33:ae:16:02:77:44:5a:e7:81:0a:3c:a7: + 44:2e:79:b8:3f:04:bc:5c:a0:87:e1:1b:af:51:8e: + cd:ec:2c:fa:f8:fe:6d:f0:3a:7c:aa:8b:e4:67:95: + 31:8d + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + CE:C3:4A:B9:99:55:F2:B8:DB:60:BF:A9:7E:BD:56:B5:97:36:A7:D6 + Signature Algorithm: sha256WithRSAEncryption + ca:a5:55:8c:e3:c8:41:6e:69:27:a7:75:11:ef:3c:86:36:6f: + d2:9d:c6:78:38:1d:69:96:a2:92:69:2e:38:6c:9b:7d:04:d4: + 89:a5:b1:31:37:8a:c9:21:cc:ab:6c:cd:8b:1c:9a:d6:bf:48: + d2:32:66:c1:8a:c0:f3:2f:3a:ef:c0:e3:d4:91:86:d1:50:e3: + 03:db:73:77:6f:4a:39:53:ed:de:26:c7:b5:7d:af:2b:42:d1: + 75:62:e3:4a:2b:02:c7:50:4b:e0:69:e2:96:6c:0e:44:66:10: + 44:8f:ad:05:eb:f8:79:ac:a6:1b:e8:37:34:9d:53:c9:61:aa: + a2:52:af:4a:70:16:86:c2:3a:c8:b1:13:70:36:d8:cf:ee:f4: + 0a:34:d5:5b:4c:fd:07:9c:a2:ba:d9:01:72:5c:f3:4d:c1:dd: + 0e:b1:1c:0d:c4:63:be:ad:f4:14:fb:89:ec:a2:41:0e:4c:cc: + c8:57:40:d0:6e:03:aa:cd:0c:8e:89:99:99:6c:f0:3c:30:af: + 38:df:6f:bc:a3:be:29:20:27:ab:74:ff:13:22:78:de:97:52: + 55:1e:83:b5:54:20:03:ee:ae:c0:4f:56:de:37:cc:c3:7f:aa: + 04:27:bb:d3:77:b8:62:db:17:7c:9c:28:22:13:73:6c:cf:26: + f5:8a:29:e7 +-----BEGIN CERTIFICATE----- +MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBl +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv +b3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl +cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSA +n61UQbVH35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4Htecc +biJVMWWXvdMX0h5i89vqbFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9Hp +EgjAALAcKxHad3A2m67OeYfcgnDmCXRwVWmvo2ifv922ebPynXApVfSr/5Vh88lA +bx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OPYLfykqGxvYmJHzDNw6Yu +YjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+RnlTGNAgMB +AAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQW +BBTOw0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPI +QW5pJ6d1Ee88hjZv0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I +0jJmwYrA8y8678Dj1JGG0VDjA9tzd29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4Gni +lmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAWhsI6yLETcDbYz+70CjTVW0z9 +B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0MjomZmWzwPDCv +ON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo +IhNzbM8m9Yop5w== +-----END CERTIFICATE----- diff --git a/chromium/net/data/ssl/ev_roots/7e37cb8b4c47090cab36551ba6f45db840680fba166a952db100717f43053fc2.pem b/chromium/net/data/ssl/ev_roots/7e37cb8b4c47090cab36551ba6f45db840680fba166a952db100717f43053fc2.pem new file mode 100644 index 00000000000..5a8515c9f5c --- /dev/null +++ b/chromium/net/data/ssl/ev_roots/7e37cb8b4c47090cab36551ba6f45db840680fba166a952db100717f43053fc2.pem @@ -0,0 +1,53 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 0b:a1:5a:fa:1d:df:a0:b5:49:44:af:cd:24:a0:6c:ec + Signature Algorithm: ecdsa-with-SHA384 + Issuer: C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert Assured ID Root G3 + Validity + Not Before: Aug 1 12:00:00 2013 GMT + Not After : Jan 15 12:00:00 2038 GMT + Subject: C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert Assured ID Root G3 + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (384 bit) + pub: + 04:19:e7:bc:ac:44:65:ed:cd:b8:3f:58:fb:8d:b1: + 57:a9:44:2d:05:15:f2:ef:0b:ff:10:74:9f:b5:62: + 52:5f:66:7e:1f:e5:dc:1b:45:79:0b:cc:c6:53:0a: + 9d:8d:5d:02:d9:a9:59:de:02:5a:f6:95:2a:0e:8d: + 38:4a:8a:49:c6:bc:c6:03:38:07:5f:55:da:7e:09: + 6e:e2:7f:5e:d0:45:20:0f:59:76:10:d6:a0:24:f0: + 2d:de:36:f2:6c:29:39 + ASN1 OID: secp384r1 + NIST CURVE: P-384 + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + CB:D0:BD:A9:E1:98:05:51:A1:4D:37:A2:83:79:CE:8D:1D:2A:E4:84 + Signature Algorithm: ecdsa-with-SHA384 + 30:64:02:30:25:a4:81:45:02:6b:12:4b:75:74:4f:c8:23:e3: + 70:f2:75:72:de:7c:89:f0:cf:91:72:61:9e:5e:10:92:59:56: + b9:83:c7:10:e7:38:e9:58:26:36:7d:d5:e4:34:86:39:02:30: + 7c:36:53:f0:30:e5:62:63:3a:99:e2:b6:a3:3b:9b:34:fa:1e: + da:10:92:71:5e:91:13:a7:dd:a4:6e:92:cc:32:d6:f5:21:66: + c7:2f:ea:96:63:6a:65:45:92:95:01:b4 +-----BEGIN CERTIFICATE----- +MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQsw +CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu +ZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3Qg +RzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQGEwJV +UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu +Y29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQBgcq +hkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJf +Zn4f5dwbRXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17Q +RSAPWXYQ1qAk8C3eNvJsKTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ +BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgFUaFNN6KDec6NHSrkhDAKBggqhkjOPQQD +AwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5FyYZ5eEJJZVrmDxxDnOOlY +JjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy1vUhZscv +6pZjamVFkpUBtA== +-----END CERTIFICATE----- diff --git a/chromium/net/data/ssl/ev_roots/8d722f81a9c113c0791df136a2966db26c950a971db46b4199f4ea54b78bfb9f.pem b/chromium/net/data/ssl/ev_roots/8d722f81a9c113c0791df136a2966db26c950a971db46b4199f4ea54b78bfb9f.pem deleted file mode 100644 index ff13d5593b6..00000000000 --- a/chromium/net/data/ssl/ev_roots/8d722f81a9c113c0791df136a2966db26c950a971db46b4199f4ea54b78bfb9f.pem +++ /dev/null @@ -1,82 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 34:4e:d5:57:20:d5:ed:ec:49:f4:2f:ce:37:db:2b:6d - Signature Algorithm: sha1WithRSAEncryption - Issuer: C=US, O=thawte, Inc., OU=Certification Services Division, OU=(c) 2006 thawte, Inc. - For authorized use only, CN=thawte Primary Root CA - Validity - Not Before: Nov 17 00:00:00 2006 GMT - Not After : Jul 16 23:59:59 2036 GMT - Subject: C=US, O=thawte, Inc., OU=Certification Services Division, OU=(c) 2006 thawte, Inc. - For authorized use only, CN=thawte Primary Root CA - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (2048 bit) - Modulus: - 00:ac:a0:f0:fb:80:59:d4:9c:c7:a4:cf:9d:a1:59: - 73:09:10:45:0c:0d:2c:6e:68:f1:6c:5b:48:68:49: - 59:37:fc:0b:33:19:c2:77:7f:cc:10:2d:95:34:1c: - e6:eb:4d:09:a7:1c:d2:b8:c9:97:36:02:b7:89:d4: - 24:5f:06:c0:cc:44:94:94:8d:02:62:6f:eb:5a:dd: - 11:8d:28:9a:5c:84:90:10:7a:0d:bd:74:66:2f:6a: - 38:a0:e2:d5:54:44:eb:1d:07:9f:07:ba:6f:ee:e9: - fd:4e:0b:29:f5:3e:84:a0:01:f1:9c:ab:f8:1c:7e: - 89:a4:e8:a1:d8:71:65:0d:a3:51:7b:ee:bc:d2:22: - 60:0d:b9:5b:9d:df:ba:fc:51:5b:0b:af:98:b2:e9: - 2e:e9:04:e8:62:87:de:2b:c8:d7:4e:c1:4c:64:1e: - dd:cf:87:58:ba:4a:4f:ca:68:07:1d:1c:9d:4a:c6: - d5:2f:91:cc:7c:71:72:1c:c5:c0:67:eb:32:fd:c9: - 92:5c:94:da:85:c0:9b:bf:53:7d:2b:09:f4:8c:9d: - 91:1f:97:6a:52:cb:de:09:36:a4:77:d8:7b:87:50: - 44:d5:3e:6e:29:69:fb:39:49:26:1e:09:a5:80:7b: - 40:2d:eb:e8:27:85:c9:fe:61:fd:7e:e6:7c:97:1d: - d5:9d - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Basic Constraints: critical - CA:TRUE - X509v3 Key Usage: critical - Certificate Sign, CRL Sign - X509v3 Subject Key Identifier: - 7B:5B:45:CF:AF:CE:CB:7A:FD:31:92:1A:6A:B6:F3:46:EB:57:48:50 - Signature Algorithm: sha1WithRSAEncryption - 79:11:c0:4b:b3:91:b6:fc:f0:e9:67:d4:0d:6e:45:be:55:e8: - 93:d2:ce:03:3f:ed:da:25:b0:1d:57:cb:1e:3a:76:a0:4c:ec: - 50:76:e8:64:72:0c:a4:a9:f1:b8:8b:d6:d6:87:84:bb:32:e5: - 41:11:c0:77:d9:b3:60:9d:eb:1b:d5:d1:6e:44:44:a9:a6:01: - ec:55:62:1d:77:b8:5c:8e:48:49:7c:9c:3b:57:11:ac:ad:73: - 37:8e:2f:78:5c:90:68:47:d9:60:60:e6:fc:07:3d:22:20:17: - c4:f7:16:e9:c4:d8:72:f9:c8:73:7c:df:16:2f:15:a9:3e:fd: - 6a:27:b6:a1:eb:5a:ba:98:1f:d5:e3:4d:64:0a:9d:13:c8:61: - ba:f5:39:1c:87:ba:b8:bd:7b:22:7f:f6:fe:ac:40:79:e5:ac: - 10:6f:3d:8f:1b:79:76:8b:c4:37:b3:21:18:84:e5:36:00:eb: - 63:20:99:b9:e9:fe:33:04:bb:41:c8:c1:02:f9:44:63:20:9e: - 81:ce:42:d3:d6:3f:2c:76:d3:63:9c:59:dd:8f:a6:e1:0e:a0: - 2e:41:f7:2e:95:47:cf:bc:fd:33:f3:f6:0b:61:7e:7e:91:2b: - 81:47:c2:27:30:ee:a7:10:5d:37:8f:5c:39:2b:e4:04:f0:7b: - 8d:56:8c:68 ------BEGIN CERTIFICATE----- -MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCB -qTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf -Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw -MDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNV -BAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3MDAwMDAwWhcNMzYw -NzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5j -LjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYG -A1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl -IG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqG -SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsoPD7gFnUnMekz52hWXMJEEUMDSxuaPFs -W0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ1CRfBsDMRJSUjQJib+ta -3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGcq/gcfomk -6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6 -Sk/KaAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94J -NqR32HuHUETVPm4pafs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBA -MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XP -r87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUFAAOCAQEAeRHAS7ORtvzw6WfU -DW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeEuzLlQRHAd9mz -YJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX -xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2 -/qxAeeWsEG89jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/ -LHbTY5xZ3Y+m4Q6gLkH3LpVHz7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7 -jVaMaA== ------END CERTIFICATE----- diff --git a/chromium/net/data/ssl/ev_roots/9acfab7e43c8d880d06b262a94deeee4b4659989c3d0caf19baf6405e41ab7df.pem b/chromium/net/data/ssl/ev_roots/9acfab7e43c8d880d06b262a94deeee4b4659989c3d0caf19baf6405e41ab7df.pem deleted file mode 100644 index 4589be06f87..00000000000 --- a/chromium/net/data/ssl/ev_roots/9acfab7e43c8d880d06b262a94deeee4b4659989c3d0caf19baf6405e41ab7df.pem +++ /dev/null @@ -1,87 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 18:da:d1:9e:26:7d:e8:bb:4a:21:58:cd:cc:6b:3b:4a - Signature Algorithm: sha1WithRSAEncryption - Issuer: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 2006 VeriSign, Inc. - For authorized use only, CN=VeriSign Class 3 Public Primary Certification Authority - G5 - Validity - Not Before: Nov 8 00:00:00 2006 GMT - Not After : Jul 16 23:59:59 2036 GMT - Subject: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 2006 VeriSign, Inc. - For authorized use only, CN=VeriSign Class 3 Public Primary Certification Authority - G5 - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (2048 bit) - Modulus: - 00:af:24:08:08:29:7a:35:9e:60:0c:aa:e7:4b:3b: - 4e:dc:7c:bc:3c:45:1c:bb:2b:e0:fe:29:02:f9:57: - 08:a3:64:85:15:27:f5:f1:ad:c8:31:89:5d:22:e8: - 2a:aa:a6:42:b3:8f:f8:b9:55:b7:b1:b7:4b:b3:fe: - 8f:7e:07:57:ec:ef:43:db:66:62:15:61:cf:60:0d: - a4:d8:de:f8:e0:c3:62:08:3d:54:13:eb:49:ca:59: - 54:85:26:e5:2b:8f:1b:9f:eb:f5:a1:91:c2:33:49: - d8:43:63:6a:52:4b:d2:8f:e8:70:51:4d:d1:89:69: - 7b:c7:70:f6:b3:dc:12:74:db:7b:5d:4b:56:d3:96: - bf:15:77:a1:b0:f4:a2:25:f2:af:1c:92:67:18:e5: - f4:06:04:ef:90:b9:e4:00:e4:dd:3a:b5:19:ff:02: - ba:f4:3c:ee:e0:8b:eb:37:8b:ec:f4:d7:ac:f2:f6: - f0:3d:af:dd:75:91:33:19:1d:1c:40:cb:74:24:19: - 21:93:d9:14:fe:ac:2a:52:c7:8f:d5:04:49:e4:8d: - 63:47:88:3c:69:83:cb:fe:47:bd:2b:7e:4f:c5:95: - ae:0e:9d:d4:d1:43:c0:67:73:e3:14:08:7e:e5:3f: - 9f:73:b8:33:0a:cf:5d:3f:34:87:96:8a:ee:53:e8: - 25:15 - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Basic Constraints: critical - CA:TRUE - X509v3 Key Usage: critical - Certificate Sign, CRL Sign - 1.3.6.1.5.5.7.1.12: - 0_.].[0Y0W0U..image/gif0!0.0...+..............k...j.H.,{..0%.#http://logo.verisign.com/vslogo.gif - X509v3 Subject Key Identifier: - 7F:D3:65:A7:C2:DD:EC:BB:F0:30:09:F3:43:39:FA:02:AF:33:31:33 - Signature Algorithm: sha1WithRSAEncryption - 93:24:4a:30:5f:62:cf:d8:1a:98:2f:3d:ea:dc:99:2d:bd:77: - f6:a5:79:22:38:ec:c4:a7:a0:78:12:ad:62:0e:45:70:64:c5: - e7:97:66:2d:98:09:7e:5f:af:d6:cc:28:65:f2:01:aa:08:1a: - 47:de:f9:f9:7c:92:5a:08:69:20:0d:d9:3e:6d:6e:3c:0d:6e: - d8:e6:06:91:40:18:b9:f8:c1:ed:df:db:41:aa:e0:96:20:c9: - cd:64:15:38:81:c9:94:ee:a2:84:29:0b:13:6f:8e:db:0c:dd: - 25:02:db:a4:8b:19:44:d2:41:7a:05:69:4a:58:4f:60:ca:7e: - 82:6a:0b:02:aa:25:17:39:b5:db:7f:e7:84:65:2a:95:8a:bd: - 86:de:5e:81:16:83:2d:10:cc:de:fd:a8:82:2a:6d:28:1f:0d: - 0b:c4:e5:e7:1a:26:19:e1:f4:11:6f:10:b5:95:fc:e7:42:05: - 32:db:ce:9d:51:5e:28:b6:9e:85:d3:5b:ef:a5:7d:45:40:72: - 8e:b7:0e:6b:0e:06:fb:33:35:48:71:b8:9d:27:8b:c4:65:5f: - 0d:86:76:9c:44:7a:f6:95:5c:f6:5d:32:08:33:a4:54:b6:18: - 3f:68:5c:f2:42:4a:85:38:54:83:5f:d1:e8:2c:f2:ac:11:d6: - a8:ed:63:6a ------BEGIN CERTIFICATE----- -MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB -yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL -ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp -U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW -ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0 -aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL -MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW -ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln -biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp -U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y -aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1 -nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex -t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz -SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG -BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+ -rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/ -NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E -BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH -BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy -aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv -MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE -p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y -5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK -WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ -4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N -hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq ------END CERTIFICATE----- diff --git a/chromium/net/data/ssl/ev_roots/a22dba681e97376e2d397d728aae3a9b6296b9fdba60bc2e11f647f2c675fb37.pem b/chromium/net/data/ssl/ev_roots/a22dba681e97376e2d397d728aae3a9b6296b9fdba60bc2e11f647f2c675fb37.pem deleted file mode 100644 index e034a8a2b3c..00000000000 --- a/chromium/net/data/ssl/ev_roots/a22dba681e97376e2d397d728aae3a9b6296b9fdba60bc2e11f647f2c675fb37.pem +++ /dev/null @@ -1,77 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: 0 (0x0) - Signature Algorithm: sha1WithRSAEncryption - Issuer: C=JP, O=SECOM Trust Systems CO.,LTD., OU=Security Communication EV RootCA1 - Validity - Not Before: Jun 6 02:12:32 2007 GMT - Not After : Jun 6 02:12:32 2037 GMT - Subject: C=JP, O=SECOM Trust Systems CO.,LTD., OU=Security Communication EV RootCA1 - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (2048 bit) - Modulus: - 00:bc:7f:ec:57:9b:24:e0:fe:9c:ba:42:79:a9:88: - 8a:fa:80:e0:f5:07:29:43:ea:8e:0a:34:36:8d:1c: - fa:a7:b5:39:78:ff:97:75:f7:2f:e4:aa:6b:04:84: - 44:ca:a6:e2:68:8e:fd:55:50:62:0f:a4:71:0e:ce: - 07:38:2d:42:85:50:ad:3c:96:6f:8b:d5:a2:0e:cf: - de:49:89:3d:d6:64:2e:38:e5:1e:6c:b5:57:8a:9e: - ef:48:0e:cd:7a:69:16:87:44:b5:90:e4:06:9d:ae: - a1:04:97:58:79:ef:20:4a:82:6b:8c:22:bf:ec:1f: - 0f:e9:84:71:ed:f1:0e:e4:b8:18:13:cc:56:36:5d: - d1:9a:1e:51:6b:39:6e:60:76:88:34:0b:f3:b3:d1: - b0:9d:ca:61:e2:64:1d:c1:46:07:b8:63:dd:1e:33: - 65:b3:8e:09:55:52:3d:b5:bd:ff:07:eb:ad:61:55: - 18:2c:a9:69:98:4a:aa:40:c5:33:14:65:74:00:f9: - 91:de:af:03:48:c5:40:54:dc:0f:84:90:68:20:c5: - 92:96:dc:2e:e5:02:45:aa:c0:5f:54:f8:6d:ea:49: - cf:5d:6c:4b:af:ef:9a:c2:56:5c:c6:35:56:42:6a: - 30:5f:c2:ab:f6:e2:3d:3f:b3:c9:11:8f:31:4c:d7: - 9f:49 - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Subject Key Identifier: - 35:4A:F5:4D:AF:3F:D7:82:38:AC:AB:71:65:17:75:8C:9D:55:93:E6 - X509v3 Key Usage: critical - Certificate Sign, CRL Sign - X509v3 Basic Constraints: critical - CA:TRUE - Signature Algorithm: sha1WithRSAEncryption - a8:87:e9:ec:f8:40:67:5d:c3:c1:66:c7:40:4b:97:fc:87:13: - 90:5a:c4:ef:a0:ca:5f:8b:b7:a7:b7:f1:d6:b5:64:b7:8a:b3: - b8:1b:cc:da:fb:ac:66:88:41:ce:e8:fc:e4:db:1e:88:a6:ed: - 27:50:1b:02:30:24:46:79:fe:04:87:70:97:40:73:d1:c0:c1: - 57:19:9a:69:a5:27:99:ab:9d:62:84:f6:51:c1:2c:c9:23:15: - d8:28:b7:ab:25:13:b5:46:e1:86:02:ff:26:8c:c4:88:92:1d: - 56:fe:19:67:f2:55:e4:80:a3:6b:9c:ab:77:e1:51:71:0d:20: - db:10:9a:db:bd:76:79:07:77:99:28:ad:9a:5e:da:b1:4f:44: - 2c:35:8e:a5:96:c7:fd:83:f0:58:c6:79:d6:98:7c:a8:8d:fe: - 86:3e:07:16:92:e1:7b:e7:1d:ec:33:76:7e:42:2e:4a:85:f9: - 91:89:68:84:03:81:a5:9b:9a:be:e3:37:c5:54:ab:56:3b:18: - 2d:41:a4:0c:f8:42:db:99:a0:e0:72:6f:bb:5d:e1:16:4f:53: - 0a:64:f9:4e:f4:bf:4e:54:bd:78:6c:88:ea:bf:9c:13:24:c2: - 70:69:a2:7f:0f:c8:3c:ad:08:c9:b0:98:40:a3:2a:e7:88:83: - ed:77:8f:74 ------BEGIN CERTIFICATE----- -MIIDfTCCAmWgAwIBAgIBADANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJKUDEl -MCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEqMCgGA1UECxMh -U2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBFViBSb290Q0ExMB4XDTA3MDYwNjAyMTIz -MloXDTM3MDYwNjAyMTIzMlowYDELMAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09N -IFRydXN0IFN5c3RlbXMgQ08uLExURC4xKjAoBgNVBAsTIVNlY3VyaXR5IENvbW11 -bmljYXRpb24gRVYgUm9vdENBMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC -ggEBALx/7FebJOD+nLpCeamIivqA4PUHKUPqjgo0No0c+qe1OXj/l3X3L+SqawSE -RMqm4miO/VVQYg+kcQ7OBzgtQoVQrTyWb4vVog7P3kmJPdZkLjjlHmy1V4qe70gO -zXppFodEtZDkBp2uoQSXWHnvIEqCa4wiv+wfD+mEce3xDuS4GBPMVjZd0ZoeUWs5 -bmB2iDQL87PRsJ3KYeJkHcFGB7hj3R4zZbOOCVVSPbW9/wfrrWFVGCypaZhKqkDF -MxRldAD5kd6vA0jFQFTcD4SQaCDFkpbcLuUCRarAX1T4bepJz11sS6/vmsJWXMY1 -VkJqMF/Cq/biPT+zyRGPMUzXn0kCAwEAAaNCMEAwHQYDVR0OBBYEFDVK9U2vP9eC -OKyrcWUXdYydVZPmMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0G -CSqGSIb3DQEBBQUAA4IBAQCoh+ns+EBnXcPBZsdAS5f8hxOQWsTvoMpfi7ent/HW -tWS3irO4G8za+6xmiEHO6Pzk2x6Ipu0nUBsCMCRGef4Eh3CXQHPRwMFXGZpppSeZ -q51ihPZRwSzJIxXYKLerJRO1RuGGAv8mjMSIkh1W/hln8lXkgKNrnKt34VFxDSDb -EJrbvXZ5B3eZKK2aXtqxT0QsNY6llsf9g/BYxnnWmHyojf6GPgcWkuF75x3sM3Z+ -Qi5KhfmRiWiEA4Glm5q+4zfFVKtWOxgtQaQM+ELbmaDgcm+7XeEWT1MKZPlO9L9O -VL14bIjqv5wTJMJwaaJ/D8g8rQjJsJhAoyrniIPtd490 ------END CERTIFICATE----- diff --git a/chromium/net/data/ssl/ev_roots/a4310d50af18a6447190372a86afaf8b951ffb431d837f1e5688b45971ed1557.pem b/chromium/net/data/ssl/ev_roots/a4310d50af18a6447190372a86afaf8b951ffb431d837f1e5688b45971ed1557.pem deleted file mode 100644 index 764184e9c66..00000000000 --- a/chromium/net/data/ssl/ev_roots/a4310d50af18a6447190372a86afaf8b951ffb431d837f1e5688b45971ed1557.pem +++ /dev/null @@ -1,53 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 35:fc:26:5c:d9:84:4f:c9:3d:26:3d:57:9b:ae:d7:56 - Signature Algorithm: ecdsa-with-SHA384 - Issuer: C=US, O=thawte, Inc., OU=(c) 2007 thawte, Inc. - For authorized use only, CN=thawte Primary Root CA - G2 - Validity - Not Before: Nov 5 00:00:00 2007 GMT - Not After : Jan 18 23:59:59 2038 GMT - Subject: C=US, O=thawte, Inc., OU=(c) 2007 thawte, Inc. - For authorized use only, CN=thawte Primary Root CA - G2 - Subject Public Key Info: - Public Key Algorithm: id-ecPublicKey - Public-Key: (384 bit) - pub: - 04:a2:d5:9c:82:7b:95:9d:f1:52:78:87:fe:8a:16: - bf:05:e6:df:a3:02:4f:0d:07:c6:00:51:ba:0c:02: - 52:2d:22:a4:42:39:c4:fe:8f:ea:c9:c1:be:d4:4d: - ff:9f:7a:9e:e2:b1:7c:9a:ad:a7:86:09:73:87:d1: - e7:9a:e3:7a:a5:aa:6e:fb:ba:b3:70:c0:67:88:a2: - 35:d4:a3:9a:b1:fd:ad:c2:ef:31:fa:a8:b9:f3:fb: - 08:c6:91:d1:fb:29:95 - ASN1 OID: secp384r1 - X509v3 extensions: - X509v3 Basic Constraints: critical - CA:TRUE - X509v3 Key Usage: critical - Certificate Sign, CRL Sign - X509v3 Subject Key Identifier: - 9A:D8:00:30:00:E7:6B:7F:85:18:EE:8B:B6:CE:8A:0C:F8:11:E1:BB - Signature Algorithm: ecdsa-with-SHA384 - 30:66:02:31:00:dd:f8:e0:57:47:5b:a7:e6:0a:c3:bd:f5:80: - 8a:97:35:0d:1b:89:3c:54:86:77:28:ca:a1:f4:79:de:b5:e6: - 38:b0:f0:65:70:8c:7f:02:54:c2:bf:ff:d8:a1:3e:d9:cf:02: - 31:00:c4:8d:94:fc:dc:53:d2:dc:9d:78:16:1f:15:33:23:53: - 52:e3:5a:31:5d:9d:ca:ae:bd:13:29:44:0d:27:5b:a8:e7:68: - 9c:12:f7:58:3f:2e:72:02:57:a3:8f:a1:14:2e ------BEGIN CERTIFICATE----- -MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDEL -MAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMp -IDIwMDcgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAi -BgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMjAeFw0wNzExMDUwMDAw -MDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh -d3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBGb3Ig -YXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9v -dCBDQSAtIEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/ -BebfowJPDQfGAFG6DAJSLSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6 -papu+7qzcMBniKI11KOasf2twu8x+qi58/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8E -BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUmtgAMADna3+FGO6Lts6K -DPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUNG4k8VIZ3 -KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41ox -XZ3Krr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg== ------END CERTIFICATE----- diff --git a/chromium/net/data/ssl/ev_roots/a53125188d2110aa964b02c7b7c6da3203170894e5fb71fffb6667d5e6810a36.pem b/chromium/net/data/ssl/ev_roots/a53125188d2110aa964b02c7b7c6da3203170894e5fb71fffb6667d5e6810a36.pem deleted file mode 100644 index 3139d848e56..00000000000 --- a/chromium/net/data/ssl/ev_roots/a53125188d2110aa964b02c7b7c6da3203170894e5fb71fffb6667d5e6810a36.pem +++ /dev/null @@ -1,48 +0,0 @@ -Certificate: - Data: - Version: 1 (0x0) - Serial Number: 421 (0x1a5) - Signature Algorithm: md5WithRSAEncryption - Issuer: C=US, O=GTE Corporation, OU=GTE CyberTrust Solutions, Inc., CN=GTE CyberTrust Global Root - Validity - Not Before: Aug 13 00:29:00 1998 GMT - Not After : Aug 13 23:59:00 2018 GMT - Subject: C=US, O=GTE Corporation, OU=GTE CyberTrust Solutions, Inc., CN=GTE CyberTrust Global Root - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (1024 bit) - Modulus: - 00:95:0f:a0:b6:f0:50:9c:e8:7a:c7:88:cd:dd:17: - 0e:2e:b0:94:d0:1b:3d:0e:f6:94:c0:8a:94:c7:06: - c8:90:97:c8:b8:64:1a:7a:7e:6c:3c:53:e1:37:28: - 73:60:7f:b2:97:53:07:9f:53:f9:6d:58:94:d2:af: - 8d:6d:88:67:80:e6:ed:b2:95:cf:72:31:ca:a5:1c: - 72:ba:5c:02:e7:64:42:e7:f9:a9:2c:d6:3a:0d:ac: - 8d:42:aa:24:01:39:e6:9c:3f:01:85:57:0d:58:87: - 45:f8:d3:85:aa:93:69:26:85:70:48:80:3f:12:15: - c7:79:b4:1f:05:2f:3b:62:99 - Exponent: 65537 (0x10001) - Signature Algorithm: md5WithRSAEncryption - 6d:eb:1b:09:e9:5e:d9:51:db:67:22:61:a4:2a:3c:48:77:e3: - a0:7c:a6:de:73:a2:14:03:85:3d:fb:ab:0e:30:c5:83:16:33: - 81:13:08:9e:7b:34:4e:df:40:c8:74:d7:b9:7d:dc:f4:76:55: - 7d:9b:63:54:18:e9:f0:ea:f3:5c:b1:d9:8b:42:1e:b9:c0:95: - 4e:ba:fa:d5:e2:7c:f5:68:61:bf:8e:ec:05:97:5f:5b:b0:d7: - a3:85:34:c4:24:a7:0d:0f:95:93:ef:cb:94:d8:9e:1f:9d:5c: - 85:6d:c7:aa:ae:4f:1f:22:b5:cd:95:ad:ba:a7:cc:f9:ab:0b: - 7a:7f ------BEGIN CERTIFICATE----- -MIICWjCCAcMCAgGlMA0GCSqGSIb3DQEBBAUAMHUxCzAJBgNVBAYTAlVTMRgwFgYD -VQQKEw9HVEUgQ29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRydXN0IFNv -bHV0aW9ucywgSW5jLjEjMCEGA1UEAxMaR1RFIEN5YmVyVHJ1c3QgR2xvYmFsIFJv -b3QwHhcNOTgwODEzMDAyOTAwWhcNMTgwODEzMjM1OTAwWjB1MQswCQYDVQQGEwJV -UzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQLEx5HVEUgQ3liZXJU -cnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMTGkdURSBDeWJlclRydXN0IEds -b2JhbCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVD6C28FCc6HrH -iM3dFw4usJTQGz0O9pTAipTHBsiQl8i4ZBp6fmw8U+E3KHNgf7KXUwefU/ltWJTS -r41tiGeA5u2ylc9yMcqlHHK6XALnZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X4 -04Wqk2kmhXBIgD8SFcd5tB8FLztimQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBAG3r -GwnpXtlR22ciYaQqPEh346B8pt5zohQDhT37qw4wxYMWM4ETCJ57NE7fQMh017l9 -3PR2VX2bY1QY6fDq81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OFNMQkpw0P -lZPvy5TYnh+dXIVtx6quTx8itc2VrbqnzPmrC3p/ ------END CERTIFICATE----- diff --git a/chromium/net/data/ssl/ev_roots/a71272aeaaa3cfe8727f7fb39f0fb3d1e5426e9060b06ee6f13e9a3c5833cd43.pem b/chromium/net/data/ssl/ev_roots/a71272aeaaa3cfe8727f7fb39f0fb3d1e5426e9060b06ee6f13e9a3c5833cd43.pem deleted file mode 100644 index 9e5c0f8833e..00000000000 --- a/chromium/net/data/ssl/ev_roots/a71272aeaaa3cfe8727f7fb39f0fb3d1e5426e9060b06ee6f13e9a3c5833cd43.pem +++ /dev/null @@ -1,94 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: 1 (0x1) - Signature Algorithm: sha1WithRSAEncryption - Issuer: C=US, O=Wells Fargo WellsSecure, OU=Wells Fargo Bank NA, CN=WellsSecure Public Root Certificate Authority - Validity - Not Before: Dec 13 17:07:54 2007 GMT - Not After : Dec 14 00:07:54 2022 GMT - Subject: C=US, O=Wells Fargo WellsSecure, OU=Wells Fargo Bank NA, CN=WellsSecure Public Root Certificate Authority - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (2048 bit) - Modulus: - 00:ee:6f:b4:bd:79:e2:8f:08:21:9e:38:04:41:25: - ef:ab:5b:1c:53:92:ac:6d:9e:dd:c2:c4:2e:45:94: - 03:35:88:67:74:57:e3:df:8c:b8:a7:76:8f:3b:f7: - a8:c4:db:29:63:0e:91:68:36:8a:97:8e:8a:71:68: - 09:07:e4:e8:d4:0e:4f:f8:d6:2b:4c:a4:16:f9:ef: - 43:98:8f:b3:9e:52:df:6d:91:39:8f:38:bd:77:8b: - 43:63:eb:b7:93:fc:30:4c:1c:01:93:b6:13:fb:f7: - a1:1f:bf:25:e1:74:37:2c:1e:a4:5e:3c:68:f8:4b: - bf:0d:b9:1e:2e:36:e8:a9:e4:a7:f8:0f:cb:82:75: - 7c:35:2d:22:d6:c2:bf:0b:f3:b4:fc:6c:95:61:1e: - 57:d7:04:81:32:83:52:79:e6:83:63:cf:b7:cb:63: - 8b:11:e2:bd:5e:eb:f6:8d:ed:95:72:28:b4:ac:12: - 62:e9:4a:33:e6:83:32:ae:05:75:95:bd:84:95:db: - 2a:5c:9b:8e:2e:0c:b8:81:2b:41:e6:38:56:9f:49: - 9b:6c:76:fa:8a:5d:f7:01:79:81:7c:c1:83:40:05: - fe:71:fd:0c:3f:cc:4e:60:09:0e:65:47:10:2f:01: - c0:05:3f:8f:f8:b3:41:ef:5a:42:7e:59:ef:d2:97: - 0c:65 - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Basic Constraints: critical - CA:TRUE - X509v3 CRL Distribution Points: - - Full Name: - URI:http://crl.pki.wellsfargo.com/wsprca.crl - - X509v3 Key Usage: critical - Digital Signature, Non Repudiation, Certificate Sign, CRL Sign - X509v3 Subject Key Identifier: - 26:95:19:10:D9:E8:A1:97:91:FF:DC:19:D9:B5:04:3E:D2:73:0A:6A - X509v3 Authority Key Identifier: - keyid:26:95:19:10:D9:E8:A1:97:91:FF:DC:19:D9:B5:04:3E:D2:73:0A:6A - DirName:/C=US/O=Wells Fargo WellsSecure/OU=Wells Fargo Bank NA/CN=WellsSecure Public Root Certificate Authority - serial:01 - - Signature Algorithm: sha1WithRSAEncryption - b9:15:b1:44:91:cc:23:c8:2b:4d:77:e3:f8:9a:7b:27:0d:cd: - 72:bb:99:00:ca:7c:66:19:50:c6:d5:98:ed:ab:bf:03:5a:e5: - 4d:e5:1e:c8:4f:71:97:86:d5:e3:1d:fd:90:c9:3c:75:77:57: - 7a:7d:f8:de:f4:d4:d5:f7:95:e6:74:6e:1d:3c:ae:7c:9d:db: - 02:03:05:2c:71:4b:25:3e:07:e3:5e:9a:f5:66:17:29:88:1a: - 38:9f:cf:aa:41:03:84:97:6b:93:38:7a:ca:30:44:1b:24:44: - 33:d0:e4:d1:dc:28:38:f4:13:43:35:35:29:63:a8:7c:a2:b5: - ad:38:a4:ed:ad:fd:c6:9a:1f:ff:97:73:fe:fb:b3:35:a7:93: - 86:c6:76:91:00:e6:ac:51:16:c4:27:32:5c:db:73:da:a5:93: - 57:8e:3e:6d:35:26:08:59:d5:e7:44:d7:76:20:63:e7:ac:13: - 67:c3:6d:b1:70:46:7c:d5:96:11:3d:89:6f:5d:a8:a1:eb:8d: - 0a:da:c3:1d:33:6c:a3:ea:67:19:9a:99:7f:4b:3d:83:51:2a: - 1d:ca:2f:86:0c:a2:7e:10:2d:2b:d4:16:95:0b:07:aa:2e:14: - 92:49:b7:29:6f:d8:6d:31:7d:f5:fc:a1:10:07:87:ce:2f:59: - dc:3e:58:db ------BEGIN CERTIFICATE----- -MIIEvTCCA6WgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBhTELMAkGA1UEBhMCVVMx -IDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxs -cyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9v -dCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDcxMjEzMTcwNzU0WhcNMjIxMjE0 -MDAwNzU0WjCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdl -bGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQD -DC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkw -ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDub7S9eeKPCCGeOARBJe+r -WxxTkqxtnt3CxC5FlAM1iGd0V+PfjLindo8796jE2yljDpFoNoqXjopxaAkH5OjU -Dk/41itMpBb570OYj7OeUt9tkTmPOL13i0Nj67eT/DBMHAGTthP796EfvyXhdDcs -HqRePGj4S78NuR4uNuip5Kf4D8uCdXw1LSLWwr8L87T8bJVhHlfXBIEyg1J55oNj -z7fLY4sR4r1e6/aN7ZVyKLSsEmLpSjPmgzKuBXWVvYSV2ypcm44uDLiBK0HmOFaf -SZtsdvqKXfcBeYF8wYNABf5x/Qw/zE5gCQ5lRxAvAcAFP4/4s0HvWkJ+We/Slwxl -AgMBAAGjggE0MIIBMDAPBgNVHRMBAf8EBTADAQH/MDkGA1UdHwQyMDAwLqAsoCqG -KGh0dHA6Ly9jcmwucGtpLndlbGxzZmFyZ28uY29tL3dzcHJjYS5jcmwwDgYDVR0P -AQH/BAQDAgHGMB0GA1UdDgQWBBQmlRkQ2eihl5H/3BnZtQQ+0nMKajCBsgYDVR0j -BIGqMIGngBQmlRkQ2eihl5H/3BnZtQQ+0nMKaqGBi6SBiDCBhTELMAkGA1UEBhMC -VVMxIDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNX -ZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMg -Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHmCAQEwDQYJKoZIhvcNAQEFBQADggEB -ALkVsUSRzCPIK0134/iaeycNzXK7mQDKfGYZUMbVmO2rvwNa5U3lHshPcZeG1eMd -/ZDJPHV3V3p9+N701NX3leZ0bh08rnyd2wIDBSxxSyU+B+NemvVmFymIGjifz6pB -A4SXa5M4esowRBskRDPQ5NHcKDj0E0M1NSljqHyita04pO2t/caaH/+Xc/77szWn -k4bGdpEA5qxRFsQnMlzbc9qlk1eOPm01JghZ1edE13YgY+esE2fDbbFwRnzVlhE9 -iW9dqKHrjQrawx0zbKPqZxmamX9LPYNRKh3KL4YMon4QLSvUFpULB6ouFJJJtylv -2G0xffX8oRAHh84vWdw+WNs= ------END CERTIFICATE----- diff --git a/chromium/net/data/ssl/ev_roots/ab7036365c7154aa29c2c29f5d4191163b162a2225011357d56d07ffa7bc1f72.pem b/chromium/net/data/ssl/ev_roots/ab7036365c7154aa29c2c29f5d4191163b162a2225011357d56d07ffa7bc1f72.pem deleted file mode 100644 index ed8a8611be9..00000000000 --- a/chromium/net/data/ssl/ev_roots/ab7036365c7154aa29c2c29f5d4191163b162a2225011357d56d07ffa7bc1f72.pem +++ /dev/null @@ -1,55 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: 1 (0x1) - Signature Algorithm: md5WithRSAEncryption - Issuer: C=ZA, ST=Western Cape, L=Cape Town, O=Thawte Consulting cc, OU=Certification Services Division, CN=Thawte Premium Server CA/emailAddress=premium-server@thawte.com - Validity - Not Before: Aug 1 00:00:00 1996 GMT - Not After : Dec 31 23:59:59 2020 GMT - Subject: C=ZA, ST=Western Cape, L=Cape Town, O=Thawte Consulting cc, OU=Certification Services Division, CN=Thawte Premium Server CA/emailAddress=premium-server@thawte.com - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (1024 bit) - Modulus: - 00:d2:36:36:6a:8b:d7:c2:5b:9e:da:81:41:62:8f: - 38:ee:49:04:55:d6:d0:ef:1c:1b:95:16:47:ef:18: - 48:35:3a:52:f4:2b:6a:06:8f:3b:2f:ea:56:e3:af: - 86:8d:9e:17:f7:9e:b4:65:75:02:4d:ef:cb:09:a2: - 21:51:d8:9b:d0:67:d0:ba:0d:92:06:14:73:d4:93: - cb:97:2a:00:9c:5c:4e:0c:bc:fa:15:52:fc:f2:44: - 6e:da:11:4a:6e:08:9f:2f:2d:e3:f9:aa:3a:86:73: - b6:46:53:58:c8:89:05:bd:83:11:b8:73:3f:aa:07: - 8d:f4:42:4d:e7:40:9d:1c:37 - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Basic Constraints: critical - CA:TRUE - Signature Algorithm: md5WithRSAEncryption - 26:48:2c:16:c2:58:fa:e8:16:74:0c:aa:aa:5f:54:3f:f2:d7: - c9:78:60:5e:5e:6e:37:63:22:77:36:7e:b2:17:c4:34:b9:f5: - 08:85:fc:c9:01:38:ff:4d:be:f2:16:42:43:e7:bb:5a:46:fb: - c1:c6:11:1f:f1:4a:b0:28:46:c9:c3:c4:42:7d:bc:fa:ab:59: - 6e:d5:b7:51:88:11:e3:a4:85:19:6b:82:4c:a4:0c:12:ad:e9: - a4:ae:3f:f1:c3:49:65:9a:8c:c5:c8:3e:25:b7:94:99:bb:92: - 32:71:07:f0:86:5e:ed:50:27:a6:0d:a6:23:f9:bb:cb:a6:07: - 14:42 ------BEGIN CERTIFICATE----- -MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMCWkEx -FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD -VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv -biBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFByZW1pdW0gU2Vy -dmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNlcnZlckB0aGF3dGUuY29t -MB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgc4xCzAJBgNVBAYTAlpB -MRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEdMBsG -A1UEChMUVGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNVBAsTH0NlcnRpZmljYXRp -b24gU2VydmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNl -cnZlciBDQTEoMCYGCSqGSIb3DQEJARYZcHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNv -bTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2aovXwlue2oFBYo847kkE -VdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIhUdib0GfQ -ug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMR -uHM/qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG -9w0BAQQFAAOBgQAmSCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUI -hfzJATj/Tb7yFkJD57taRvvBxhEf8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZa4JM -pAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7tUCemDaYj+bvLpgcUQg== ------END CERTIFICATE----- diff --git a/chromium/net/data/ssl/ev_roots/b478b812250df878635c2aa7ec7d155eaa625ee82916e2cd294361886cd1fbd4.pem b/chromium/net/data/ssl/ev_roots/b478b812250df878635c2aa7ec7d155eaa625ee82916e2cd294361886cd1fbd4.pem deleted file mode 100644 index 9d11047e2ce..00000000000 --- a/chromium/net/data/ssl/ev_roots/b478b812250df878635c2aa7ec7d155eaa625ee82916e2cd294361886cd1fbd4.pem +++ /dev/null @@ -1,81 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 15:ac:6e:94:19:b2:79:4b:41:f6:27:a9:c3:18:0f:1f - Signature Algorithm: sha256WithRSAEncryption - Issuer: C=US, O=GeoTrust Inc., OU=(c) 2008 GeoTrust Inc. - For authorized use only, CN=GeoTrust Primary Certification Authority - G3 - Validity - Not Before: Apr 2 00:00:00 2008 GMT - Not After : Dec 1 23:59:59 2037 GMT - Subject: C=US, O=GeoTrust Inc., OU=(c) 2008 GeoTrust Inc. - For authorized use only, CN=GeoTrust Primary Certification Authority - G3 - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (2048 bit) - Modulus: - 00:dc:e2:5e:62:58:1d:33:57:39:32:33:fa:eb:cb: - 87:8c:a7:d4:4a:dd:06:88:ea:64:8e:31:98:a5:38: - 90:1e:98:cf:2e:63:2b:f0:46:bc:44:b2:89:a1:c0: - 28:0c:49:70:21:95:9f:64:c0:a6:93:12:02:65:26: - 86:c6:a5:89:f0:fa:d7:84:a0:70:af:4f:1a:97:3f: - 06:44:d5:c9:eb:72:10:7d:e4:31:28:fb:1c:61:e6: - 28:07:44:73:92:22:69:a7:03:88:6c:9d:63:c8:52: - da:98:27:e7:08:4c:70:3e:b4:c9:12:c1:c5:67:83: - 5d:33:f3:03:11:ec:6a:d0:53:e2:d1:ba:36:60:94: - 80:bb:61:63:6c:5b:17:7e:df:40:94:1e:ab:0d:c2: - 21:28:70:88:ff:d6:26:6c:6c:60:04:25:4e:55:7e: - 7d:ef:bf:94:48:de:b7:1d:dd:70:8d:05:5f:88:a5: - 9b:f2:c2:ee:ea:d1:40:41:6d:62:38:1d:56:06:c5: - 03:47:51:20:19:fc:7b:10:0b:0e:62:ae:76:55:bf: - 5f:77:be:3e:49:01:53:3d:98:25:03:76:24:5a:1d: - b4:db:89:ea:79:e5:b6:b3:3b:3f:ba:4c:28:41:7f: - 06:ac:6a:8e:c1:d0:f6:05:1d:7d:e6:42:86:e3:a5: - d5:47 - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Basic Constraints: critical - CA:TRUE - X509v3 Key Usage: critical - Certificate Sign, CRL Sign - X509v3 Subject Key Identifier: - C4:79:CA:8E:A1:4E:03:1D:1C:DC:6B:DB:31:5B:94:3E:3F:30:7F:2D - Signature Algorithm: sha256WithRSAEncryption - 2d:c5:13:cf:56:80:7b:7a:78:bd:9f:ae:2c:99:e7:ef:da:df: - 94:5e:09:69:a7:e7:6e:68:8c:bd:72:be:47:a9:0e:97:12:b8: - 4a:f1:64:d3:39:df:25:34:d4:c1:cd:4e:81:f0:0f:04:c4:24: - b3:34:96:c6:a6:aa:30:df:68:61:73:d7:f9:8e:85:89:ef:0e: - 5e:95:28:4a:2a:27:8f:10:8e:2e:7c:86:c4:02:9e:da:0c:77: - 65:0e:44:0d:92:fd:fd:b3:16:36:fa:11:0d:1d:8c:0e:07:89: - 6a:29:56:f7:72:f4:dd:15:9c:77:35:66:57:ab:13:53:d8:8e: - c1:40:c5:d7:13:16:5a:72:c7:b7:69:01:c4:7a:b1:83:01:68: - 7d:8d:41:a1:94:18:c1:25:5c:fc:f0:fe:83:02:87:7c:0d:0d: - cf:2e:08:5c:4a:40:0d:3e:ec:81:61:e6:24:db:ca:e0:0e:2d: - 07:b2:3e:56:dc:8d:f5:41:85:07:48:9b:0c:0b:cb:49:3f:7d: - ec:b7:fd:cb:8d:67:89:1a:ab:ed:bb:1e:a3:00:08:08:17:2a: - 82:5c:31:5d:46:8a:2d:0f:86:9b:74:d9:45:fb:d4:40:b1:7a: - aa:68:2d:86:b2:99:22:e1:c1:2b:c7:9c:f8:f3:5f:a8:82:12: - eb:19:11:2d ------BEGIN CERTIFICATE----- -MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCB -mDELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsT -MChjKSAyMDA4IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25s -eTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv -cml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIzNTk1OVowgZgxCzAJ -BgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg -MjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0 -BgNVBAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg -LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz -+uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5jK/BGvESyiaHAKAxJcCGVn2TAppMSAmUm -hsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdEc5IiaacDiGydY8hS2pgn -5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3CIShwiP/W -JmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exAL -DmKudlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZC -huOl1UcCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw -HQYDVR0OBBYEFMR5yo6hTgMdHNxr2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IB -AQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9cr5HqQ6XErhK8WTTOd8lNNTB -zU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbEAp7aDHdlDkQN -kv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD -AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUH -SJsMC8tJP33st/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2G -spki4cErx5z481+oghLrGREt ------END CERTIFICATE----- diff --git a/chromium/net/data/ssl/ev_roots/b7b12b171f821daa990cd0fe5087b128448ba8e5184f84c51e02b5c8fb962b24.pem b/chromium/net/data/ssl/ev_roots/b7b12b171f821daa990cd0fe5087b128448ba8e5184f84c51e02b5c8fb962b24.pem deleted file mode 100644 index 8f25bab4c27..00000000000 --- a/chromium/net/data/ssl/ev_roots/b7b12b171f821daa990cd0fe5087b128448ba8e5184f84c51e02b5c8fb962b24.pem +++ /dev/null @@ -1,76 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: 2 (0x2) - Signature Algorithm: sha1WithRSAEncryption - Issuer: C=NO, O=Buypass AS-983163327, CN=Buypass Class 3 CA 1 - Validity - Not Before: May 9 14:13:03 2005 GMT - Not After : May 9 14:13:03 2015 GMT - Subject: C=NO, O=Buypass AS-983163327, CN=Buypass Class 3 CA 1 - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (2048 bit) - Modulus: - 00:a4:8e:d7:74:d9:29:64:de:5f:1f:87:80:91:ea: - 4e:39:e6:19:c6:44:0b:80:d5:0b:af:53:07:8b:12: - bd:e6:67:f0:02:b1:89:f6:60:8a:c4:5b:b0:42:d1: - c0:21:a8:cb:e1:9b:ef:64:51:b6:a7:cf:15:f5:74: - 80:68:04:90:a0:58:a2:e6:74:a6:53:53:55:48:63: - 3f:92:56:dd:24:4e:8e:f8:ba:2b:ff:f3:34:8a:9e: - 28:d7:34:9f:ac:2f:d6:0f:f1:a4:2f:bd:52:b2:49: - 85:6d:39:35:f0:44:30:93:46:24:f3:b6:e7:53:fb: - bc:61:af:a9:a3:14:fb:c2:17:17:84:6c:e0:7c:88: - f8:c9:1c:57:2c:f0:3d:7e:94:bc:25:93:84:e8:9a: - 00:9a:45:05:42:57:80:f4:4e:ce:d9:ae:39:f6:c8: - 53:10:0c:65:3a:47:7b:60:c2:d6:fa:91:c9:c6:71: - 6c:bd:91:87:3c:91:86:49:ab:f3:0f:a0:6c:26:76: - 5e:1c:ac:9b:71:e5:8d:bc:9b:21:1e:9c:d6:38:7e: - 24:80:15:31:82:96:b1:49:d3:62:37:5b:88:0c:0a: - 62:34:fe:a7:48:7e:99:b1:30:8b:90:37:95:1c:a8: - 1f:a5:2c:8d:f4:55:c8:db:dd:59:0a:c2:ad:78:a0: - f4:8b - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Basic Constraints: critical - CA:TRUE - X509v3 Subject Key Identifier: - 38:14:E6:C8:F0:A9:A4:03:F4:4E:3E:22:A3:5B:F2:D6:E0:AD:40:74 - X509v3 Key Usage: critical - Certificate Sign, CRL Sign - Signature Algorithm: sha1WithRSAEncryption - 01:67:a3:8c:c9:25:3d:13:63:5d:16:6f:ec:a1:3e:09:5c:91: - 15:2a:2a:d9:80:21:4f:05:dc:bb:a5:89:ab:13:33:2a:9e:38: - b7:8c:6f:02:72:63:c7:73:77:1e:09:06:ba:3b:28:7b:a4:47: - c9:61:6b:08:08:20:fc:8a:05:8a:1f:bc:ba:c6:c2:fe:cf:6e: - ec:13:33:71:67:2e:69:fa:a9:2c:3f:66:c0:12:59:4d:0b:54: - 02:92:84:bb:db:12:ef:83:70:70:78:c8:53:fa:df:c6:c6:ff: - dc:88:2f:07:c0:49:9d:32:57:60:d3:f2:f6:99:29:5f:e7:aa: - 01:cc:ac:33:a8:1c:0a:bb:91:c4:03:a0:6f:b6:34:f9:86:d3: - b3:76:54:98:f4:4a:81:b3:53:9d:4d:40:ec:e5:77:13:45:af: - 5b:aa:1f:d8:2f:4c:82:7b:fe:2a:c4:58:bb:4f:fc:9e:fd:03: - 65:1a:2a:0e:c3:a5:20:16:94:6b:79:a6:a2:12:b4:bb:1a:a4: - 23:7a:5f:f0:ae:84:24:e4:f3:2b:fb:8a:24:a3:27:98:65:da: - 30:75:76:fc:19:91:e8:db:eb:9b:3f:32:bf:40:97:07:26:ba: - cc:f3:94:85:4a:7a:27:93:cf:90:42:d4:b8:5b:16:a6:e7:cb: - 40:03:dd:79 ------BEGIN CERTIFICATE----- -MIIDUzCCAjugAwIBAgIBAjANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEd -MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3Mg -Q2xhc3MgMyBDQSAxMB4XDTA1MDUwOTE0MTMwM1oXDTE1MDUwOTE0MTMwM1owSzEL -MAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MR0wGwYD -VQQDDBRCdXlwYXNzIENsYXNzIDMgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEP -ADCCAQoCggEBAKSO13TZKWTeXx+HgJHqTjnmGcZEC4DVC69TB4sSveZn8AKxifZg -isRbsELRwCGoy+Gb72RRtqfPFfV0gGgEkKBYouZ0plNTVUhjP5JW3SROjvi6K//z -NIqeKNc0n6wv1g/xpC+9UrJJhW05NfBEMJNGJPO251P7vGGvqaMU+8IXF4Rs4HyI -+MkcVyzwPX6UvCWThOiaAJpFBUJXgPROztmuOfbIUxAMZTpHe2DC1vqRycZxbL2R -hzyRhkmr8w+gbCZ2Xhysm3HljbybIR6c1jh+JIAVMYKWsUnTYjdbiAwKYjT+p0h+ -mbEwi5A3lRyoH6UsjfRVyNvdWQrCrXig9IsCAwEAAaNCMEAwDwYDVR0TAQH/BAUw -AwEB/zAdBgNVHQ4EFgQUOBTmyPCppAP0Tj4io1vy1uCtQHQwDgYDVR0PAQH/BAQD -AgEGMA0GCSqGSIb3DQEBBQUAA4IBAQABZ6OMySU9E2NdFm/soT4JXJEVKirZgCFP -Bdy7pYmrEzMqnji3jG8CcmPHc3ceCQa6Oyh7pEfJYWsICCD8igWKH7y6xsL+z27s -EzNxZy5p+qksP2bAEllNC1QCkoS72xLvg3BweMhT+t/Gxv/ciC8HwEmdMldg0/L2 -mSlf56oBzKwzqBwKu5HEA6BvtjT5htOzdlSY9EqBs1OdTUDs5XcTRa9bqh/YL0yC -e/4qxFi7T/ye/QNlGioOw6UgFpRreaaiErS7GqQjel/wroQk5PMr+4okoyeYZdow -dXb8GZHo2+ubPzK/QJcHJrrM85SFSnonk8+QQtS4Wxam58tAA915 ------END CERTIFICATE----- diff --git a/chromium/net/data/ssl/ev_roots/bec94911c2955676db6c0a550986d76e3ba005667c442c9762b4fbb773de228c.pem b/chromium/net/data/ssl/ev_roots/bec94911c2955676db6c0a550986d76e3ba005667c442c9762b4fbb773de228c.pem deleted file mode 100644 index 511423f7373..00000000000 --- a/chromium/net/data/ssl/ev_roots/bec94911c2955676db6c0a550986d76e3ba005667c442c9762b4fbb773de228c.pem +++ /dev/null @@ -1,46 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 2a:38:a4:1c:96:0a:04:de:42:b2:28:a5:0b:e8:34:98:02 - Signature Algorithm: ecdsa-with-SHA256 - Issuer: OU=GlobalSign ECC Root CA - R4, O=GlobalSign, CN=GlobalSign - Validity - Not Before: Nov 13 00:00:00 2012 GMT - Not After : Jan 19 03:14:07 2038 GMT - Subject: OU=GlobalSign ECC Root CA - R4, O=GlobalSign, CN=GlobalSign - Subject Public Key Info: - Public Key Algorithm: id-ecPublicKey - Public-Key: (256 bit) - pub: - 04:b8:c6:79:d3:8f:6c:25:0e:9f:2e:39:19:1c:03: - a4:ae:9a:e5:39:07:09:16:ca:63:b1:b9:86:f8:8a: - 57:c1:57:ce:42:fa:73:a1:f7:65:42:ff:1e:c1:00: - b2:6e:73:0e:ff:c7:21:e5:18:a4:aa:d9:71:3f:a8: - d4:b9:ce:8c:1d - ASN1 OID: prime256v1 - X509v3 extensions: - X509v3 Key Usage: critical - Certificate Sign, CRL Sign - X509v3 Basic Constraints: critical - CA:TRUE - X509v3 Subject Key Identifier: - 54:B0:7B:AD:45:B8:E2:40:7F:FB:0A:6E:FB:BE:33:C9:3C:A3:84:D5 - Signature Algorithm: ecdsa-with-SHA256 - 30:45:02:21:00:dc:92:a1:a0:13:a6:cf:03:b0:e6:c4:21:97: - 90:fa:14:57:2d:03:ec:ee:3c:d3:6e:ca:a8:6c:76:bc:a2:de: - bb:02:20:27:a8:85:27:35:9b:56:c6:a3:f2:47:d2:b7:6e:1b: - 02:00:17:aa:67:a6:15:91:de:fa:94:ec:7b:0b:f8:9f:84 ------BEGIN CERTIFICATE----- -MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEk -MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpH -bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX -DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD -QSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu -MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprlOQcJ -FspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAw -DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61F -uOJAf/sKbvu+M8k8o4TVMAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGX -kPoUVy0D7O48027KqGx2vKLeuwIgJ6iFJzWbVsaj8kfSt24bAgAXqmemFZHe+pTs -ewv4n4Q= ------END CERTIFICATE----- diff --git a/chromium/net/data/ssl/ev_roots/c766a9bef2d4071c863a31aa4920e813b2d198608cb7b7cfe21143b836df09ea.pem b/chromium/net/data/ssl/ev_roots/c766a9bef2d4071c863a31aa4920e813b2d198608cb7b7cfe21143b836df09ea.pem deleted file mode 100644 index bf37b6ab59a..00000000000 --- a/chromium/net/data/ssl/ev_roots/c766a9bef2d4071c863a31aa4920e813b2d198608cb7b7cfe21143b836df09ea.pem +++ /dev/null @@ -1,152 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: 1 (0x1) - Signature Algorithm: sha1WithRSAEncryption - Issuer: C=IL, O=StartCom Ltd., OU=Secure Digital Certificate Signing, CN=StartCom Certification Authority - Validity - Not Before: Sep 17 19:46:36 2006 GMT - Not After : Sep 17 19:46:36 2036 GMT - Subject: C=IL, O=StartCom Ltd., OU=Secure Digital Certificate Signing, CN=StartCom Certification Authority - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (4096 bit) - Modulus: - 00:c1:88:db:09:bc:6c:46:7c:78:9f:95:7b:b5:33: - 90:f2:72:62:d6:c1:36:20:22:24:5e:ce:e9:77:f2: - 43:0a:a2:06:64:a4:cc:8e:36:f8:38:e6:23:f0:6e: - 6d:b1:3c:dd:72:a3:85:1c:a1:d3:3d:b4:33:2b:d3: - 2f:af:fe:ea:b0:41:59:67:b6:c4:06:7d:0a:9e:74: - 85:d6:79:4c:80:37:7a:df:39:05:52:59:f7:f4:1b: - 46:43:a4:d2:85:85:d2:c3:71:f3:75:62:34:ba:2c: - 8a:7f:1e:8f:ee:ed:34:d0:11:c7:96:cd:52:3d:ba: - 33:d6:dd:4d:de:0b:3b:4a:4b:9f:c2:26:2f:fa:b5: - 16:1c:72:35:77:ca:3c:5d:e6:ca:e1:26:8b:1a:36: - 76:5c:01:db:74:14:25:fe:ed:b5:a0:88:0f:dd:78: - ca:2d:1f:07:97:30:01:2d:72:79:fa:46:d6:13:2a: - a8:b9:a6:ab:83:49:1d:e5:f2:ef:dd:e4:01:8e:18: - 0a:8f:63:53:16:85:62:a9:0e:19:3a:cc:b5:66:a6: - c2:6b:74:07:e4:2b:e1:76:3e:b4:6d:d8:f6:44:e1: - 73:62:1f:3b:c4:be:a0:53:56:25:6c:51:09:f7:aa: - ab:ca:bf:76:fd:6d:9b:f3:9d:db:bf:3d:66:bc:0c: - 56:aa:af:98:48:95:3a:4b:df:a7:58:50:d9:38:75: - a9:5b:ea:43:0c:02:ff:99:eb:e8:6c:4d:70:5b:29: - 65:9c:dd:aa:5d:cc:af:01:31:ec:0c:eb:d2:8d:e8: - ea:9c:7b:e6:6e:f7:27:66:0c:1a:48:d7:6e:42:e3: - 3f:de:21:3e:7b:e1:0d:70:fb:63:aa:a8:6c:1a:54: - b4:5c:25:7a:c9:a2:c9:8b:16:a6:bb:2c:7e:17:5e: - 05:4d:58:6e:12:1d:01:ee:12:10:0d:c6:32:7f:18: - ff:fc:f4:fa:cd:6e:91:e8:36:49:be:1a:48:69:8b: - c2:96:4d:1a:12:b2:69:17:c1:0a:90:d6:fa:79:22: - 48:bf:ba:7b:69:f8:70:c7:fa:7a:37:d8:d8:0d:d2: - 76:4f:57:ff:90:b7:e3:91:d2:dd:ef:c2:60:b7:67: - 3a:dd:fe:aa:9c:f0:d4:8b:7f:72:22:ce:c6:9f:97: - b6:f8:af:8a:a0:10:a8:d9:fb:18:c6:b6:b5:5c:52: - 3c:89:b6:19:2a:73:01:0a:0f:03:b3:12:60:f2:7a: - 2f:81:db:a3:6e:ff:26:30:97:f5:8b:dd:89:57:b6: - ad:3d:b3:af:2b:c5:b7:76:02:f0:a5:d6:2b:9a:86: - 14:2a:72:f6:e3:33:8c:5d:09:4b:13:df:bb:8c:74: - 13:52:4b - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Basic Constraints: - CA:TRUE - X509v3 Key Usage: - Digital Signature, Key Encipherment, Key Agreement, Certificate Sign, CRL Sign - X509v3 Subject Key Identifier: - 4E:0B:EF:1A:A4:40:5B:A5:17:69:87:30:CA:34:68:43:D0:41:AE:F2 - X509v3 CRL Distribution Points: - - Full Name: - URI:http://cert.startcom.org/sfsca-crl.crl - - Full Name: - URI:http://crl.startcom.org/sfsca-crl.crl - - X509v3 Certificate Policies: - Policy: 1.3.6.1.4.1.23223.1.1.1 - CPS: http://cert.startcom.org/policy.pdf - CPS: http://cert.startcom.org/intermediate.pdf - User Notice: - Organization: Start Commercial (StartCom) Ltd. - Number: 1 - Explicit Text: Limited Liability, read the section *Legal Limitations* of the StartCom Certification Authority Policy available at http://cert.startcom.org/policy.pdf - - Netscape Cert Type: - SSL CA, S/MIME CA, Object Signing CA - Netscape Comment: - StartCom Free SSL Certification Authority - Signature Algorithm: sha1WithRSAEncryption - 16:6c:99:f4:66:0c:34:f5:d0:85:5e:7d:0a:ec:da:10:4e:38: - 1c:5e:df:a6:25:05:4b:91:32:c1:e8:3b:f1:3d:dd:44:09:5b: - 07:49:8a:29:cb:66:02:b7:b1:9a:f7:25:98:09:3c:8e:1b:e1: - dd:36:87:2b:4b:bb:68:d3:39:66:3d:a0:26:c7:f2:39:91:1d: - 51:ab:82:7b:7e:d5:ce:5a:e4:e2:03:57:70:69:97:08:f9:5e: - 58:a6:0a:df:8c:06:9a:45:16:16:38:0a:5e:57:f6:62:c7:7a: - 02:05:e6:bc:1e:b5:f2:9e:f4:a9:29:83:f8:b2:14:e3:6e:28: - 87:44:c3:90:1a:de:38:a9:3c:ac:43:4d:64:45:ce:dd:28:a9: - 5c:f2:73:7b:04:f8:17:e8:ab:b1:f3:2e:5c:64:6e:73:31:3a: - 12:b8:bc:b3:11:e4:7d:8f:81:51:9a:3b:8d:89:f4:4d:93:66: - 7b:3c:03:ed:d3:9a:1d:9a:f3:65:50:f5:a0:d0:75:9f:2f:af: - f0:ea:82:43:98:f8:69:9c:89:79:c4:43:8e:46:72:e3:64:36: - 12:af:f7:25:1e:38:89:90:77:7e:c3:6b:6a:b9:c3:cb:44:4b: - ac:78:90:8b:e7:c7:2c:1e:4b:11:44:c8:34:52:27:cd:0a:5d: - 9f:85:c1:89:d5:1a:78:f2:95:10:53:32:dd:80:84:66:75:d9: - b5:68:28:fb:61:2e:be:84:a8:38:c0:99:12:86:a5:1e:67:64: - ad:06:2e:2f:a9:70:85:c7:96:0f:7c:89:65:f5:8e:43:54:0e: - ab:dd:a5:80:39:94:60:c0:34:c9:96:70:2c:a3:12:f5:1f:48: - 7b:bd:1c:7e:6b:b7:9d:90:f4:22:3b:ae:f8:fc:2a:ca:fa:82: - 52:a0:ef:af:4b:55:93:eb:c1:b5:f0:22:8b:ac:34:4e:26:22: - 04:a1:87:2c:75:4a:b7:e5:7d:13:d7:b8:0c:64:c0:36:d2:c9: - 2f:86:12:8c:23:09:c1:1b:82:3b:73:49:a3:6a:57:87:94:e5: - d6:78:c5:99:43:63:e3:4d:e0:77:2d:e1:65:99:72:69:04:1a: - 47:09:e6:0f:01:56:24:fb:1f:bf:0e:79:a9:58:2e:b9:c4:09: - 01:7e:95:ba:6d:00:06:3e:b2:ea:4a:10:39:d8:d0:2b:f5:bf: - ec:75:bf:97:02:c5:09:1b:08:dc:55:37:e2:81:fb:37:84:43: - 62:20:ca:e7:56:4b:65:ea:fe:6c:c1:24:93:24:a1:34:eb:05: - ff:9a:22:ae:9b:7d:3f:f1:65:51:0a:a6:30:6a:b3:f4:88:1c: - 80:0d:fc:72:8a:e8:83:5e ------BEGIN CERTIFICATE----- -MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEW -MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg -Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh -dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM2WhcNMzYwOTE3MTk0NjM2WjB9 -MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi -U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh -cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA -A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk -pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf -OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C -Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT -Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi -HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM -Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w -+2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+ -Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3 -Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B -26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID -AQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE -FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9j -ZXJ0LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3Js -LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFM -BgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUHAgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0 -Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRwOi8vY2VydC5zdGFy -dGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYgU3Rh -cnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlh -YmlsaXR5LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2Yg -dGhlIFN0YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFp -bGFibGUgYXQgaHR0cDovL2NlcnQuc3RhcnRjb20ub3JnL3BvbGljeS5wZGYwEQYJ -YIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNT -TCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOCAgEAFmyZ -9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8 -jhvh3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUW -FjgKXlf2Ysd6AgXmvB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJz -ewT4F+irsfMuXGRuczE6Eri8sxHkfY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1 -ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3fsNrarnDy0RLrHiQi+fHLB5L -EUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZEoalHmdkrQYu -L6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq -yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuC -O3NJo2pXh5Tl1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6V -um0ABj6y6koQOdjQK/W/7HW/lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkySh -NOsF/5oirpt9P/FlUQqmMGqz9IgcgA38corog14= ------END CERTIFICATE----- diff --git a/chromium/net/data/ssl/ev_roots/ca42dd41745fd0b81eb902362cf9d8bf719da1bd1b1efc946f5b4c99f42c1b9e.pem b/chromium/net/data/ssl/ev_roots/ca42dd41745fd0b81eb902362cf9d8bf719da1bd1b1efc946f5b4c99f42c1b9e.pem deleted file mode 100644 index 4f852e635af..00000000000 --- a/chromium/net/data/ssl/ev_roots/ca42dd41745fd0b81eb902362cf9d8bf719da1bd1b1efc946f5b4c99f42c1b9e.pem +++ /dev/null @@ -1,87 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 04:00:00:00:00:01:0f:86:26:e6:0d - Signature Algorithm: sha1WithRSAEncryption - Issuer: OU=GlobalSign Root CA - R2, O=GlobalSign, CN=GlobalSign - Validity - Not Before: Dec 15 08:00:00 2006 GMT - Not After : Dec 15 08:00:00 2021 GMT - Subject: OU=GlobalSign Root CA - R2, O=GlobalSign, CN=GlobalSign - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (2048 bit) - Modulus: - 00:a6:cf:24:0e:be:2e:6f:28:99:45:42:c4:ab:3e: - 21:54:9b:0b:d3:7f:84:70:fa:12:b3:cb:bf:87:5f: - c6:7f:86:d3:b2:30:5c:d6:fd:ad:f1:7b:dc:e5:f8: - 60:96:09:92:10:f5:d0:53:de:fb:7b:7e:73:88:ac: - 52:88:7b:4a:a6:ca:49:a6:5e:a8:a7:8c:5a:11:bc: - 7a:82:eb:be:8c:e9:b3:ac:96:25:07:97:4a:99:2a: - 07:2f:b4:1e:77:bf:8a:0f:b5:02:7c:1b:96:b8:c5: - b9:3a:2c:bc:d6:12:b9:eb:59:7d:e2:d0:06:86:5f: - 5e:49:6a:b5:39:5e:88:34:ec:bc:78:0c:08:98:84: - 6c:a8:cd:4b:b4:a0:7d:0c:79:4d:f0:b8:2d:cb:21: - ca:d5:6c:5b:7d:e1:a0:29:84:a1:f9:d3:94:49:cb: - 24:62:91:20:bc:dd:0b:d5:d9:cc:f9:ea:27:0a:2b: - 73:91:c6:9d:1b:ac:c8:cb:e8:e0:a0:f4:2f:90:8b: - 4d:fb:b0:36:1b:f6:19:7a:85:e0:6d:f2:61:13:88: - 5c:9f:e0:93:0a:51:97:8a:5a:ce:af:ab:d5:f7:aa: - 09:aa:60:bd:dc:d9:5f:df:72:a9:60:13:5e:00:01: - c9:4a:fa:3f:a4:ea:07:03:21:02:8e:82:ca:03:c2: - 9b:8f - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Key Usage: critical - Certificate Sign, CRL Sign - X509v3 Basic Constraints: critical - CA:TRUE - X509v3 Subject Key Identifier: - 9B:E2:07:57:67:1C:1E:C0:6A:06:DE:59:B4:9A:2D:DF:DC:19:86:2E - X509v3 CRL Distribution Points: - - Full Name: - URI:http://crl.globalsign.net/root-r2.crl - - X509v3 Authority Key Identifier: - keyid:9B:E2:07:57:67:1C:1E:C0:6A:06:DE:59:B4:9A:2D:DF:DC:19:86:2E - - Signature Algorithm: sha1WithRSAEncryption - 99:81:53:87:1c:68:97:86:91:ec:e0:4a:b8:44:0b:ab:81:ac: - 27:4f:d6:c1:b8:1c:43:78:b3:0c:9a:fc:ea:2c:3c:6e:61:1b: - 4d:4b:29:f5:9f:05:1d:26:c1:b8:e9:83:00:62:45:b6:a9:08: - 93:b9:a9:33:4b:18:9a:c2:f8:87:88:4e:db:dd:71:34:1a:c1: - 54:da:46:3f:e0:d3:2a:ab:6d:54:22:f5:3a:62:cd:20:6f:ba: - 29:89:d7:dd:91:ee:d3:5c:a2:3e:a1:5b:41:f5:df:e5:64:43: - 2d:e9:d5:39:ab:d2:a2:df:b7:8b:d0:c0:80:19:1c:45:c0:2d: - 8c:e8:f8:2d:a4:74:56:49:c5:05:b5:4f:15:de:6e:44:78:39: - 87:a8:7e:bb:f3:79:18:91:bb:f4:6f:9d:c1:f0:8c:35:8c:5d: - 01:fb:c3:6d:b9:ef:44:6d:79:46:31:7e:0a:fe:a9:82:c1:ff: - ef:ab:6e:20:c4:50:c9:5f:9d:4d:9b:17:8c:0c:e5:01:c9:a0: - 41:6a:73:53:fa:a5:50:b4:6e:25:0f:fb:4c:18:f4:fd:52:d9: - 8e:69:b1:e8:11:0f:de:88:d8:fb:1d:49:f7:aa:de:95:cf:20: - 78:c2:60:12:db:25:40:8c:6a:fc:7e:42:38:40:64:12:f7:9e: - 81:e1:93:2e ------BEGIN CERTIFICATE----- -MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G -A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp -Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1 -MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG -A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL -v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8 -eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq -tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd -C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa -zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB -mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH -V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n -bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG -3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs -J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO -291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS -ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd -AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7 -TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg== ------END CERTIFICATE----- diff --git a/chromium/net/data/ssl/ev_roots/d43af9b35473755c9684fc06d7d8cb70ee5c28e773fb294eb41ee71722924d24.pem b/chromium/net/data/ssl/ev_roots/d43af9b35473755c9684fc06d7d8cb70ee5c28e773fb294eb41ee71722924d24.pem new file mode 100644 index 00000000000..90752467d03 --- /dev/null +++ b/chromium/net/data/ssl/ev_roots/d43af9b35473755c9684fc06d7d8cb70ee5c28e773fb294eb41ee71722924d24.pem @@ -0,0 +1,119 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 4f:d2:2b:8f:f5:64:c8:33:9e:4f:34:58:66:23:70:60 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C = CN, O = UniTrust, CN = UCA Extended Validation Root + Validity + Not Before: Mar 13 00:00:00 2015 GMT + Not After : Dec 31 00:00:00 2038 GMT + Subject: C = CN, O = UniTrust, CN = UCA Extended Validation Root + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (4096 bit) + Modulus: + 00:a9:09:07:28:13:02:b0:99:e0:64:aa:1e:43:16: + 7a:73:b1:91:a0:75:3e:a8:fa:e3:38:00:7a:ec:89: + 6a:20:0f:8b:c5:b0:9b:33:03:5a:86:c6:58:86:d5: + c1:85:bb:4f:c6:9c:40:4d:ca:be:ee:69:96:b8:ad: + 81:30:9a:7c:92:05:eb:05:2b:9a:48:d0:b8:76:3e: + 96:c8:20:bb:d2:b0:f1:8f:d8:ac:45:46:ff:aa:67: + 60:b4:77:7e:6a:1f:3c:1a:52:7a:04:3d:07:3c:85: + 0d:84:d0:1f:76:0a:f7:6a:14:df:72:e3:34:7c:57: + 4e:56:01:3e:79:f1:aa:29:3b:6c:fa:f8:8f:6d:4d: + c8:35:df:ae:eb:dc:24:ee:79:45:a7:85:b6:05:88: + de:88:5d:25:7c:97:64:67:09:d9:bf:5a:15:05:86: + f3:09:1e:ec:58:32:33:11:f3:77:64:b0:76:1f:e4: + 10:35:17:1b:f2:0e:b1:6c:a4:2a:a3:73:fc:09:1f: + 1e:32:19:53:11:e7:d9:b3:2c:2e:76:2e:a1:a3:de: + 7e:6a:88:09:e8:f2:07:8a:f8:b2:cd:10:e7:e2:73: + 40:93:bb:08:d1:3f:e1:fc:0b:94:b3:25:ef:7c:a6: + d7:d1:af:9f:ff:96:9a:f5:91:7b:98:0b:77:d4:7e: + e8:07:d2:62:b5:95:39:e3:f3:f1:6d:0f:0e:65:84: + 8a:63:54:c5:80:b6:e0:9e:4b:7d:47:26:a7:01:08: + 5d:d1:88:9e:d7:c3:32:44:fa:82:4a:0a:68:54:7f: + 38:53:03:cc:a4:00:33:64:51:59:0b:a3:82:91:7a: + 5e:ec:16:c2:f3:2a:e6:62:da:2a:db:59:62:10:25: + 4a:2a:81:0b:47:07:43:06:70:87:d2:fa:93:11:29: + 7a:48:4d:eb:94:c7:70:4d:af:67:d5:51:b1:80:20: + 01:01:b4:7a:08:a6:90:7f:4e:e0:ef:07:41:87:af: + 6a:a5:5e:8b:fb:cf:50:b2:9a:54:af:c3:89:ba:58: + 2d:f5:30:98:b1:36:72:39:7e:49:04:fd:29:a7:4c: + 79:e4:05:57:db:94:b9:16:53:8d:46:b3:1d:95:61: + 57:56:7f:af:f0:16:5b:61:58:6f:36:50:11:0b:d8: + ac:2b:95:16:1a:0e:1f:08:cd:36:34:65:10:62:66: + d5:80:5f:14:20:5f:2d:0c:a0:78:0a:68:d6:2c:d7: + e9:6f:2b:d2:4a:05:93:fc:9e:6f:6b:67:ff:88:f1: + 4e:a5:69:4a:52:37:05:ea:c6:16:8d:d2:c4:99:d1: + 82:2b:3b:ba:35:75:f7:51:51:58:f3:c8:07:dd:e4: + b4:03:7f + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + D9:74:3A:E4:30:3D:0D:F7:12:DC:7E:5A:05:9F:1E:34:9A:F7:E1:14 + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + Signature Algorithm: sha256WithRSAEncryption + 36:8d:97:cc:42:15:64:29:37:9b:26:2c:d6:fb:ae:15:69:2c: + 6b:1a:1a:f7:5f:b6:f9:07:4c:59:ea:f3:c9:c8:b9:ae:cc:ba: + 2e:7a:dc:c0:f5:b0:2d:c0:3b:af:9f:70:05:11:6a:9f:25:4f: + 01:29:70:e3:e5:0c:e1:ea:5a:7c:dc:49:bb:c1:1e:2a:81:f5: + 16:4b:72:91:c8:a2:31:b9:aa:da:fc:9d:1f:f3:5d:40:02:13: + fc:4e:1c:06:ca:b3:14:90:54:17:19:12:1a:f1:1f:d7:0c:69: + 5a:f6:71:78:f4:94:7d:91:0b:8e:ec:90:54:8e:bc:6f:a1:4c: + ab:fc:74:64:fd:71:9a:f8:41:07:a1:cd:91:e4:3c:9a:e0:9b: + 32:39:73:ab:2a:d5:69:c8:78:91:26:31:7d:e2:c7:30:f1:fc: + 14:78:77:12:0e:13:f4:dd:16:94:bf:4b:67:7b:70:53:85:ca: + b0:bb:f3:38:4d:2c:90:39:c0:0d:c2:5d:6b:e9:e2:e5:d5:88: + 8d:d6:2c:bf:ab:1b:be:b5:28:87:12:17:74:6e:fc:7d:fc:8f: + d0:87:26:b0:1b:fb:b9:6c:ab:e2:9e:3d:15:c1:3b:2e:67:02: + 58:91:9f:ef:f8:42:1f:2c:b7:68:f5:75:ad:cf:b5:f6:ff:11: + 7d:c2:f0:24:a5:ad:d3:fa:a0:3c:a9:fa:5d:dc:a5:a0:ef:44: + a4:be:d6:e8:e5:e4:13:96:17:7b:06:3e:32:ed:c7:b7:42:bc: + 76:a3:d8:65:38:2b:38:35:51:21:0e:0e:6f:2e:34:13:40:e1: + 2b:67:0c:6d:4a:41:30:18:23:5a:32:55:99:c9:17:e0:3c:de: + f6:ec:79:ad:2b:58:19:a2:ad:2c:22:1a:95:8e:be:96:90:5d: + 42:57:c4:f9:14:03:35:2b:1c:2d:51:57:08:a7:3a:de:3f:e4: + c8:b4:03:73:c2:c1:26:80:bb:0b:42:1f:ad:0d:af:26:72:da: + cc:be:b3:a3:83:58:0d:82:c5:1f:46:51:e3:9c:18:cc:8d:9b: + 8d:ec:49:eb:75:50:d5:8c:28:59:ca:74:34:da:8c:0b:21:ab: + 1e:ea:1b:e5:c7:fd:15:3e:c0:17:aa:fb:23:6e:26:46:cb:fa: + f9:b1:72:6b:69:cf:22:84:0b:62:0f:ac:d9:19:00:94:a2:76: + 3c:d4:2d:9a:ed:04:9e:2d:06:62:10:37:52:1c:85:72:1b:27: + e5:cc:c6:31:ec:37:ec:63:59:9b:0b:1d:76:cc:7e:32:9a:88: + 95:08:36:52:bb:de:76:5f:76:49:49:ad:7f:bd:65:20:b2:c9: + c1:2b:76:18:76:9f:56:b1 +-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgIQT9Irj/VkyDOeTzRYZiNwYDANBgkqhkiG9w0BAQsFADBH +MQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNVBAMMHFVDQSBF +eHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwHhcNMTUwMzEzMDAwMDAwWhcNMzgxMjMx +MDAwMDAwWjBHMQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNV +BAMMHFVDQSBFeHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQCpCQcoEwKwmeBkqh5DFnpzsZGgdT6o+uM4AHrsiWog +D4vFsJszA1qGxliG1cGFu0/GnEBNyr7uaZa4rYEwmnySBesFK5pI0Lh2PpbIILvS +sPGP2KxFRv+qZ2C0d35qHzwaUnoEPQc8hQ2E0B92CvdqFN9y4zR8V05WAT558aop +O2z6+I9tTcg1367r3CTueUWnhbYFiN6IXSV8l2RnCdm/WhUFhvMJHuxYMjMR83dk +sHYf5BA1FxvyDrFspCqjc/wJHx4yGVMR59mzLC52LqGj3n5qiAno8geK+LLNEOfi +c0CTuwjRP+H8C5SzJe98ptfRr5//lpr1kXuYC3fUfugH0mK1lTnj8/FtDw5lhIpj +VMWAtuCeS31HJqcBCF3RiJ7XwzJE+oJKCmhUfzhTA8ykADNkUVkLo4KRel7sFsLz +KuZi2irbWWIQJUoqgQtHB0MGcIfS+pMRKXpITeuUx3BNr2fVUbGAIAEBtHoIppB/ +TuDvB0GHr2qlXov7z1CymlSvw4m6WC31MJixNnI5fkkE/SmnTHnkBVfblLkWU41G +sx2VYVdWf6/wFlthWG82UBEL2KwrlRYaDh8IzTY0ZRBiZtWAXxQgXy0MoHgKaNYs +1+lvK9JKBZP8nm9rZ/+I8U6laUpSNwXqxhaN0sSZ0YIrO7o1dfdRUVjzyAfd5LQD +fwIDAQABo0IwQDAdBgNVHQ4EFgQU2XQ65DA9DfcS3H5aBZ8eNJr34RQwDwYDVR0T +AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADggIBADaN +l8xCFWQpN5smLNb7rhVpLGsaGvdftvkHTFnq88nIua7Mui563MD1sC3AO6+fcAUR +ap8lTwEpcOPlDOHqWnzcSbvBHiqB9RZLcpHIojG5qtr8nR/zXUACE/xOHAbKsxSQ +VBcZEhrxH9cMaVr2cXj0lH2RC47skFSOvG+hTKv8dGT9cZr4QQehzZHkPJrgmzI5 +c6sq1WnIeJEmMX3ixzDx/BR4dxIOE/TdFpS/S2d7cFOFyrC78zhNLJA5wA3CXWvp +4uXViI3WLL+rG761KIcSF3Ru/H38j9CHJrAb+7lsq+KePRXBOy5nAliRn+/4Qh8s +t2j1da3Ptfb/EX3C8CSlrdP6oDyp+l3cpaDvRKS+1ujl5BOWF3sGPjLtx7dCvHaj +2GU4Kzg1USEODm8uNBNA4StnDG1KQTAYI1oyVZnJF+A83vbsea0rWBmirSwiGpWO +vpaQXUJXxPkUAzUrHC1RVwinOt4/5Mi0A3PCwSaAuwtCH60NryZy2sy+s6ODWA2C +xR9GUeOcGMyNm43sSet1UNWMKFnKdDTajAshqx7qG+XH/RU+wBeq+yNuJkbL+vmx +cmtpzyKEC2IPrNkZAJSidjzULZrtBJ4tBmIQN1IchXIbJ+XMxjHsN+xjWZsLHXbM +fjKaiJUINlK73nZfdklJrX+9ZSCyycErdhh2n1ax +-----END CERTIFICATE----- diff --git a/chromium/net/data/ssl/ev_roots/d95fea3ca4eedce74cd76e75fc6d1ff62c441f0fa8bc77f034b19e5db258015d.pem b/chromium/net/data/ssl/ev_roots/d95fea3ca4eedce74cd76e75fc6d1ff62c441f0fa8bc77f034b19e5db258015d.pem deleted file mode 100644 index e3ded339c9c..00000000000 --- a/chromium/net/data/ssl/ev_roots/d95fea3ca4eedce74cd76e75fc6d1ff62c441f0fa8bc77f034b19e5db258015d.pem +++ /dev/null @@ -1,127 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - f2:fa:64:e2:74:63:d3:8d:fd:10:1d:04:1f:76:ca:58 - Signature Algorithm: sha256WithRSAEncryption - Issuer: C=ch, O=Swisscom, OU=Digital Certificate Services, CN=Swisscom Root EV CA 2 - Validity - Not Before: Jun 24 09:45:08 2011 GMT - Not After : Jun 25 08:45:08 2031 GMT - Subject: C=ch, O=Swisscom, OU=Digital Certificate Services, CN=Swisscom Root EV CA 2 - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (4096 bit) - Modulus: - 00:c4:f7:1d:2f:57:ea:57:6c:f7:70:5d:63:b0:71: - 52:09:60:44:28:33:a3:7a:4e:0a:fa:d8:ea:6c:8b: - 51:16:1a:55:ae:54:26:c4:cc:45:07:41:4f:10:79: - 7f:71:d2:7a:4e:3f:38:4e:b3:00:c6:95:ca:5b:cd: - c1:2a:83:d7:27:1f:31:0e:23:16:b7:25:cb:1c:b4: - b9:80:32:5e:1a:9d:93:f1:e8:3c:60:2c:a7:5e:57: - 19:58:51:5e:bc:2c:56:0b:b8:d8:ef:8b:82:b4:3c: - b8:c2:24:a8:13:c7:a0:21:36:1b:7a:57:29:28:a7: - 2e:bf:71:25:90:f3:44:83:69:50:a4:e4:e1:1b:62: - 19:94:09:a3:f3:c3:bc:ef:f4:bd:ec:db:13:9d:cf: - 9d:48:09:52:67:c0:37:29:11:1e:fb:d2:11:a7:85: - 18:74:79:e4:4f:85:14:eb:52:37:e2:b1:45:d8:cc: - 0d:43:7f:ae:13:d2:6b:2b:3f:a7:c2:e2:a8:6d:76: - 5b:43:9f:be:b4:9d:b3:26:86:3b:1f:7f:e5:f2:e8: - 66:28:16:25:d0:4b:97:38:a7:e4:cf:09:d1:36:c3: - 0b:be:da:3b:44:58:8d:be:f1:9e:09:6b:3e:f3:32: - c7:2b:87:c6:ec:5e:9c:f6:87:65:ad:33:29:c4:2f: - 89:d9:b9:cb:c9:03:9d:fb:6c:94:51:97:10:1b:86: - 0b:1a:1b:3f:f6:02:7e:7b:d4:c5:51:64:28:9d:f5: - d3:ac:83:81:88:d3:74:b4:59:9d:c1:eb:61:33:5a: - 45:d1:cb:39:d0:06:6a:53:60:1d:af:f6:fb:69:bc: - 6a:dc:01:cf:bd:f9:8f:d9:bd:5b:c1:3a:5f:8e:da: - 0f:4b:a9:9b:9d:2a:28:6b:1a:0a:7c:3c:ab:22:0b: - e5:77:2d:71:f6:82:35:81:ae:f8:7b:81:e6:ea:fe: - ac:f4:1a:9b:74:5c:e8:8f:24:f6:5d:9d:46:c4:2c: - d2:1e:2b:21:6a:83:27:67:55:4a:a4:e3:c8:32:97: - 66:90:72:da:e3:d4:64:2e:5f:e3:a1:6a:f6:60:d4: - e7:35:cd:ca:c4:68:8d:d7:71:c8:d3:24:33:73:b1: - 6c:f9:6a:e1:28:db:5f:c6:3d:e8:be:55:e6:37:1b: - ed:24:d9:0f:19:8f:5f:63:18:58:50:81:51:65:6f: - f2:9f:7e:6a:04:e7:34:24:71:ba:76:4b:58:1e:19: - bd:15:60:45:aa:0c:12:40:01:9d:10:e2:c7:38:07: - 72:0a:65:c0:b6:bb:25:29:da:16:9e:8b:35:8b:61: - ed:e5:71:57:83:b5:3c:71:9f:e3:4f:bf:7e:1e:81: - 9f:41:97 - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Key Usage: critical - Digital Signature, Certificate Sign, CRL Sign - X509v3 Policy Mappings: - 2.16.756.1.83.2.2:2.16.756.1.83.2.2 - X509v3 Basic Constraints: critical - CA:TRUE, pathlen:3 - X509v3 Subject Key Identifier: - 45:D9:A5:81:6E:3D:88:4D:8D:71:D2:46:C1:6E:45:1E:F3:C4:80:9D - X509v3 Authority Key Identifier: - keyid:45:D9:A5:81:6E:3D:88:4D:8D:71:D2:46:C1:6E:45:1E:F3:C4:80:9D - - Signature Algorithm: sha256WithRSAEncryption - 94:3a:73:06:9f:52:4b:30:5c:d4:fe:b1:5c:25:f9:d7:8e:6f: - f5:87:64:9f:ed:14:8e:b8:04:8e:28:4b:8f:aa:7b:8e:39:b4: - d9:58:f6:7b:a1:35:0a:a1:9d:8a:f7:63:e5:eb:bd:39:82:d4: - e3:7a:2d:6f:df:13:3c:ba:fe:7e:56:98:0b:f3:54:9f:cd:44: - 4e:6e:3c:e1:3e:15:bf:06:26:9d:e4:f0:90:b6:d4:c2:9e:30: - 2e:1f:ef:c7:7a:c4:50:c7:ea:7b:da:50:cb:7a:26:cb:00:b4: - 5a:ab:b5:93:1f:80:89:84:04:95:8d:8d:7f:09:93:bf:d4:a8: - a8:e4:63:6d:d9:64:e4:b8:29:5a:08:bf:50:e1:84:0f:55:7b: - 5f:08:22:1b:f5:bd:99:1e:14:f6:ce:f4:58:10:82:b3:0a:3d: - 19:c1:bf:5b:ab:aa:99:d8:f2:31:bd:e5:38:66:dc:58:05:c7: - ed:63:1a:2e:0a:97:7c:87:93:2b:b2:8a:e3:f1:ec:18:e5:75: - b6:29:87:e7:dc:8b:1a:7e:b4:d8:c9:d3:8a:17:6c:7d:29:44: - be:8a:aa:f5:7e:3a:2e:68:31:93:b9:6a:da:9a:e0:db:e9:2e: - a5:84:cd:1c:0a:b8:4a:08:f9:9c:f1:61:26:98:93:b7:7b:66: - ec:91:5e:dd:51:3f:db:73:0f:ad:04:58:09:dd:04:02:95:0a: - 3e:d3:76:df:a6:10:1e:80:3d:e8:cd:a4:64:d1:33:c7:92:c7: - e2:4e:44:e3:09:c9:4e:c2:5d:87:0e:12:9e:bf:0f:c9:05:10: - de:7a:a3:b1:3c:f2:3f:a5:aa:27:79:ad:31:7d:1f:fd:fc:19: - 69:c5:dd:b9:3f:7c:cd:c6:b4:c2:30:1e:7e:6e:92:d7:7f:61: - 76:5a:8f:eb:95:4d:bc:11:6e:21:7c:59:37:99:d0:06:bc:f9: - 06:6d:32:16:a5:d9:69:a8:e1:dc:3c:80:1e:60:51:dc:d7:54: - 21:1e:ca:62:77:4f:fa:d8:8f:b3:2b:3a:0d:78:72:c9:68:41: - 5a:47:4a:c2:a3:eb:1a:d7:0a:ab:3c:32:55:c8:0a:11:9c:df: - 74:d6:f0:40:15:1d:c8:b9:8f:b5:36:c5:af:f8:22:b8:ca:1d: - f3:d6:b6:19:0f:9f:61:65:6a:ea:74:c8:7c:8f:c3:4f:5d:65: - 82:1f:d9:0d:89:da:75:72:fb:ef:f1:47:67:13:b3:c8:d1:19: - 88:27:26:9a:99:79:7f:1e:e4:2c:3f:7b:ee:f1:de:4d:8b:96: - 97:c3:d5:3f:7c:1b:23:ed:a4:b3:1d:16:72:43:4b:20:e1:59: - 7e:c2:e8:ad:26:bf:a2:f7 ------BEGIN CERTIFICATE----- -MIIF4DCCA8igAwIBAgIRAPL6ZOJ0Y9ON/RAdBB92ylgwDQYJKoZIhvcNAQELBQAw -ZzELMAkGA1UEBhMCY2gxETAPBgNVBAoTCFN3aXNzY29tMSUwIwYDVQQLExxEaWdp -dGFsIENlcnRpZmljYXRlIFNlcnZpY2VzMR4wHAYDVQQDExVTd2lzc2NvbSBSb290 -IEVWIENBIDIwHhcNMTEwNjI0MDk0NTA4WhcNMzEwNjI1MDg0NTA4WjBnMQswCQYD -VQQGEwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0YWwgQ2Vy -dGlmaWNhdGUgU2VydmljZXMxHjAcBgNVBAMTFVN3aXNzY29tIFJvb3QgRVYgQ0Eg -MjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMT3HS9X6lds93BdY7Bx -UglgRCgzo3pOCvrY6myLURYaVa5UJsTMRQdBTxB5f3HSek4/OE6zAMaVylvNwSqD -1ycfMQ4jFrclyxy0uYAyXhqdk/HoPGAsp15XGVhRXrwsVgu42O+LgrQ8uMIkqBPH -oCE2G3pXKSinLr9xJZDzRINpUKTk4RtiGZQJo/PDvO/0vezbE53PnUgJUmfANykR -HvvSEaeFGHR55E+FFOtSN+KxRdjMDUN/rhPSays/p8LiqG12W0OfvrSdsyaGOx9/ -5fLoZigWJdBLlzin5M8J0TbDC77aO0RYjb7xnglrPvMyxyuHxuxenPaHZa0zKcQv -idm5y8kDnftslFGXEBuGCxobP/YCfnvUxVFkKJ3106yDgYjTdLRZncHrYTNaRdHL -OdAGalNgHa/2+2m8atwBz735j9m9W8E6X47aD0upm50qKGsaCnw8qyIL5XctcfaC -NYGu+HuB5ur+rPQam3Rc6I8k9l2dRsQs0h4rIWqDJ2dVSqTjyDKXZpBy2uPUZC5f -46Fq9mDU5zXNysRojddxyNMkM3OxbPlq4SjbX8Y96L5V5jcb7STZDxmPX2MYWFCB -UWVv8p9+agTnNCRxunZLWB4ZvRVgRaoMEkABnRDixzgHcgplwLa7JSnaFp6LNYth -7eVxV4O1PHGf40+/fh6Bn0GXAgMBAAGjgYYwgYMwDgYDVR0PAQH/BAQDAgGGMB0G -A1UdIQQWMBQwEgYHYIV0AVMCAgYHYIV0AVMCAjASBgNVHRMBAf8ECDAGAQH/AgED -MB0GA1UdDgQWBBRF2aWBbj2ITY1x0kbBbkUe88SAnTAfBgNVHSMEGDAWgBRF2aWB -bj2ITY1x0kbBbkUe88SAnTANBgkqhkiG9w0BAQsFAAOCAgEAlDpzBp9SSzBc1P6x -XCX5145v9Ydkn+0UjrgEjihLj6p7jjm02Vj2e6E1CqGdivdj5eu9OYLU43otb98T -PLr+flaYC/NUn81ETm484T4VvwYmneTwkLbUwp4wLh/vx3rEUMfqe9pQy3omywC0 -Wqu1kx+AiYQElY2NfwmTv9SoqORjbdlk5LgpWgi/UOGED1V7XwgiG/W9mR4U9s70 -WBCCswo9GcG/W6uqmdjyMb3lOGbcWAXH7WMaLgqXfIeTK7KK4/HsGOV1timH59yL -Gn602MnTihdsfSlEvoqq9X46Lmgxk7lq2prg2+kupYTNHAq4Sgj5nPFhJpiTt3tm -7JFe3VE/23MPrQRYCd0EApUKPtN236YQHoA96M2kZNEzx5LH4k5E4wnJTsJdhw4S -nr8PyQUQ3nqjsTzyP6WqJ3mtMX0f/fwZacXduT98zca0wjAefm6S139hdlqP65VN -vBFuIXxZN5nQBrz5Bm0yFqXZaajh3DyAHmBR3NdUIR7KYndP+tiPsys6DXhyyWhB -WkdKwqPrGtcKqzwyVcgKEZzfdNbwQBUdyLmPtTbFr/giuMod89a2GQ+fYWVq6nTI -fI/DT11lgh/ZDYnadXL77/FHZxOzyNEZiCcmmpl5fx7kLD977vHeTYuWl8PVP3wb -I+2ksx0WckNLIOFZfsLorSa/ovc= ------END CERTIFICATE----- diff --git a/chromium/net/data/ssl/ev_roots/e7685634efacf69ace939a6b255b7b4fabef42935b50a265acb5cb6027e44e70.pem b/chromium/net/data/ssl/ev_roots/e7685634efacf69ace939a6b255b7b4fabef42935b50a265acb5cb6027e44e70.pem deleted file mode 100644 index c35c26eb4ed..00000000000 --- a/chromium/net/data/ssl/ev_roots/e7685634efacf69ace939a6b255b7b4fabef42935b50a265acb5cb6027e44e70.pem +++ /dev/null @@ -1,48 +0,0 @@ -Certificate: - Data: - Version: 1 (0x0) - Serial Number: - 70:ba:e4:1d:10:d9:29:34:b6:38:ca:7b:03:cc:ba:bf - Signature Algorithm: md2WithRSAEncryption - Issuer: C=US, O=VeriSign, Inc., OU=Class 3 Public Primary Certification Authority - Validity - Not Before: Jan 29 00:00:00 1996 GMT - Not After : Aug 1 23:59:59 2028 GMT - Subject: C=US, O=VeriSign, Inc., OU=Class 3 Public Primary Certification Authority - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (1024 bit) - Modulus: - 00:c9:5c:59:9e:f2:1b:8a:01:14:b4:10:df:04:40: - db:e3:57:af:6a:45:40:8f:84:0c:0b:d1:33:d9:d9: - 11:cf:ee:02:58:1f:25:f7:2a:a8:44:05:aa:ec:03: - 1f:78:7f:9e:93:b9:9a:00:aa:23:7d:d6:ac:85:a2: - 63:45:c7:72:27:cc:f4:4c:c6:75:71:d2:39:ef:4f: - 42:f0:75:df:0a:90:c6:8e:20:6f:98:0f:f8:ac:23: - 5f:70:29:36:a4:c9:86:e7:b1:9a:20:cb:53:a5:85: - e7:3d:be:7d:9a:fe:24:45:33:dc:76:15:ed:0f:a2: - 71:64:4c:65:2e:81:68:45:a7 - Exponent: 65537 (0x10001) - Signature Algorithm: md2WithRSAEncryption - bb:4c:12:2b:cf:2c:26:00:4f:14:13:dd:a6:fb:fc:0a:11:84: - 8c:f3:28:1c:67:92:2f:7c:b6:c5:fa:df:f0:e8:95:bc:1d:8f: - 6c:2c:a8:51:cc:73:d8:a4:c0:53:f0:4e:d6:26:c0:76:01:57: - 81:92:5e:21:f1:d1:b1:ff:e7:d0:21:58:cd:69:17:e3:44:1c: - 9c:19:44:39:89:5c:dc:9c:00:0f:56:8d:02:99:ed:a2:90:45: - 4c:e4:bb:10:a4:3d:f0:32:03:0e:f1:ce:f8:e8:c9:51:8c:e6: - 62:9f:e6:9f:c0:7d:b7:72:9c:c9:36:3a:6b:9f:4e:a8:ff:64: - 0d:64 ------BEGIN CERTIFICATE----- -MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkG -A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz -cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2 -MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV -BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt -YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN -ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE -BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is -I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G -CSqGSIb3DQEBAgUAA4GBALtMEivPLCYATxQT3ab7/AoRhIzzKBxnki98tsX63/Do -lbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59AhWM1pF+NEHJwZRDmJXNyc -AA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2OmufTqj/ZA1k ------END CERTIFICATE----- diff --git a/chromium/net/data/ssl/scripts/generate-test-certs.sh b/chromium/net/data/ssl/scripts/generate-test-certs.sh index 6a195fac246..e3f539b35fe 100755 --- a/chromium/net/data/ssl/scripts/generate-test-certs.sh +++ b/chromium/net/data/ssl/scripts/generate-test-certs.sh @@ -16,7 +16,7 @@ set -e -x # The current built-in verifier max lifetime is 39 months # The current OS verifier max lifetime is 825 days, which comes from # iOS 13/macOS 10.15 - https://support.apple.com/en-us/HT210176 -# 731 is used here as just a short-hand for 2 years +# 730 is used here as just a short-hand for 2 years CERT_LIFETIME=730 rm -rf out @@ -461,6 +461,44 @@ CA_NAME="req_ca_dn" \ -out ../certificates/pre_june_2016.pem \ -config ca.cnf +# Issued after 2020-09-01, lifetime == 399 days (bad) +openssl req -config ../scripts/ee.cnf \ + -newkey rsa:2048 -text -out out/399_days_after_2020_09_01.req +CA_NAME="req_ca_dn" \ + openssl ca \ + -batch \ + -extensions user_cert \ + -startdate 200902000000Z \ + -enddate 211006000000Z \ + -in out/399_days_after_2020_09_01.req \ + -out ../certificates/399_days_after_2020_09_01.pem \ + -config ca.cnf +# Issued after 2020-09-01, lifetime == 398 days (good) +openssl req -config ../scripts/ee.cnf \ + -newkey rsa:2048 -text -out out/398_days_after_2020_09_01.req +CA_NAME="req_ca_dn" \ + openssl ca \ + -batch \ + -extensions user_cert \ + -startdate 200902000000Z \ + -enddate 211005000000Z \ + -in out/398_days_after_2020_09_01.req \ + -out ../certificates/398_days_after_2020_09_01.pem \ + -config ca.cnf +# Issued after 2020-09-01, lifetime == 825 days and one second (bad) +openssl req -config ../scripts/ee.cnf \ + -newkey rsa:2048 -text -out out/398_days_1_second_after_2020_09_01.req +CA_NAME="req_ca_dn" \ + openssl ca \ + -batch \ + -extensions user_cert \ + -startdate 200902000000Z \ + -enddate 211005000001Z \ + -in out/398_days_1_second_after_2020_09_01.req \ + -out ../certificates/398_days_1_second_after_2020_09_01.pem \ + -config ca.cnf + + # Issued after 1 June 2016 (Symantec CT Enforcement Date) openssl req -config ../scripts/ee.cnf \ -newkey rsa:2048 -text -out out/post_june_2016.req diff --git a/chromium/net/data/websocket/close_observer.html b/chromium/net/data/websocket/close_observer.html index e0bf4df290e..759f81b44b2 100644 --- a/chromium/net/data/websocket/close_observer.html +++ b/chromium/net/data/websocket/close_observer.html @@ -9,20 +9,22 @@ let url = protocol + '//' + location.host + '/close-observer?role=observer'; // Do connection test. let ws = new WebSocket(url); +const id = setTimeout(() => { + console.log('close_observer.html had timeout'); + document.title = 'FAIL'; +}, 3000); + ws.onmessage = e => { + clearTimeout(id); console.log('close_observer.html got message: ' + e.data); document.title = (e.data === 'OK' ? 'PASS' : 'FAIL'); ws.onclose = null; } ws.onclose = () => { + clearTimeout(id); console.log('close_observer.html saw close with no message'); document.title = 'FAIL'; } -setTimeout(() => { - console.log('close_observer.html had timeout'); - document.title = 'FAIL'; -}, 1000); - </script> diff --git a/chromium/net/der/tag.h b/chromium/net/der/tag.h index 82d3b257e78..c7dda941f98 100644 --- a/chromium/net/der/tag.h +++ b/chromium/net/der/tag.h @@ -60,7 +60,7 @@ const unsigned kTagNumberMask = CBS_ASN1_TAG_NUMBER_MASK; const unsigned kTagConstructionMask = CBS_ASN1_CONSTRUCTED; const unsigned kTagClassMask = CBS_ASN1_CLASS_MASK; -// Creates the value for the outter tag of an explicitly tagged type. +// Creates the value for the outer tag of an explicitly tagged type. // // The ASN.1 keyword for this is: // [tag_number] EXPLICIT diff --git a/chromium/net/disk_cache/backend_unittest.cc b/chromium/net/disk_cache/backend_unittest.cc index 8f88d07a799..e64900765eb 100644 --- a/chromium/net/disk_cache/backend_unittest.cc +++ b/chromium/net/disk_cache/backend_unittest.cc @@ -5279,3 +5279,38 @@ TEST_F(DiskCacheBackendTest, SimpleDontLeakPostDoomCreate) { // Should not have leaked files here. } + +TEST_F(DiskCacheBackendTest, BlockFileDelayedWriteFailureRecovery) { + // Test that blockfile recovers appropriately when some entries are + // in a screwed up state due to an error in delayed writeback. + // + // https://crbug.com/1086727 + InitCache(); + + const char kKey[] = "Key2"; + disk_cache::Entry* entry = nullptr; + ASSERT_THAT(CreateEntry(kKey, &entry), IsOk()); + + const int kBufSize = 24320; + scoped_refptr<net::IOBuffer> buffer = + base::MakeRefCounted<net::IOBuffer>(kBufSize); + CacheTestFillBuffer(buffer->data(), kBufSize, true); + + ASSERT_EQ(kBufSize, WriteSparseData(entry, 0, buffer.get(), kBufSize)); + + // Setting the size limit artificially low injects a failure on writing back + // data buffered above. + SetMaxSize(4096); + + // This causes SparseControl to close the child entry corresponding to + // low portion of offset space, triggering the writeback --- which fails + // due to the space cap, and in particular fails to allocate data for + // a stream, so it gets address 0. + ASSERT_EQ(net::ERR_FAILED, WriteSparseData(entry, 16773118, buffer.get(), 4)); + + // Now try reading the broken child. This should report an error, not + // DCHECK. + ASSERT_EQ(net::ERR_FAILED, ReadSparseData(entry, 4, buffer.get(), 4)); + + entry->Close(); +} diff --git a/chromium/net/disk_cache/blockfile/addr.h b/chromium/net/disk_cache/blockfile/addr.h index 32e035eac99..c7a9a2ae614 100644 --- a/chromium/net/disk_cache/blockfile/addr.h +++ b/chromium/net/disk_cache/blockfile/addr.h @@ -11,7 +11,7 @@ #include <stddef.h> #include <stdint.h> -#include "base/logging.h" +#include "base/notreached.h" #include "net/base/net_export.h" #include "net/disk_cache/blockfile/disk_format_base.h" diff --git a/chromium/net/disk_cache/blockfile/entry_impl.cc b/chromium/net/disk_cache/blockfile/entry_impl.cc index 668101caf45..e83e5475851 100644 --- a/chromium/net/disk_cache/blockfile/entry_impl.cc +++ b/chromium/net/disk_cache/blockfile/entry_impl.cc @@ -1064,7 +1064,6 @@ int EntryImpl::InternalReadData(int index, } address.set_value(entry_.Data()->data_addr[index]); - DCHECK(address.is_initialized()); if (!address.is_initialized()) { DoomImpl(); return net::ERR_FAILED; diff --git a/chromium/net/disk_cache/blockfile/in_flight_io.h b/chromium/net/disk_cache/blockfile/in_flight_io.h index 6857d370946..9ab21762baf 100644 --- a/chromium/net/disk_cache/blockfile/in_flight_io.h +++ b/chromium/net/disk_cache/blockfile/in_flight_io.h @@ -7,7 +7,7 @@ #include <set> -#include "base/logging.h" +#include "base/check.h" #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/synchronization/lock.h" diff --git a/chromium/net/disk_cache/blockfile/mapped_file_posix.cc b/chromium/net/disk_cache/blockfile/mapped_file_posix.cc index 99cf49c1890..7921ffdf40f 100644 --- a/chromium/net/disk_cache/blockfile/mapped_file_posix.cc +++ b/chromium/net/disk_cache/blockfile/mapped_file_posix.cc @@ -16,24 +16,24 @@ namespace disk_cache { void* MappedFile::Init(const base::FilePath& name, size_t size) { DCHECK(!init_); if (init_ || !File::Init(name)) - return NULL; + return nullptr; size_t temp_len = size ? size : 4096; if (!size) size = GetLength(); - buffer_ = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, + buffer_ = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, platform_file(), 0); init_ = true; view_size_ = size; DPLOG_IF(FATAL, buffer_ == MAP_FAILED) << "Failed to mmap " << name.value(); if (buffer_ == MAP_FAILED) - buffer_ = 0; + buffer_ = nullptr; // Make sure we detect hardware failures reading the headers. std::unique_ptr<char[]> temp(new char[temp_len]); if (!Read(temp.get(), temp_len, 0)) - return NULL; + return nullptr; return buffer_; } diff --git a/chromium/net/disk_cache/blockfile/stress_support.h b/chromium/net/disk_cache/blockfile/stress_support.h index 2f07de83e0c..b4d3a6be0c6 100644 --- a/chromium/net/disk_cache/blockfile/stress_support.h +++ b/chromium/net/disk_cache/blockfile/stress_support.h @@ -5,7 +5,8 @@ #ifndef NET_DISK_CACHE_BLOCKFILE_STRESS_SUPPORT_H_ #define NET_DISK_CACHE_BLOCKFILE_STRESS_SUPPORT_H_ -#include "base/logging.h" +#include "base/check.h" +#include "base/notreached.h" namespace disk_cache { diff --git a/chromium/net/disk_cache/entry_unittest.cc b/chromium/net/disk_cache/entry_unittest.cc index 1e3226a2642..68b8319898c 100644 --- a/chromium/net/disk_cache/entry_unittest.cc +++ b/chromium/net/disk_cache/entry_unittest.cc @@ -2974,7 +2974,6 @@ bool DiskCacheEntryTest::SimpleCacheMakeBadChecksumEntry(const std::string& key, } TEST_F(DiskCacheEntryTest, SimpleCacheBadChecksum) { - base::HistogramTester histogram_tester; SetSimpleCacheMode(); InitCache(); @@ -2994,14 +2993,10 @@ TEST_F(DiskCacheEntryTest, SimpleCacheBadChecksum) { base::MakeRefCounted<net::IOBuffer>(kLargeSize); EXPECT_EQ(net::ERR_CACHE_CHECKSUM_MISMATCH, ReadData(entry, 1, 0, read_buffer.get(), kLargeSize)); - histogram_tester.ExpectUniqueSample( - "SimpleCache.Http.ReadResult", - disk_cache::READ_RESULT_SYNC_CHECKSUM_FAILURE, 1); } // Tests that an entry that has had an IO error occur can still be Doomed(). TEST_F(DiskCacheEntryTest, SimpleCacheErrorThenDoom) { - base::HistogramTester histogram_tester; SetSimpleCacheMode(); InitCache(); @@ -3020,9 +3015,6 @@ TEST_F(DiskCacheEntryTest, SimpleCacheErrorThenDoom) { base::MakeRefCounted<net::IOBuffer>(kLargeSize); EXPECT_EQ(net::ERR_CACHE_CHECKSUM_MISMATCH, ReadData(entry, 1, 0, read_buffer.get(), kLargeSize)); - histogram_tester.ExpectUniqueSample( - "SimpleCache.Http.ReadResult", - disk_cache::READ_RESULT_SYNC_CHECKSUM_FAILURE, 1); entry->Doom(); // Should not crash. } @@ -5540,22 +5532,17 @@ class DiskCacheSimplePrefetchTest : public DiskCacheEntryTest { } void SetupFullAndTrailerPrefetch(int full_size, - bool trailer_hint, int trailer_speculative_size) { std::map<std::string, std::string> params; params[disk_cache::kSimpleCacheFullPrefetchBytesParam] = base::NumberToString(full_size); - params[disk_cache::kSimpleCacheTrailerPrefetchHintParam] = - trailer_hint ? "true" : "false"; params[disk_cache::kSimpleCacheTrailerPrefetchSpeculativeBytesParam] = base::NumberToString(trailer_speculative_size); scoped_feature_list_.InitAndEnableFeatureWithParameters( disk_cache::kSimpleCachePrefetchExperiment, params); } - void SetupFullPrefetch(int size) { - SetupFullAndTrailerPrefetch(size, false, 0); - } + void SetupFullPrefetch(int size) { SetupFullAndTrailerPrefetch(size, 0); } void InitCacheAndCreateEntry(const std::string& key) { SetSimpleCacheMode(); @@ -5597,12 +5584,21 @@ class DiskCacheSimplePrefetchTest : public DiskCacheEntryTest { entry->Close(); } - void TryRead(const std::string& key) { + void TryRead(const std::string& key, bool expect_preread_stream1) { disk_cache::Entry* entry = nullptr; ASSERT_THAT(OpenEntry(key, &entry), IsOk()); scoped_refptr<net::IOBuffer> read_buf = base::MakeRefCounted<net::IOBuffer>(kEntrySize); - EXPECT_EQ(kEntrySize, ReadData(entry, 1, 0, read_buf.get(), kEntrySize)); + net::TestCompletionCallback cb; + int rv = entry->ReadData(1, 0, read_buf.get(), kEntrySize, cb.callback()); + + // if preload happened, sync reply is expected. + if (expect_preread_stream1) + EXPECT_EQ(kEntrySize, rv); + else + EXPECT_EQ(net::ERR_IO_PENDING, rv); + rv = cb.GetResult(rv); + EXPECT_EQ(kEntrySize, rv); EXPECT_EQ(0, memcmp(read_buf->data(), payload_->data(), kEntrySize)); entry->Close(); } @@ -5618,12 +5614,10 @@ TEST_F(DiskCacheSimplePrefetchTest, NoPrefetch) { const char kKey[] = "a key"; InitCacheAndCreateEntry(kKey); - TryRead(kKey); + TryRead(kKey, /* expect_preread_stream1 */ false); histogram_tester.ExpectUniqueSample("SimpleCache.Http.SyncOpenPrefetchMode", disk_cache::OPEN_PREFETCH_NONE, 1); - histogram_tester.ExpectUniqueSample( - "SimpleCache.Http.ReadStream1FromPrefetched", false, 1); } TEST_F(DiskCacheSimplePrefetchTest, YesPrefetch) { @@ -5632,12 +5626,10 @@ TEST_F(DiskCacheSimplePrefetchTest, YesPrefetch) { const char kKey[] = "a key"; InitCacheAndCreateEntry(kKey); - TryRead(kKey); + TryRead(kKey, /* expect_preread_stream1 */ true); histogram_tester.ExpectUniqueSample("SimpleCache.Http.SyncOpenPrefetchMode", disk_cache::OPEN_PREFETCH_FULL, 1); - histogram_tester.ExpectUniqueSample( - "SimpleCache.Http.ReadStream1FromPrefetched", true, 1); } TEST_F(DiskCacheSimplePrefetchTest, YesPrefetchNoRead) { @@ -5653,12 +5645,6 @@ TEST_F(DiskCacheSimplePrefetchTest, YesPrefetchNoRead) { histogram_tester.ExpectUniqueSample("SimpleCache.Http.SyncOpenPrefetchMode", disk_cache::OPEN_PREFETCH_FULL, 1); - // Have to use GetHistogramSamplesSinceCreation here since it's the only - // API that handles the cases where the histogram hasn't even been created. - std::unique_ptr<base::HistogramSamples> samples( - histogram_tester.GetHistogramSamplesSinceCreation( - "SimpleCache.Http.ReadStream1FromPrefetched")); - EXPECT_EQ(0, samples->TotalCount()); } // This makes sure we detect checksum error on entry that's small enough to be @@ -5685,11 +5671,8 @@ TEST_F(DiskCacheSimplePrefetchTest, ChecksumNoPrefetch) { SetupFullPrefetch(0); const char kKey[] = "a key"; InitCacheAndCreateEntry(kKey); - TryRead(kKey); + TryRead(kKey, /* expect_preread_stream1 */ false); - // Expect 2 CRCs --- stream 0 and stream 1. - histogram_tester.ExpectUniqueSample("SimpleCache.Http.SyncCheckEOFHasCrc", - true, 2); histogram_tester.ExpectUniqueSample("SimpleCache.Http.SyncCheckEOFResult", disk_cache::CHECK_EOF_RESULT_SUCCESS, 2); } @@ -5700,14 +5683,8 @@ TEST_F(DiskCacheSimplePrefetchTest, NoChecksumNoPrefetch) { SetupFullPrefetch(0); const char kKey[] = "a key"; InitCacheAndCreateEntryWithNoCrc(kKey); - TryRead(kKey); + TryRead(kKey, /* expect_preread_stream1 */ false); - // Stream 0 has CRC, stream 1 doesn't. - histogram_tester.ExpectBucketCount("SimpleCache.Http.SyncCheckEOFHasCrc", - true, 1); - histogram_tester.ExpectBucketCount("SimpleCache.Http.SyncCheckEOFHasCrc", - false, 1); - // EOF check is recorded even if there is no CRC there. histogram_tester.ExpectUniqueSample("SimpleCache.Http.SyncCheckEOFResult", disk_cache::CHECK_EOF_RESULT_SUCCESS, 2); } @@ -5718,11 +5695,8 @@ TEST_F(DiskCacheSimplePrefetchTest, ChecksumPrefetch) { SetupFullPrefetch(2 * kEntrySize); const char kKey[] = "a key"; InitCacheAndCreateEntry(kKey); - TryRead(kKey); + TryRead(kKey, /* expect_preread_stream1 */ true); - // Expect 2 CRCs --- stream 0 and stream 1. - histogram_tester.ExpectUniqueSample("SimpleCache.Http.SyncCheckEOFHasCrc", - true, 2); histogram_tester.ExpectUniqueSample("SimpleCache.Http.SyncCheckEOFResult", disk_cache::CHECK_EOF_RESULT_SUCCESS, 2); } @@ -5733,13 +5707,8 @@ TEST_F(DiskCacheSimplePrefetchTest, NoChecksumPrefetch) { SetupFullPrefetch(2 * kEntrySize); const char kKey[] = "a key"; InitCacheAndCreateEntryWithNoCrc(kKey); - TryRead(kKey); + TryRead(kKey, /* expect_preread_stream1 */ true); - // Stream 0 has CRC, stream 1 doesn't. - histogram_tester.ExpectBucketCount("SimpleCache.Http.SyncCheckEOFHasCrc", - true, 1); - histogram_tester.ExpectBucketCount("SimpleCache.Http.SyncCheckEOFHasCrc", - false, 1); // EOF check is recorded even if there is no CRC there. histogram_tester.ExpectUniqueSample("SimpleCache.Http.SyncCheckEOFResult", disk_cache::CHECK_EOF_RESULT_SUCCESS, 2); @@ -5765,240 +5734,119 @@ TEST_F(DiskCacheSimplePrefetchTest, PrefetchReadsSync) { entry->Close(); } -TEST_F(DiskCacheSimplePrefetchTest, NoFullNoHintNoSpeculative) { - base::HistogramTester histogram_tester; - SetupFullAndTrailerPrefetch(0, false, 0); - - const char kKey[] = "a key"; - InitCacheAndCreateEntry(kKey); - TryRead(kKey); - - histogram_tester.ExpectUniqueSample("SimpleCache.Http.SyncOpenPrefetchMode", - disk_cache::OPEN_PREFETCH_NONE, 1); - histogram_tester.ExpectTotalCount("SimpleCache.Http.EntryTrailerPrefetchSize", - 0); - histogram_tester.ExpectTotalCount("SimpleCache.Http.EntryTrailerSize", 1); - histogram_tester.ExpectTotalCount( - "SimpleCache.Http.EntryTrailerPrefetchDelta", 0); - histogram_tester.ExpectUniqueSample( - "SimpleCache.Http.ReadStream1FromPrefetched", false, 1); -} - -TEST_F(DiskCacheSimplePrefetchTest, NoFullYesHintNoSpeculative) { +TEST_F(DiskCacheSimplePrefetchTest, NoFullNoSpeculative) { base::HistogramTester histogram_tester; - // Trailer prefetch hint should do nothing outside of APP_CACHE mode. - SetupFullAndTrailerPrefetch(0, true, 0); + SetupFullAndTrailerPrefetch(0, 0); const char kKey[] = "a key"; InitCacheAndCreateEntry(kKey); - TryRead(kKey); + TryRead(kKey, /* expect_preread_stream1 */ false); histogram_tester.ExpectUniqueSample("SimpleCache.Http.SyncOpenPrefetchMode", disk_cache::OPEN_PREFETCH_NONE, 1); histogram_tester.ExpectTotalCount("SimpleCache.Http.EntryTrailerPrefetchSize", 0); - histogram_tester.ExpectTotalCount("SimpleCache.Http.EntryTrailerSize", 1); histogram_tester.ExpectTotalCount( "SimpleCache.Http.EntryTrailerPrefetchDelta", 0); - histogram_tester.ExpectUniqueSample( - "SimpleCache.Http.ReadStream1FromPrefetched", false, 1); } -TEST_F(DiskCacheSimplePrefetchTest, NoFullNoHintSmallSpeculative) { +TEST_F(DiskCacheSimplePrefetchTest, NoFullSmallSpeculative) { base::HistogramTester histogram_tester; - SetupFullAndTrailerPrefetch(0, false, kEntrySize / 2); + SetupFullAndTrailerPrefetch(0, kEntrySize / 2); const char kKey[] = "a key"; InitCacheAndCreateEntry(kKey); - TryRead(kKey); + TryRead(kKey, /* expect_preread_stream1 */ false); histogram_tester.ExpectUniqueSample("SimpleCache.Http.SyncOpenPrefetchMode", disk_cache::OPEN_PREFETCH_TRAILER, 1); histogram_tester.ExpectTotalCount("SimpleCache.Http.EntryTrailerPrefetchSize", 1); - histogram_tester.ExpectTotalCount("SimpleCache.Http.EntryTrailerSize", 1); histogram_tester.ExpectTotalCount( "SimpleCache.Http.EntryTrailerPrefetchDelta", 1); - histogram_tester.ExpectUniqueSample( - "SimpleCache.Http.ReadStream1FromPrefetched", false, 1); } -TEST_F(DiskCacheSimplePrefetchTest, NoFullNoHintLargeSpeculative) { +TEST_F(DiskCacheSimplePrefetchTest, NoFullLargeSpeculative) { base::HistogramTester histogram_tester; // A large speculative trailer prefetch that exceeds the entry file // size should effectively trigger full prefetch behavior. - SetupFullAndTrailerPrefetch(0, false, kEntrySize * 2); + SetupFullAndTrailerPrefetch(0, kEntrySize * 2); const char kKey[] = "a key"; InitCacheAndCreateEntry(kKey); - TryRead(kKey); + TryRead(kKey, /* expect_preread_stream1 */ true); histogram_tester.ExpectUniqueSample("SimpleCache.Http.SyncOpenPrefetchMode", disk_cache::OPEN_PREFETCH_FULL, 1); histogram_tester.ExpectTotalCount("SimpleCache.Http.EntryTrailerPrefetchSize", 0); - histogram_tester.ExpectTotalCount("SimpleCache.Http.EntryTrailerSize", 1); histogram_tester.ExpectTotalCount( "SimpleCache.Http.EntryTrailerPrefetchDelta", 0); - histogram_tester.ExpectUniqueSample( - "SimpleCache.Http.ReadStream1FromPrefetched", true, 1); } -TEST_F(DiskCacheSimplePrefetchTest, NoFullYesHintSmallSpeculative) { +TEST_F(DiskCacheSimplePrefetchTest, SmallFullNoSpeculative) { base::HistogramTester histogram_tester; - // Trailer prefetch hint should do nothing outside of APP_CACHE mode. - SetupFullAndTrailerPrefetch(0, true, kEntrySize / 2); + SetupFullAndTrailerPrefetch(kEntrySize / 2, 0); const char kKey[] = "a key"; InitCacheAndCreateEntry(kKey); - TryRead(kKey); - - histogram_tester.ExpectUniqueSample("SimpleCache.Http.SyncOpenPrefetchMode", - disk_cache::OPEN_PREFETCH_TRAILER, 1); - histogram_tester.ExpectTotalCount("SimpleCache.Http.EntryTrailerPrefetchSize", - 1); - histogram_tester.ExpectTotalCount("SimpleCache.Http.EntryTrailerSize", 1); - histogram_tester.ExpectTotalCount( - "SimpleCache.Http.EntryTrailerPrefetchDelta", 1); - histogram_tester.ExpectUniqueSample( - "SimpleCache.Http.ReadStream1FromPrefetched", false, 1); -} - -TEST_F(DiskCacheSimplePrefetchTest, NoFullYesHintLargeSpeculative) { - base::HistogramTester histogram_tester; - // Trailer prefetch hint should do nothing outside of APP_CACHE mode. - SetupFullAndTrailerPrefetch(0, true, kEntrySize * 2); - - const char kKey[] = "a key"; - InitCacheAndCreateEntry(kKey); - TryRead(kKey); - - histogram_tester.ExpectUniqueSample("SimpleCache.Http.SyncOpenPrefetchMode", - disk_cache::OPEN_PREFETCH_FULL, 1); - histogram_tester.ExpectTotalCount("SimpleCache.Http.EntryTrailerPrefetchSize", - 0); - histogram_tester.ExpectTotalCount("SimpleCache.Http.EntryTrailerSize", 1); - histogram_tester.ExpectTotalCount( - "SimpleCache.Http.EntryTrailerPrefetchDelta", 0); - histogram_tester.ExpectUniqueSample( - "SimpleCache.Http.ReadStream1FromPrefetched", true, 1); -} - -TEST_F(DiskCacheSimplePrefetchTest, SmallFullNoHintNoSpeculative) { - base::HistogramTester histogram_tester; - SetupFullAndTrailerPrefetch(kEntrySize / 2, false, 0); - - const char kKey[] = "a key"; - InitCacheAndCreateEntry(kKey); - TryRead(kKey); + TryRead(kKey, /* expect_preread_stream1 */ false); histogram_tester.ExpectUniqueSample("SimpleCache.Http.SyncOpenPrefetchMode", disk_cache::OPEN_PREFETCH_NONE, 1); histogram_tester.ExpectTotalCount("SimpleCache.Http.EntryTrailerPrefetchSize", 0); - histogram_tester.ExpectTotalCount("SimpleCache.Http.EntryTrailerSize", 1); histogram_tester.ExpectTotalCount( "SimpleCache.Http.EntryTrailerPrefetchDelta", 0); - histogram_tester.ExpectUniqueSample( - "SimpleCache.Http.ReadStream1FromPrefetched", false, 1); } -TEST_F(DiskCacheSimplePrefetchTest, LargeFullNoHintNoSpeculative) { +TEST_F(DiskCacheSimplePrefetchTest, LargeFullNoSpeculative) { base::HistogramTester histogram_tester; - SetupFullAndTrailerPrefetch(kEntrySize * 2, false, 0); + SetupFullAndTrailerPrefetch(kEntrySize * 2, 0); const char kKey[] = "a key"; InitCacheAndCreateEntry(kKey); - TryRead(kKey); + TryRead(kKey, /* expect_preread_stream1 */ true); histogram_tester.ExpectUniqueSample("SimpleCache.Http.SyncOpenPrefetchMode", disk_cache::OPEN_PREFETCH_FULL, 1); histogram_tester.ExpectTotalCount("SimpleCache.Http.EntryTrailerPrefetchSize", 0); - histogram_tester.ExpectTotalCount("SimpleCache.Http.EntryTrailerSize", 1); histogram_tester.ExpectTotalCount( "SimpleCache.Http.EntryTrailerPrefetchDelta", 0); - histogram_tester.ExpectUniqueSample( - "SimpleCache.Http.ReadStream1FromPrefetched", true, 1); } -TEST_F(DiskCacheSimplePrefetchTest, SmallFullYesHintNoSpeculative) { +TEST_F(DiskCacheSimplePrefetchTest, SmallFullSmallSpeculative) { base::HistogramTester histogram_tester; - // Trailer prefetch hint should do nothing outside of APP_CACHE mode. - SetupFullAndTrailerPrefetch(kEntrySize / 2, true, 0); + SetupFullAndTrailerPrefetch(kEntrySize / 2, kEntrySize / 2); const char kKey[] = "a key"; InitCacheAndCreateEntry(kKey); - TryRead(kKey); - - histogram_tester.ExpectUniqueSample("SimpleCache.Http.SyncOpenPrefetchMode", - disk_cache::OPEN_PREFETCH_NONE, 1); - histogram_tester.ExpectTotalCount("SimpleCache.Http.EntryTrailerPrefetchSize", - 0); - histogram_tester.ExpectTotalCount("SimpleCache.Http.EntryTrailerSize", 1); - histogram_tester.ExpectTotalCount( - "SimpleCache.Http.EntryTrailerPrefetchDelta", 0); - histogram_tester.ExpectUniqueSample( - "SimpleCache.Http.ReadStream1FromPrefetched", false, 1); -} - -TEST_F(DiskCacheSimplePrefetchTest, LargeFullYesHintNoSpeculative) { - base::HistogramTester histogram_tester; - // Trailer prefetch hint should do nothing outside of APP_CACHE mode. - SetupFullAndTrailerPrefetch(kEntrySize * 2, true, 0); - - const char kKey[] = "a key"; - InitCacheAndCreateEntry(kKey); - TryRead(kKey); - - histogram_tester.ExpectUniqueSample("SimpleCache.Http.SyncOpenPrefetchMode", - disk_cache::OPEN_PREFETCH_FULL, 1); - histogram_tester.ExpectTotalCount("SimpleCache.Http.EntryTrailerPrefetchSize", - 0); - histogram_tester.ExpectTotalCount("SimpleCache.Http.EntryTrailerSize", 1); - histogram_tester.ExpectTotalCount( - "SimpleCache.Http.EntryTrailerPrefetchDelta", 0); - histogram_tester.ExpectUniqueSample( - "SimpleCache.Http.ReadStream1FromPrefetched", true, 1); -} - -TEST_F(DiskCacheSimplePrefetchTest, SmallFullNoHintSmallSpeculative) { - base::HistogramTester histogram_tester; - SetupFullAndTrailerPrefetch(kEntrySize / 2, false, kEntrySize / 2); - - const char kKey[] = "a key"; - InitCacheAndCreateEntry(kKey); - TryRead(kKey); + TryRead(kKey, /* expect_preread_stream1 */ false); histogram_tester.ExpectUniqueSample("SimpleCache.Http.SyncOpenPrefetchMode", disk_cache::OPEN_PREFETCH_TRAILER, 1); histogram_tester.ExpectTotalCount("SimpleCache.Http.EntryTrailerPrefetchSize", 1); - histogram_tester.ExpectTotalCount("SimpleCache.Http.EntryTrailerSize", 1); histogram_tester.ExpectTotalCount( "SimpleCache.Http.EntryTrailerPrefetchDelta", 1); - histogram_tester.ExpectUniqueSample( - "SimpleCache.Http.ReadStream1FromPrefetched", false, 1); } -TEST_F(DiskCacheSimplePrefetchTest, LargeFullNoHintSmallSpeculative) { +TEST_F(DiskCacheSimplePrefetchTest, LargeFullSmallSpeculative) { base::HistogramTester histogram_tester; // Full prefetch takes precedence over a trailer speculative prefetch. - SetupFullAndTrailerPrefetch(kEntrySize * 2, false, kEntrySize / 2); + SetupFullAndTrailerPrefetch(kEntrySize * 2, kEntrySize / 2); const char kKey[] = "a key"; InitCacheAndCreateEntry(kKey); - TryRead(kKey); + TryRead(kKey, /* expect_preread_stream1 */ true); histogram_tester.ExpectUniqueSample("SimpleCache.Http.SyncOpenPrefetchMode", disk_cache::OPEN_PREFETCH_FULL, 1); histogram_tester.ExpectTotalCount("SimpleCache.Http.EntryTrailerPrefetchSize", 0); - histogram_tester.ExpectTotalCount("SimpleCache.Http.EntryTrailerSize", 1); histogram_tester.ExpectTotalCount( "SimpleCache.Http.EntryTrailerPrefetchDelta", 0); - histogram_tester.ExpectUniqueSample( - "SimpleCache.Http.ReadStream1FromPrefetched", true, 1); } class DiskCacheSimpleAppCachePrefetchTest : public DiskCacheSimplePrefetchTest { @@ -6007,237 +5855,119 @@ class DiskCacheSimpleAppCachePrefetchTest : public DiskCacheSimplePrefetchTest { net::CacheType SimpleCacheType() const override { return net::APP_CACHE; } }; -TEST_F(DiskCacheSimpleAppCachePrefetchTest, NoFullNoHintNoSpeculative) { +TEST_F(DiskCacheSimpleAppCachePrefetchTest, NoFullNoSpeculative) { base::HistogramTester histogram_tester; - SetupFullAndTrailerPrefetch(0, false, 0); + SetupFullAndTrailerPrefetch(0, 0); const char kKey[] = "a key"; InitCacheAndCreateEntry(kKey); - TryRead(kKey); - - histogram_tester.ExpectUniqueSample("SimpleCache.App.SyncOpenPrefetchMode", - disk_cache::OPEN_PREFETCH_NONE, 1); - histogram_tester.ExpectTotalCount("SimpleCache.App.EntryTrailerPrefetchSize", - 0); - histogram_tester.ExpectTotalCount("SimpleCache.App.EntryTrailerSize", 1); - histogram_tester.ExpectTotalCount("SimpleCache.App.EntryTrailerPrefetchDelta", - 0); - histogram_tester.ExpectUniqueSample( - "SimpleCache.App.ReadStream1FromPrefetched", false, 1); -} - -TEST_F(DiskCacheSimpleAppCachePrefetchTest, NoFullYesHintNoSpeculative) { - base::HistogramTester histogram_tester; - SetupFullAndTrailerPrefetch(0, true, 0); - - const char kKey[] = "a key"; - InitCacheAndCreateEntry(kKey); - TryRead(kKey); + TryRead(kKey, /* expect_preread_stream1 */ false); histogram_tester.ExpectUniqueSample("SimpleCache.App.SyncOpenPrefetchMode", disk_cache::OPEN_PREFETCH_TRAILER, 1); histogram_tester.ExpectTotalCount("SimpleCache.App.EntryTrailerPrefetchSize", 1); - histogram_tester.ExpectTotalCount("SimpleCache.App.EntryTrailerSize", 1); histogram_tester.ExpectUniqueSample( "SimpleCache.App.EntryTrailerPrefetchDelta", 0, 1); - histogram_tester.ExpectUniqueSample( - "SimpleCache.App.ReadStream1FromPrefetched", false, 1); -} - -TEST_F(DiskCacheSimpleAppCachePrefetchTest, NoFullNoHintSmallSpeculative) { - base::HistogramTester histogram_tester; - SetupFullAndTrailerPrefetch(0, false, kEntrySize / 2); - - const char kKey[] = "a key"; - InitCacheAndCreateEntry(kKey); - TryRead(kKey); - - histogram_tester.ExpectUniqueSample("SimpleCache.App.SyncOpenPrefetchMode", - disk_cache::OPEN_PREFETCH_TRAILER, 1); - histogram_tester.ExpectTotalCount("SimpleCache.App.EntryTrailerPrefetchSize", - 1); - histogram_tester.ExpectTotalCount("SimpleCache.App.EntryTrailerSize", 1); - histogram_tester.ExpectTotalCount("SimpleCache.App.EntryTrailerPrefetchDelta", - 1); - histogram_tester.ExpectUniqueSample( - "SimpleCache.App.ReadStream1FromPrefetched", false, 1); -} - -TEST_F(DiskCacheSimpleAppCachePrefetchTest, NoFullNoHintLargeSpeculative) { - base::HistogramTester histogram_tester; - // A large speculative trailer prefetch that exceeds the entry file - // size should effectively trigger full prefetch behavior. - SetupFullAndTrailerPrefetch(0, false, kEntrySize * 2); - - const char kKey[] = "a key"; - InitCacheAndCreateEntry(kKey); - TryRead(kKey); - - histogram_tester.ExpectUniqueSample("SimpleCache.App.SyncOpenPrefetchMode", - disk_cache::OPEN_PREFETCH_FULL, 1); - histogram_tester.ExpectTotalCount("SimpleCache.App.EntryTrailerPrefetchSize", - 0); - histogram_tester.ExpectTotalCount("SimpleCache.App.EntryTrailerSize", 1); - histogram_tester.ExpectTotalCount("SimpleCache.App.EntryTrailerPrefetchDelta", - 0); - histogram_tester.ExpectUniqueSample( - "SimpleCache.App.ReadStream1FromPrefetched", true, 1); } -TEST_F(DiskCacheSimpleAppCachePrefetchTest, NoFullYesHintSmallSpeculative) { +TEST_F(DiskCacheSimpleAppCachePrefetchTest, NoFullSmallSpeculative) { base::HistogramTester histogram_tester; - SetupFullAndTrailerPrefetch(0, true, kEntrySize / 2); + SetupFullAndTrailerPrefetch(0, kEntrySize / 2); const char kKey[] = "a key"; InitCacheAndCreateEntry(kKey); - TryRead(kKey); + TryRead(kKey, /* expect_preread_stream1 */ false); histogram_tester.ExpectUniqueSample("SimpleCache.App.SyncOpenPrefetchMode", disk_cache::OPEN_PREFETCH_TRAILER, 1); histogram_tester.ExpectTotalCount("SimpleCache.App.EntryTrailerPrefetchSize", 1); - histogram_tester.ExpectTotalCount("SimpleCache.App.EntryTrailerSize", 1); histogram_tester.ExpectUniqueSample( "SimpleCache.App.EntryTrailerPrefetchDelta", 0, 1); - histogram_tester.ExpectUniqueSample( - "SimpleCache.App.ReadStream1FromPrefetched", false, 1); } -TEST_F(DiskCacheSimpleAppCachePrefetchTest, NoFullYesHintLargeSpeculative) { +TEST_F(DiskCacheSimpleAppCachePrefetchTest, NoFullLargeSpeculative) { base::HistogramTester histogram_tester; // Even though the speculative trailer prefetch size is larger than the // file size, the hint should take precedence and still perform a limited // trailer prefetch. - SetupFullAndTrailerPrefetch(0, true, kEntrySize * 2); + SetupFullAndTrailerPrefetch(0, kEntrySize * 2); const char kKey[] = "a key"; InitCacheAndCreateEntry(kKey); - TryRead(kKey); + TryRead(kKey, /* expect_preread_stream1 */ false); histogram_tester.ExpectUniqueSample("SimpleCache.App.SyncOpenPrefetchMode", disk_cache::OPEN_PREFETCH_TRAILER, 1); histogram_tester.ExpectTotalCount("SimpleCache.App.EntryTrailerPrefetchSize", 1); - histogram_tester.ExpectTotalCount("SimpleCache.App.EntryTrailerSize", 1); histogram_tester.ExpectUniqueSample( "SimpleCache.App.EntryTrailerPrefetchDelta", 0, 1); - histogram_tester.ExpectUniqueSample( - "SimpleCache.App.ReadStream1FromPrefetched", false, 1); } -TEST_F(DiskCacheSimpleAppCachePrefetchTest, SmallFullNoHintNoSpeculative) { +TEST_F(DiskCacheSimpleAppCachePrefetchTest, SmallFullNoSpeculative) { base::HistogramTester histogram_tester; - SetupFullAndTrailerPrefetch(kEntrySize / 2, false, 0); + SetupFullAndTrailerPrefetch(kEntrySize / 2, 0); const char kKey[] = "a key"; InitCacheAndCreateEntry(kKey); - TryRead(kKey); - - histogram_tester.ExpectUniqueSample("SimpleCache.App.SyncOpenPrefetchMode", - disk_cache::OPEN_PREFETCH_NONE, 1); - histogram_tester.ExpectTotalCount("SimpleCache.App.EntryTrailerPrefetchSize", - 0); - histogram_tester.ExpectTotalCount("SimpleCache.App.EntryTrailerSize", 1); - histogram_tester.ExpectTotalCount("SimpleCache.App.EntryTrailerPrefetchDelta", - 0); - histogram_tester.ExpectUniqueSample( - "SimpleCache.App.ReadStream1FromPrefetched", false, 1); -} - -TEST_F(DiskCacheSimpleAppCachePrefetchTest, LargeFullNoHintNoSpeculative) { - base::HistogramTester histogram_tester; - SetupFullAndTrailerPrefetch(kEntrySize * 2, false, 0); - - const char kKey[] = "a key"; - InitCacheAndCreateEntry(kKey); - TryRead(kKey); - - histogram_tester.ExpectUniqueSample("SimpleCache.App.SyncOpenPrefetchMode", - disk_cache::OPEN_PREFETCH_FULL, 1); - histogram_tester.ExpectTotalCount("SimpleCache.App.EntryTrailerPrefetchSize", - 0); - histogram_tester.ExpectTotalCount("SimpleCache.App.EntryTrailerSize", 1); - histogram_tester.ExpectTotalCount("SimpleCache.App.EntryTrailerPrefetchDelta", - 0); - histogram_tester.ExpectUniqueSample( - "SimpleCache.App.ReadStream1FromPrefetched", true, 1); -} - -TEST_F(DiskCacheSimpleAppCachePrefetchTest, SmallFullYesHintNoSpeculative) { - base::HistogramTester histogram_tester; - SetupFullAndTrailerPrefetch(kEntrySize / 2, true, 0); - - const char kKey[] = "a key"; - InitCacheAndCreateEntry(kKey); - TryRead(kKey); + TryRead(kKey, /* expect_preread_stream1 */ false); histogram_tester.ExpectUniqueSample("SimpleCache.App.SyncOpenPrefetchMode", disk_cache::OPEN_PREFETCH_TRAILER, 1); histogram_tester.ExpectTotalCount("SimpleCache.App.EntryTrailerPrefetchSize", 1); - histogram_tester.ExpectTotalCount("SimpleCache.App.EntryTrailerSize", 1); histogram_tester.ExpectUniqueSample( "SimpleCache.App.EntryTrailerPrefetchDelta", 0, 1); - histogram_tester.ExpectUniqueSample( - "SimpleCache.App.ReadStream1FromPrefetched", false, 1); } -TEST_F(DiskCacheSimpleAppCachePrefetchTest, LargeFullYesHintNoSpeculative) { +TEST_F(DiskCacheSimpleAppCachePrefetchTest, LargeFullNoSpeculative) { base::HistogramTester histogram_tester; // Full prefetch takes precedence over a trailer hint prefetch. - SetupFullAndTrailerPrefetch(kEntrySize * 2, true, 0); + SetupFullAndTrailerPrefetch(kEntrySize * 2, 0); const char kKey[] = "a key"; InitCacheAndCreateEntry(kKey); - TryRead(kKey); + TryRead(kKey, /* expect_preread_stream1 */ true); histogram_tester.ExpectUniqueSample("SimpleCache.App.SyncOpenPrefetchMode", disk_cache::OPEN_PREFETCH_FULL, 1); histogram_tester.ExpectTotalCount("SimpleCache.App.EntryTrailerPrefetchSize", 0); - histogram_tester.ExpectTotalCount("SimpleCache.App.EntryTrailerSize", 1); histogram_tester.ExpectTotalCount("SimpleCache.App.EntryTrailerPrefetchDelta", 0); - histogram_tester.ExpectUniqueSample( - "SimpleCache.App.ReadStream1FromPrefetched", true, 1); } -TEST_F(DiskCacheSimpleAppCachePrefetchTest, SmallFullNoHintSmallSpeculative) { +TEST_F(DiskCacheSimpleAppCachePrefetchTest, SmallFullSmallSpeculative) { base::HistogramTester histogram_tester; - SetupFullAndTrailerPrefetch(kEntrySize / 2, false, kEntrySize / 2); + SetupFullAndTrailerPrefetch(kEntrySize / 2, kEntrySize / 2); const char kKey[] = "a key"; InitCacheAndCreateEntry(kKey); - TryRead(kKey); + TryRead(kKey, /* expect_preread_stream1 */ false); histogram_tester.ExpectUniqueSample("SimpleCache.App.SyncOpenPrefetchMode", disk_cache::OPEN_PREFETCH_TRAILER, 1); histogram_tester.ExpectTotalCount("SimpleCache.App.EntryTrailerPrefetchSize", 1); - histogram_tester.ExpectTotalCount("SimpleCache.App.EntryTrailerSize", 1); histogram_tester.ExpectTotalCount("SimpleCache.App.EntryTrailerPrefetchDelta", 1); - histogram_tester.ExpectUniqueSample( - "SimpleCache.App.ReadStream1FromPrefetched", false, 1); } -TEST_F(DiskCacheSimpleAppCachePrefetchTest, LargeFullNoHintSmallSpeculative) { +TEST_F(DiskCacheSimpleAppCachePrefetchTest, LargeFullSmallSpeculative) { base::HistogramTester histogram_tester; // Full prefetch takes precedence over a trailer speculative prefetch. - SetupFullAndTrailerPrefetch(kEntrySize * 2, false, kEntrySize / 2); + SetupFullAndTrailerPrefetch(kEntrySize * 2, kEntrySize / 2); const char kKey[] = "a key"; InitCacheAndCreateEntry(kKey); - TryRead(kKey); + TryRead(kKey, /* expect_preread_stream1 */ true); histogram_tester.ExpectUniqueSample("SimpleCache.App.SyncOpenPrefetchMode", disk_cache::OPEN_PREFETCH_FULL, 1); histogram_tester.ExpectTotalCount("SimpleCache.App.EntryTrailerPrefetchSize", 0); - histogram_tester.ExpectTotalCount("SimpleCache.App.EntryTrailerSize", 1); histogram_tester.ExpectTotalCount("SimpleCache.App.EntryTrailerPrefetchDelta", 0); - histogram_tester.ExpectUniqueSample( - "SimpleCache.App.ReadStream1FromPrefetched", true, 1); } diff --git a/chromium/net/disk_cache/memory/mem_backend_impl.cc b/chromium/net/disk_cache/memory/mem_backend_impl.cc index 51a46a0ee29..ea9789f7d49 100644 --- a/chromium/net/disk_cache/memory/mem_backend_impl.cc +++ b/chromium/net/disk_cache/memory/mem_backend_impl.cc @@ -62,6 +62,7 @@ MemBackendImpl::MemBackendImpl(net::NetLog* net_log) current_size_(0), net_log_(net_log), memory_pressure_listener_( + FROM_HERE, base::BindRepeating(&MemBackendImpl::OnMemoryPressure, base::Unretained(this))) {} diff --git a/chromium/net/disk_cache/simple/post_doom_waiter.cc b/chromium/net/disk_cache/simple/post_doom_waiter.cc index 0f355c33462..8814efbfb0e 100644 --- a/chromium/net/disk_cache/simple/post_doom_waiter.cc +++ b/chromium/net/disk_cache/simple/post_doom_waiter.cc @@ -14,8 +14,7 @@ namespace disk_cache { SimplePostDoomWaiter::SimplePostDoomWaiter() {} SimplePostDoomWaiter::SimplePostDoomWaiter(base::OnceClosure to_run_post_doom) - : time_queued(base::TimeTicks::Now()), - run_post_doom(std::move(to_run_post_doom)) {} + : run_post_doom(std::move(to_run_post_doom)) {} SimplePostDoomWaiter::SimplePostDoomWaiter(SimplePostDoomWaiter&& other) = default; @@ -40,12 +39,7 @@ void SimplePostDoomWaiterTable::OnDoomComplete(uint64_t entry_hash) { to_handle_waiters.swap(it->second); entries_pending_doom_.erase(it); - SIMPLE_CACHE_UMA(COUNTS_1000, "NumOpsBlockedByPendingDoom", cache_type_, - to_handle_waiters.size()); - for (SimplePostDoomWaiter& post_doom : to_handle_waiters) { - SIMPLE_CACHE_UMA(TIMES, "QueueLatency.PendingDoom", cache_type_, - (base::TimeTicks::Now() - post_doom.time_queued)); std::move(post_doom.run_post_doom).Run(); } } diff --git a/chromium/net/disk_cache/simple/post_doom_waiter.h b/chromium/net/disk_cache/simple/post_doom_waiter.h index a7b42682ff2..1dff54bde84 100644 --- a/chromium/net/disk_cache/simple/post_doom_waiter.h +++ b/chromium/net/disk_cache/simple/post_doom_waiter.h @@ -19,13 +19,11 @@ namespace disk_cache { struct SimplePostDoomWaiter { SimplePostDoomWaiter(); - // Also initializes |time_queued|. explicit SimplePostDoomWaiter(base::OnceClosure to_run_post_doom); explicit SimplePostDoomWaiter(SimplePostDoomWaiter&& other); ~SimplePostDoomWaiter(); SimplePostDoomWaiter& operator=(SimplePostDoomWaiter&& other); - base::TimeTicks time_queued; base::OnceClosure run_post_doom; }; diff --git a/chromium/net/disk_cache/simple/simple_entry_impl.cc b/chromium/net/disk_cache/simple/simple_entry_impl.cc index 2e3eadcb2d5..5dfa78c1b07 100644 --- a/chromium/net/disk_cache/simple/simple_entry_impl.cc +++ b/chromium/net/disk_cache/simple/simple_entry_impl.cc @@ -45,17 +45,6 @@ namespace { // the cache. const int64_t kMaxSparseDataSizeDivisor = 10; -// Used in histograms, please only add entries at the end. -enum SimpleEntryWriteResult { - SIMPLE_ENTRY_WRITE_RESULT_SUCCESS = 0, - SIMPLE_ENTRY_WRITE_RESULT_INVALID_ARGUMENT = 1, - SIMPLE_ENTRY_WRITE_RESULT_OVER_MAX_SIZE = 2, - SIMPLE_ENTRY_WRITE_RESULT_BAD_STATE = 3, - SIMPLE_ENTRY_WRITE_RESULT_SYNC_WRITE_FAILURE = 4, - SIMPLE_ENTRY_WRITE_RESULT_FAST_EMPTY_RETURN = 5, - SIMPLE_ENTRY_WRITE_RESULT_MAX = 6, -}; - OpenEntryIndexEnum ComputeIndexState(SimpleBackendImpl* backend, uint64_t entry_hash) { if (!backend->index()->initialized()) @@ -71,17 +60,6 @@ void RecordOpenEntryIndexState(net::CacheType cache_type, INDEX_MAX); } -void RecordReadResult(net::CacheType cache_type, SimpleReadResult result) { - SIMPLE_CACHE_UMA(ENUMERATION, - "ReadResult", cache_type, result, READ_RESULT_MAX); -} - -void RecordWriteResult(net::CacheType cache_type, - SimpleEntryWriteResult result) { - SIMPLE_CACHE_UMA(ENUMERATION, "WriteResult2", cache_type, result, - SIMPLE_ENTRY_WRITE_RESULT_MAX); -} - void RecordHeaderSize(net::CacheType cache_type, int size) { SIMPLE_CACHE_UMA(COUNTS_10000, "HeaderSize", cache_type, size); } @@ -426,7 +404,6 @@ int SimpleEntryImpl::ReadData(int stream_index, net::NetLogEventPhase::NONE, net::ERR_INVALID_ARGUMENT); } - RecordReadResult(cache_type_, READ_RESULT_INVALID_ARGUMENT); return net::ERR_INVALID_ARGUMENT; } @@ -469,7 +446,6 @@ int SimpleEntryImpl::WriteData(int stream_index, net_log_, net::NetLogEventType::SIMPLE_CACHE_ENTRY_WRITE_END, net::NetLogEventPhase::NONE, net::ERR_INVALID_ARGUMENT); } - RecordWriteResult(cache_type_, SIMPLE_ENTRY_WRITE_RESULT_INVALID_ARGUMENT); return net::ERR_INVALID_ARGUMENT; } int end_offset; @@ -480,7 +456,6 @@ int SimpleEntryImpl::WriteData(int stream_index, net_log_, net::NetLogEventType::SIMPLE_CACHE_ENTRY_WRITE_END, net::NetLogEventPhase::NONE, net::ERR_FAILED); } - RecordWriteResult(cache_type_, SIMPLE_ENTRY_WRITE_RESULT_OVER_MAX_SIZE); return net::ERR_FAILED; } ScopedOperationRunner operation_runner(this); @@ -853,7 +828,7 @@ void SimpleEntryImpl::OpenEntryInternal( base::OnceClosure task = base::BindOnce( &SimpleSynchronousEntry::OpenEntry, cache_type_, path_, key_, entry_hash_, - start_time, file_tracker_, trailer_prefetch_size, results.get()); + file_tracker_, trailer_prefetch_size, results.get()); base::OnceClosure reply = base::BindOnce( &SimpleEntryImpl::CreationOperationComplete, this, result_state, @@ -897,9 +872,9 @@ void SimpleEntryImpl::CreateEntryInternal( new SimpleEntryCreationResults(SimpleEntryStat( last_used_, last_modified_, data_size_, sparse_data_size_))); - OnceClosure task = base::BindOnce(&SimpleSynchronousEntry::CreateEntry, - cache_type_, path_, key_, entry_hash_, - start_time, file_tracker_, results.get()); + OnceClosure task = + base::BindOnce(&SimpleSynchronousEntry::CreateEntry, cache_type_, path_, + key_, entry_hash_, file_tracker_, results.get()); OnceClosure reply = base::BindOnce( &SimpleEntryImpl::CreationOperationComplete, this, result_state, std::move(callback), start_time, base::Time(), std::move(results), @@ -958,10 +933,10 @@ void SimpleEntryImpl::OpenOrCreateEntryInternal( } } - base::OnceClosure task = base::BindOnce( - &SimpleSynchronousEntry::OpenOrCreateEntry, cache_type_, path_, key_, - entry_hash_, index_state, optimistic_create, start_time, file_tracker_, - trailer_prefetch_size, results.get()); + base::OnceClosure task = + base::BindOnce(&SimpleSynchronousEntry::OpenOrCreateEntry, cache_type_, + path_, key_, entry_hash_, index_state, optimistic_create, + file_tracker_, trailer_prefetch_size, results.get()); base::OnceClosure reply = base::BindOnce( &SimpleEntryImpl::CreationOperationComplete, this, result_state, @@ -1047,7 +1022,6 @@ int SimpleEntryImpl::ReadDataInternal(bool sync_possible, } if (state_ == STATE_FAILURE || state_ == STATE_UNINITIALIZED) { - RecordReadResult(cache_type_, READ_RESULT_BAD_STATE); if (net_log_.IsCapturing()) { NetLogReadWriteComplete(net_log_, net::NetLogEventType::SIMPLE_CACHE_ENTRY_READ_END, @@ -1061,9 +1035,6 @@ int SimpleEntryImpl::ReadDataInternal(bool sync_possible, } DCHECK_EQ(STATE_READY, state_); if (offset >= GetDataSize(stream_index) || offset < 0 || !buf_len) { - RecordReadResult(cache_type_, sync_possible - ? READ_RESULT_NONBLOCK_EMPTY_RETURN - : READ_RESULT_FAST_EMPTY_RETURN); // If there is nothing to read, we bail out before setting state_ to // STATE_IO_PENDING (so ScopedOperationRunner might start us on next op // here). @@ -1081,12 +1052,6 @@ int SimpleEntryImpl::ReadDataInternal(bool sync_possible, // Sometimes we can read in-ram prefetched stream 1 data immediately, too. if (stream_index == 1) { - if (is_initial_stream1_read_) { - SIMPLE_CACHE_UMA(BOOLEAN, "ReadStream1FromPrefetched", cache_type_, - stream_1_prefetch_data_ != nullptr); - } - is_initial_stream1_read_ = false; - if (stream_1_prefetch_data_) { int rv = ReadFromBuffer(stream_1_prefetch_data_.get(), offset, buf_len, buf); @@ -1143,7 +1108,6 @@ void SimpleEntryImpl::WriteDataInternal(int stream_index, } if (state_ == STATE_FAILURE || state_ == STATE_UNINITIALIZED) { - RecordWriteResult(cache_type_, SIMPLE_ENTRY_WRITE_RESULT_BAD_STATE); if (net_log_.IsCapturing()) { NetLogReadWriteComplete( net_log_, net::NetLogEventType::SIMPLE_CACHE_ENTRY_WRITE_END, @@ -1173,8 +1137,6 @@ void SimpleEntryImpl::WriteDataInternal(int stream_index, if (buf_len == 0) { int32_t data_size = data_size_[stream_index]; if (truncate ? (offset == data_size) : (offset <= data_size)) { - RecordWriteResult(cache_type_, - SIMPLE_ENTRY_WRITE_RESULT_FAST_EMPTY_RETURN); if (!callback.is_null()) { base::SequencedTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::BindOnce(std::move(callback), 0)); @@ -1595,7 +1557,7 @@ void SimpleEntryImpl::ReadOperationComplete( crc_check_state_[stream_index] = CRC_CHECK_NOT_DONE; } } - RecordReadResultConsideringChecksum(read_result); + if (net_log_.IsCapturing()) { NetLogReadWriteComplete(net_log_, net::NetLogEventType::SIMPLE_CACHE_ENTRY_READ_END, @@ -1612,11 +1574,6 @@ void SimpleEntryImpl::WriteOperationComplete( std::unique_ptr<SimpleSynchronousEntry::WriteResult> write_result, net::IOBuffer* buf) { int result = write_result->result; - if (result >= 0) - RecordWriteResult(cache_type_, SIMPLE_ENTRY_WRITE_RESULT_SUCCESS); - else - RecordWriteResult(cache_type_, - SIMPLE_ENTRY_WRITE_RESULT_SYNC_WRITE_FAILURE); if (net_log_.IsCapturing()) { NetLogReadWriteComplete(net_log_, net::NetLogEventType::SIMPLE_CACHE_ENTRY_WRITE_END, @@ -1697,24 +1654,6 @@ void SimpleEntryImpl::DoomOperationComplete( } } -void SimpleEntryImpl::RecordReadResultConsideringChecksum( - const std::unique_ptr<SimpleSynchronousEntry::ReadResult>& read_result) - const { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DCHECK(synchronous_entry_); - DCHECK_EQ(STATE_IO_PENDING, state_); - - if (read_result->result >= 0) { - RecordReadResult(cache_type_, READ_RESULT_SUCCESS); - } else { - if (read_result->crc_updated && read_result->crc_performed_verify && - !read_result->crc_verify_ok) - RecordReadResult(cache_type_, READ_RESULT_SYNC_CHECKSUM_FAILURE); - else - RecordReadResult(cache_type_, READ_RESULT_SYNC_READ_FAILURE); - } -} - void SimpleEntryImpl::CloseOperationComplete( std::unique_ptr<SimpleEntryCloseResults> in_results) { DCHECK(!synchronous_entry_); @@ -1771,7 +1710,6 @@ int SimpleEntryImpl::ReadFromBuffer(net::GrowableIOBuffer* in_buf, memcpy(out_buf->data(), in_buf->data() + offset, buf_len); UpdateDataFromEntryStat(SimpleEntryStat(base::Time::Now(), last_modified_, data_size_, sparse_data_size_)); - RecordReadResult(cache_type_, READ_RESULT_SUCCESS); return buf_len; } @@ -1813,7 +1751,6 @@ int SimpleEntryImpl::SetStream0Data(net::IOBuffer* buf, UpdateDataFromEntryStat( SimpleEntryStat(modification_time, modification_time, data_size_, sparse_data_size_)); - RecordWriteResult(cache_type_, SIMPLE_ENTRY_WRITE_RESULT_SUCCESS); return buf_len; } diff --git a/chromium/net/disk_cache/simple/simple_entry_impl.h b/chromium/net/disk_cache/simple/simple_entry_impl.h index ad2d267da97..2d66478bddd 100644 --- a/chromium/net/disk_cache/simple/simple_entry_impl.h +++ b/chromium/net/disk_cache/simple/simple_entry_impl.h @@ -336,10 +336,6 @@ class NET_EXPORT_PRIVATE SimpleEntryImpl : public Entry, State state_to_restore, int result); - void RecordReadResultConsideringChecksum( - const std::unique_ptr<SimpleSynchronousEntry::ReadResult>& read_result) - const; - // Called after completion of an operation, to either incoproprate file info // received from I/O done on the worker pool, or to simply bump the // timestamps. Updates the metadata both in |this| and in the index. @@ -381,7 +377,6 @@ class NET_EXPORT_PRIVATE SimpleEntryImpl : public Entry, const base::FilePath path_; const uint64_t entry_hash_; const bool use_optimistic_operations_; - bool is_initial_stream1_read_ = true; // used for metrics only. std::string key_; // |last_used_|, |last_modified_| and |data_size_| are copied from the diff --git a/chromium/net/disk_cache/simple/simple_histogram_enums.h b/chromium/net/disk_cache/simple/simple_histogram_enums.h index 0fd28b757b7..01cd170e064 100644 --- a/chromium/net/disk_cache/simple/simple_histogram_enums.h +++ b/chromium/net/disk_cache/simple/simple_histogram_enums.h @@ -8,18 +8,6 @@ namespace disk_cache { // Used in histograms, please only add entries at the end. -enum SimpleReadResult { - READ_RESULT_SUCCESS = 0, - READ_RESULT_INVALID_ARGUMENT = 1, - READ_RESULT_NONBLOCK_EMPTY_RETURN = 2, - READ_RESULT_BAD_STATE = 3, - READ_RESULT_FAST_EMPTY_RETURN = 4, - READ_RESULT_SYNC_READ_FAILURE = 5, - READ_RESULT_SYNC_CHECKSUM_FAILURE = 6, - READ_RESULT_MAX = 7, -}; - -// Used in histograms, please only add entries at the end. enum OpenEntryResult { OPEN_ENTRY_SUCCESS = 0, OPEN_ENTRY_PLATFORM_FILE_ERROR = 1, @@ -72,14 +60,6 @@ enum CloseResult { }; // Used in histograms, please only add entries at the end. -enum class KeySHA256Result { - NOT_PRESENT = 0, - MATCHED = 1, - NO_MATCH = 2, - MAX = 3 -}; - -// Used in histograms, please only add entries at the end. enum FileDescriptorLimiterOp { FD_LIMIT_CLOSE_FILE = 0, FD_LIMIT_REOPEN_FILE = 1, diff --git a/chromium/net/disk_cache/simple/simple_index.cc b/chromium/net/disk_cache/simple/simple_index.cc index 0775f57ff5a..7e65f1aad68 100644 --- a/chromium/net/disk_cache/simple/simple_index.cc +++ b/chromium/net/disk_cache/simple/simple_index.cc @@ -58,11 +58,6 @@ static const int kEstimatedEntryOverhead = 512; namespace disk_cache { -const base::Feature - SimpleIndex::kSimpleCacheDisableEvictionSizeHeuristicForCodeCache{ - "SimpleCacheDisableEvictionSizeHeuristicForCodeCache", - base::FEATURE_DISABLED_BY_DEFAULT}; - EntryMetadata::EntryMetadata() : last_used_time_seconds_since_epoch_(0), entry_size_256b_chunks_(0), @@ -422,11 +417,7 @@ void SimpleIndex::StartEvictionIfNeeded() { MEMORY_KB, "Eviction.MaxCacheSizeOnStart2", cache_type_, static_cast<base::HistogramBase::Sample>(max_size_ / kBytesInKb)); - bool use_size_heuristic = true; - if (cache_type_ == net::GENERATED_BYTE_CODE_CACHE) { - use_size_heuristic = !base::FeatureList::IsEnabled( - kSimpleCacheDisableEvictionSizeHeuristicForCodeCache); - } + bool use_size_heuristic = (cache_type_ != net::GENERATED_BYTE_CODE_CACHE); // Flatten for sorting. std::vector<std::pair<uint64_t, const EntrySet::value_type*>> entries; @@ -603,9 +594,6 @@ void SimpleIndex::MergeInitializingSet( if (load_result->flush_required) WriteToDisk(INDEX_WRITE_REASON_STARTUP_MERGE); - SIMPLE_CACHE_UMA(CUSTOM_COUNTS, - "IndexInitializationWaiters", cache_type_, - to_run_when_initialized_.size(), 0, 100, 20); SIMPLE_CACHE_UMA(CUSTOM_COUNTS, "IndexNumEntriesOnInit", cache_type_, entries_set_.size(), 0, 100000, 50); SIMPLE_CACHE_UMA( @@ -656,19 +644,6 @@ void SimpleIndex::WriteToDisk(IndexWriteToDiskReason reason) { SIMPLE_CACHE_UMA(CUSTOM_COUNTS, "IndexNumEntriesOnWrite", cache_type_, entries_set_.size(), 0, 100000, 50); - const base::TimeTicks start = base::TimeTicks::Now(); - if (!last_write_to_disk_.is_null()) { - if (app_on_background_) { - SIMPLE_CACHE_UMA(MEDIUM_TIMES, - "IndexWriteInterval.Background", cache_type_, - start - last_write_to_disk_); - } else { - SIMPLE_CACHE_UMA(MEDIUM_TIMES, - "IndexWriteInterval.Foreground", cache_type_, - start - last_write_to_disk_); - } - } - last_write_to_disk_ = start; base::OnceClosure after_write; if (cleanup_tracker_) { @@ -680,7 +655,7 @@ void SimpleIndex::WriteToDisk(IndexWriteToDiskReason reason) { } index_file_->WriteToDisk(cache_type_, reason, entries_set_, cache_size_, - start, app_on_background_, std::move(after_write)); + std::move(after_write)); } } // namespace disk_cache diff --git a/chromium/net/disk_cache/simple/simple_index.h b/chromium/net/disk_cache/simple/simple_index.h index f8cdd3c102d..8a62fb1d16e 100644 --- a/chromium/net/disk_cache/simple/simple_index.h +++ b/chromium/net/disk_cache/simple/simple_index.h @@ -14,7 +14,6 @@ #include <vector> #include "base/callback.h" -#include "base/feature_list.h" #include "base/files/file_path.h" #include "base/gtest_prod_util.h" #include "base/memory/ref_counted.h" @@ -297,11 +296,6 @@ class NET_EXPORT_PRIVATE SimpleIndex // enforces this. SEQUENCE_CHECKER(sequence_checker_); - // Timestamp of the last time we wrote the index to disk. - // PostponeWritingToDisk() may give up postponing and allow the write if it - // has been a while since last time we wrote. - base::TimeTicks last_write_to_disk_; - base::OneShotTimer write_to_disk_timer_; base::RepeatingClosure write_to_disk_cb_; @@ -312,9 +306,6 @@ class NET_EXPORT_PRIVATE SimpleIndex // background we can write the index much more frequently, to insure fresh // index on next startup. bool app_on_background_ = false; - - static const base::Feature - kSimpleCacheDisableEvictionSizeHeuristicForCodeCache; }; } // namespace disk_cache diff --git a/chromium/net/disk_cache/simple/simple_index_file.cc b/chromium/net/disk_cache/simple/simple_index_file.cc index 9d53a5e90c5..06a0fff535b 100644 --- a/chromium/net/disk_cache/simple/simple_index_file.cc +++ b/chromium/net/disk_cache/simple/simple_index_file.cc @@ -296,9 +296,7 @@ void SimpleIndexFile::SyncWriteToDisk(net::CacheType cache_type, const base::FilePath& cache_directory, const base::FilePath& index_filename, const base::FilePath& temp_index_filename, - std::unique_ptr<base::Pickle> pickle, - const base::TimeTicks& start_time, - bool app_on_background) { + std::unique_ptr<base::Pickle> pickle) { DCHECK_EQ(index_filename.DirName().value(), temp_index_filename.DirName().value()); base::FilePath index_file_directory = temp_index_filename.DirName(); @@ -327,16 +325,6 @@ void SimpleIndexFile::SyncWriteToDisk(net::CacheType cache_type, // Atomically rename the temporary index file to become the real one. if (!base::ReplaceFile(temp_index_filename, index_filename, nullptr)) return; - - if (app_on_background) { - SIMPLE_CACHE_UMA(TIMES, - "IndexWriteToDiskTime.Background", cache_type, - (base::TimeTicks::Now() - start_time)); - } else { - SIMPLE_CACHE_UMA(TIMES, - "IndexWriteToDiskTime.Foreground", cache_type, - (base::TimeTicks::Now() - start_time)); - } } bool SimpleIndexFile::IndexMetadata::CheckIndexMetadata() { @@ -383,17 +371,14 @@ void SimpleIndexFile::WriteToDisk(net::CacheType cache_type, SimpleIndex::IndexWriteToDiskReason reason, const SimpleIndex::EntrySet& entry_set, uint64_t cache_size, - const base::TimeTicks& start, - bool app_on_background, base::OnceClosure callback) { UmaRecordIndexWriteReason(reason, cache_type_); IndexMetadata index_metadata(reason, entry_set.size(), cache_size); std::unique_ptr<base::Pickle> pickle = Serialize(cache_type, index_metadata, entry_set); - base::OnceClosure task = - base::BindOnce(&SimpleIndexFile::SyncWriteToDisk, cache_type_, - cache_directory_, index_file_, temp_index_file_, - std::move(pickle), start, app_on_background); + base::OnceClosure task = base::BindOnce( + &SimpleIndexFile::SyncWriteToDisk, cache_type_, cache_directory_, + index_file_, temp_index_file_, std::move(pickle)); if (callback.is_null()) cache_runner_->PostTask(FROM_HERE, std::move(task)); else @@ -447,8 +432,6 @@ void SimpleIndexFile::SyncLoadIndexEntries( SyncRestoreFromDisk(cache_type, cache_directory, index_file_path, out_result); SIMPLE_CACHE_UMA(MEDIUM_TIMES, "IndexRestoreTime", cache_type, base::TimeTicks::Now() - start); - SIMPLE_CACHE_UMA(COUNTS_1M, "IndexEntriesRestored", cache_type, - out_result->entries.size()); if (index_file_existed) { out_result->init_method = SimpleIndex::INITIALIZE_METHOD_RECOVERED; diff --git a/chromium/net/disk_cache/simple/simple_index_file.h b/chromium/net/disk_cache/simple/simple_index_file.h index ae9345659e6..0e768f98656 100644 --- a/chromium/net/disk_cache/simple/simple_index_file.h +++ b/chromium/net/disk_cache/simple/simple_index_file.h @@ -13,7 +13,6 @@ #include "base/files/file_path.h" #include "base/gtest_prod_util.h" -#include "base/logging.h" #include "base/macros.h" #include "base/pickle.h" #include "net/base/cache_type.h" @@ -107,8 +106,6 @@ class NET_EXPORT_PRIVATE SimpleIndexFile { SimpleIndex::IndexWriteToDiskReason reason, const SimpleIndex::EntrySet& entry_set, uint64_t cache_size, - const base::TimeTicks& start, - bool app_on_background, base::OnceClosure callback); private: @@ -178,9 +175,7 @@ class NET_EXPORT_PRIVATE SimpleIndexFile { const base::FilePath& cache_directory, const base::FilePath& index_filename, const base::FilePath& temp_index_filename, - std::unique_ptr<base::Pickle> pickle, - const base::TimeTicks& start_time, - bool app_on_background); + std::unique_ptr<base::Pickle> pickle); // Scan the index directory for entries, returning an EntrySet of all entries // found. diff --git a/chromium/net/disk_cache/simple/simple_index_file_unittest.cc b/chromium/net/disk_cache/simple/simple_index_file_unittest.cc index c193f72fd47..a162ca7e564 100644 --- a/chromium/net/disk_cache/simple/simple_index_file_unittest.cc +++ b/chromium/net/disk_cache/simple/simple_index_file_unittest.cc @@ -462,9 +462,9 @@ TEST_F(SimpleIndexFileTest, WriteThenLoadIndex) { net::TestClosure closure; { WrappedSimpleIndexFile simple_index_file(cache_dir.GetPath()); - simple_index_file.WriteToDisk( - net::DISK_CACHE, SimpleIndex::INDEX_WRITE_REASON_SHUTDOWN, entries, - kCacheSize, base::TimeTicks(), false, closure.closure()); + simple_index_file.WriteToDisk(net::DISK_CACHE, + SimpleIndex::INDEX_WRITE_REASON_SHUTDOWN, + entries, kCacheSize, closure.closure()); closure.WaitForResult(); EXPECT_TRUE(base::PathExists(simple_index_file.GetIndexFilePath())); } @@ -637,9 +637,9 @@ TEST_F(SimpleIndexFileTest, OverwritesStaleTempFile) { SimpleIndex::EntrySet entries; SimpleIndex::InsertInEntrySet(11, EntryMetadata(Time(), 11u), &entries); net::TestClosure closure; - simple_index_file.WriteToDisk( - net::DISK_CACHE, SimpleIndex::INDEX_WRITE_REASON_SHUTDOWN, entries, 120U, - base::TimeTicks(), false, closure.closure()); + simple_index_file.WriteToDisk(net::DISK_CACHE, + SimpleIndex::INDEX_WRITE_REASON_SHUTDOWN, + entries, 120U, closure.closure()); closure.WaitForResult(); // Check that the temporary file was deleted and the index file was created. diff --git a/chromium/net/disk_cache/simple/simple_index_unittest.cc b/chromium/net/disk_cache/simple/simple_index_unittest.cc index e6e8e932d64..2f70905c705 100644 --- a/chromium/net/disk_cache/simple/simple_index_unittest.cc +++ b/chromium/net/disk_cache/simple/simple_index_unittest.cc @@ -78,8 +78,6 @@ class MockSimpleIndexFile : public SimpleIndexFile, SimpleIndex::IndexWriteToDiskReason reason, const SimpleIndex::EntrySet& entry_set, uint64_t cache_size, - const base::TimeTicks& start, - bool app_on_background, base::OnceClosure callback) override { disk_writes_++; disk_write_entry_set_ = entry_set; @@ -642,10 +640,6 @@ TEST_F(SimpleIndexTest, EvictBySize) { } TEST_F(SimpleIndexCodeCacheTest, DisableEvictBySize) { - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitWithFeatures( - {SimpleIndex::kSimpleCacheDisableEvictionSizeHeuristicForCodeCache}, {}); - base::Time now(base::Time::Now()); index()->SetMaxSize(50000); InsertIntoIndexFileReturn(hashes_.at<1>(), now - base::TimeDelta::FromDays(2), @@ -675,40 +669,6 @@ TEST_F(SimpleIndexCodeCacheTest, DisableEvictBySize) { ASSERT_EQ(2u, last_doom_entry_hashes().size()); } -TEST_F(SimpleIndexCodeCacheTest, EnableEvictBySize) { - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitWithFeatures( - {}, {SimpleIndex::kSimpleCacheDisableEvictionSizeHeuristicForCodeCache}); - - base::Time now(base::Time::Now()); - index()->SetMaxSize(50000); - InsertIntoIndexFileReturn(hashes_.at<1>(), now - base::TimeDelta::FromDays(2), - 475u); - InsertIntoIndexFileReturn(hashes_.at<2>(), now - base::TimeDelta::FromDays(1), - 40000u); - ReturnIndexFile(); - WaitForTimeChange(); - - index()->Insert(hashes_.at<3>()); - // Confirm index is as expected: No eviction, everything there. - EXPECT_EQ(3, index()->GetEntryCount()); - EXPECT_EQ(0, doom_entries_calls()); - EXPECT_TRUE(index()->Has(hashes_.at<1>())); - EXPECT_TRUE(index()->Has(hashes_.at<2>())); - EXPECT_TRUE(index()->Has(hashes_.at<3>())); - - // Trigger an eviction, and make sure the right things are tossed. - // This has size-weighting enabled, so it end sup kickicking out entry - // 2, which is biggest, and is enough, even though <1> is older. - index()->UpdateEntrySize(hashes_.at<3>(), 40000u); - EXPECT_EQ(1, doom_entries_calls()); - EXPECT_EQ(2, index()->GetEntryCount()); - EXPECT_TRUE(index()->Has(hashes_.at<1>())); - EXPECT_FALSE(index()->Has(hashes_.at<2>())); - EXPECT_TRUE(index()->Has(hashes_.at<3>())); - ASSERT_EQ(1u, last_doom_entry_hashes().size()); -} - // Same as test above, but using much older entries to make sure that small // things eventually get evictied. TEST_F(SimpleIndexTest, EvictBySize2) { diff --git a/chromium/net/disk_cache/simple/simple_synchronous_entry.cc b/chromium/net/disk_cache/simple/simple_synchronous_entry.cc index 6effe85bb22..140067a5864 100644 --- a/chromium/net/disk_cache/simple/simple_synchronous_entry.cc +++ b/chromium/net/disk_cache/simple/simple_synchronous_entry.cc @@ -60,12 +60,6 @@ void RecordCloseResult(net::CacheType cache_type, CloseResult result) { "SyncCloseResult", cache_type, result, CLOSE_RESULT_MAX); } -void RecordKeySHA256Result(net::CacheType cache_type, KeySHA256Result result) { - SIMPLE_CACHE_UMA(ENUMERATION, "SyncKeySHA256Result", cache_type, - static_cast<int>(result), - static_cast<int>(KeySHA256Result::MAX)); -} - void RecordOpenPrefetchMode(net::CacheType cache_type, OpenPrefetchMode mode) { SIMPLE_CACHE_UMA(ENUMERATION, "SyncOpenPrefetchMode", cache_type, mode, OPEN_PREFETCH_MAX); @@ -208,11 +202,6 @@ const char kSimpleCacheFullPrefetchBytesParam[] = "FullPrefetchBytes"; constexpr base::FeatureParam<int> kSimpleCacheFullPrefetchSize{ &kSimpleCachePrefetchExperiment, kSimpleCacheFullPrefetchBytesParam, 0}; -const char kSimpleCacheTrailerPrefetchHintParam[] = "TrailerPrefetchHint"; -constexpr base::FeatureParam<bool> kSimpleCacheTrailerPrefetchHint{ - &kSimpleCachePrefetchExperiment, kSimpleCacheTrailerPrefetchHintParam, - true}; - const char kSimpleCacheTrailerPrefetchSpeculativeBytesParam[] = "TrailerPrefetchSpeculativeBytes"; constexpr base::FeatureParam<int> kSimpleCacheTrailerPrefetchSpeculativeBytes{ @@ -224,7 +213,7 @@ int GetSimpleCacheFullPrefetchSize() { } int GetSimpleCacheTrailerPrefetchSize(int hint_size) { - if (kSimpleCacheTrailerPrefetchHint.Get() && hint_size > 0) + if (hint_size > 0) return hint_size; return kSimpleCacheTrailerPrefetchSpeculativeBytes.Get(); } @@ -338,13 +327,10 @@ void SimpleSynchronousEntry::OpenEntry( const FilePath& path, const std::string& key, const uint64_t entry_hash, - const base::TimeTicks& time_enqueued, SimpleFileTracker* file_tracker, int32_t trailer_prefetch_size, SimpleEntryCreationResults* out_results) { base::TimeTicks start_sync_open_entry = base::TimeTicks::Now(); - SIMPLE_CACHE_UMA(TIMES, "QueueLatency.OpenEntry", cache_type, - (start_sync_open_entry - time_enqueued)); SimpleSynchronousEntry* sync_entry = new SimpleSynchronousEntry( cache_type, path, key, entry_hash, file_tracker, trailer_prefetch_size); @@ -371,13 +357,10 @@ void SimpleSynchronousEntry::CreateEntry( const FilePath& path, const std::string& key, const uint64_t entry_hash, - const base::TimeTicks& time_enqueued, SimpleFileTracker* file_tracker, SimpleEntryCreationResults* out_results) { DCHECK_EQ(entry_hash, GetEntryHashKey(key)); base::TimeTicks start_sync_create_entry = base::TimeTicks::Now(); - SIMPLE_CACHE_UMA(TIMES, "QueueLatency.CreateEntry", cache_type, - (start_sync_create_entry - time_enqueued)); SimpleSynchronousEntry* sync_entry = new SimpleSynchronousEntry( cache_type, path, key, entry_hash, file_tracker, -1); @@ -404,13 +387,10 @@ void SimpleSynchronousEntry::OpenOrCreateEntry( const uint64_t entry_hash, OpenEntryIndexEnum index_state, bool optimistic_create, - const base::TimeTicks& time_enqueued, SimpleFileTracker* file_tracker, int32_t trailer_prefetch_size, SimpleEntryCreationResults* out_results) { base::TimeTicks start = base::TimeTicks::Now(); - SIMPLE_CACHE_UMA(TIMES, "QueueLatency.OpenOrCreateEntry", cache_type, - (start - time_enqueued)); if (index_state == INDEX_MISS) { // Try to just create. auto sync_entry = base::WrapUnique( @@ -431,8 +411,8 @@ void SimpleSynchronousEntry::OpenOrCreateEntry( // In this case, ::OpenOrCreateEntry already returned claiming it made // a new entry. Try extra-hard to make that the actual case. sync_entry->Doom(); - CreateEntry(cache_type, path, key, entry_hash, time_enqueued, - file_tracker, out_results); + CreateEntry(cache_type, path, key, entry_hash, file_tracker, + out_results); return; } // Otherwise can just try opening. @@ -445,12 +425,11 @@ void SimpleSynchronousEntry::OpenOrCreateEntry( } // Try open, then if that fails create. - OpenEntry(cache_type, path, key, entry_hash, time_enqueued, file_tracker, + OpenEntry(cache_type, path, key, entry_hash, file_tracker, trailer_prefetch_size, out_results); if (out_results->sync_entry) return; - CreateEntry(cache_type, path, key, entry_hash, time_enqueued, file_tracker, - out_results); + CreateEntry(cache_type, path, key, entry_hash, file_tracker, out_results); } // static @@ -628,8 +607,7 @@ void SimpleSynchronousEntry::WriteData(const WriteRequest& in_entry_op, out_write_result->result = net::ERR_CACHE_WRITE_FAILURE; return; } - CreateEntryResult result; - if (!InitializeCreatedFile(file_index, &result)) { + if (!InitializeCreatedFile(file_index)) { RecordWriteResult(cache_type_, SYNC_WRITE_RESULT_LAZY_INITIALIZE_FAILURE); Doom(); out_write_result->result = net::ERR_CACHE_WRITE_FAILURE; @@ -1203,7 +1181,6 @@ bool SimpleSynchronousEntry::OpenFiles(SimpleEntryStat* out_entry_stat) { have_open_files_ = true; base::Time after_open_files = base::Time::Now(); - base::TimeDelta entry_age = after_open_files - base::Time::UnixEpoch(); for (int i = 0; i < kSimpleEntryNormalFileCount; ++i) { if (empty_file_omitted_[i]) { out_entry_stat->set_data_size(i + 1, 0); @@ -1221,11 +1198,6 @@ bool SimpleSynchronousEntry::OpenFiles(SimpleEntryStat* out_entry_stat) { out_entry_stat->set_last_used(file_info.last_accessed); out_entry_stat->set_last_modified(file_info.last_modified); - base::TimeDelta stream_age = - base::Time::Now() - out_entry_stat->last_modified(); - if (stream_age < entry_age) - entry_age = stream_age; - // Two things prevent from knowing the right values for |data_size|: // 1) The key might not be known, hence its length might be unknown. // 2) Stream 0 and stream 1 are in the same file, and the exact size for @@ -1263,9 +1235,6 @@ bool SimpleSynchronousEntry::OpenFiles(SimpleEntryStat* out_entry_stat) { } } } - SIMPLE_CACHE_UMA(CUSTOM_COUNTS, - "SyncOpenEntryAge", cache_type_, - entry_age.InHours(), 1, 1000, 50); return true; } @@ -1274,7 +1243,6 @@ bool SimpleSynchronousEntry::CreateFiles(SimpleEntryStat* out_entry_stat) { for (int i = 0; i < kSimpleEntryNormalFileCount; ++i) { base::File::Error error; if (!MaybeCreateFile(i, FILE_NOT_REQUIRED, &error)) { - RecordSyncCreateResult(CREATE_ENTRY_PLATFORM_FILE_ERROR); SIMPLE_CACHE_UMA(ENUMERATION, "SyncCreatePlatformFileError", cache_type_, -error, -base::File::FILE_ERROR_MAX); @@ -1468,15 +1436,11 @@ int SimpleSynchronousEntry::InitializeForOpen( return net::OK; } -bool SimpleSynchronousEntry::InitializeCreatedFile( - int file_index, - CreateEntryResult* out_result) { +bool SimpleSynchronousEntry::InitializeCreatedFile(int file_index) { SimpleFileTracker::FileHandle file = file_tracker_->Acquire(this, SubFileForFileIndex(file_index)); - if (!file.IsOK()) { - *out_result = CREATE_ENTRY_CANT_WRITE_HEADER; + if (!file.IsOK()) return false; - } SimpleFileHeader header; header.initial_magic_number = kSimpleInitialMagicNumber; @@ -1487,16 +1451,12 @@ bool SimpleSynchronousEntry::InitializeCreatedFile( int bytes_written = file->Write(0, reinterpret_cast<char*>(&header), sizeof(header)); - if (bytes_written != sizeof(header)) { - *out_result = CREATE_ENTRY_CANT_WRITE_HEADER; + if (bytes_written != sizeof(header)) return false; - } bytes_written = file->Write(sizeof(header), key_.data(), key_.size()); - if (bytes_written != base::checked_cast<int>(key_.size())) { - *out_result = CREATE_ENTRY_CANT_WRITE_KEY; + if (bytes_written != base::checked_cast<int>(key_.size())) return false; - } return true; } @@ -1512,13 +1472,9 @@ int SimpleSynchronousEntry::InitializeForCreate( if (empty_file_omitted_[i]) continue; - CreateEntryResult result; - if (!InitializeCreatedFile(i, &result)) { - RecordSyncCreateResult(result); + if (!InitializeCreatedFile(i)) return net::ERR_FAILED; - } } - RecordSyncCreateResult(CREATE_ENTRY_SUCCESS); initialized_ = true; return net::OK; } @@ -1617,12 +1573,9 @@ int SimpleSynchronousEntry::ReadAndValidateStream0AndMaybe1( // Note the exact range needed in order to read the EOF record and stream 0. // In APP_CACHE mode this will be stored directly in the index so we can - // know exactly how much to read next time. Its also reported in a histogram - // so we can tune the speculative trailer prefetching experiment. + // know exactly how much to read next time. computed_trailer_prefetch_size_ = prefetch_data.GetDesiredTrailerPrefetchSize(); - SIMPLE_CACHE_UMA(COUNTS_100000, "EntryTrailerSize", cache_type_, - computed_trailer_prefetch_size_); // If we performed a trailer prefetch, record how accurate the prefetch was // compared to the ideal value. @@ -1663,15 +1616,11 @@ int SimpleSynchronousEntry::ReadAndValidateStream0AndMaybe1( std::memcmp(&hash_value, stream_prefetch_data[0].data->data() + stream_0_size, sizeof(hash_value)) == 0; - if (!matched) { - RecordKeySHA256Result(cache_type_, KeySHA256Result::NO_MATCH); + if (!matched) return net::ERR_FAILED; - } + // Elide header check if we verified sha256(key) via footer. header_and_key_check_needed_[0] = false; - RecordKeySHA256Result(cache_type_, KeySHA256Result::MATCHED); - } else { - RecordKeySHA256Result(cache_type_, KeySHA256Result::NOT_PRESENT); } // Ensure the key is validated before completion. @@ -1733,9 +1682,6 @@ int SimpleSynchronousEntry::GetEOFRecordData(base::File* file, if (!base::IsValueInRangeForNumericType<int32_t>(eof_record->stream_size)) return net::ERR_FAILED; - SIMPLE_CACHE_UMA(BOOLEAN, "SyncCheckEOFHasCrc", cache_type_, - (eof_record->flags & SimpleFileEOF::FLAG_HAS_CRC32) == - SimpleFileEOF::FLAG_HAS_CRC32); return net::OK; } @@ -1781,12 +1727,6 @@ bool SimpleSynchronousEntry::TruncateFilesForEntryHash( return result; } -void SimpleSynchronousEntry::RecordSyncCreateResult(CreateEntryResult result) { - DCHECK_LT(result, CREATE_ENTRY_MAX); - SIMPLE_CACHE_UMA(ENUMERATION, - "SyncCreateResult", cache_type_, result, CREATE_ENTRY_MAX); -} - FilePath SimpleSynchronousEntry::GetFilenameFromFileIndex( int file_index) const { return path_.AppendASCII( diff --git a/chromium/net/disk_cache/simple/simple_synchronous_entry.h b/chromium/net/disk_cache/simple/simple_synchronous_entry.h index 958a052ec39..9e1536b1b42 100644 --- a/chromium/net/disk_cache/simple/simple_synchronous_entry.h +++ b/chromium/net/disk_cache/simple/simple_synchronous_entry.h @@ -38,7 +38,6 @@ namespace disk_cache { NET_EXPORT_PRIVATE extern const base::Feature kSimpleCachePrefetchExperiment; NET_EXPORT_PRIVATE extern const char kSimpleCacheFullPrefetchBytesParam[]; -NET_EXPORT_PRIVATE extern const char kSimpleCacheTrailerPrefetchHintParam[]; NET_EXPORT_PRIVATE extern const char kSimpleCacheTrailerPrefetchSpeculativeBytesParam[]; @@ -191,13 +190,10 @@ class SimpleSynchronousEntry { // Opens a disk cache entry on disk. The |key| parameter is optional, if empty // the operation may be slower. The |entry_hash| parameter is required. - // |time_enqueued| is when this operation was added to the I/O thread pool, - // and is provided only for histograms. static void OpenEntry(net::CacheType cache_type, const base::FilePath& path, const std::string& key, uint64_t entry_hash, - const base::TimeTicks& time_enqueued, SimpleFileTracker* file_tracker, int32_t trailer_prefetch_size, SimpleEntryCreationResults* out_results); @@ -206,7 +202,6 @@ class SimpleSynchronousEntry { const base::FilePath& path, const std::string& key, uint64_t entry_hash, - const base::TimeTicks& time_enqueued, SimpleFileTracker* file_tracker, SimpleEntryCreationResults* out_results); @@ -216,7 +211,6 @@ class SimpleSynchronousEntry { uint64_t entry_hash, OpenEntryIndexEnum index_state, bool optimistic_create, - const base::TimeTicks& time_enqueued, SimpleFileTracker* file_tracker, int32_t trailer_prefetch_size, SimpleEntryCreationResults* out_results); @@ -304,14 +298,6 @@ class SimpleSynchronousEntry { friend class SimpleFileTrackerTest; class PrefetchData; - enum CreateEntryResult { - CREATE_ENTRY_SUCCESS = 0, - CREATE_ENTRY_PLATFORM_FILE_ERROR = 1, - CREATE_ENTRY_CANT_WRITE_HEADER = 2, - CREATE_ENTRY_CANT_WRITE_KEY = 3, - CREATE_ENTRY_MAX = 4, - }; - enum FileRequired { FILE_NOT_REQUIRED, FILE_REQUIRED @@ -368,9 +354,8 @@ class SimpleSynchronousEntry { SimpleStreamPrefetchData stream_prefetch_data[2]); // Writes the header and key to a newly-created stream file. |index| is the - // index of the stream. Returns true on success; returns false and sets - // |*out_result| on failure. - bool InitializeCreatedFile(int index, CreateEntryResult* out_result); + // index of the stream. Returns true on success; returns false and failure. + bool InitializeCreatedFile(int index); // Returns a net error, including net::OK on success and net::FILE_EXISTS // when the entry already exists. @@ -469,8 +454,6 @@ class SimpleSynchronousEntry { static bool TruncateFilesForEntryHash(const base::FilePath& path, uint64_t entry_hash); - void RecordSyncCreateResult(CreateEntryResult result); - base::FilePath GetFilenameFromFileIndex(int file_index) const; bool sparse_file_open() const { return sparse_file_open_; } diff --git a/chromium/net/dns/BUILD.gn b/chromium/net/dns/BUILD.gn index 74680eccfea..3e24edd0b48 100644 --- a/chromium/net/dns/BUILD.gn +++ b/chromium/net/dns/BUILD.gn @@ -5,6 +5,10 @@ import("//net/features.gni") import("//testing/libfuzzer/fuzzer_test.gni") +if (is_android) { + import("//build/config/android/rules.gni") +} + enable_built_in_dns = !is_ios source_set("dns") { @@ -62,7 +66,6 @@ source_set("dns") { "dns_transaction.cc", "dns_udp_tracker.cc", "dns_udp_tracker.h", - "esni_content.cc", "host_cache.cc", "host_resolver.cc", "host_resolver_manager.cc", @@ -72,6 +75,8 @@ source_set("dns") { "host_resolver_mdns_task.h", "host_resolver_proc.cc", "host_resolver_proc.h", + "httpssvc_metrics.cc", + "httpssvc_metrics.h", "mapped_host_resolver.cc", "notify_watcher_mac.cc", "notify_watcher_mac.h", @@ -198,7 +203,6 @@ source_set("host_resolver") { sources += [ "dns_config.h", "dns_config_overrides.h", - "esni_content.h", "host_cache.h", "host_resolver.h", "host_resolver_source.h", @@ -371,6 +375,12 @@ source_set("mdns_client") { public_deps = [ "//net:net_public_deps" ] } +if (is_android) { + java_cpp_enum("secure_dns_mode_generated_enum") { + sources = [ "dns_config.h" ] + } +} + source_set("tests") { testonly = true sources = [ @@ -386,9 +396,9 @@ source_set("tests") { "dns_transaction_unittest.cc", "dns_udp_tracker_unittest.cc", "dns_util_unittest.cc", - "esni_content_unittest.cc", "host_cache_unittest.cc", "host_resolver_manager_unittest.cc", + "httpssvc_metrics_unittest.cc", "mapped_host_resolver_unittest.cc", "record_parsed_unittest.cc", "record_rdata_unittest.cc", diff --git a/chromium/net/dns/address_info.cc b/chromium/net/dns/address_info.cc index ec8016a33f3..67a357a112e 100644 --- a/chromium/net/dns/address_info.cc +++ b/chromium/net/dns/address_info.cc @@ -5,6 +5,7 @@ #include "net/dns/address_info.h" #include "base/logging.h" +#include "base/notreached.h" #include "base/sys_byteorder.h" #include "net/base/address_list.h" #include "net/base/net_errors.h" diff --git a/chromium/net/dns/context_host_resolver.cc b/chromium/net/dns/context_host_resolver.cc index 0ae8cc862f7..32a7a0ddf27 100644 --- a/chromium/net/dns/context_host_resolver.cc +++ b/chromium/net/dns/context_host_resolver.cc @@ -150,16 +150,6 @@ class ContextHostResolver::WrappedResolveHostRequest return inner_request_->GetHostnameResults(); } - const base::Optional<EsniContent>& GetEsniResults() const override { - if (!inner_request_) { - static const base::NoDestructor<base::Optional<EsniContent>> - nullopt_result; - return *nullopt_result; - } - - return inner_request_->GetEsniResults(); - } - net::ResolveErrorInfo GetResolveErrorInfo() const override { if (!inner_request_) { return resolve_error_info_; diff --git a/chromium/net/dns/dns_config.h b/chromium/net/dns/dns_config.h index 9e1e3e917d0..d65a31eb45d 100644 --- a/chromium/net/dns/dns_config.h +++ b/chromium/net/dns/dns_config.h @@ -51,6 +51,7 @@ struct NET_EXPORT DnsConfig { return !nameservers.empty() || !dns_over_https_servers.empty(); } + // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.net // The SecureDnsMode specifies what types of lookups (secure/insecure) should // be performed and in what order when resolving a specific query. The int // values should not be changed as they are logged. diff --git a/chromium/net/dns/dns_hosts.cc b/chromium/net/dns/dns_hosts.cc index 13ee84b7d0b..04b1596e613 100644 --- a/chromium/net/dns/dns_hosts.cc +++ b/chromium/net/dns/dns_hosts.cc @@ -7,7 +7,6 @@ #include "base/check.h" #include "base/files/file_util.h" #include "base/macros.h" -#include "base/metrics/histogram_macros.h" #include "base/strings/string_util.h" #include "net/dns/dns_util.h" @@ -199,9 +198,6 @@ bool ParseHostsFile(const base::FilePath& path, DnsHosts* dns_hosts) { if (!base::GetFileSize(path, &size)) return false; - UMA_HISTOGRAM_COUNTS_1M("AsyncDNS.HostsSize", - static_cast<base::HistogramBase::Sample>(size)); - // Reject HOSTS files larger than |kMaxHostsSize| bytes. const int64_t kMaxHostsSize = 1 << 25; // 32MB if (size > kMaxHostsSize) diff --git a/chromium/net/dns/dns_response.cc b/chromium/net/dns/dns_response.cc index 523ccc2725b..860eebbc5e7 100644 --- a/chromium/net/dns/dns_response.cc +++ b/chromium/net/dns/dns_response.cc @@ -93,8 +93,10 @@ DnsResourceRecord& DnsResourceRecord::operator=(DnsResourceRecord&& other) { } void DnsResourceRecord::SetOwnedRdata(std::string value) { + DCHECK(!value.empty()); owned_rdata = std::move(value); rdata = owned_rdata; + DCHECK_EQ(owned_rdata.data(), rdata.data()); } size_t DnsResourceRecord::CalculateRecordSize() const { @@ -570,8 +572,7 @@ bool DnsResponse::WriteQuestion(base::BigEndianWriter* writer, bool DnsResponse::WriteRecord(base::BigEndianWriter* writer, const DnsResourceRecord& record) { - if (record.rdata.data() != record.owned_rdata.data() || - record.rdata.size() != record.owned_rdata.size()) { + if (record.rdata != base::StringPiece(record.owned_rdata)) { VLOG(1) << "record.rdata should point to record.owned_rdata."; return false; } diff --git a/chromium/net/dns/dns_response.h b/chromium/net/dns/dns_response.h index 75d69707345..b7fa79aadc5 100644 --- a/chromium/net/dns/dns_response.h +++ b/chromium/net/dns/dns_response.h @@ -44,8 +44,8 @@ struct NET_EXPORT_PRIVATE DnsResourceRecord { DnsResourceRecord& operator=(const DnsResourceRecord& other); DnsResourceRecord& operator=(DnsResourceRecord&& other); - // A helper to set |owned_rdata| that also sets |rdata| to point to it. - // See the definition of |owned_rdata| below. + // A helper to set |owned_rdata| that also sets |rdata| to point to it. The + // |value| must be non-empty. See the definition of |owned_rdata| below. void SetOwnedRdata(std::string value); // NAME (variable length) + TYPE (2 bytes) + CLASS (2 bytes) + TTL (4 bytes) + @@ -208,9 +208,9 @@ class NET_EXPORT_PRIVATE DnsResponse { bool WriteHeader(base::BigEndianWriter* writer, const dns_protocol::Header& header); bool WriteQuestion(base::BigEndianWriter* writer, const DnsQuery& query); - bool WriteRecord(base::BigEndianWriter* wirter, + bool WriteRecord(base::BigEndianWriter* writer, const DnsResourceRecord& record); - bool WriteAnswer(base::BigEndianWriter* wirter, + bool WriteAnswer(base::BigEndianWriter* writer, const DnsResourceRecord& answer, const base::Optional<DnsQuery>& query); diff --git a/chromium/net/dns/dns_test_util.cc b/chromium/net/dns/dns_test_util.cc index 0497c197e4f..efcec21579d 100644 --- a/chromium/net/dns/dns_test_util.cc +++ b/chromium/net/dns/dns_test_util.cc @@ -166,77 +166,25 @@ DnsResourceRecord BuildServiceRecord(std::string name, return record; } -void AppendU16LengthPrefixed(base::StringPiece in, std::string* out) { - DCHECK(out); - char buf[2]; - base::WriteBigEndian(buf, base::checked_cast<uint16_t>(in.size())); - out->append(buf, 2); - out->insert(out->end(), in.begin(), in.end()); -} - -// Builds an ESNI (TLS 1.3 Encrypted Server Name Indication, draft 4) record. -// -// An ESNI record associates an "ESNI key object" (an opaque string used -// by the TLS library) with a collection of IP addresses. -DnsResourceRecord BuildEsniRecord(std::string name, EsniContent esni_content) { - DCHECK(!name.empty()); + + +DnsResourceRecord BuildIntegrityRecord( + std::string name, + const std::vector<uint8_t>& serialized_rdata) { + CHECK(!name.empty()); DnsResourceRecord record; record.name = std::move(name); - record.type = dns_protocol::kExperimentalTypeEsniDraft4; + record.type = dns_protocol::kExperimentalTypeIntegrity; record.klass = dns_protocol::kClassIN; record.ttl = base::TimeDelta::FromDays(1).InSeconds(); - std::string rdata; - - // An esni_content struct corresponding to a single record - // should have exactly one key object, along with zero or more addresses - // corresponding to the key object. - DCHECK_EQ(esni_content.keys().size(), 1u); - rdata += *esni_content.keys().begin(); - - if (esni_content.keys_for_addresses().empty()) { - // No addresses: leave the "dns_extensions" field of the - // ESNI record empty and conclude the rdata with the - // "dns_extensions" field's length prefix (two zero bytes). - rdata.push_back(0); - rdata.push_back(0); - record.SetOwnedRdata(std::move(rdata)); - return record; - } - - // When the "dns_extensions" field of a draft-4 ESNI record is nonempty, - // it stores an IP addresses: more specifically, it contains - // - a 16-bit length prefix, - // - the 16-bit "extension type" label of the single address_set - // extension (the only type of extension) contained in the extensions object, - // - a 16-bit length prefix for the address_set extension's contents, and - // - the contents of the address_set extension, which is just a list - // of type-prefixed network-order IP addresses. - // - // (See the draft spec for the complete definition.) - std::string dns_extensions; - - std::string address_set; - char buf[2]; - base::WriteBigEndian(buf, EsniRecordRdata::kAddressSetExtensionType); - address_set.append(buf, 2); - - std::string serialized_addresses; - for (const auto& kv : esni_content.keys_for_addresses()) { - IPAddress address = kv.first; - - uint8_t address_type = address.IsIPv4() ? 4 : 6; - serialized_addresses.push_back(address_type); - serialized_addresses.insert(serialized_addresses.end(), - address.bytes().begin(), address.bytes().end()); - } + std::string serialized_rdata_str(serialized_rdata.begin(), + serialized_rdata.end()); + record.SetOwnedRdata(std::move(serialized_rdata_str)); - AppendU16LengthPrefixed(serialized_addresses, &address_set); - AppendU16LengthPrefixed(address_set, &dns_extensions); - rdata.append(dns_extensions); + CHECK_EQ(record.rdata.data(), record.owned_rdata.data()); - record.SetOwnedRdata(std::move(rdata)); return record; } @@ -257,28 +205,6 @@ DnsResourceRecord BuildTestAddressRecord(std::string name, return record; } -const char kWellFormedEsniKeys[] = { - 0xff, 0x3, 0x0, 0x1, 0xff, 0x0, 0x24, 0x0, 0x1d, 0x0, 0x20, - 0xed, 0xed, 0xc8, 0x68, 0xc1, 0x71, 0xd6, 0x9e, 0xa9, 0xf0, 0xa2, - 0xc9, 0xf5, 0xa9, 0xdc, 0xcf, 0xf9, 0xb8, 0xed, 0x15, 0x5c, 0xc4, - 0x5a, 0xec, 0x6f, 0xb2, 0x86, 0x14, 0xb7, 0x71, 0x1b, 0x7c, 0x0, - 0x2, 0x13, 0x1, 0x1, 0x4, 0x0, 0x0}; -const size_t kWellFormedEsniKeysSize = sizeof(kWellFormedEsniKeys); - -std::string GenerateWellFormedEsniKeys(base::StringPiece custom_data) { - std::string well_formed_esni_keys(kWellFormedEsniKeys, - kWellFormedEsniKeysSize); - // Dead-reckon to the first byte after ESNIKeys.keys.group (0x001d). - // - // Overwrite at most 0x22 bytes: this is the length of the "keys" field - // in the example struct (0x0024, specified as a 16-bit big-endian value - // by the index-5 and index-6 bytes), minus 2 because the 0x0, 0x1d bytes - // will not be overwritten. - custom_data = custom_data.substr(0, 0x22); - std::copy(custom_data.begin(), custom_data.end(), - well_formed_esni_keys.begin() + 9); - return well_formed_esni_keys; -} std::unique_ptr<DnsResponse> BuildTestDnsResponse(std::string name, const IPAddress& ip) { @@ -387,28 +313,23 @@ std::unique_ptr<DnsResponse> BuildTestDnsServiceResponse( std::vector<DnsResourceRecord>() /* additional_records */, query); } -std::unique_ptr<DnsResponse> BuildTestDnsEsniResponse( +std::unique_ptr<DnsResponse> BuildTestDnsIntegrityResponse( std::string hostname, - std::vector<EsniContent> esni_records, - std::string answer_name) { - if (answer_name.empty()) - answer_name = hostname; + const std::vector<uint8_t>& serialized_rdata) { + CHECK(!hostname.empty()); - std::vector<DnsResourceRecord> answers; - answers.reserve(esni_records.size()); - for (EsniContent& c : esni_records) { - answers.push_back(BuildEsniRecord(answer_name, c)); - } + std::vector<DnsResourceRecord> answers{ + BuildIntegrityRecord(hostname, serialized_rdata)}; std::string dns_name; CHECK(DNSDomainFromDot(hostname, &dns_name)); base::Optional<DnsQuery> query(base::in_place, 0, dns_name, - dns_protocol::kExperimentalTypeEsniDraft4); + dns_protocol::kExperimentalTypeIntegrity); return std::make_unique<DnsResponse>( 0, false, std::move(answers), - std::vector<DnsResourceRecord>() /* authority_records */, - std::vector<DnsResourceRecord>() /* additional_records */, query); + std::vector<DnsResourceRecord>() /* authority_records */, + std::vector<DnsResourceRecord>() /* additional_records */, query); } MockDnsClientRule::Result::Result(ResultType type) : type(type) {} @@ -560,15 +481,17 @@ class MockDnsTransactionFactory::MockTransaction case MockDnsClientRule::NODOMAIN: case MockDnsClientRule::FAIL: std::move(callback_).Run(this, ERR_NAME_NOT_RESOLVED, - result_.response.get()); + result_.response.get(), base::nullopt); break; case MockDnsClientRule::EMPTY: case MockDnsClientRule::OK: case MockDnsClientRule::MALFORMED: - std::move(callback_).Run(this, OK, result_.response.get()); + std::move(callback_).Run(this, OK, result_.response.get(), + base::nullopt); break; case MockDnsClientRule::TIMEOUT: - std::move(callback_).Run(this, ERR_DNS_TIMED_OUT, nullptr); + std::move(callback_).Run(this, ERR_DNS_TIMED_OUT, nullptr, + base::nullopt); break; } } diff --git a/chromium/net/dns/dns_test_util.h b/chromium/net/dns/dns_test_util.h index bc056cd8a80..40c619976a0 100644 --- a/chromium/net/dns/dns_test_util.h +++ b/chromium/net/dns/dns_test_util.h @@ -23,7 +23,6 @@ #include "net/dns/dns_response.h" #include "net/dns/dns_transaction.h" #include "net/dns/dns_util.h" -#include "net/dns/esni_content.h" #include "net/dns/public/dns_protocol.h" #include "net/socket/socket_test_util.h" @@ -184,22 +183,6 @@ static const char* const kT4IpAddresses[] = {"172.217.6.195"}; static const int kT4TTL = 0x0000012b; static const unsigned kT4RecordCount = base::size(kT0IpAddresses); -//-------------------------------------------------------------------- -// A well-formed ESNI (TLS 1.3 Encrypted Server Name Indication, -// draft 4) keys object ("ESNIKeys" member of the ESNIRecord struct from -// the spec). -// -// (This is cribbed from boringssl SSLTest.ESNIKeysDeserialize (CL 37704/13).) -extern const char kWellFormedEsniKeys[]; -extern const size_t kWellFormedEsniKeysSize; - -// Returns a well-formed ESNI keys object identical to kWellFormedEsniKeys, -// except that the first 0x22 bytes of |custom_data| are written over -// fields of the keys object in a manner that leaves length prefixes -// correct and enum members valid, and so that distinct values of -// |custom_data| result in distinct returned keys. -std::string GenerateWellFormedEsniKeys(base::StringPiece custom_data = ""); - class AddressSorter; class DnsClient; class DnsSession; @@ -241,10 +224,9 @@ std::unique_ptr<DnsResponse> BuildTestDnsServiceResponse( std::vector<TestServiceRecord> service_records, std::string answer_name = ""); -std::unique_ptr<DnsResponse> BuildTestDnsEsniResponse( +std::unique_ptr<DnsResponse> BuildTestDnsIntegrityResponse( std::string hostname, - std::vector<EsniContent> esni_records, - std::string answer_name = ""); + const std::vector<uint8_t>& serialized_rdata); struct MockDnsClientRule { enum ResultType { diff --git a/chromium/net/dns/dns_transaction.cc b/chromium/net/dns/dns_transaction.cc index 8c58aeca906..60e97bf23f3 100644 --- a/chromium/net/dns/dns_transaction.cc +++ b/chromium/net/dns/dns_transaction.cc @@ -129,7 +129,7 @@ base::Value NetLogStartParams(const std::string& hostname, uint16_t qtype) { // matches. Logging is done in the socket and in the outer DnsTransaction. class DnsAttempt { public: - explicit DnsAttempt(int server_index) + explicit DnsAttempt(size_t server_index) : result_(ERR_FAILED), server_index_(server_index) {} virtual ~DnsAttempt() = default; @@ -147,10 +147,9 @@ class DnsAttempt { // Returns the net log bound to the source of the socket. virtual const NetLogWithSource& GetSocketNetLog() const = 0; - // Returns the index of the destination server within DnsConfig::nameservers. - // If the server index is -1, indicates that no request was sent and that the - // attempt was resolved synchronously with failure. - int server_index() const { return server_index_; } + // Returns the index of the destination server within DnsConfig::nameservers + // (or DnsConfig::dns_over_https_servers for secure transactions). + size_t server_index() const { return server_index_; } // Returns a Value representing the received response, along with a reference // to the NetLog source source of the UDP socket used. The request must have @@ -180,7 +179,7 @@ class DnsAttempt { // Result of last operation. int result_; - const int server_index_; + const size_t server_index_; DISALLOW_COPY_AND_ASSIGN(DnsAttempt); }; @@ -570,7 +569,7 @@ class DnsHTTPAttempt : public DnsAttempt, public URLRequest::Delegate { }; void ConstructDnsHTTPAttempt(DnsSession* session, - int doh_server_index, + size_t doh_server_index, std::string hostname, uint16_t qtype, const OptRecordRdata* opt_rdata, @@ -589,9 +588,7 @@ void ConstructDnsHTTPAttempt(DnsSession* session, query = attempts->at(0)->GetQuery()->CloneWithNewId(id); } - DCHECK_GE(doh_server_index, 0); - DCHECK_LT(doh_server_index, - (int)session->config().dns_over_https_servers.size()); + DCHECK_LT(doh_server_index, session->config().dns_over_https_servers.size()); const DnsOverHttpsServerConfig& doh_config = session->config().dns_over_https_servers[doh_server_index]; GURL gurl_without_parameters( @@ -922,7 +919,7 @@ class DnsOverHttpsProbeRunner : public DnsProbeRunner { base::WeakPtrFactory<ProbeStats> weak_factory{this}; }; - void ContinueProbe(int doh_server_index, + void ContinueProbe(size_t doh_server_index, base::WeakPtr<ProbeStats> probe_stats, bool network_change, base::TimeTicks sequence_start_time) { @@ -973,7 +970,7 @@ class DnsOverHttpsProbeRunner : public DnsProbeRunner { } void ProbeComplete(unsigned attempt_number, - int doh_server_index, + size_t doh_server_index, base::WeakPtr<ProbeStats> probe_stats, bool network_change, base::TimeTicks sequence_start_time, @@ -1187,7 +1184,14 @@ class DnsTransactionImpl : public DnsTransaction, net_log_.EndEventWithNetErrorCode(NetLogEventType::DNS_TRANSACTION, result.rv); - std::move(callback_).Run(this, result.rv, response); + base::Optional<std::string> doh_provider_id; + if (secure_ && result.attempt) { + size_t server_index = result.attempt->server_index(); + doh_provider_id = GetDohProviderIdForHistogramFromDohConfig( + session_->config().dns_over_https_servers[server_index]); + } + + std::move(callback_).Run(this, result.rv, response, doh_provider_id); } AttemptResult MakeAttempt() { @@ -1406,7 +1410,7 @@ class DnsTransactionImpl : public DnsTransaction, if (result.attempt) { resolve_context_->RecordServerFailure( result.attempt->server_index(), secure_ /* is_doh_server */, - session_.get()); + result.rv, session_.get()); } if (MoreAttemptsAllowed()) { result = MakeAttempt(); @@ -1424,14 +1428,20 @@ class DnsTransactionImpl : public DnsTransaction, default: // Server failure. DCHECK(result.attempt); + + // If attempt is not the most recent attempt, means this error is for + // an attempt that already timed out and was treated as complete but + // allowed to continue attempting in parallel with new attempts (see + // the ERR_DNS_TIMED_OUT case above). As the failure was already + // recorded at timeout time and is no longer being waited on, ignore + // this failure. if (result.attempt != attempts_.back().get()) { - // This attempt already timed out. Ignore it. - DCHECK_GE(result.attempt->server_index(), 0); - resolve_context_->RecordServerFailure( - result.attempt->server_index(), secure_ /* is_doh_server */, - session_.get()); return AttemptResult(ERR_IO_PENDING, nullptr); } + + resolve_context_->RecordServerFailure(result.attempt->server_index(), + secure_ /* is_doh_server */, + result.rv, session_.get()); if (!MoreAttemptsAllowed()) { return result; } diff --git a/chromium/net/dns/dns_transaction.h b/chromium/net/dns/dns_transaction.h index 7bb9501d09b..bc182ff7612 100644 --- a/chromium/net/dns/dns_transaction.h +++ b/chromium/net/dns/dns_transaction.h @@ -80,9 +80,14 @@ class NET_EXPORT_PRIVATE DnsTransactionFactory { // Called with the response or NULL if no matching response was received. // Note that the |GetDottedName()| of the response may be different than the // original |hostname| as a result of suffix search. + // + // The |doh_provider_id| contains the provider ID for histograms of the last + // DoH server attempted. If the name is unavailable, or this is not a DoH + // transaction, |doh_provider_id| is nullopt. typedef base::OnceCallback<void(DnsTransaction* transaction, int neterror, - const DnsResponse* response)> + const DnsResponse* response, + base::Optional<std::string> doh_provider_id)> CallbackType; DnsTransactionFactory(); diff --git a/chromium/net/dns/dns_transaction_unittest.cc b/chromium/net/dns/dns_transaction_unittest.cc index e3196cfc21e..17f6bf62e72 100644 --- a/chromium/net/dns/dns_transaction_unittest.cc +++ b/chromium/net/dns/dns_transaction_unittest.cc @@ -28,6 +28,7 @@ #include "net/base/port_util.h" #include "net/base/upload_bytes_element_reader.h" #include "net/base/url_util.h" +#include "net/cookies/cookie_inclusion_status.h" #include "net/cookies/cookie_util.h" #include "net/dns/dns_config.h" #include "net/dns/dns_query.h" @@ -324,7 +325,8 @@ class TransactionHelper { void OnTransactionComplete(DnsTransaction* t, int rv, - const DnsResponse* response) { + const DnsResponse* response, + base::Optional<std::string> doh_provider_id) { EXPECT_FALSE(completed_); EXPECT_EQ(transaction_.get(), t); @@ -1200,8 +1202,17 @@ TEST_F(DnsTransactionTestWithMockTime, ServerFallbackAndRotate) { EXPECT_TRUE(helper1.Run(transaction_factory_.get())); size_t kOrder[] = { - 0, 1, 2, 0, 1, // The first transaction. - 1, 2, 0, // The second transaction starts from the next server. + // The first transaction. + 0, + 1, + 2, + 0, + 1, + // The second transaction starts from the next server, and 0 is skipped + // because it already has 2 consecutive failures. + 1, + 2, + 1, }; CheckServerOrder(kOrder, base::size(kOrder)); } @@ -2178,14 +2189,15 @@ class CookieCallback { CookieCallback() : result_(false), loop_to_quit_(std::make_unique<base::RunLoop>()) {} - void SetCookieCallback(CanonicalCookie::CookieInclusionStatus result) { + void SetCookieCallback(CookieInclusionStatus result) { result_ = result.IsInclude(); loop_to_quit_->Quit(); } - void GetCookieListCallback(const net::CookieStatusList& list, - const net::CookieStatusList& excluded_cookies) { - list_ = cookie_util::StripStatuses(list); + void GetCookieListCallback( + const net::CookieAccessResultList& list, + const net::CookieAccessResultList& excluded_cookies) { + list_ = cookie_util::StripAccessResults(list); loop_to_quit_->Quit(); } @@ -2384,6 +2396,63 @@ TEST_F(DnsTransactionTest, HttpsPostLookupWithLog) { EXPECT_EQ(observer.dict_count(), 3); } +// Test for when a slow DoH response is delayed until after the initial timeout +// and no more attempts are configured. +TEST_F(DnsTransactionTestWithMockTime, SlowHttpsResponse_SingleAttempt) { + config_.doh_attempts = 1; + ConfigureDohServers(false /* use_post */); + + AddQueryAndTimeout(kT0HostName, kT0Qtype, + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); + + TransactionHelper helper(kT0HostName, kT0Qtype, true /* secure */, + ERR_DNS_TIMED_OUT, resolve_context_.get()); + ASSERT_FALSE(helper.Run(transaction_factory_.get())); + + // Only one attempt configured, so expect immediate failure after timeout + // period. + FastForwardBy(resolve_context_->NextDohTimeout(0 /* doh_server_index */, + session_.get())); + EXPECT_TRUE(helper.has_completed()); +} + +// Test for when a slow DoH response is delayed until after the initial timeout +// but a retry is configured. +TEST_F(DnsTransactionTestWithMockTime, SlowHttpsResponse_TwoAttempts) { + config_.doh_attempts = 2; + ConfigureDohServers(false /* use_post */); + + // Simulate a slow response by using an ERR_IO_PENDING read error to delay + // until SequencedSocketData::Resume() is called. + auto data = std::make_unique<DnsSocketData>( + 1 /* id */, kT1HostName, kT1Qtype, ASYNC, Transport::HTTPS, + nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); + data->AddReadError(ERR_IO_PENDING, ASYNC); + data->AddResponseData(kT1ResponseDatagram, base::size(kT1ResponseDatagram), + ASYNC); + SequencedSocketData* sequenced_socket_data = data->GetProvider(); + AddSocketData(std::move(data)); + + TransactionHelper helper(kT1HostName, kT1Qtype, true /* secure */, + kT1RecordCount, resolve_context_.get()); + ASSERT_FALSE(helper.Run(transaction_factory_.get())); + ASSERT_TRUE(sequenced_socket_data->IsPaused()); + + // Another attempt configured, so transaction should not fail after initial + // timeout. Setup the second attempt to never receive a response. + AddQueryAndTimeout(kT1HostName, kT1Qtype, + DnsQuery::PaddingStrategy::BLOCK_LENGTH_128); + FastForwardBy(resolve_context_->NextDohTimeout(0 /* doh_server_index */, + session_.get())); + EXPECT_FALSE(helper.has_completed()); + + // Expect first attempt to continue in parallel with retry, so expect the + // transaction to complete when the first query is allowed to resume. + sequenced_socket_data->Resume(); + base::RunLoop().RunUntilIdle(); + EXPECT_TRUE(helper.has_completed()); +} + TEST_F(DnsTransactionTest, TCPLookup) { AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC); @@ -3100,8 +3169,9 @@ TEST_F(DnsTransactionTestWithMockTime, RestartFinishedProbe) { // Mark server unavailabe and restart runner. for (int i = 0; i < ResolveContext::kAutomaticModeFailureLimit; ++i) { - resolve_context_->RecordServerFailure( - 0u /* server_index */, true /* is_doh_server */, session_.get()); + resolve_context_->RecordServerFailure(0u /* server_index */, + true /* is_doh_server */, ERR_FAILED, + session_.get()); } ASSERT_FALSE(resolve_context_->GetDohServerAvailability( 0u /* doh_server_index */, session_.get())); @@ -3149,8 +3219,9 @@ TEST_F(DnsTransactionTestWithMockTime, FastProbeRestart) { // becoming unavailable and might as well replecate real behavior for the // test. for (int i = 0; i < ResolveContext::kAutomaticModeFailureLimit; ++i) { - resolve_context_->RecordServerFailure( - 0u /* server_index */, true /* is_doh_server */, session_.get()); + resolve_context_->RecordServerFailure(0u /* server_index */, + true /* is_doh_server */, ERR_FAILED, + session_.get()); } ASSERT_FALSE(resolve_context_->GetDohServerAvailability( 0u /* doh_server_index */, session_.get())); diff --git a/chromium/net/dns/dns_util.cc b/chromium/net/dns/dns_util.cc index 49bfdfc8323..9ad7d53637c 100644 --- a/chromium/net/dns/dns_util.cc +++ b/chromium/net/dns/dns_util.cc @@ -21,7 +21,7 @@ #include "net/base/address_list.h" #include "net/base/url_util.h" #include "net/dns/public/dns_protocol.h" -#include "net/dns/public/doh_provider_list.h" +#include "net/dns/public/doh_provider_entry.h" #include "net/dns/public/util.h" #include "net/third_party/uri_template/uri_template.h" #include "url/url_canon.h" @@ -113,21 +113,21 @@ bool DNSDomainFromDot(const base::StringPiece& dotted, return true; } -std::vector<const DohProviderEntry*> GetDohProviderEntriesFromNameservers( +DohProviderEntry::List GetDohProviderEntriesFromNameservers( const std::vector<IPEndPoint>& dns_servers, const std::vector<std::string>& excluded_providers) { - const std::vector<DohProviderEntry>& providers = GetDohProviderList(); - std::vector<const DohProviderEntry*> entries; + const DohProviderEntry::List& providers = DohProviderEntry::GetList(); + DohProviderEntry::List entries; for (const auto& server : dns_servers) { - for (const auto& entry : providers) { - if (base::Contains(excluded_providers, entry.provider)) + for (const auto* entry : providers) { + if (base::Contains(excluded_providers, entry->provider)) continue; // DoH servers should only be added once. - if (base::Contains(entry.ip_addresses, server.address()) && - !base::Contains(entries, &entry)) { - entries.push_back(&entry); + if (base::Contains(entry->ip_addresses, server.address()) && + !base::Contains(entries, entry)) { + entries.push_back(entry); } } } @@ -289,8 +289,8 @@ uint16_t DnsQueryTypeToQtype(DnsQueryType dns_query_type) { return dns_protocol::kTypePTR; case DnsQueryType::SRV: return dns_protocol::kTypeSRV; - case DnsQueryType::ESNI: - return dns_protocol::kExperimentalTypeEsniDraft4; + case DnsQueryType::INTEGRITY: + return dns_protocol::kExperimentalTypeIntegrity; } } @@ -311,23 +311,21 @@ DnsQueryType AddressFamilyToDnsQueryType(AddressFamily address_family) { std::vector<DnsOverHttpsServerConfig> GetDohUpgradeServersFromDotHostname( const std::string& dot_server, const std::vector<std::string>& excluded_providers) { - const std::vector<DohProviderEntry>& entries = GetDohProviderList(); std::vector<DnsOverHttpsServerConfig> doh_servers; if (dot_server.empty()) return doh_servers; - for (const auto& entry : entries) { - if (base::Contains(excluded_providers, entry.provider)) + for (const auto* entry : DohProviderEntry::GetList()) { + if (base::Contains(excluded_providers, entry->provider)) continue; - if (base::Contains(entry.dns_over_tls_hostnames, dot_server)) { + if (base::Contains(entry->dns_over_tls_hostnames, dot_server)) { std::string server_method; - CHECK(dns_util::IsValidDohTemplate(entry.dns_over_https_template, + CHECK(dns_util::IsValidDohTemplate(entry->dns_over_https_template, &server_method)); - doh_servers.push_back(DnsOverHttpsServerConfig( - entry.dns_over_https_template, server_method == "POST")); - break; + doh_servers.emplace_back(entry->dns_over_https_template, + server_method == "POST"); } } return doh_servers; @@ -336,38 +334,35 @@ std::vector<DnsOverHttpsServerConfig> GetDohUpgradeServersFromDotHostname( std::vector<DnsOverHttpsServerConfig> GetDohUpgradeServersFromNameservers( const std::vector<IPEndPoint>& dns_servers, const std::vector<std::string>& excluded_providers) { - std::vector<const DohProviderEntry*> entries = + const auto entries = GetDohProviderEntriesFromNameservers(dns_servers, excluded_providers); std::vector<DnsOverHttpsServerConfig> doh_servers; - std::string server_method; - for (const auto* entry : entries) { - CHECK(dns_util::IsValidDohTemplate(entry->dns_over_https_template, - &server_method)); - doh_servers.push_back(DnsOverHttpsServerConfig( - entry->dns_over_https_template, server_method == "POST")); - } + doh_servers.reserve(entries.size()); + std::transform(entries.begin(), entries.end(), + std::back_inserter(doh_servers), [](const auto* entry) { + std::string server_method; + CHECK(dns_util::IsValidDohTemplate( + entry->dns_over_https_template, &server_method)); + return DnsOverHttpsServerConfig( + entry->dns_over_https_template, server_method == "POST"); + }); return doh_servers; } std::string GetDohProviderIdForHistogramFromDohConfig( const DnsOverHttpsServerConfig& doh_server) { - const std::vector<DohProviderEntry>& entries = GetDohProviderList(); - for (const auto& entry : entries) { - if (doh_server.server_template == entry.dns_over_https_template) { - return entry.provider; - } - } - return "Other"; + const auto& entries = DohProviderEntry::GetList(); + const auto it = + std::find_if(entries.begin(), entries.end(), [&](const auto* entry) { + return entry->dns_over_https_template == doh_server.server_template; + }); + return it != entries.end() ? (*it)->provider : "Other"; } std::string GetDohProviderIdForHistogramFromNameserver( const IPEndPoint& nameserver) { - std::vector<const DohProviderEntry*> entries = - GetDohProviderEntriesFromNameservers({nameserver}, {}); - if (entries.size() == 0) - return "Other"; - else - return entries[0]->provider; + const auto entries = GetDohProviderEntriesFromNameservers({nameserver}, {}); + return entries.empty() ? "Other" : entries[0]->provider; } std::string SecureDnsModeToString( diff --git a/chromium/net/dns/dns_util_unittest.cc b/chromium/net/dns/dns_util_unittest.cc index f07c342e442..39a89880b4f 100644 --- a/chromium/net/dns/dns_util_unittest.cc +++ b/chromium/net/dns/dns_util_unittest.cc @@ -6,6 +6,7 @@ #include "base/stl_util.h" #include "net/dns/public/dns_protocol.h" +#include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" namespace net { @@ -183,20 +184,24 @@ TEST_F(DNSUtilTest, GetDohUpgradeServersFromNameservers) { doh_servers = GetDohUpgradeServersFromNameservers(nameservers, std::vector<std::string>()); - EXPECT_EQ(3u, doh_servers.size()); - EXPECT_EQ("https://chrome.cloudflare-dns.com/dns-query", - doh_servers[0].server_template); - EXPECT_EQ("https://doh.cleanbrowsing.org/doh/family-filter{?dns}", - doh_servers[1].server_template); - EXPECT_EQ("https://doh.cleanbrowsing.org/doh/security-filter{?dns}", - doh_servers[2].server_template); + EXPECT_THAT( + doh_servers, + testing::ElementsAre( + DnsOverHttpsServerConfig( + "https://chrome.cloudflare-dns.com/dns-query", true), + DnsOverHttpsServerConfig( + "https://doh.cleanbrowsing.org/doh/family-filter{?dns}", false), + DnsOverHttpsServerConfig( + "https://doh.cleanbrowsing.org/doh/security-filter{?dns}", + false))); doh_servers = GetDohUpgradeServersFromNameservers( nameservers, std::vector<std::string>( {"CleanBrowsingSecure", "Cloudflare", "Unexpected"})); - EXPECT_EQ(1u, doh_servers.size()); - EXPECT_EQ("https://doh.cleanbrowsing.org/doh/family-filter{?dns}", - doh_servers[0].server_template); + EXPECT_THAT( + doh_servers, + testing::ElementsAre(DnsOverHttpsServerConfig( + "https://doh.cleanbrowsing.org/doh/family-filter{?dns}", false))); } TEST_F(DNSUtilTest, GetDohProviderIdForHistogramFromDohConfig) { diff --git a/chromium/net/dns/esni_content.cc b/chromium/net/dns/esni_content.cc deleted file mode 100644 index 014d492942b..00000000000 --- a/chromium/net/dns/esni_content.cc +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/dns/esni_content.h" - -namespace net { - -EsniContent::EsniContent() = default; -EsniContent::EsniContent(const EsniContent& other) { - MergeFrom(other); -} -EsniContent::EsniContent(EsniContent&& other) = default; -EsniContent& EsniContent::operator=(const EsniContent& other) { - MergeFrom(other); - return *this; -} -EsniContent& EsniContent::operator=(EsniContent&& other) = default; -EsniContent::~EsniContent() = default; - -bool operator==(const EsniContent& c1, const EsniContent& c2) { - return c1.keys() == c2.keys() && - c1.keys_for_addresses() == c2.keys_for_addresses(); -} - -const std::set<std::string, EsniContent::StringPieceComparator>& -EsniContent::keys() const { - return keys_; -} - -const std::map<IPAddress, std::set<base::StringPiece>>& -EsniContent::keys_for_addresses() const { - return keys_for_addresses_; -} - -void EsniContent::AddKey(base::StringPiece key) { - if (keys_.find(key) == keys_.end()) - keys_.insert(std::string(key)); -} - -void EsniContent::AddKeyForAddress(const IPAddress& address, - base::StringPiece key) { - auto key_it = keys_.find(key); - if (key_it == keys_.end()) { - bool key_was_added; - std::tie(key_it, key_was_added) = keys_.insert(std::string(key)); - DCHECK(key_was_added); - } - keys_for_addresses_[address].insert(base::StringPiece(*key_it)); -} - -void EsniContent::MergeFrom(const EsniContent& other) { - for (const auto& kv : other.keys_for_addresses()) { - const IPAddress& address = kv.first; - const auto& keys_for_address = kv.second; - for (base::StringPiece key : keys_for_address) - AddKeyForAddress(address, key); - } - for (const std::string& key : other.keys()) - AddKey(key); -} - -} // namespace net diff --git a/chromium/net/dns/esni_content.h b/chromium/net/dns/esni_content.h deleted file mode 100644 index 8c6a8e0d0cc..00000000000 --- a/chromium/net/dns/esni_content.h +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_DNS_ESNI_CONTENT_H_ -#define NET_DNS_ESNI_CONTENT_H_ - -#include <map> -#include <set> -#include <string> - -#include "base/strings/string_piece.h" -#include "net/base/ip_address.h" -#include "net/base/net_export.h" - -namespace net { - -// An EsniContent struct represents an aggregation of the -// content of several ESNI (TLS 1.3 Encrypted Server Name Indication, -// draft 4) resource records. -// -// This aggregation contains: -// (1) The ESNI key objects from each of the ESNI records, and -// (2) A collection of IP addresses, each of which is associated -// with one or more of the key objects. (Each key will likely also -// be associated with several destination addresses.) -class NET_EXPORT EsniContent { - public: - EsniContent(); - EsniContent(const EsniContent& other); - EsniContent(EsniContent&& other); - EsniContent& operator=(const EsniContent& other); - EsniContent& operator=(EsniContent&& other); - ~EsniContent(); - - // Key objects (which might be up to ~50K in length) are stored - // in a collection of std::string; use transparent comparison - // to allow checking whether a given base::StringPiece is in - // the collection without making copies. - struct StringPieceComparator { - using is_transparent = int; - - bool operator()(const base::StringPiece lhs, - const base::StringPiece rhs) const { - return lhs < rhs; - } - }; - - const std::set<std::string, StringPieceComparator>& keys() const; - const std::map<IPAddress, std::set<base::StringPiece>>& keys_for_addresses() - const; - - // Adds |key| (if it is not already stored) without associating it - // with any particular addresss; if this addition is performed, it - // copies the underlying string. - void AddKey(base::StringPiece key); - - // Associates a key with an address, copying the underlying string to - // the internal collection of keys if it is not already stored. - void AddKeyForAddress(const IPAddress& address, base::StringPiece key); - - // Merges the contents of |other|: - // 1. unions the collection of stored keys with |other.keys()| and - // 2. unions the stored address-key associations with - // |other.keys_for_addresses()|. - void MergeFrom(const EsniContent& other); - - private: - // In order to keep the StringPieces in |keys_for_addresses_| valid, - // |keys_| must be of a collection type guaranteeing stable pointers. - std::set<std::string, StringPieceComparator> keys_; - - std::map<IPAddress, std::set<base::StringPiece>> keys_for_addresses_; -}; - -// Two EsniContent structs are equal if they have the same set of keys, the -// same set of IP addresses, and the same subset of the keys corresponding to -// each IP address. -NET_EXPORT_PRIVATE -bool operator==(const EsniContent& c1, const EsniContent& c2); - -} // namespace net - -#endif // NET_DNS_ESNI_CONTENT_H_ diff --git a/chromium/net/dns/esni_content_unittest.cc b/chromium/net/dns/esni_content_unittest.cc deleted file mode 100644 index 50bc5d81dca..00000000000 --- a/chromium/net/dns/esni_content_unittest.cc +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/dns/esni_content.h" - -#include "base/strings/string_number_conversions.h" - -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace net { - -namespace { - -IPAddress MakeIPAddress() { - // Introduce some (deterministic) variation in the IP addresses - // generated. - static uint8_t next_octet = 0; - next_octet += 4; - - return IPAddress(next_octet, next_octet + 1, next_octet + 2, next_octet + 3); -} - -// Make sure we can add keys. -TEST(EsniContentTest, AddKey) { - EsniContent c1; - c1.AddKey("a"); - EXPECT_THAT(c1.keys(), ::testing::UnorderedElementsAre("a")); - c1.AddKey("a"); - EXPECT_THAT(c1.keys(), ::testing::UnorderedElementsAre("a")); - c1.AddKey("b"); - EXPECT_THAT(c1.keys(), ::testing::UnorderedElementsAre("a", "b")); -} - -// Make sure we can add key-address pairs. -TEST(EsniContentTest, AddKeyForAddress) { - EsniContent c1; - auto address = MakeIPAddress(); - c1.AddKeyForAddress(address, "a"); - EXPECT_THAT(c1.keys(), ::testing::UnorderedElementsAre("a")); - EXPECT_THAT(c1.keys_for_addresses(), - ::testing::UnorderedElementsAre(::testing::Pair( - address, ::testing::UnorderedElementsAre("a")))); -} - -TEST(EsniContentTest, AssociateAddressWithExistingKey) { - EsniContent c1; - auto address = MakeIPAddress(); - c1.AddKey("a"); - c1.AddKeyForAddress(address, "a"); - EXPECT_THAT(c1.keys(), ::testing::UnorderedElementsAre("a")); - EXPECT_THAT(c1.keys_for_addresses(), - ::testing::UnorderedElementsAre(::testing::Pair( - address, ::testing::UnorderedElementsAre("a")))); -} - -// Merging to an empty EsniContent should make the result equal the source of -// the merge. -TEST(EsniContentTest, MergeToEmpty) { - EsniContent c1; - c1.AddKey("c"); - IPAddress address = MakeIPAddress(); - - c1.AddKeyForAddress(address, "a"); - c1.AddKeyForAddress(address, "b"); - EsniContent empty; - empty.MergeFrom(c1); - EXPECT_EQ(c1, empty); -} - -TEST(EsniContentTest, MergeFromEmptyNoOp) { - EsniContent c1, c2; - c1.AddKey("a"); - c2.AddKey("a"); - EsniContent empty; - c1.MergeFrom(empty); - EXPECT_EQ(c1, c2); -} - -// Test that merging multiple keys corresponding to a single address works. -TEST(EsniContentTest, MergeKeysForSingleHost) { - EsniContent c1, c2; - IPAddress address = MakeIPAddress(); - - c1.AddKeyForAddress(address, "a"); - c1.AddKeyForAddress(address, "b"); - c2.AddKeyForAddress(address, "b"); - c2.AddKeyForAddress(address, "c"); - c1.MergeFrom(c2); - - EXPECT_THAT(c1.keys(), ::testing::UnorderedElementsAre("a", "b", "c")); - EXPECT_THAT(c1.keys_for_addresses(), - ::testing::UnorderedElementsAre(::testing::Pair( - address, ::testing::UnorderedElementsAre("a", "b", "c")))); -} - -// Test that merging multiple addresss corresponding to a single key works. -TEST(EsniContentTest, MergeHostsForSingleKey) { - EsniContent c1, c2; - IPAddress address = MakeIPAddress(); - IPAddress second_address = MakeIPAddress(); - c1.AddKeyForAddress(address, "a"); - c2.AddKeyForAddress(second_address, "a"); - c1.MergeFrom(c2); - - EXPECT_THAT(c1.keys(), ::testing::UnorderedElementsAre("a")); - EXPECT_THAT( - c1.keys_for_addresses(), - ::testing::UnorderedElementsAre( - ::testing::Pair(address, ::testing::UnorderedElementsAre("a")), - ::testing::Pair(second_address, - ::testing::UnorderedElementsAre("a")))); -} - -// Test merging some more complex instances of the class. -TEST(EsniContentTest, MergeSeveralHostsAndKeys) { - EsniContent c1, c2, expected; - for (int i = 0; i < 50; ++i) { - IPAddress address = MakeIPAddress(); - std::string key = base::NumberToString(i); - switch (i % 3) { - case 0: - c1.AddKey(key); - expected.AddKey(key); - break; - case 1: - c2.AddKey(key); - expected.AddKey(key); - break; - } - // Associate each address with a subset of the keys seen so far - { - int j = 0; - for (auto key : c1.keys()) { - if (j % 2) { - c1.AddKeyForAddress(address, key); - expected.AddKeyForAddress(address, key); - } - ++j; - } - } - { - int j = 0; - for (auto key : c2.keys()) { - if (j % 3 == 1) { - c2.AddKeyForAddress(address, key); - expected.AddKeyForAddress(address, key); - } - ++j; - } - } - } - { - EsniContent merge_dest = c1; - EsniContent merge_src = c2; - merge_dest.MergeFrom(merge_src); - EXPECT_EQ(merge_dest, expected); - } - { - EsniContent merge_dest = c2; - EsniContent merge_src = c1; - merge_dest.MergeFrom(merge_src); - EXPECT_EQ(merge_dest, expected); - } -} - -} // namespace - -} // namespace net diff --git a/chromium/net/dns/host_cache.cc b/chromium/net/dns/host_cache.cc index 647d44ae427..70805898089 100644 --- a/chromium/net/dns/host_cache.cc +++ b/chromium/net/dns/host_cache.cc @@ -13,6 +13,7 @@ #include "base/strings/string_number_conversions.h" #include "base/time/default_tick_clock.h" #include "base/trace_event/trace_event.h" +#include "net/base/address_family.h" #include "net/base/ip_endpoint.h" #include "net/base/trace_constants.h" #include "net/dns/host_resolver.h" @@ -47,7 +48,6 @@ const char kAddressesKey[] = "addresses"; const char kTextRecordsKey[] = "text_records"; const char kHostnameResultsKey[] = "hostname_results"; const char kHostPortsKey[] = "host_ports"; -const char kEsniDataKey[] = "esni_data"; bool AddressListFromListValue(const base::ListValue* value, base::Optional<AddressList>* out_list) { @@ -69,67 +69,6 @@ bool AddressListFromListValue(const base::ListValue* value, return true; } -// Serializes the cache's ESNI content as -// { -// key 0: [addresses for key 0], -// ..., -// key N: [address for key N] -// } -base::Value EsniContentToValue(const EsniContent& content) { - base::Value addresses_for_keys_value(base::Value::Type::DICTIONARY); - - for (const auto& key : content.keys()) { - addresses_for_keys_value.SetKey(key, base::Value(base::Value::Type::LIST)); - } - - for (const auto& kv : content.keys_for_addresses()) { - const IPAddress& address = kv.first; - const auto& keys_for_address = kv.second; - for (base::StringPiece key : keys_for_address) { - base::Value* addresses_for_key = addresses_for_keys_value.FindKey(key); - DCHECK(addresses_for_key); - addresses_for_key->Append(address.ToString()); - } - } - - return addresses_for_keys_value; -} - -bool EsniContentFromValue(const base::Value& esni_content_value, - base::Optional<EsniContent>* out_esni_content) { - EsniContent content_for_cache; - - // The esni_data cache member is encoded as a - // { key: list of associated IP addresses } dictionary. - if (!esni_content_value.is_dict()) - return false; - - for (const auto& kv : esni_content_value.DictItems()) { - const std::string& key = kv.first; - const base::Value& serialized_addresses = kv.second; - if (!serialized_addresses.is_list()) - return false; - if (serialized_addresses.GetList().empty()) { - content_for_cache.AddKey(key); - } else { - for (const base::Value& serialized_address_value : - serialized_addresses.GetList()) { - if (!serialized_address_value.is_string()) - return false; - const std::string& serialized_address = - serialized_address_value.GetString(); - IPAddress address; - if (!address.AssignFromIPLiteral(serialized_address)) - return false; - content_for_cache.AddKeyForAddress(address, key); - } - } - } - - *out_esni_content = std::move(content_for_cache); - return true; -} - template <typename T> void MergeLists(base::Optional<T>* target, const base::Optional<T>& source) { if (target->has_value() && source) { @@ -220,11 +159,7 @@ HostCache::Entry HostCache::Entry::MergeEntries(Entry front, Entry back) { front.MergeAddressesFrom(back); MergeLists(&front.text_records_, back.text_records()); MergeLists(&front.hostnames_, back.hostnames()); - if (back.esni_data_ && !front.esni_data_) { - front.esni_data_ = std::move(back.esni_data_); - } else if (front.esni_data_ && back.esni_data_) { - front.esni_data_->MergeFrom(back.esni_data_.value()); - } + MergeLists(&front.integrity_data_, back.integrity_data()); // Use canonical name from |back| iff empty in |front|. if (front.addresses() && front.addresses().value().canonical_name().empty() && @@ -298,7 +233,7 @@ HostCache::Entry::Entry(const HostCache::Entry& entry, addresses_(entry.addresses()), text_records_(entry.text_records()), hostnames_(entry.hostnames()), - esni_data_(entry.esni_data()), + integrity_data_(entry.integrity_data()), source_(entry.source()), ttl_(entry.ttl()), expires_(now + ttl), @@ -308,7 +243,7 @@ HostCache::Entry::Entry(int error, const base::Optional<AddressList>& addresses, base::Optional<std::vector<std::string>>&& text_records, base::Optional<std::vector<HostPortPair>>&& hostnames, - base::Optional<EsniContent>&& esni_data, + base::Optional<std::vector<bool>>&& integrity_data, Source source, base::TimeTicks expires, int network_changes) @@ -316,11 +251,15 @@ HostCache::Entry::Entry(int error, addresses_(addresses), text_records_(std::move(text_records)), hostnames_(std::move(hostnames)), - esni_data_(std::move(esni_data)), + integrity_data_(std::move(integrity_data)), source_(source), expires_(expires), network_changes_(network_changes) {} +void HostCache::Entry::PrepareForCacheInsertion() { + integrity_data_.reset(); +} + bool HostCache::Entry::IsStale(base::TimeTicks now, int network_changes) const { EntryStaleness stale; stale.expired_by = now - expires_; @@ -355,28 +294,11 @@ void HostCache::Entry::MergeAddressesFrom(const HostCache::Entry& source) { addresses_->Deduplicate(); - auto has_keys = [&](const IPEndPoint& e) { - return (esni_data() && - esni_data()->keys_for_addresses().count(e.address())) || - (source.esni_data() && - source.esni_data()->keys_for_addresses().count(e.address())); - }; - std::stable_sort(addresses_->begin(), addresses_->end(), - [&](const IPEndPoint& lhs, const IPEndPoint& rhs) { - // Prefer an address with ESNI keys to one without; - // break ties by address family. - - // Store one lookup's result to avoid repeating the lookup. - bool lhs_has_keys = has_keys(lhs); - if (lhs_has_keys != has_keys(rhs)) - return lhs_has_keys; - - if ((lhs.GetFamily() == ADDRESS_FAMILY_IPV6) != - (rhs.GetFamily() == ADDRESS_FAMILY_IPV6)) - return (lhs.GetFamily() == ADDRESS_FAMILY_IPV6); - - return false; + [](const IPEndPoint& lhs, const IPEndPoint& rhs) { + // Return true iff |lhs < rhs|. + return lhs.GetFamily() == ADDRESS_FAMILY_IPV6 && + rhs.GetFamily() == ADDRESS_FAMILY_IPV4; }); } @@ -433,10 +355,6 @@ base::DictionaryValue HostCache::Entry::GetAsValue( entry_dict.SetKey(kHostnameResultsKey, std::move(hostnames_value)); entry_dict.SetKey(kHostPortsKey, std::move(host_ports_value)); } - - if (esni_data()) { - entry_dict.SetKey(kEsniDataKey, EsniContentToValue(*esni_data())); - } } return entry_dict; @@ -632,7 +550,9 @@ void HostCache::Set(const Key& key, EvictOneEntry(now); } - AddEntry(key, Entry(entry, now, ttl, network_changes_)); + Entry entry_for_cache(entry, now, ttl, network_changes_); + entry_for_cache.PrepareForCacheInsertion(); + AddEntry(key, std::move(entry_for_cache)); if (delegate_ && result_changed) delegate_->ScheduleWrite(); @@ -801,7 +721,6 @@ bool HostCache::RestoreFromListValue(const base::ListValue& old_cache) { const base::ListValue* text_records_value = nullptr; const base::ListValue* hostname_records_value = nullptr; const base::ListValue* host_ports_value = nullptr; - const base::Value* esni_content_value = nullptr; if (!entry_dict->GetInteger(kErrorKey, &error)) { entry_dict->GetList(kAddressesKey, &addresses_value); entry_dict->GetList(kTextRecordsKey, &text_records_value); @@ -810,8 +729,6 @@ bool HostCache::RestoreFromListValue(const base::ListValue& old_cache) { entry_dict->GetList(kHostPortsKey, &host_ports_value)) { return false; } - - entry_dict->Get(kEsniDataKey, &esni_content_value); } int64_t time_internal; @@ -860,15 +777,12 @@ bool HostCache::RestoreFromListValue(const base::ListValue& old_cache) { } } - base::Optional<EsniContent> esni_content; - if (esni_content_value && - !EsniContentFromValue(*esni_content_value, &esni_content)) { - return false; - } + // We do not intend to serialize INTEGRITY records with the host cache. + base::Optional<std::vector<bool>> integrity_data; // Assume an empty address list if we have an address type and no results. if (IsAddressType(dns_query_type) && !address_list && !text_records && - !hostname_records && !esni_content) { + !hostname_records) { address_list.emplace(); } @@ -882,9 +796,9 @@ bool HostCache::RestoreFromListValue(const base::ListValue& old_cache) { auto found = entries_.find(key); if (found == entries_.end()) { AddEntry(key, Entry(error, address_list, std::move(text_records), - std::move(hostname_records), std::move(esni_content), - Entry::SOURCE_UNKNOWN, expiration_time, - network_changes_ - 1)); + std::move(hostname_records), + std::move(integrity_data), Entry::SOURCE_UNKNOWN, + expiration_time, network_changes_ - 1)); restore_size_++; } } diff --git a/chromium/net/dns/host_cache.h b/chromium/net/dns/host_cache.h index 11f92932edd..a74f7dc5ba9 100644 --- a/chromium/net/dns/host_cache.h +++ b/chromium/net/dns/host_cache.h @@ -15,8 +15,8 @@ #include <utility> #include <vector> +#include "base/check.h" #include "base/gtest_prod_util.h" -#include "base/logging.h" #include "base/macros.h" #include "base/numerics/clamped_math.h" #include "base/optional.h" @@ -31,7 +31,6 @@ #include "net/base/net_export.h" #include "net/base/network_isolation_key.h" #include "net/dns/dns_util.h" -#include "net/dns/esni_content.h" #include "net/dns/host_resolver_source.h" #include "net/dns/public/dns_query_type.h" #include "net/log/net_log_capture_mode.h" @@ -161,10 +160,13 @@ class NET_EXPORT HostCache { void set_hostnames(base::Optional<std::vector<HostPortPair>> hostnames) { hostnames_ = std::move(hostnames); } - const base::Optional<EsniContent>& esni_data() const { return esni_data_; } - void set_esni_data(base::Optional<EsniContent> esni_data) { - esni_data_ = std::move(esni_data); + const base::Optional<std::vector<bool>>& integrity_data() const { + return integrity_data_; } + void set_integrity_data(base::Optional<std::vector<bool>> integrity_data) { + integrity_data_ = std::move(integrity_data); + } + Source source() const { return source_; } bool has_ttl() const { return ttl_ >= base::TimeDelta(); } base::TimeDelta ttl() const { return ttl_; } @@ -176,16 +178,14 @@ class NET_EXPORT HostCache { // Public for the net-internals UI. int network_changes() const { return network_changes_; } - // Merge |front| and |back|, representing results from multiple - // transactions for the same overall host resolution query. + // Merge |front| and |back|, representing results from multiple transactions + // for the same overall host resolution query. // - // - When merging result hostname and text record lists, result - // elements from |front| will be merged in front of elements from |back|. - // - Merging address lists deduplicates addresses and sorts them in a stable - // manner by (breaking ties by continuing down the list): - // 1. Addresses with associated ESNI keys precede addresses without - // 2. IPv6 addresses precede IPv4 addresses - // - Fields that cannot be merged take precedence from |front|. + // Merges lists, placing elements from |front| before elements from |back|. + // Further, dedupes address lists and moves IPv6 addresses before IPv4 + // addresses (maintaining stable order otherwise). + // + // Fields that cannot be merged take precedence from |front|. static Entry MergeEntries(Entry front, Entry back); // Creates a value representation of the entry for use with NetLog. @@ -207,11 +207,13 @@ class NET_EXPORT HostCache { const base::Optional<AddressList>& addresses, base::Optional<std::vector<std::string>>&& text_results, base::Optional<std::vector<HostPortPair>>&& hostnames, - base::Optional<EsniContent>&& esni_data, + base::Optional<std::vector<bool>>&& integrity_data, Source source, base::TimeTicks expires, int network_changes); + void PrepareForCacheInsertion(); + void SetResult(AddressList addresses) { addresses_ = std::move(addresses); } void SetResult(std::vector<std::string> text_records) { text_records_ = std::move(text_records); @@ -219,7 +221,9 @@ class NET_EXPORT HostCache { void SetResult(std::vector<HostPortPair> hostnames) { hostnames_ = std::move(hostnames); } - void SetResult(EsniContent esni_data) { esni_data_ = std::move(esni_data); } + void SetResult(std::vector<bool> integrity_data) { + integrity_data_ = std::move(integrity_data); + } int total_hits() const { return total_hits_; } int stale_hits() const { return stale_hits_; } @@ -230,20 +234,11 @@ class NET_EXPORT HostCache { int network_changes, EntryStaleness* out) const; - // Combines the addresses of |source| with those already stored, - // resulting in the following order: - // - // 1. IPv6 addresses associated with ESNI keys - // 2. IPv4 addresses associated with ESNI keys - // 3. IPv6 addresses not associated with ESNI keys - // 4. IPv4 addresses not associated with ESNI keys - // - // - Conducts the merge in a stable fashion (other things equal, addresses - // from |*this| will precede those from |source|, and addresses earlier in - // one entry's list will precede other addresses from later in the same - // list). - // - Deduplicates the entries during the merge so that |*this|'s - // address list will not contain duplicates after the call. + // Merges addresses from |source| into the stored list of addresses and + // deduplicates. The address list can be accessed with |addresses()|. This + // method performs a stable sort to ensure IPv6 addresses precede IPv4 + // addresses. IP versions being equal, addresses from |*this| will precede + // those from |source|. void MergeAddressesFrom(const HostCache::Entry& source); base::DictionaryValue GetAsValue(bool include_staleness) const; @@ -253,7 +248,7 @@ class NET_EXPORT HostCache { base::Optional<AddressList> addresses_; base::Optional<std::vector<std::string>> text_records_; base::Optional<std::vector<HostPortPair>> hostnames_; - base::Optional<EsniContent> esni_data_; + base::Optional<std::vector<bool>> integrity_data_; // Where results were obtained (e.g. DNS lookup, hosts file, etc). Source source_ = SOURCE_UNKNOWN; // TTL obtained from the nameserver. Negative if unknown. diff --git a/chromium/net/dns/host_cache_unittest.cc b/chromium/net/dns/host_cache_unittest.cc index b78a51f854c..61939a71a2c 100644 --- a/chromium/net/dns/host_cache_unittest.cc +++ b/chromium/net/dns/host_cache_unittest.cc @@ -939,7 +939,6 @@ TEST(HostCacheTest, SerializeAndDeserialize) { EXPECT_TRUE(result1->first.secure); ASSERT_TRUE(result1->second.addresses()); EXPECT_FALSE(result1->second.text_records()); - EXPECT_FALSE(result1->second.esni_data()); EXPECT_FALSE(result1->second.hostnames()); EXPECT_EQ(1u, result1->second.addresses().value().size()); EXPECT_EQ(address_ipv4, @@ -1106,105 +1105,6 @@ TEST(HostCacheTest, SerializeAndDeserialize_Text) { EXPECT_EQ(text_records, result->second.text_records().value()); } -TEST(HostCacheTest, SerializeAndDeserialize_Esni) { - base::TimeTicks now; - - base::TimeDelta ttl = base::TimeDelta::FromSeconds(99); - HostCache::Key key("example.com", DnsQueryType::A, 0, HostResolverSource::DNS, - NetworkIsolationKey()); - key.secure = true; - - const std::string kEsniKey = "a"; - const std::string kAddresslessEsniKey = "b"; - const IPAddress kAddressBack(0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0); - EsniContent esni_content; - esni_content.AddKeyForAddress(kAddressBack, kEsniKey); - esni_content.AddKey(kAddresslessEsniKey); - HostCache::Entry entry(OK, esni_content, HostCache::Entry::SOURCE_DNS, ttl); - ASSERT_TRUE(entry.esni_data()); - - HostCache cache(kMaxCacheEntries); - cache.Set(key, entry, now, ttl); - EXPECT_EQ(1u, cache.size()); - - base::ListValue serialized_cache; - cache.GetAsListValue(&serialized_cache, false /* include_staleness */, - HostCache::SerializationType::kRestorable); - HostCache restored_cache(kMaxCacheEntries); - restored_cache.RestoreFromListValue(serialized_cache); - - ASSERT_EQ(1u, restored_cache.size()); - HostCache::EntryStaleness staleness; - const std::pair<const HostCache::Key, HostCache::Entry>* result = - restored_cache.LookupStale(key, now, &staleness); - ASSERT_TRUE(result); - EXPECT_TRUE(result->first.secure); - - EXPECT_FALSE(result->second.addresses()); - EXPECT_FALSE(result->second.text_records()); - EXPECT_FALSE(result->second.hostnames()); - EXPECT_THAT(result->second.esni_data(), Optional(esni_content)); -} - -class HostCacheMalformedEsniSerializationTest : public ::testing::Test { - public: - HostCacheMalformedEsniSerializationTest() - : serialized_cache_(), - // We'll only need one entry. - restored_cache_(1) {} - - protected: - void SetUp() override { - base::TimeTicks now; - - base::TimeDelta ttl = base::TimeDelta::FromSeconds(99); - HostCache::Key key("example.com", DnsQueryType::A, 0, - HostResolverSource::DNS, NetworkIsolationKey()); - key.secure = true; - - const std::string esni_key = "a"; - const IPAddress kAddressBack(0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0); - EsniContent esni_content; - esni_content.AddKeyForAddress(kAddressBack, esni_key); - HostCache::Entry entry(OK, esni_content, HostCache::Entry::SOURCE_DNS, ttl); - ASSERT_TRUE(entry.esni_data()); - HostCache cache(kMaxCacheEntries); - cache.Set(key, entry, now, ttl); - EXPECT_EQ(1u, cache.size()); - cache.GetAsListValue(&serialized_cache_, true /* include_staleness */, - HostCache::SerializationType::kRestorable); - } - - base::ListValue serialized_cache_; - HostCache restored_cache_; -}; - -// The key corresponds to kEsniDataKey from host_cache.cc. -const char kEsniDataKey[] = "esni_data"; - -TEST_F(HostCacheMalformedEsniSerializationTest, RejectsNonDictElement) { - base::Value non_dict_element(base::Value::Type::LIST); - - base::Value::ListStorage cache_entries = serialized_cache_.TakeList(); - cache_entries[0].SetKey(kEsniDataKey, std::move(non_dict_element)); - serialized_cache_ = base::ListValue(std::move(cache_entries)); - - EXPECT_FALSE(restored_cache_.RestoreFromListValue(serialized_cache_)); -} - -TEST_F(HostCacheMalformedEsniSerializationTest, RejectsNonStringAddress) { - base::Value dict_with_non_string_value(base::Value::Type::DICTIONARY); - dict_with_non_string_value.SetKey("a", base::Value(1)); - - base::Value::ListStorage cache_entries = serialized_cache_.TakeList(); - cache_entries[0].SetKey(kEsniDataKey, std::move(dict_with_non_string_value)); - serialized_cache_ = base::ListValue(std::move(cache_entries)); - - EXPECT_FALSE(restored_cache_.RestoreFromListValue(serialized_cache_)); -} - TEST(HostCacheTest, SerializeAndDeserialize_Hostname) { base::TimeTicks now; @@ -1234,7 +1134,6 @@ TEST(HostCacheTest, SerializeAndDeserialize_Hostname) { EXPECT_FALSE(result->first.secure); EXPECT_FALSE(result->second.addresses()); EXPECT_FALSE(result->second.text_records()); - EXPECT_FALSE(result->second.esni_data()); ASSERT_TRUE(result->second.hostnames()); EXPECT_EQ(hostnames, result->second.hostnames().value()); } @@ -1394,136 +1293,25 @@ TEST(HostCacheTest, SortsAndDeduplicatesAddresses) { ElementsAreArray(MakeEndpoints({"::3", "0.0.0.1", "0.0.0.2"}))))); } -TEST(HostCacheTest, PrefersAddressesWithEsniContent) { - IPAddressList front_addresses = MakeIPList({"0.0.0.2", "0.0.0.4"}); +TEST(HostCacheTest, PrefersAddressesWithIpv6) { + IPAddressList front_addresses = MakeIPList({"::1", "0.0.0.2", "0.0.0.4"}); IPAddressList back_addresses = MakeIPList({"0.0.0.2", "0.0.0.2", "::3", "::3", "0.0.0.4"}); - EsniContent esni_content_front, esni_content_back; - esni_content_front.AddKeyForAddress(MakeIP("0.0.0.4"), "key for 0.0.0.4"); - esni_content_back.AddKeyForAddress(MakeIP("::3"), "key for ::3"); - HostCache::Entry front( OK, AddressList::CreateFromIPAddressList(front_addresses, "front"), HostCache::Entry::SOURCE_DNS); - front.set_esni_data(esni_content_front); HostCache::Entry back( OK, AddressList::CreateFromIPAddressList(back_addresses, "back"), HostCache::Entry::SOURCE_DNS); - back.set_esni_data(esni_content_back); - - HostCache::Entry result = - HostCache::Entry::MergeEntries(std::move(front), std::move(back)); - - EXPECT_THAT( - result.addresses(), - Optional(Property( - &AddressList::endpoints, - ElementsAreArray(MakeEndpoints({"::3", "0.0.0.4", "0.0.0.2"}))))); - - EXPECT_THAT(result.esni_data(), - Optional(Property( - &EsniContent::keys_for_addresses, - UnorderedElementsAre( - Pair(MakeIP("::3"), UnorderedElementsAre("key for ::3")), - Pair(MakeIP("0.0.0.4"), - UnorderedElementsAre("key for 0.0.0.4")))))); -} - -TEST(HostCacheTest, MergesManyEntriesWithEsniContent) { - IPAddressList front_addresses, back_addresses; - EsniContent esni_content_front, esni_content_back; - - // Add several IPv4 and IPv6 addresses to both the front and - // back ESNI structs and address_lists, and associate some of each - // with ESNI keys. - const std::string ipv4_prefix = "1.2.3.", ipv6_prefix = "::"; - for (int i = 0; i < 50; ++i) { - IPAddress next = - MakeIP((i % 2 ? ipv4_prefix : ipv6_prefix) + base::NumberToString(i)); - bool is_front = !!(i % 3); - if (is_front) { - front_addresses.push_back(next); - } else { - back_addresses.push_back(next); - } - if (i % 5) { - std::string key = base::NumberToString(i % 5); - if (is_front) { - esni_content_front.AddKeyForAddress(next, key); - } else { - esni_content_back.AddKeyForAddress(next, key); - } - } - } - - HostCache::Entry front( - OK, - AddressList::CreateFromIPAddressList(front_addresses, "front_canonname"), - HostCache::Entry::SOURCE_DNS); - front.set_esni_data(esni_content_front); - - HostCache::Entry back( - OK, - AddressList::CreateFromIPAddressList(back_addresses, "back_canonname"), - HostCache::Entry::SOURCE_DNS); - back.set_esni_data(esni_content_back); HostCache::Entry result = HostCache::Entry::MergeEntries(std::move(front), std::move(back)); - ASSERT_TRUE(result.addresses()); - EXPECT_EQ(result.addresses()->canonical_name(), "front_canonname"); - - EXPECT_EQ(result.addresses()->size(), - std::set<IPEndPoint>(result.addresses()->begin(), - result.addresses()->end()) - .size()) - << "Addresses should have been deduplicated."; - - ASSERT_TRUE(result.esni_data()); - - auto has_keys = [&](const IPEndPoint& e) { - return !!result.esni_data()->keys_for_addresses().count(e.address()); - }; - - // Helper for determining whether the resulting addresses are correctly - // ordered. Returns true if it's an error for |e2| to come before |e1| in - // *results.addresses(). - auto address_must_precede = [&](const IPEndPoint& e1, - const IPEndPoint& e2) -> bool { - if (has_keys(e1) != has_keys(e2)) { - return has_keys(e1) && !has_keys(e2); - } - if (e1.address().IsIPv6() != e2.address().IsIPv6()) { - return e1.address().IsIPv6() && !e2.address().IsIPv6(); - } - - // If e1 and e2 were in the same input entry, and they're otherwise - // tied in the precedence ordering, then their order in the input entry - // should be preserved in the output. - bool e1_in_front = base::Contains(front_addresses, e1.address()); - bool e2_in_front = base::Contains(front_addresses, e2.address()); - bool e1_in_back = base::Contains(back_addresses, e1.address()); - bool e2_in_back = base::Contains(back_addresses, e2.address()); - if (e1_in_front == e2_in_front && e1_in_front != e1_in_back && - e2_in_front != e2_in_back) { - const IPAddressList common_list = - e1_in_front ? front_addresses : back_addresses; - return std::find(common_list.begin(), common_list.end(), e1.address()) < - std::find(common_list.begin(), common_list.end(), e2.address()); - } - return false; - }; - - for (size_t i = 0; i < result.addresses()->size() - 1; ++i) { - EXPECT_FALSE(address_must_precede((*result.addresses())[i + 1], - (*result.addresses())[i])); - } - - auto esni_content_merged = esni_content_front; - esni_content_merged.MergeFrom(esni_content_back); - EXPECT_THAT(result.esni_data(), Optional(esni_content_merged)); + EXPECT_THAT(result.addresses(), + Optional(Property(&AddressList::endpoints, + ElementsAreArray(MakeEndpoints( + {"::1", "::3", "0.0.0.2", "0.0.0.4"}))))); } TEST(HostCacheTest, MergeEntries_frontEmpty) { @@ -1536,10 +1324,6 @@ TEST(HostCacheTest, MergeEntries_frontEmpty) { HostCache::Entry::SOURCE_DNS, base::TimeDelta::FromHours(4)); back.set_text_records(std::vector<std::string>{"text2"}); - EsniContent esni_content_back; - const std::string esni_key = "a"; - esni_content_back.AddKeyForAddress(kAddressBack, esni_key); - back.set_esni_data(esni_content_back); const HostPortPair kHostnameBack("host", 2); back.set_hostnames(std::vector<HostPortPair>{kHostnameBack}); @@ -1554,7 +1338,6 @@ TEST(HostCacheTest, MergeEntries_frontEmpty) { ElementsAre(kEndpointBack)); EXPECT_THAT(result.text_records(), Optional(ElementsAre("text2"))); EXPECT_THAT(result.hostnames(), Optional(ElementsAre(kHostnameBack))); - EXPECT_THAT(result.esni_data(), Optional(esni_content_back)); EXPECT_EQ(base::TimeDelta::FromHours(4), result.ttl()); } @@ -1566,10 +1349,6 @@ TEST(HostCacheTest, MergeEntries_backEmpty) { HostCache::Entry::SOURCE_DNS, base::TimeDelta::FromMinutes(5)); front.set_text_records(std::vector<std::string>{"text1"}); - EsniContent esni_content_front; - const std::string esni_key = "a"; - esni_content_front.AddKeyForAddress(kAddressFront, esni_key); - front.set_esni_data(esni_content_front); const HostPortPair kHostnameFront("host", 1); front.set_hostnames(std::vector<HostPortPair>{kHostnameFront}); @@ -1586,7 +1365,6 @@ TEST(HostCacheTest, MergeEntries_backEmpty) { ElementsAre(kEndpointFront)); EXPECT_THAT(result.text_records(), Optional(ElementsAre("text1"))); EXPECT_THAT(result.hostnames(), Optional(ElementsAre(kHostnameFront))); - EXPECT_THAT(result.esni_data(), Optional(esni_content_front)); EXPECT_EQ(base::TimeDelta::FromMinutes(5), result.ttl()); } @@ -1604,7 +1382,6 @@ TEST(HostCacheTest, MergeEntries_bothEmpty) { EXPECT_FALSE(result.addresses()); EXPECT_FALSE(result.text_records()); EXPECT_FALSE(result.hostnames()); - EXPECT_FALSE(result.esni_data()); EXPECT_FALSE(result.has_ttl()); } diff --git a/chromium/net/dns/host_resolver.cc b/chromium/net/dns/host_resolver.cc index 4d7dee3f90c..2fb635a7a28 100644 --- a/chromium/net/dns/host_resolver.cc +++ b/chromium/net/dns/host_resolver.cc @@ -8,6 +8,7 @@ #include "base/bind.h" #include "base/check.h" +#include "base/immediate_crash.h" #include "base/macros.h" #include "base/no_destructor.h" #include "base/notreached.h" @@ -56,11 +57,6 @@ class FailingRequestImpl : public HostResolver::ResolveHostRequest, return *nullopt_result; } - const base::Optional<EsniContent>& GetEsniResults() const override { - static const base::NoDestructor<base::Optional<EsniContent>> nullopt_result; - return *nullopt_result; - } - ResolveErrorInfo GetResolveErrorInfo() const override { return ResolveErrorInfo(error_); } @@ -80,6 +76,11 @@ class FailingRequestImpl : public HostResolver::ResolveHostRequest, } // namespace +const base::Optional<std::vector<bool>>& +HostResolver::ResolveHostRequest::GetIntegrityResultsForTesting() const { + IMMEDIATE_CRASH(); +} + const size_t HostResolver::ManagerOptions::kDefaultRetryAttempts = static_cast<size_t>(-1); @@ -107,14 +108,6 @@ HostResolver::ResolveHostParameters::ResolveHostParameters( HostResolver::~HostResolver() = default; -std::unique_ptr<HostResolver::ResolveHostRequest> HostResolver::CreateRequest( - const HostPortPair& host, - const NetLogWithSource& net_log, - const base::Optional<ResolveHostParameters>& optional_parameters) { - return CreateRequest(host, NetworkIsolationKey(), net_log, - optional_parameters); -} - std::unique_ptr<HostResolver::ProbeRequest> HostResolver::CreateDohProbeRequest() { // Should be overridden in any HostResolver implementation where this method diff --git a/chromium/net/dns/host_resolver.h b/chromium/net/dns/host_resolver.h index 264ab583500..87db841cf71 100644 --- a/chromium/net/dns/host_resolver.h +++ b/chromium/net/dns/host_resolver.h @@ -98,12 +98,10 @@ class NET_EXPORT HostResolver { virtual const base::Optional<std::vector<HostPortPair>>& GetHostnameResults() const = 0; - // TLS 1.3 Encrypted Server Name Indication, draft 4 (ESNI, - // https://tools.ietf.org/html/draft-ietf-tls-esni-04) - // results of the request. Should only be called after - // Start() signals completion, either by invoking the callback or by - // returning a result other than |ERR_IO_PENDING|. - virtual const base::Optional<EsniContent>& GetEsniResults() const = 0; + // INTEGRITY results for an initial experiment related to HTTPSSVC. Each + // boolean value indicates the intactness of an INTEGRITY record. + NET_EXPORT virtual const base::Optional<std::vector<bool>>& + GetIntegrityResultsForTesting() const; // Error info for the request. // @@ -312,15 +310,6 @@ class NET_EXPORT HostResolver { const NetLogWithSource& net_log, const base::Optional<ResolveHostParameters>& optional_parameters) = 0; - // Deprecated version of above method that uses an empty NetworkIsolationKey. - // - // TODO(mmenke): Once all consumers have been updated to use the other - // overload instead, remove this method and make above method pure virtual. - virtual std::unique_ptr<ResolveHostRequest> CreateRequest( - const HostPortPair& host, - const NetLogWithSource& net_log, - const base::Optional<ResolveHostParameters>& optional_parameters); - // Creates a request to probe configured DoH servers to find which can be used // successfully. virtual std::unique_ptr<ProbeRequest> CreateDohProbeRequest(); diff --git a/chromium/net/dns/host_resolver_manager.cc b/chromium/net/dns/host_resolver_manager.cc index 87bc925b8a0..82347fd6bf8 100644 --- a/chromium/net/dns/host_resolver_manager.cc +++ b/chromium/net/dns/host_resolver_manager.cc @@ -82,6 +82,7 @@ #include "net/dns/host_resolver_mdns_listener_impl.h" #include "net/dns/host_resolver_mdns_task.h" #include "net/dns/host_resolver_proc.h" +#include "net/dns/httpssvc_metrics.h" #include "net/dns/mdns_client.h" #include "net/dns/public/dns_protocol.h" #include "net/dns/public/resolve_error_info.h" @@ -499,7 +500,8 @@ class HostResolverManager::RequestImpl const base::Optional<ResolveHostParameters>& optional_parameters, ResolveContext* resolve_context, HostCache* host_cache, - base::WeakPtr<HostResolverManager> resolver) + base::WeakPtr<HostResolverManager> resolver, + const base::TickClock* tick_clock) : source_net_log_(source_net_log), request_host_(request_host), network_isolation_key_( @@ -516,7 +518,8 @@ class HostResolverManager::RequestImpl priority_(parameters_.initial_priority), job_(nullptr), resolver_(resolver), - complete_(false) {} + complete_(false), + tick_clock_(tick_clock) {} ~RequestImpl() override { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); @@ -544,7 +547,7 @@ class HostResolverManager::RequestImpl } else { DCHECK(!job_); complete_ = true; - LogFinishRequest(rv); + LogFinishRequest(rv, false /* async_completion */); } resolver_ = nullptr; @@ -573,10 +576,12 @@ class HostResolverManager::RequestImpl return results_ ? results_.value().hostnames() : *nullopt_result; } - const base::Optional<EsniContent>& GetEsniResults() const override { + const base::Optional<std::vector<bool>>& GetIntegrityResultsForTesting() + const override { DCHECK(complete_); - static const base::NoDestructor<base::Optional<EsniContent>> nullopt_result; - return results_ ? results_.value().esni_data() : *nullopt_result; + static const base::NoDestructor<base::Optional<std::vector<bool>>> + nullopt_result; + return results_ ? results_.value().integrity_data() : *nullopt_result; } net::ResolveErrorInfo GetResolveErrorInfo() const override { @@ -649,7 +654,7 @@ class HostResolverManager::RequestImpl DCHECK(!complete_); complete_ = true; - LogFinishRequest(error); + LogFinishRequest(error, true /* async_completion */); DCHECK(callback_); std::move(callback_).Run(HostResolver::SquashErrorCode(error)); @@ -679,19 +684,12 @@ class HostResolverManager::RequestImpl bool complete() const { return complete_; } - base::TimeTicks request_time() const { - DCHECK(!request_time_.is_null()); - return request_time_; - } - void set_request_time(base::TimeTicks request_time) { - DCHECK(request_time_.is_null()); - DCHECK(!request_time.is_null()); - request_time_ = request_time; - } - private: - // Logs when a request has just been started. + // Logging and metrics for when a request has just been started. void LogStartRequest() { + DCHECK(request_time_.is_null()); + request_time_ = tick_clock_->NowTicks(); + source_net_log_.BeginEvent( NetLogEventType::HOST_RESOLVER_IMPL_REQUEST, [this] { base::Value dict(base::Value::Type::DICTIONARY); @@ -708,10 +706,20 @@ class HostResolverManager::RequestImpl }); } - // Logs when a request has just completed (before its callback is run). - void LogFinishRequest(int net_error) { + // Logging and metrics for when a request has just completed (before its + // callback is run). + void LogFinishRequest(int net_error, bool async_completion) { source_net_log_.EndEventWithNetErrorCode( NetLogEventType::HOST_RESOLVER_IMPL_REQUEST, net_error); + + if (!parameters_.is_speculative) { + DCHECK(!request_time_.is_null()); + base::TimeDelta duration = tick_clock_->NowTicks() - request_time_; + + UMA_HISTOGRAM_MEDIUM_TIMES("Net.DNS.Request.TotalTime", duration); + if (async_completion) + UMA_HISTOGRAM_MEDIUM_TIMES("Net.DNS.Request.TotalTimeAsync", duration); + } } // Logs when a request has been cancelled. @@ -744,6 +752,7 @@ class HostResolverManager::RequestImpl base::Optional<HostCache::EntryStaleness> stale_info_; ResolveErrorInfo error_info_; + const base::TickClock* const tick_clock_; base::TimeTicks request_time_; SEQUENCE_CHECKER(sequence_checker_); @@ -1107,9 +1116,21 @@ class HostResolverManager::DnsTask : public base::SupportsWeakPtr<DnsTask> { transactions_needed_.push(DnsQueryType::A); transactions_needed_.push(DnsQueryType::AAAA); - if (secure_ && - base::FeatureList::IsEnabled(features::kRequestEsniDnsRecords)) { - transactions_needed_.push(DnsQueryType::ESNI); + // Queue up an INTEGRITY query if we are allowed to. + const bool is_httpssvc_experiment_domain = + httpssvc_domain_cache_.IsExperimental(hostname); + const bool is_httpssvc_control_domain = + httpssvc_domain_cache_.IsControl(hostname); + if (base::FeatureList::IsEnabled(features::kDnsHttpssvc) && + features::kDnsHttpssvcUseIntegrity.Get() && + (secure_ || features::kDnsHttpssvcEnableQueryOverInsecure.Get()) && + (is_httpssvc_experiment_domain || is_httpssvc_control_domain)) { + // We should not be configured to query HTTPSSVC *and* INTEGRITY. + DCHECK(!features::kDnsHttpssvcUseHttpssvc.Get()); + + httpssvc_metrics_.emplace( + is_httpssvc_experiment_domain /* expect_intact */); + transactions_needed_.push(DnsQueryType::INTEGRITY); } } num_needed_transactions_ = transactions_needed_.size(); @@ -1170,15 +1191,25 @@ class HostResolverManager::DnsTask : public base::SupportsWeakPtr<DnsTask> { return trans; } - void OnEsniTransactionTimeout() { - // Currently, the ESNI transaction timer only gets started - // when all non-ESNI transactions have completed. - DCHECK(TaskIsCompleteOrOnlyEsniTransactionsRemain()); + void OnExperimentalQueryTimeout(uint16_t qtype, + base::Optional<std::string> doh_provider_id) { + // The experimental query timer is only started when all other transactions + // have completed. + DCHECK(TaskIsCompleteOrOnlyQtypeTransactionsRemain(qtype)); num_completed_transactions_ += transactions_started_.size(); DCHECK(num_completed_transactions_ == num_needed_transactions()); transactions_started_.clear(); + if (qtype == dns_protocol::kExperimentalTypeIntegrity) { + DCHECK(httpssvc_metrics_); + + // Record that this INTEGRITY query timed out in the metrics. + base::TimeDelta elapsed_time = tick_clock_->NowTicks() - task_start_time_; + httpssvc_metrics_->SaveForIntegrity( + doh_provider_id, HttpssvcDnsRcode::kTimedOut, {}, elapsed_time); + } + ProcessResultsOnCompletion(); } @@ -1186,7 +1217,8 @@ class HostResolverManager::DnsTask : public base::SupportsWeakPtr<DnsTask> { DnsQueryType dns_query_type, DnsTransaction* transaction, int net_error, - const DnsResponse* response) { + const DnsResponse* response, + base::Optional<std::string> doh_provider_id) { DCHECK(transaction); // Once control leaves OnTransactionComplete, there's no further @@ -1202,10 +1234,30 @@ class HostResolverManager::DnsTask : public base::SupportsWeakPtr<DnsTask> { transactions_started_.erase(it); } + base::TimeDelta elapsed_time = tick_clock_->NowTicks() - task_start_time_; + enum HttpssvcDnsRcode rcode_for_httpssvc = HttpssvcDnsRcode::kNoError; + if (httpssvc_metrics_) { + if (net_error == ERR_DNS_TIMED_OUT) { + rcode_for_httpssvc = HttpssvcDnsRcode::kTimedOut; + } else if (net_error == ERR_NAME_NOT_RESOLVED) { + rcode_for_httpssvc = HttpssvcDnsRcode::kNoError; + } else if (response == nullptr) { + rcode_for_httpssvc = HttpssvcDnsRcode::kMissingDnsResponse; + } else { + rcode_for_httpssvc = + TranslateDnsRcodeForHttpssvcExperiment(response->rcode()); + } + } + if (net_error != OK && !(net_error == ERR_NAME_NOT_RESOLVED && response && response->IsValid())) { - OnFailure(net_error, DnsResponse::DNS_PARSE_OK, base::nullopt); - return; + if (dns_query_type == DnsQueryType::INTEGRITY) { + // Do not allow an INTEGRITY query to fail the whole DnsTask. + response = nullptr; + } else { + OnFailure(net_error, DnsResponse::DNS_PARSE_OK, base::nullopt); + return; + } } DnsResponse::Result parse_result = DnsResponse::DNS_PARSE_RESULT_MAX; @@ -1228,8 +1280,9 @@ class HostResolverManager::DnsTask : public base::SupportsWeakPtr<DnsTask> { case DnsQueryType::SRV: parse_result = ParseServiceDnsResponse(response, &results); break; - case DnsQueryType::ESNI: - parse_result = ParseEsniDnsResponse(response, &results); + case DnsQueryType::INTEGRITY: + // Parse the INTEGRITY records, condensing them into a vector<bool>. + parse_result = ParseIntegrityDnsResponse(response, &results); break; } DCHECK_LT(parse_result, DnsResponse::DNS_PARSE_RESULT_MAX); @@ -1239,6 +1292,21 @@ class HostResolverManager::DnsTask : public base::SupportsWeakPtr<DnsTask> { return; } + if (httpssvc_metrics_) { + if (dns_query_type != DnsQueryType::INTEGRITY) { + httpssvc_metrics_->SaveForNonIntegrity(doh_provider_id, elapsed_time, + rcode_for_httpssvc); + } else { + const base::Optional<std::vector<bool>>& condensed = + results.integrity_data(); + CHECK(condensed.has_value()); + // INTEGRITY queries can time out the normal way (here), or when the + // experimental query timer runs out (OnExperimentalQueryTimeout). + httpssvc_metrics_->SaveForIntegrity(doh_provider_id, rcode_for_httpssvc, + *condensed, elapsed_time); + } + } + // Merge results with saved results from previous transactions. if (saved_results_) { DCHECK_LE(2, num_needed_transactions()); @@ -1257,10 +1325,7 @@ class HostResolverManager::DnsTask : public base::SupportsWeakPtr<DnsTask> { results = HostCache::Entry::MergeEntries( std::move(results), std::move(saved_results_).value()); break; - case DnsQueryType::ESNI: - // It doesn't matter whether the ESNI record is the "front" - // or the "back" argument to the merge, since the logic for - // merging addresses from ESNI records is the same in each case. + case DnsQueryType::INTEGRITY: results = HostCache::Entry::MergeEntries( std::move(results), std::move(saved_results_).value()); break; @@ -1277,13 +1342,16 @@ class HostResolverManager::DnsTask : public base::SupportsWeakPtr<DnsTask> { ++num_completed_transactions_; if (num_completed_transactions_ < num_needed_transactions()) { delegate_->OnIntermediateTransactionComplete(); - MaybeStartEsniTimer(); + // If the experimental query times out, blame the provider that gave the + // last A/AAAA result. If we were being 100% correct, we would blame the + // provider associated with the experimental query. + MaybeStartExperimentalQueryTimer(doh_provider_id); return; } - // Since all transactions are complete, in particular, all ESNI transactions - // are complete (if any were started). - esni_cancellation_timer_.Stop(); + // Since all transactions are complete, in particular, all experimental + // transactions are complete (if any were started). + experimental_query_cancellation_timer_.Stop(); ProcessResultsOnCompletion(); } @@ -1296,20 +1364,13 @@ class HostResolverManager::DnsTask : public base::SupportsWeakPtr<DnsTask> { // If there are multiple addresses, and at least one is IPv6, need to // sort them. - // When there are no ESNI keys in the record, IPv6 addresses are always - // put before IPv4 ones, so it's sufficient to just check the family of - // the first address. - // When there are ESNI keys, there could be ESNI-equipped - // IPv4 addresses preceding the first IPv6 address, so it's necessary to - // scan the list. bool at_least_one_ipv6_address = results.addresses() && !results.addresses().value().empty() && (results.addresses().value()[0].GetFamily() == ADDRESS_FAMILY_IPV6 || - (results.esni_data() && - std::any_of(results.addresses().value().begin(), - results.addresses().value().end(), [](auto& e) { - return e.GetFamily() == ADDRESS_FAMILY_IPV6; - }))); + std::any_of(results.addresses().value().begin(), + results.addresses().value().end(), [](auto& e) { + return e.GetFamily() == ADDRESS_FAMILY_IPV6; + })); if (at_least_one_ipv6_address) { // Sort addresses if needed. Sort could complete synchronously. @@ -1326,6 +1387,7 @@ class HostResolverManager::DnsTask : public base::SupportsWeakPtr<DnsTask> { DnsResponse::Result ParseAddressDnsResponse(const DnsResponse* response, HostCache::Entry* out_results) { + DCHECK(response); AddressList addresses; base::TimeDelta ttl; DnsResponse::Result parse_result = @@ -1346,6 +1408,7 @@ class HostResolverManager::DnsTask : public base::SupportsWeakPtr<DnsTask> { DnsResponse::Result ParseTxtDnsResponse(const DnsResponse* response, HostCache::Entry* out_results) { + DCHECK(response); std::vector<std::unique_ptr<const RecordParsed>> records; base::Optional<base::TimeDelta> response_ttl; DnsResponse::Result parse_result = ParseAndFilterResponseRecords( @@ -1371,6 +1434,7 @@ class HostResolverManager::DnsTask : public base::SupportsWeakPtr<DnsTask> { DnsResponse::Result ParsePointerDnsResponse(const DnsResponse* response, HostCache::Entry* out_results) { + DCHECK(response); std::vector<std::unique_ptr<const RecordParsed>> records; base::Optional<base::TimeDelta> response_ttl; DnsResponse::Result parse_result = ParseAndFilterResponseRecords( @@ -1399,6 +1463,7 @@ class HostResolverManager::DnsTask : public base::SupportsWeakPtr<DnsTask> { DnsResponse::Result ParseServiceDnsResponse(const DnsResponse* response, HostCache::Entry* out_results) { + DCHECK(response); std::vector<std::unique_ptr<const RecordParsed>> records; base::Optional<base::TimeDelta> response_ttl; DnsResponse::Result parse_result = ParseAndFilterResponseRecords( @@ -1428,55 +1493,39 @@ class HostResolverManager::DnsTask : public base::SupportsWeakPtr<DnsTask> { return DnsResponse::DNS_PARSE_OK; } - DnsResponse::Result ParseEsniDnsResponse(const DnsResponse* response, - HostCache::Entry* out_results) { - std::vector<std::unique_ptr<const RecordParsed>> records; + DnsResponse::Result ParseIntegrityDnsResponse(const DnsResponse* response, + HostCache::Entry* out_results) { base::Optional<base::TimeDelta> response_ttl; + const HostCache::Entry default_entry( + OK, std::vector<bool>(), HostCache::Entry::SOURCE_DNS, response_ttl); + + if (response == nullptr) { + *out_results = default_entry; + return DnsResponse::Result::DNS_PARSE_OK; + } + + std::vector<std::unique_ptr<const RecordParsed>> records; DnsResponse::Result parse_result = ParseAndFilterResponseRecords( - response, dns_protocol::kExperimentalTypeEsniDraft4, &records, + response, dns_protocol::kExperimentalTypeIntegrity, &records, &response_ttl); if (parse_result != DnsResponse::DNS_PARSE_OK) { - *out_results = GetMalformedResponseResult(); - return parse_result; + *out_results = default_entry; + return DnsResponse::Result::DNS_PARSE_OK; } - // Glom the ESNI response records into a single EsniContent; - // this also dedups keys and (key, address) associations. - EsniContent content; + // Condense results into a list of booleans. We do not cache the results, + // but this enables us to write some unit tests. + std::vector<bool> condensed_results; for (const auto& record : records) { - const EsniRecordRdata& rdata = *record->rdata<EsniRecordRdata>(); - - for (const IPAddress& address : rdata.addresses()) - content.AddKeyForAddress(address, rdata.esni_keys()); - } - - // As a first pass, deliberately ignore ESNI records with no addresses - // included. Later, the implementation can be extended to handle "at-large" - // ESNI keys not specifically associated with collections of addresses. - // (We're declining the "...clients MAY initiate..." choice in ESNI draft 4, - // Section 4.2.2 Step 2.) - if (content.keys_for_addresses().empty()) { - *out_results = - HostCache::Entry(ERR_NAME_NOT_RESOLVED, EsniContent(), - HostCache::Entry::SOURCE_DNS, response_ttl); - } else { - AddressList addresses, ipv4_addresses_temporary; - addresses.set_canonical_name(hostname_); - for (const auto& kv : content.keys_for_addresses()) - (kv.first.IsIPv6() ? addresses : ipv4_addresses_temporary) - .push_back(IPEndPoint(kv.first, 0)); - addresses.insert(addresses.end(), ipv4_addresses_temporary.begin(), - ipv4_addresses_temporary.end()); - - // Store the addresses separately from the ESNI key-address - // associations, so that the addresses can be merged later with - // addresses from A and AAAA records. - *out_results = HostCache::Entry( - OK, std::move(content), HostCache::Entry::SOURCE_DNS, response_ttl); - out_results->set_addresses(std::move(addresses)); + const IntegrityRecordRdata& rdata = + *record->rdata<IntegrityRecordRdata>(); + condensed_results.push_back(rdata.IsIntact()); } + *out_results = HostCache::Entry(OK, std::move(condensed_results), + HostCache::Entry::SOURCE_DNS, response_ttl); + DCHECK_EQ(parse_result, DnsResponse::DNS_PARSE_OK); return parse_result; } @@ -1605,6 +1654,9 @@ class HostResolverManager::DnsTask : public base::SupportsWeakPtr<DnsTask> { void OnFailure(int net_error, DnsResponse::Result parse_result, base::Optional<base::TimeDelta> ttl) { + if (httpssvc_metrics_) + httpssvc_metrics_->SaveNonIntegrityFailure(); + DCHECK_NE(OK, net_error); HostCache::Entry results(net_error, HostCache::Entry::SOURCE_UNKNOWN); @@ -1636,52 +1688,57 @@ class HostResolverManager::DnsTask : public base::SupportsWeakPtr<DnsTask> { delegate_->OnDnsTaskComplete(task_start_time_, results, secure_); } - // Returns whether all transactions left to execute are of transaction - // type ESNI. (In particular, this is the case if all transactions are - // complete.) - // Used for logging and starting the ESNI transaction timer (see - // MaybeStartEsniTimer). - bool TaskIsCompleteOrOnlyEsniTransactionsRemain() const { - // Since DoH runs all transactions concurrently and - // DnsQueryType::UNSPECIFIED-with-ESNI tasks are only run using DoH, - // this method only needs to check the transactions in transactions_started_ - // because transactions_needed_ is empty from the time the first - // transaction is started. + // Returns whether all transactions left to execute are of transaction type + // |qtype|. (In particular, this is the case if all transactions are + // complete.) Used for logging and starting the experimental query timer (see + // MaybeStartExperimentalQueryTimer). + bool TaskIsCompleteOrOnlyQtypeTransactionsRemain(uint16_t qtype) const { + // Since DoH runs all transactions concurrently and experimental types are + // only queried over DoH, this method only needs to check the transactions + // in transactions_started_ because transactions_needed_ is empty from the + // time the first transaction is started. DCHECK(transactions_needed_.empty()); return std::all_of( transactions_started_.begin(), transactions_started_.end(), [&](const std::unique_ptr<DnsTransaction>& p) { DCHECK(p); - return p->GetType() == dns_protocol::kExperimentalTypeEsniDraft4; + return p->GetType() == qtype; }); } - // If ESNI transactions are being executed as part of this task - // and all transactions except the ESNI transactions have finished, and the - // ESNI transactions have not finished, starts a timer after which to abort - // the ESNI transactions. - // - // This timer has duration equal to the shorter of two parameterized values: - // - a fixed, absolute duration - // - a relative duration (as a proportion of the total time taken for - // the task's other transactions). - void MaybeStartEsniTimer() { + + void MaybeStartExperimentalQueryTimer( + base::Optional<std::string> doh_provider_id) { DCHECK(!transactions_started_.empty()); - DCHECK(saved_results_); - if (!esni_cancellation_timer_.IsRunning() && - TaskIsCompleteOrOnlyEsniTransactionsRemain()) { - base::TimeDelta total_time_taken_for_other_transactions = + + // Abort if neither HTTPSSVC nor INTEGRITY querying is enabled. + if (!base::FeatureList::IsEnabled(features::kDnsHttpssvc) || + (!features::kDnsHttpssvcUseIntegrity.Get() && + !features::kDnsHttpssvcUseHttpssvc.Get())) { + return; + } + + if (!experimental_query_cancellation_timer_.IsRunning() && + TaskIsCompleteOrOnlyQtypeTransactionsRemain( + dns_protocol::kExperimentalTypeIntegrity)) { + const base::TimeDelta kExtraTimeAbsolute = + features::dns_httpssvc_experiment::GetExtraTimeAbsolute(); + const int kExtraTimePercent = + features::kDnsHttpssvcExtraTimePercent.Get(); + + base::TimeDelta total_time_for_other_transactions = tick_clock_->NowTicks() - task_start_time_; + base::TimeDelta relative_timeout = + total_time_for_other_transactions * kExtraTimePercent / 100; - esni_cancellation_timer_.Start( - FROM_HERE, - std::min( - features::EsniDnsMaxAbsoluteAdditionalWait(), - total_time_taken_for_other_transactions * - (0.01 * - features::kEsniDnsMaxRelativeAdditionalWaitPercent.Get())), - this, &DnsTask::OnEsniTransactionTimeout); + base::TimeDelta timeout = std::min(kExtraTimeAbsolute, relative_timeout); + + experimental_query_cancellation_timer_.Start( + FROM_HERE, timeout, + base::BindOnce( + &DnsTask::OnExperimentalQueryTimeout, base::Unretained(this), + dns_protocol::kExperimentalTypeIntegrity, doh_provider_id)); } } @@ -1711,16 +1768,12 @@ class HostResolverManager::DnsTask : public base::SupportsWeakPtr<DnsTask> { const base::TickClock* tick_clock_; base::TimeTicks task_start_time_; - // In order to histogram the relative end-to-end elapsed times of - // a task's ESNI and non-ESNI transactions, store the end-to-end time - // elapsed from task start to the end of the task's ESNI transaction - // (if any) and its final non-ESNI transaction. - base::TimeDelta esni_elapsed_for_logging_; - base::TimeDelta non_esni_elapsed_for_logging_; + HttpssvcExperimentDomainCache httpssvc_domain_cache_; + base::Optional<HttpssvcMetrics> httpssvc_metrics_; - // Timer for early abort of ESNI transactions. See comments describing - // the timeout parameters in net/base/features.h. - base::OneShotTimer esni_cancellation_timer_; + // Timer for early abort of experimental queries. See comments describing the + // timeout parameters in net/base/features.h. + base::OneShotTimer experimental_query_cancellation_timer_; DISALLOW_COPY_AND_ASSIGN(DnsTask); }; @@ -2396,7 +2449,7 @@ class HostResolverManager::Job : public PrioritizedDispatcher::Job, query_types.push_back(query_type_); } - MDnsClient* client; + MDnsClient* client = nullptr; int rv = resolver_->GetOrCreateMdnsClient(&client); mdns_task_ = std::make_unique<HostResolverMdnsTask>(client, hostname_, query_types); @@ -2454,23 +2507,6 @@ class HostResolverManager::Job : public PrioritizedDispatcher::Job, if (had_non_speculative_request_) { category = RESOLVE_SUCCESS; UMA_HISTOGRAM_LONG_TIMES_100("Net.DNS.ResolveSuccessTime", duration); - switch (query_type_) { - case DnsQueryType::A: - UMA_HISTOGRAM_LONG_TIMES_100("Net.DNS.ResolveSuccessTime.IPV4", - duration); - break; - case DnsQueryType::AAAA: - UMA_HISTOGRAM_LONG_TIMES_100("Net.DNS.ResolveSuccessTime.IPV6", - duration); - break; - case DnsQueryType::UNSPECIFIED: - UMA_HISTOGRAM_LONG_TIMES_100("Net.DNS.ResolveSuccessTime.UNSPEC", - duration); - break; - default: - // No histogram for other query types. - break; - } } else { category = RESOLVE_SPECULATIVE_SUCCESS; } @@ -2482,23 +2518,6 @@ class HostResolverManager::Job : public PrioritizedDispatcher::Job, if (had_non_speculative_request_) { category = RESOLVE_FAIL; UMA_HISTOGRAM_LONG_TIMES_100("Net.DNS.ResolveFailureTime", duration); - switch (query_type_) { - case DnsQueryType::A: - UMA_HISTOGRAM_LONG_TIMES_100("Net.DNS.ResolveFailureTime.IPV4", - duration); - break; - case DnsQueryType::AAAA: - UMA_HISTOGRAM_LONG_TIMES_100("Net.DNS.ResolveFailureTime.IPV6", - duration); - break; - case DnsQueryType::UNSPECIFIED: - UMA_HISTOGRAM_LONG_TIMES_100("Net.DNS.ResolveFailureTime.UNSPEC", - duration); - break; - default: - // No histogram for other query types. - break; - } } else { category = RESOLVE_SPECULATIVE_FAIL; } @@ -2514,6 +2533,13 @@ class HostResolverManager::Job : public PrioritizedDispatcher::Job, else base::UmaHistogramSparse("Net.DNS.ResolveError.Slow", std::abs(error)); } + + if (had_non_speculative_request_) { + UmaHistogramMediumTimes( + base::StringPrintf("Net.DNS.SecureDnsMode.%s.ResolveTime", + SecureDnsModeToString(secure_dns_mode_).c_str()), + duration); + } } void MaybeCacheResult(const HostCache::Entry& results, @@ -2587,13 +2613,7 @@ class HostResolverManager::Job : public PrioritizedDispatcher::Job, RequestImpl* req = requests_.head()->value(); req->RemoveFromList(); DCHECK_EQ(this, req->job()); - // Update the net log and notify registered observers. - if (results.did_complete()) { - // Record effective total time from creation to completion. - resolver_->RecordTotalTime( - req->parameters().is_speculative, false /* from_cache */, - secure_dns_mode_, tick_clock_->NowTicks() - req->request_time()); - } + if (results.error() == OK && !req->parameters().is_speculative) { req->set_results( results.CopyWithDefaultPort(req->request_host().port())); @@ -2808,7 +2828,7 @@ HostResolverManager::CreateRequest( return std::make_unique<RequestImpl>( net_log, host, network_isolation_key, optional_parameters, - resolve_context, host_cache, weak_ptr_factory_.GetWeakPtr()); + resolve_context, host_cache, weak_ptr_factory_.GetWeakPtr(), tick_clock_); } std::unique_ptr<HostResolverManager::CancellableProbeRequest> @@ -2971,8 +2991,6 @@ int HostResolverManager::Resolve(RequestImpl* request) { ResolveHostParameters::CacheUsage::ALLOWED); DCHECK(!invalidation_in_progress_); - request->set_request_time(tick_clock_->NowTicks()); - DnsQueryType effective_query_type; HostResolverFlags effective_host_resolver_flags; DnsConfig::SecureDnsMode effective_secure_dns_mode; @@ -2996,8 +3014,6 @@ int HostResolverManager::Resolve(RequestImpl* request) { } if (stale_info && !request->parameters().is_speculative) request->set_stale_info(std::move(stale_info).value()); - RecordTotalTime(request->parameters().is_speculative, true /* from_cache */, - effective_secure_dns_mode, base::TimeDelta()); request->set_error_info(results.error(), false /* is_secure_network_error */); return HostResolver::SquashErrorCode(results.error()); @@ -3317,24 +3333,6 @@ void HostResolverManager::CacheResult(HostCache* cache, cache->Set(key, entry, tick_clock_->NowTicks(), ttl); } -// Record time from Request creation until a valid DNS response. -void HostResolverManager::RecordTotalTime( - bool speculative, - bool from_cache, - DnsConfig::SecureDnsMode secure_dns_mode, - base::TimeDelta duration) const { - if (!speculative) { - UMA_HISTOGRAM_LONG_TIMES_100("Net.DNS.TotalTime", duration); - UmaHistogramMediumTimes( - base::StringPrintf("Net.DNS.SecureDnsMode.%s.TotalTime", - SecureDnsModeToString(secure_dns_mode).c_str()), - duration); - - if (!from_cache) - UMA_HISTOGRAM_LONG_TIMES_100("Net.DNS.TotalTimeNotCached", duration); - } -} - std::unique_ptr<HostResolverManager::Job> HostResolverManager::RemoveJob( JobMap::iterator job_it) { DCHECK(job_it != jobs_.end()); diff --git a/chromium/net/dns/host_resolver_manager.h b/chromium/net/dns/host_resolver_manager.h index 4c4799ea00f..c712824c3d1 100644 --- a/chromium/net/dns/host_resolver_manager.h +++ b/chromium/net/dns/host_resolver_manager.h @@ -414,12 +414,6 @@ class NET_EXPORT HostResolverManager const HostCache::Entry& entry, base::TimeDelta ttl); - // Record time from Request creation until a valid DNS response. - void RecordTotalTime(bool speculative, - bool from_cache, - DnsConfig::SecureDnsMode secure_dns_mode, - base::TimeDelta duration) const; - // Removes |job_it| from |jobs_| and return. std::unique_ptr<Job> RemoveJob(JobMap::iterator job_it); diff --git a/chromium/net/dns/host_resolver_manager_fuzzer.cc b/chromium/net/dns/host_resolver_manager_fuzzer.cc index 8380657fef5..a6ae1ddaf81 100644 --- a/chromium/net/dns/host_resolver_manager_fuzzer.cc +++ b/chromium/net/dns/host_resolver_manager_fuzzer.cc @@ -17,6 +17,7 @@ #include "net/base/address_family.h" #include "net/base/address_list.h" #include "net/base/net_errors.h" +#include "net/base/network_isolation_key.h" #include "net/base/request_priority.h" #include "net/dns/context_host_resolver.h" #include "net/dns/fuzzed_host_resolver_util.h" @@ -161,7 +162,8 @@ class DnsRequest { const char* hostname = data_provider_->PickValueInArray(kHostNames); request_ = host_resolver_->CreateRequest( - net::HostPortPair(hostname, 80), net::NetLogWithSource(), parameters); + net::HostPortPair(hostname, 80), net::NetworkIsolationKey(), + net::NetLogWithSource(), parameters); int rv = request_->Start( base::BindOnce(&DnsRequest::OnCallback, base::Unretained(this))); if (rv != net::ERR_IO_PENDING) diff --git a/chromium/net/dns/host_resolver_manager_unittest.cc b/chromium/net/dns/host_resolver_manager_unittest.cc index 16d70163982..f467b8e1eac 100644 --- a/chromium/net/dns/host_resolver_manager_unittest.cc +++ b/chromium/net/dns/host_resolver_manager_unittest.cc @@ -86,6 +86,7 @@ using ::testing::AllOf; using ::testing::Between; using ::testing::ByMove; using ::testing::Eq; +using ::testing::IsEmpty; using ::testing::Optional; using ::testing::Pair; using ::testing::Property; @@ -2779,7 +2780,7 @@ TEST_F(HostResolverManagerTest, Mdns) { CreateExpected("000a:0000:0000:0000:0001:0002:0003:0004", 80))); EXPECT_FALSE(response.request()->GetTextResults()); EXPECT_FALSE(response.request()->GetHostnameResults()); - EXPECT_FALSE(response.request()->GetEsniResults()); + EXPECT_FALSE(response.request()->GetIntegrityResultsForTesting()); } TEST_F(HostResolverManagerTest, Mdns_AaaaOnly) { @@ -2831,7 +2832,7 @@ TEST_F(HostResolverManagerTest, Mdns_Txt) { EXPECT_THAT(response.request()->GetTextResults(), testing::Optional(testing::ElementsAre("foo", "bar"))); EXPECT_FALSE(response.request()->GetHostnameResults()); - EXPECT_FALSE(response.request()->GetEsniResults()); + EXPECT_FALSE(response.request()->GetIntegrityResultsForTesting()); } TEST_F(HostResolverManagerTest, Mdns_Ptr) { @@ -2856,7 +2857,7 @@ TEST_F(HostResolverManagerTest, Mdns_Ptr) { EXPECT_THAT(response.result_error(), IsOk()); EXPECT_FALSE(response.request()->GetAddressResults()); EXPECT_FALSE(response.request()->GetTextResults()); - EXPECT_FALSE(response.request()->GetEsniResults()); + EXPECT_FALSE(response.request()->GetIntegrityResultsForTesting()); EXPECT_THAT( response.request()->GetHostnameResults(), testing::Optional(testing::ElementsAre(HostPortPair("foo.com", 83)))); @@ -2884,7 +2885,7 @@ TEST_F(HostResolverManagerTest, Mdns_Srv) { EXPECT_THAT(response.result_error(), IsOk()); EXPECT_FALSE(response.request()->GetAddressResults()); EXPECT_FALSE(response.request()->GetTextResults()); - EXPECT_FALSE(response.request()->GetEsniResults()); + EXPECT_FALSE(response.request()->GetIntegrityResultsForTesting()); EXPECT_THAT( response.request()->GetHostnameResults(), testing::Optional(testing::ElementsAre(HostPortPair("foo.com", 8265)))); @@ -2912,7 +2913,7 @@ TEST_F(HostResolverManagerTest, Mdns_Srv_Unrestricted) { EXPECT_THAT(response.result_error(), IsOk()); EXPECT_FALSE(response.request()->GetAddressResults()); EXPECT_FALSE(response.request()->GetTextResults()); - EXPECT_FALSE(response.request()->GetEsniResults()); + EXPECT_FALSE(response.request()->GetIntegrityResultsForTesting()); EXPECT_THAT( response.request()->GetHostnameResults(), testing::Optional(testing::ElementsAre(HostPortPair("foo.com", 8265)))); @@ -2941,7 +2942,7 @@ TEST_F(HostResolverManagerTest, Mdns_Srv_Result_Unrestricted) { EXPECT_THAT(response.result_error(), IsOk()); EXPECT_FALSE(response.request()->GetAddressResults()); EXPECT_FALSE(response.request()->GetTextResults()); - EXPECT_FALSE(response.request()->GetEsniResults()); + EXPECT_FALSE(response.request()->GetIntegrityResultsForTesting()); EXPECT_THAT(response.request()->GetHostnameResults(), testing::Optional( testing::ElementsAre(HostPortPair("foo bar.local", 8265)))); @@ -3006,7 +3007,7 @@ TEST_F(HostResolverManagerTest, Mdns_NoResponse) { EXPECT_FALSE(response.request()->GetAddressResults()); EXPECT_FALSE(response.request()->GetTextResults()); EXPECT_FALSE(response.request()->GetHostnameResults()); - EXPECT_FALSE(response.request()->GetEsniResults()); + EXPECT_FALSE(response.request()->GetIntegrityResultsForTesting()); test_task_runner->FastForwardUntilNoTasksRemain(); } @@ -3050,7 +3051,7 @@ TEST_F(HostResolverManagerTest, Mdns_WrongType) { EXPECT_FALSE(response.request()->GetAddressResults()); EXPECT_FALSE(response.request()->GetTextResults()); EXPECT_FALSE(response.request()->GetHostnameResults()); - EXPECT_FALSE(response.request()->GetEsniResults()); + EXPECT_FALSE(response.request()->GetIntegrityResultsForTesting()); test_task_runner->FastForwardUntilNoTasksRemain(); } @@ -7815,7 +7816,7 @@ TEST_F(HostResolverManagerDnsTest, TxtQuery) { EXPECT_THAT(response.result_error(), IsOk()); EXPECT_FALSE(response.request()->GetAddressResults()); EXPECT_FALSE(response.request()->GetHostnameResults()); - EXPECT_FALSE(response.request()->GetEsniResults()); + EXPECT_FALSE(response.request()->GetIntegrityResultsForTesting()); // Order between separate DNS records is undefined, but each record should // stay in order as that order may be meaningful. @@ -7868,7 +7869,7 @@ TEST_F(HostResolverManagerDnsTest, TxtQuery_NonexistentDomain) { EXPECT_FALSE(response.request()->GetAddressResults()); EXPECT_FALSE(response.request()->GetTextResults()); EXPECT_FALSE(response.request()->GetHostnameResults()); - EXPECT_FALSE(response.request()->GetEsniResults()); + EXPECT_FALSE(response.request()->GetIntegrityResultsForTesting()); } TEST_F(HostResolverManagerDnsTest, TxtQuery_Failure) { @@ -7895,7 +7896,7 @@ TEST_F(HostResolverManagerDnsTest, TxtQuery_Failure) { EXPECT_FALSE(response.request()->GetAddressResults()); EXPECT_FALSE(response.request()->GetTextResults()); EXPECT_FALSE(response.request()->GetHostnameResults()); - EXPECT_FALSE(response.request()->GetEsniResults()); + EXPECT_FALSE(response.request()->GetIntegrityResultsForTesting()); } TEST_F(HostResolverManagerDnsTest, TxtQuery_Timeout) { @@ -7922,7 +7923,7 @@ TEST_F(HostResolverManagerDnsTest, TxtQuery_Timeout) { EXPECT_FALSE(response.request()->GetAddressResults()); EXPECT_FALSE(response.request()->GetTextResults()); EXPECT_FALSE(response.request()->GetHostnameResults()); - EXPECT_FALSE(response.request()->GetEsniResults()); + EXPECT_FALSE(response.request()->GetIntegrityResultsForTesting()); } TEST_F(HostResolverManagerDnsTest, TxtQuery_Empty) { @@ -7949,7 +7950,7 @@ TEST_F(HostResolverManagerDnsTest, TxtQuery_Empty) { EXPECT_FALSE(response.request()->GetAddressResults()); EXPECT_FALSE(response.request()->GetTextResults()); EXPECT_FALSE(response.request()->GetHostnameResults()); - EXPECT_FALSE(response.request()->GetEsniResults()); + EXPECT_FALSE(response.request()->GetIntegrityResultsForTesting()); } TEST_F(HostResolverManagerDnsTest, TxtQuery_Malformed) { @@ -7976,7 +7977,7 @@ TEST_F(HostResolverManagerDnsTest, TxtQuery_Malformed) { EXPECT_FALSE(response.request()->GetAddressResults()); EXPECT_FALSE(response.request()->GetTextResults()); EXPECT_FALSE(response.request()->GetHostnameResults()); - EXPECT_FALSE(response.request()->GetEsniResults()); + EXPECT_FALSE(response.request()->GetIntegrityResultsForTesting()); } TEST_F(HostResolverManagerDnsTest, TxtQuery_MismatchedName) { @@ -8000,7 +8001,7 @@ TEST_F(HostResolverManagerDnsTest, TxtQuery_MismatchedName) { EXPECT_FALSE(response.request()->GetAddressResults()); EXPECT_FALSE(response.request()->GetTextResults()); EXPECT_FALSE(response.request()->GetHostnameResults()); - EXPECT_FALSE(response.request()->GetEsniResults()); + EXPECT_FALSE(response.request()->GetIntegrityResultsForTesting()); } TEST_F(HostResolverManagerDnsTest, TxtQuery_WrongType) { @@ -8025,7 +8026,7 @@ TEST_F(HostResolverManagerDnsTest, TxtQuery_WrongType) { EXPECT_FALSE(response.request()->GetAddressResults()); EXPECT_FALSE(response.request()->GetTextResults()); EXPECT_FALSE(response.request()->GetHostnameResults()); - EXPECT_FALSE(response.request()->GetEsniResults()); + EXPECT_FALSE(response.request()->GetIntegrityResultsForTesting()); } // Same as TxtQuery except we specify DNS HostResolverSource instead of relying @@ -8058,7 +8059,7 @@ TEST_F(HostResolverManagerDnsTest, TxtDnsQuery) { EXPECT_THAT(response.result_error(), IsOk()); EXPECT_FALSE(response.request()->GetAddressResults()); EXPECT_FALSE(response.request()->GetHostnameResults()); - EXPECT_FALSE(response.request()->GetEsniResults()); + EXPECT_FALSE(response.request()->GetIntegrityResultsForTesting()); // Order between separate DNS records is undefined, but each record should // stay in order as that order may be meaningful. @@ -8092,7 +8093,7 @@ TEST_F(HostResolverManagerDnsTest, PtrQuery) { EXPECT_THAT(response.result_error(), IsOk()); EXPECT_FALSE(response.request()->GetAddressResults()); EXPECT_FALSE(response.request()->GetTextResults()); - EXPECT_FALSE(response.request()->GetEsniResults()); + EXPECT_FALSE(response.request()->GetIntegrityResultsForTesting()); // Order between separate records is undefined. EXPECT_THAT(response.request()->GetHostnameResults(), @@ -8119,7 +8120,7 @@ TEST_F(HostResolverManagerDnsTest, PtrQuery_Ip) { EXPECT_THAT(response.result_error(), IsOk()); EXPECT_FALSE(response.request()->GetAddressResults()); EXPECT_FALSE(response.request()->GetTextResults()); - EXPECT_FALSE(response.request()->GetEsniResults()); + EXPECT_FALSE(response.request()->GetIntegrityResultsForTesting()); // Order between separate records is undefined. EXPECT_THAT(response.request()->GetHostnameResults(), @@ -8151,7 +8152,7 @@ TEST_F(HostResolverManagerDnsTest, PtrQuery_NonexistentDomain) { EXPECT_FALSE(response.request()->GetAddressResults()); EXPECT_FALSE(response.request()->GetTextResults()); EXPECT_FALSE(response.request()->GetHostnameResults()); - EXPECT_FALSE(response.request()->GetEsniResults()); + EXPECT_FALSE(response.request()->GetIntegrityResultsForTesting()); } TEST_F(HostResolverManagerDnsTest, PtrQuery_Failure) { @@ -8178,7 +8179,7 @@ TEST_F(HostResolverManagerDnsTest, PtrQuery_Failure) { EXPECT_FALSE(response.request()->GetAddressResults()); EXPECT_FALSE(response.request()->GetTextResults()); EXPECT_FALSE(response.request()->GetHostnameResults()); - EXPECT_FALSE(response.request()->GetEsniResults()); + EXPECT_FALSE(response.request()->GetIntegrityResultsForTesting()); } TEST_F(HostResolverManagerDnsTest, PtrQuery_Timeout) { @@ -8205,7 +8206,7 @@ TEST_F(HostResolverManagerDnsTest, PtrQuery_Timeout) { EXPECT_FALSE(response.request()->GetAddressResults()); EXPECT_FALSE(response.request()->GetTextResults()); EXPECT_FALSE(response.request()->GetHostnameResults()); - EXPECT_FALSE(response.request()->GetEsniResults()); + EXPECT_FALSE(response.request()->GetIntegrityResultsForTesting()); } TEST_F(HostResolverManagerDnsTest, PtrQuery_Empty) { @@ -8232,7 +8233,7 @@ TEST_F(HostResolverManagerDnsTest, PtrQuery_Empty) { EXPECT_FALSE(response.request()->GetAddressResults()); EXPECT_FALSE(response.request()->GetTextResults()); EXPECT_FALSE(response.request()->GetHostnameResults()); - EXPECT_FALSE(response.request()->GetEsniResults()); + EXPECT_FALSE(response.request()->GetIntegrityResultsForTesting()); } TEST_F(HostResolverManagerDnsTest, PtrQuery_Malformed) { @@ -8259,7 +8260,7 @@ TEST_F(HostResolverManagerDnsTest, PtrQuery_Malformed) { EXPECT_FALSE(response.request()->GetAddressResults()); EXPECT_FALSE(response.request()->GetTextResults()); EXPECT_FALSE(response.request()->GetHostnameResults()); - EXPECT_FALSE(response.request()->GetEsniResults()); + EXPECT_FALSE(response.request()->GetIntegrityResultsForTesting()); } TEST_F(HostResolverManagerDnsTest, PtrQuery_MismatchedName) { @@ -8283,7 +8284,7 @@ TEST_F(HostResolverManagerDnsTest, PtrQuery_MismatchedName) { EXPECT_FALSE(response.request()->GetAddressResults()); EXPECT_FALSE(response.request()->GetTextResults()); EXPECT_FALSE(response.request()->GetHostnameResults()); - EXPECT_FALSE(response.request()->GetEsniResults()); + EXPECT_FALSE(response.request()->GetIntegrityResultsForTesting()); } TEST_F(HostResolverManagerDnsTest, PtrQuery_WrongType) { @@ -8308,7 +8309,7 @@ TEST_F(HostResolverManagerDnsTest, PtrQuery_WrongType) { EXPECT_FALSE(response.request()->GetAddressResults()); EXPECT_FALSE(response.request()->GetTextResults()); EXPECT_FALSE(response.request()->GetHostnameResults()); - EXPECT_FALSE(response.request()->GetEsniResults()); + EXPECT_FALSE(response.request()->GetIntegrityResultsForTesting()); } // Same as PtrQuery except we specify DNS HostResolverSource instead of relying @@ -8335,7 +8336,7 @@ TEST_F(HostResolverManagerDnsTest, PtrDnsQuery) { EXPECT_THAT(response.result_error(), IsOk()); EXPECT_FALSE(response.request()->GetAddressResults()); EXPECT_FALSE(response.request()->GetTextResults()); - EXPECT_FALSE(response.request()->GetEsniResults()); + EXPECT_FALSE(response.request()->GetIntegrityResultsForTesting()); // Order between separate records is undefined. EXPECT_THAT(response.request()->GetHostnameResults(), @@ -8366,7 +8367,7 @@ TEST_F(HostResolverManagerDnsTest, SrvQuery) { EXPECT_THAT(response.result_error(), IsOk()); EXPECT_FALSE(response.request()->GetAddressResults()); EXPECT_FALSE(response.request()->GetTextResults()); - EXPECT_FALSE(response.request()->GetEsniResults()); + EXPECT_FALSE(response.request()->GetIntegrityResultsForTesting()); // Expect ordered by priority, and random within a priority. base::Optional<std::vector<HostPortPair>> results = @@ -8411,7 +8412,7 @@ TEST_F(HostResolverManagerDnsTest, SrvQuery_ZeroWeight) { EXPECT_THAT(response.result_error(), IsOk()); EXPECT_FALSE(response.request()->GetAddressResults()); EXPECT_FALSE(response.request()->GetTextResults()); - EXPECT_FALSE(response.request()->GetEsniResults()); + EXPECT_FALSE(response.request()->GetIntegrityResultsForTesting()); // Expect ordered by priority, and random within a priority. EXPECT_THAT(response.request()->GetHostnameResults(), @@ -8443,7 +8444,7 @@ TEST_F(HostResolverManagerDnsTest, SrvQuery_NonexistentDomain) { EXPECT_FALSE(response.request()->GetAddressResults()); EXPECT_FALSE(response.request()->GetTextResults()); EXPECT_FALSE(response.request()->GetHostnameResults()); - EXPECT_FALSE(response.request()->GetEsniResults()); + EXPECT_FALSE(response.request()->GetIntegrityResultsForTesting()); } TEST_F(HostResolverManagerDnsTest, SrvQuery_Failure) { @@ -8470,7 +8471,7 @@ TEST_F(HostResolverManagerDnsTest, SrvQuery_Failure) { EXPECT_FALSE(response.request()->GetAddressResults()); EXPECT_FALSE(response.request()->GetTextResults()); EXPECT_FALSE(response.request()->GetHostnameResults()); - EXPECT_FALSE(response.request()->GetEsniResults()); + EXPECT_FALSE(response.request()->GetIntegrityResultsForTesting()); } TEST_F(HostResolverManagerDnsTest, SrvQuery_Timeout) { @@ -8497,7 +8498,7 @@ TEST_F(HostResolverManagerDnsTest, SrvQuery_Timeout) { EXPECT_FALSE(response.request()->GetAddressResults()); EXPECT_FALSE(response.request()->GetTextResults()); EXPECT_FALSE(response.request()->GetHostnameResults()); - EXPECT_FALSE(response.request()->GetEsniResults()); + EXPECT_FALSE(response.request()->GetIntegrityResultsForTesting()); } TEST_F(HostResolverManagerDnsTest, SrvQuery_Empty) { @@ -8524,7 +8525,7 @@ TEST_F(HostResolverManagerDnsTest, SrvQuery_Empty) { EXPECT_FALSE(response.request()->GetAddressResults()); EXPECT_FALSE(response.request()->GetTextResults()); EXPECT_FALSE(response.request()->GetHostnameResults()); - EXPECT_FALSE(response.request()->GetEsniResults()); + EXPECT_FALSE(response.request()->GetIntegrityResultsForTesting()); } TEST_F(HostResolverManagerDnsTest, SrvQuery_Malformed) { @@ -8551,7 +8552,7 @@ TEST_F(HostResolverManagerDnsTest, SrvQuery_Malformed) { EXPECT_FALSE(response.request()->GetAddressResults()); EXPECT_FALSE(response.request()->GetTextResults()); EXPECT_FALSE(response.request()->GetHostnameResults()); - EXPECT_FALSE(response.request()->GetEsniResults()); + EXPECT_FALSE(response.request()->GetIntegrityResultsForTesting()); } TEST_F(HostResolverManagerDnsTest, SrvQuery_MismatchedName) { @@ -8575,7 +8576,7 @@ TEST_F(HostResolverManagerDnsTest, SrvQuery_MismatchedName) { EXPECT_FALSE(response.request()->GetAddressResults()); EXPECT_FALSE(response.request()->GetTextResults()); EXPECT_FALSE(response.request()->GetHostnameResults()); - EXPECT_FALSE(response.request()->GetEsniResults()); + EXPECT_FALSE(response.request()->GetIntegrityResultsForTesting()); } TEST_F(HostResolverManagerDnsTest, SrvQuery_WrongType) { @@ -8600,7 +8601,7 @@ TEST_F(HostResolverManagerDnsTest, SrvQuery_WrongType) { EXPECT_FALSE(response.request()->GetAddressResults()); EXPECT_FALSE(response.request()->GetTextResults()); EXPECT_FALSE(response.request()->GetHostnameResults()); - EXPECT_FALSE(response.request()->GetEsniResults()); + EXPECT_FALSE(response.request()->GetIntegrityResultsForTesting()); } // Same as SrvQuery except we specify DNS HostResolverSource instead of relying @@ -8631,7 +8632,7 @@ TEST_F(HostResolverManagerDnsTest, SrvDnsQuery) { EXPECT_THAT(response.result_error(), IsOk()); EXPECT_FALSE(response.request()->GetAddressResults()); EXPECT_FALSE(response.request()->GetTextResults()); - EXPECT_FALSE(response.request()->GetEsniResults()); + EXPECT_FALSE(response.request()->GetIntegrityResultsForTesting()); // Expect ordered by priority, and random within a priority. base::Optional<std::vector<HostPortPair>> results = @@ -8653,6 +8654,542 @@ TEST_F(HostResolverManagerDnsTest, SrvDnsQuery) { HostPortPair("google.com", 5))); } +class HostResolverManagerDnsTestIntegrity : public HostResolverManagerDnsTest { + public: + HostResolverManagerDnsTestIntegrity() + : HostResolverManagerDnsTest( + base::test::TaskEnvironment::TimeSource::MOCK_TIME) { + const base::FieldTrialParams params = { + {"DnsHttpssvcUseIntegrity", "true"}, + {"DnsHttpssvcExperimentDomains", "host"}, + {"DnsHttpssvcControlDomains", ""}, + {"DnsHttpssvcEnableQueryOverInsecure", "false"}, + }; + scoped_feature_list_.InitAndEnableFeatureWithParameters( + features::kDnsHttpssvc, params); + } + + protected: + struct IntegrityAddRulesOptions { + bool add_a = true; + bool add_aaaa = true; + bool add_integrity = true; + bool integrity_mangled = false; + + bool secure_a = true; + bool secure_aaaa = true; + bool secure_integrity = true; + + bool delay_a = false; + bool delay_aaaa = false; + bool delay_integrity = false; + }; + + std::vector<uint8_t> GetValidIntegrityRdata() { + const IntegrityRecordRdata kValidRecord({'f', 'o', 'o'}); + base::Optional<std::vector<uint8_t>> valid_serialized = + kValidRecord.Serialize(); + CHECK(valid_serialized); + return *valid_serialized; + } + + std::vector<uint8_t> GetMangledIntegrityRdata() { + std::vector<uint8_t> rdata = GetValidIntegrityRdata(); + constexpr size_t kOffset = 2u; + CHECK_GT(rdata.size(), kOffset); + // Create a mangled version of |kValidRecord| by erasing a byte. + rdata.erase(rdata.begin() + kOffset); + return rdata; + } + + void AddRules(MockDnsClientRuleList rules, + const IntegrityAddRulesOptions& options) { + if (options.add_a) { + rules.emplace_back("host", dns_protocol::kTypeA, options.secure_a, + MockDnsClientRule::Result(MockDnsClientRule::OK), + options.delay_a); + } + + if (options.add_aaaa) { + rules.emplace_back("host", dns_protocol::kTypeAAAA, options.secure_aaaa, + MockDnsClientRule::Result(MockDnsClientRule::OK), + options.delay_aaaa); + } + + if (options.add_integrity) { + std::vector<uint8_t> integrity_rdata = options.integrity_mangled + ? GetMangledIntegrityRdata() + : GetValidIntegrityRdata(); + rules.emplace_back( + "host", dns_protocol::kExperimentalTypeIntegrity, + options.secure_integrity, + MockDnsClientRule::Result(BuildTestDnsIntegrityResponse( + "host", std::move(integrity_rdata))), + options.delay_integrity); + } + + CreateResolver(); + UseMockDnsClient(CreateValidDnsConfig(), std::move(rules)); + } + + std::unique_ptr<ResolveHostResponseHelper> DoIntegrityQuery(bool use_secure) { + if (use_secure) { + DnsConfigOverrides overrides; + overrides.secure_dns_mode = DnsConfig::SecureDnsMode::SECURE; + resolver_->SetDnsConfigOverrides(overrides); + } + + return std::make_unique<ResolveHostResponseHelper>(resolver_->CreateRequest( + HostPortPair("host", 108), NetworkIsolationKey(), NetLogWithSource(), + HostResolver::ResolveHostParameters(), resolve_context_.get(), + resolve_context_->host_cache())); + } + + base::test::ScopedFeatureList scoped_feature_list_; +}; + +TEST_F(HostResolverManagerDnsTestIntegrity, IntegrityQuery) { + AddRules(CreateDefaultDnsRules(), IntegrityAddRulesOptions()); + + std::unique_ptr<ResolveHostResponseHelper> response = + DoIntegrityQuery(true /* use_secure */); + + EXPECT_THAT(response->result_error(), IsOk()); + base::Optional<std::vector<bool>> results = + response->request()->GetIntegrityResultsForTesting(); + + EXPECT_TRUE(response->request()->GetAddressResults()); + EXPECT_FALSE(response->request()->GetTextResults()); + EXPECT_THAT(results, Optional(UnorderedElementsAre(true))); +} + +TEST_F(HostResolverManagerDnsTestIntegrity, IntegrityQueryMangled) { + IntegrityAddRulesOptions options; + options.integrity_mangled = true; + AddRules(CreateDefaultDnsRules(), options); + + std::unique_ptr<ResolveHostResponseHelper> response = + DoIntegrityQuery(true /* use_secure */); + + EXPECT_THAT(response->result_error(), IsOk()); + base::Optional<std::vector<bool>> results = + response->request()->GetIntegrityResultsForTesting(); + + EXPECT_TRUE(response->request()->GetAddressResults()); + EXPECT_FALSE(response->request()->GetTextResults()); + EXPECT_THAT(response->request()->GetIntegrityResultsForTesting(), + Optional(UnorderedElementsAre(false))); +} + +TEST_F(HostResolverManagerDnsTestIntegrity, IntegrityQueryOnlyOverSecure) { + IntegrityAddRulesOptions rules_options; + rules_options.secure_a = false; + rules_options.secure_aaaa = false; + rules_options.secure_integrity = false; + + AddRules(CreateDefaultDnsRules(), rules_options); + std::unique_ptr<ResolveHostResponseHelper> response = + DoIntegrityQuery(false /* use_secure */); + + EXPECT_THAT(response->result_error(), IsOk()); + base::Optional<std::vector<bool>> results = + response->request()->GetIntegrityResultsForTesting(); + + EXPECT_FALSE(results); +} + +// Ensure that the address results are preserved, even when the INTEGRITY query +// completes last. +TEST_F(HostResolverManagerDnsTestIntegrity, IntegrityQueryCompletesLast) { + IntegrityAddRulesOptions rules_options; + rules_options.delay_a = true; + rules_options.delay_aaaa = true; + rules_options.delay_integrity = true; + + AddRules(CreateDefaultDnsRules(), rules_options); + std::unique_ptr<ResolveHostResponseHelper> response = + DoIntegrityQuery(true /* use_secure */); + + constexpr base::TimeDelta kQuantum = base::TimeDelta::FromMilliseconds(1); + + FastForwardBy(100 * kQuantum); + + ASSERT_TRUE( + dns_client_->CompleteOneDelayedTransactionOfType(DnsQueryType::A)); + ASSERT_TRUE( + dns_client_->CompleteOneDelayedTransactionOfType(DnsQueryType::AAAA)); + + FastForwardBy(kQuantum); + + ASSERT_TRUE(dns_client_->CompleteOneDelayedTransactionOfType( + DnsQueryType::INTEGRITY)); + + // Above, the A/AAAA queries took 100 time units. We only fast forward by 1 + // time unit (1%) before answering the INTEGRITY query, to avoid triggering + // the timeout logic. This should work, assuming + // (1) the relative timeout is > 1% and + // (2) the absolute timeout is < (101 * kQuantum). + FastForwardBy(kQuantum); + + ASSERT_THAT(response->result_error(), IsOk()); + ASSERT_TRUE(response->request()->GetAddressResults()); + EXPECT_THAT(response->request()->GetAddressResults()->endpoints(), + testing::UnorderedElementsAre(CreateExpected("127.0.0.1", 108), + CreateExpected("::1", 108))); + // If this expectation fails, the INTEGRITY query was probably timed out. + // Check the |kDnsHttpssvcExtraTimeMs| and |kDnsHttpssvcExtraTimePercent| + // feature params in relation to this test's FastForward steps. + EXPECT_THAT(response->request()->GetIntegrityResultsForTesting(), + Optional(UnorderedElementsAre(true))); +} + +// For symmetry with |IntegrityQueryCompletesLast|, test the case where the +// INTEGRITY query completes first. +TEST_F(HostResolverManagerDnsTestIntegrity, IntegrityQueryCompletesFirst) { + IntegrityAddRulesOptions rules_options; + rules_options.delay_a = true; + rules_options.delay_aaaa = true; + rules_options.delay_integrity = true; + + AddRules(CreateDefaultDnsRules(), rules_options); + std::unique_ptr<ResolveHostResponseHelper> response = + DoIntegrityQuery(true /* use_secure */); + + constexpr base::TimeDelta kQuantum = base::TimeDelta::FromMilliseconds(10); + + FastForwardBy(kQuantum); + + ASSERT_TRUE(dns_client_->CompleteOneDelayedTransactionOfType( + DnsQueryType::INTEGRITY)); + + FastForwardBy(kQuantum); + + ASSERT_TRUE( + dns_client_->CompleteOneDelayedTransactionOfType(DnsQueryType::A)); + ASSERT_TRUE( + dns_client_->CompleteOneDelayedTransactionOfType(DnsQueryType::AAAA)); + + FastForwardBy(kQuantum); + + ASSERT_THAT(response->result_error(), IsOk()); + EXPECT_THAT(response->request()->GetIntegrityResultsForTesting(), + Optional(UnorderedElementsAre(true))); + ASSERT_TRUE(response->request()->GetAddressResults()); + EXPECT_THAT(response->request()->GetAddressResults()->endpoints(), + testing::UnorderedElementsAre(CreateExpected("127.0.0.1", 108), + CreateExpected("::1", 108))); +} + +// Ensure that the address results are preserved, even when the INTEGRITY query +// completes last and fails. +TEST_F(HostResolverManagerDnsTestIntegrity, + IntegrityQueryCompletesLastWithError) { + IntegrityAddRulesOptions rules_options; + rules_options.add_a = true; + rules_options.add_aaaa = true; + rules_options.add_integrity = false; + + rules_options.delay_a = true; + rules_options.delay_aaaa = true; + rules_options.delay_integrity = true; + + AddRules(CreateDefaultDnsRules(), rules_options); + std::unique_ptr<ResolveHostResponseHelper> response = + DoIntegrityQuery(true /* use_secure */); + + constexpr base::TimeDelta kQuantum = base::TimeDelta::FromMilliseconds(1); + + FastForwardBy(100 * kQuantum); + + ASSERT_TRUE( + dns_client_->CompleteOneDelayedTransactionOfType(DnsQueryType::A)); + ASSERT_TRUE( + dns_client_->CompleteOneDelayedTransactionOfType(DnsQueryType::AAAA)); + + FastForwardBy(kQuantum); + + ASSERT_FALSE(dns_client_->CompleteOneDelayedTransactionOfType( + DnsQueryType::INTEGRITY)); + + FastForwardBy(kQuantum); + + ASSERT_THAT(response->result_error(), IsOk()); + ASSERT_TRUE(response->request()->GetAddressResults()); + EXPECT_THAT(response->request()->GetAddressResults()->endpoints(), + testing::UnorderedElementsAre(CreateExpected("127.0.0.1", 108), + CreateExpected("::1", 108))); + EXPECT_THAT(response->request()->GetIntegrityResultsForTesting(), + Optional(IsEmpty())); +} + +// Ensure that the address results are preserved, even when the INTEGRITY query +// completes first and fails. +TEST_F(HostResolverManagerDnsTestIntegrity, + IntegrityQueryCompletesFirstWithError) { + IntegrityAddRulesOptions rules_options; + rules_options.add_a = true; + rules_options.add_aaaa = true; + rules_options.add_integrity = false; + + rules_options.delay_a = true; + rules_options.delay_aaaa = true; + rules_options.delay_integrity = true; + + AddRules(CreateDefaultDnsRules(), rules_options); + std::unique_ptr<ResolveHostResponseHelper> response = + DoIntegrityQuery(true /* use_secure */); + + constexpr base::TimeDelta kQuantum = base::TimeDelta::FromMilliseconds(10); + + FastForwardBy(kQuantum); + + // This fails because there is no rule for the INTEGRITY query. + ASSERT_FALSE(dns_client_->CompleteOneDelayedTransactionOfType( + DnsQueryType::INTEGRITY)); + + FastForwardBy(kQuantum); + + ASSERT_TRUE( + dns_client_->CompleteOneDelayedTransactionOfType(DnsQueryType::A)); + ASSERT_TRUE( + dns_client_->CompleteOneDelayedTransactionOfType(DnsQueryType::AAAA)); + + FastForwardBy(kQuantum); + + ASSERT_THAT(response->result_error(), IsOk()); + EXPECT_THAT(response->request()->GetIntegrityResultsForTesting(), + Optional(IsEmpty())); + ASSERT_TRUE(response->request()->GetAddressResults()); + EXPECT_THAT(response->request()->GetAddressResults()->endpoints(), + testing::UnorderedElementsAre(CreateExpected("127.0.0.1", 108), + CreateExpected("::1", 108))); +} + +TEST_F(HostResolverManagerDnsTestIntegrity, + IntegrityQueryCompletesLastMangled) { + IntegrityAddRulesOptions rules_options; + rules_options.integrity_mangled = true; + + rules_options.delay_a = true; + rules_options.delay_aaaa = true; + rules_options.delay_integrity = true; + + AddRules(CreateDefaultDnsRules(), rules_options); + std::unique_ptr<ResolveHostResponseHelper> response = + DoIntegrityQuery(true /* use_secure */); + + constexpr base::TimeDelta kQuantum = base::TimeDelta::FromMilliseconds(1); + + FastForwardBy(100 * kQuantum); + + ASSERT_TRUE( + dns_client_->CompleteOneDelayedTransactionOfType(DnsQueryType::A)); + ASSERT_TRUE( + dns_client_->CompleteOneDelayedTransactionOfType(DnsQueryType::AAAA)); + + FastForwardBy(kQuantum); + + ASSERT_TRUE(dns_client_->CompleteOneDelayedTransactionOfType( + DnsQueryType::INTEGRITY)); + + FastForwardBy(kQuantum); + + ASSERT_THAT(response->result_error(), IsOk()); + ASSERT_TRUE(response->request()->GetAddressResults()); + EXPECT_THAT(response->request()->GetAddressResults()->endpoints(), + testing::UnorderedElementsAre(CreateExpected("127.0.0.1", 108), + CreateExpected("::1", 108))); + EXPECT_THAT(response->request()->GetIntegrityResultsForTesting(), + Optional(UnorderedElementsAre(false))); +} + +TEST_F(HostResolverManagerDnsTestIntegrity, + IntegrityQueryCompletesFirstMangled) { + IntegrityAddRulesOptions rules_options; + rules_options.integrity_mangled = true; + + rules_options.delay_a = true; + rules_options.delay_aaaa = true; + rules_options.delay_integrity = true; + + AddRules(CreateDefaultDnsRules(), rules_options); + std::unique_ptr<ResolveHostResponseHelper> response = + DoIntegrityQuery(true /* use_secure */); + + constexpr base::TimeDelta kQuantum = base::TimeDelta::FromMilliseconds(10); + + FastForwardBy(kQuantum); + + ASSERT_TRUE(dns_client_->CompleteOneDelayedTransactionOfType( + DnsQueryType::INTEGRITY)); + + FastForwardBy(kQuantum); + + ASSERT_TRUE( + dns_client_->CompleteOneDelayedTransactionOfType(DnsQueryType::A)); + ASSERT_TRUE( + dns_client_->CompleteOneDelayedTransactionOfType(DnsQueryType::AAAA)); + + FastForwardBy(kQuantum); + + ASSERT_THAT(response->result_error(), IsOk()); + EXPECT_THAT(response->request()->GetIntegrityResultsForTesting(), + Optional(UnorderedElementsAre(false))); + ASSERT_TRUE(response->request()->GetAddressResults()); + EXPECT_THAT(response->request()->GetAddressResults()->endpoints(), + testing::UnorderedElementsAre(CreateExpected("127.0.0.1", 108), + CreateExpected("::1", 108))); +} + +// Make sure that INTEGRITY queries don't get cancelled *before* the configured +// timeout, but do get cancelled after it, in the case where the absolute +// timeout dominates. +TEST_F(HostResolverManagerDnsTestIntegrity, RespectsAbsoluteTimeout) { + IntegrityAddRulesOptions rules_options; + rules_options.delay_a = true; + rules_options.delay_aaaa = true; + rules_options.delay_integrity = true; + + AddRules(CreateDefaultDnsRules(), rules_options); + + std::unique_ptr<ResolveHostResponseHelper> response = + DoIntegrityQuery(true /* use_secure */); + + // relative_timeout + // ┌────────────────────────────────┤ + // │ + // │ absolute_timeout + // ├────────────────────┤ + // a_aaaa_elapsed │ time + // ├────────────────────┼─────────────────────────────────────────────────> + // Now └ (moment when A and AAAA complete) + // + // When the A and AAAA queries complete, and only INTEGRITY remains, we start + // running the INTEGRITY timeout clock. This moment is |Now + a_aaaa_elapsed|, + // or just |a_aaaa_elapsed| if we let Now = 0. The INTEGRITY query is + // cancelled at the moment that |absolute_timeout| or |relative_timeout| runs + // out. + // + // The TimeDelta values of |absolute_timeout| and |relative_timeout| are + // computed from feature params. + // + // absolute_timeout = a_aaaa_elapsed + ExtraMs. + // + // relative_timeout = a_aaaa_elapsed * (1 + (ExtraPercent/100)). + // + // Assume ExtraMs > 0 and 0 < ExtraPercent < 100. + // + // For this test, we want the absolute timeout to happen *before* the relative + // timeout. Compute a value for a_aaaa_elapsed such that absolute_timeout + // comes before relative_timeout. + // + // Assuming ExtraPercent is not zero, we know that these two lines intersect + // for some value of a_aaaa_elapsed. Let's find it. + // + // Assume absolute_timeout = relative_timeout. + // a_aaaa_elapsed + ExtraMs = a_aaaa_elapsed * (1 + (ExtraPercent / 100)). + // ExtraMs = a_aaaa_elapsed * (1 + (ExtraPercent / 100)) - a_aaaa_elapsed. + // ExtraMs = a_aaaa_elapsed * ((1 + (ExtraPercent / 100)) - 1). + // ExtraMs / ((1 + (ExtraPercent / 100)) - 1) = a_aaaa_elapsed. + // Simplified: + // a_aaaa_elapsed = 100 * ExtraMs / ExtraPercent. + // + // For values of a_aaaa_elapsed < 100 * ExtraMs / ExtraPercent, + // relative_timeout < absolute_timeout. For larger values, absolute_timeout > + // relative_timeout. + + base::TimeDelta absolute_timeout = base::TimeDelta::FromMilliseconds( + features::kDnsHttpssvcExtraTimeMs.Get()); + base::TimeDelta intersection = + 100 * absolute_timeout / features::kDnsHttpssvcExtraTimePercent.Get(); + + // Let enough time pass during the A and AAAA transactions that the + // absolute timeout will be less than the relative timeout. + base::TimeDelta a_aaaa_elapsed = 50 * intersection; + + FastForwardBy(a_aaaa_elapsed); + ASSERT_TRUE( + dns_client_->CompleteOneDelayedTransactionOfType(DnsQueryType::A)); + ASSERT_TRUE( + dns_client_->CompleteOneDelayedTransactionOfType(DnsQueryType::AAAA)); + + // Since the A and AAAA queries have only just completed, we shouldn't + // have timed out the INTEGRITY query. + EXPECT_FALSE(response->complete()); + + // After half of the absolute timeout, the query should still be alive. + FastForwardBy(absolute_timeout / 2); + + // Since the absolute timeout has not yet elapsed, and it is shorter by + // design than the relative timeout, we shouldn't + // have timed out the INTEGRITY transaction. + EXPECT_FALSE(response->complete()); + + // After (more than) the timeout has passed, we should have cancelled + // the INTEGRITY transaction. + FastForwardBy(absolute_timeout); + ASSERT_THAT(response->result_error(), IsOk()); + + // Since we cancelled the transaction, we shouldn't have any INTEGRITY + // results. + EXPECT_FALSE(response->request()->GetIntegrityResultsForTesting()); + + // Out of paranoia, pass some more time to ensure no crashes occur. + FastForwardBy(base::TimeDelta::FromMilliseconds(100)); +} + +TEST_F(HostResolverManagerDnsTestIntegrity, RespectsRelativeTimeout) { + IntegrityAddRulesOptions rules_options; + rules_options.delay_a = false; + rules_options.delay_aaaa = true; + rules_options.delay_integrity = true; + + AddRules(CreateDefaultDnsRules(), rules_options); + + std::unique_ptr<ResolveHostResponseHelper> response = + DoIntegrityQuery(true /* use_secure */); + + base::TimeDelta absolute_timeout = base::TimeDelta::FromMilliseconds( + features::kDnsHttpssvcExtraTimeMs.Get()); + base::TimeDelta intersection = + 100 * absolute_timeout / features::kDnsHttpssvcExtraTimePercent.Get(); + + // Let little enough time pass during the A and AAAA transactions that the + // relative timeout will be less than the absolute timeout. + base::TimeDelta a_aaaa_elapsed = 0.05 * intersection; + + // Since the A and AAAA queries haven't both completed yet, we shouldn't time + // out the INTEGRITY query. + FastForwardBy(a_aaaa_elapsed); + + // Upon completing the AAAA transaction, the INTEGRITY timer should start + ASSERT_TRUE( + dns_client_->CompleteOneDelayedTransactionOfType(DnsQueryType::AAAA)); + + base::TimeDelta relative_timeout = + a_aaaa_elapsed * features::kDnsHttpssvcExtraTimePercent.Get() / 100; + + // After *less* than the relative timeout, the query shouldn't have concluded. + FastForwardBy(relative_timeout * 0.5); + + EXPECT_FALSE(response->complete()); + + // After more than the relative timeout, the query should conclude by aborting + // the INTEGRITY query. + FastForwardBy(relative_timeout); + + // The task should have completed with a cancelled INTEGRITY query. + ASSERT_THAT(response->result_error(), IsOk()); + EXPECT_FALSE(response->request()->GetIntegrityResultsForTesting()); + ASSERT_TRUE(response->request()->GetAddressResults()); + EXPECT_THAT(response->request()->GetAddressResults()->endpoints(), + testing::UnorderedElementsAre(CreateExpected("127.0.0.1", 108), + CreateExpected("::1", 108))); + + // Out of paranoia, pass some more time to ensure no crashes occur. + FastForwardBy(base::TimeDelta::FromMilliseconds(100)); +} + TEST_F(HostResolverManagerDnsTest, DohProbeRequest) { ChangeDnsConfig(CreateValidDnsConfig()); @@ -8787,349 +9324,6 @@ TEST_F(HostResolverManagerDnsTest, MultipleDohProbeRequests) { EXPECT_FALSE(dns_client_->factory()->doh_probes_running()); } -TEST_F(HostResolverManagerDnsTest, EsniQuery) { - EsniContent c1, c2, c3; - IPAddress a1(1, 2, 3, 4), a2(5, 6, 7, 8); - IPAddress a3(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1); - - std::string kKey1 = GenerateWellFormedEsniKeys("a"); - std::string kKey2 = GenerateWellFormedEsniKeys("b"); - std::string kKey3 = GenerateWellFormedEsniKeys("c"); - - c1.AddKey(kKey1); - - c2.AddKeyForAddress(a1, kKey2); - c2.AddKeyForAddress(a2, kKey2); - c2.AddKeyForAddress(a3, kKey2); - - c3.AddKeyForAddress(a1, kKey3); - - std::vector<EsniContent> esni_records = {c1, c2, c3}; - - MockDnsClientRuleList rules; - rules.emplace_back("host", dns_protocol::kExperimentalTypeEsniDraft4, - false /* secure */, - MockDnsClientRule::Result(BuildTestDnsEsniResponse( - "host", std::move(esni_records))), - false /* delay */); - - CreateResolver(); - UseMockDnsClient(CreateValidDnsConfig(), std::move(rules)); - - HostResolver::ResolveHostParameters parameters; - parameters.dns_query_type = DnsQueryType::ESNI; - - ResolveHostResponseHelper response(resolver_->CreateRequest( - HostPortPair("host", 108), NetworkIsolationKey(), NetLogWithSource(), - parameters, resolve_context_.get(), resolve_context_->host_cache())); - EXPECT_THAT(response.result_error(), IsOk()); - - EXPECT_FALSE(response.request()->GetHostnameResults()); - EXPECT_FALSE(response.request()->GetTextResults()); - - // The IPv6 address |a3| should come first, and the other - // addresses should have been deduplicated. - EXPECT_THAT( - response.request()->GetAddressResults(), - Optional(AllOf(Property(&AddressList::endpoints, - UnorderedElementsAre(IPEndPoint(a3, 108), - IPEndPoint(a1, 108), - IPEndPoint(a2, 108))), - Property(&AddressList::front, IPEndPoint(a3, 108))))); - - // During aggregation of ESNI query results, we drop ESNI keys - // with no associated addresses, like key 1 here. (This is an implementation - // decision declining a "MAY" behavior from the spec.) - // So, we require that only keys 2 and 3 are surfaced. - // - // The Eq() wrappers are necessary here because keys_for_addresses - // returns a container of StringPieces. - EXPECT_THAT( - response.request()->GetEsniResults(), - Optional(AllOf( - Property(&EsniContent::keys, - UnorderedElementsAre(Eq(kKey2), Eq(kKey3))), - Property(&EsniContent::keys_for_addresses, - UnorderedElementsAre( - Pair(a1, UnorderedElementsAre(Eq(kKey2), Eq(kKey3))), - Pair(a2, UnorderedElementsAre(Eq(kKey2))), - Pair(a3, UnorderedElementsAre(Eq(kKey2)))))))); -} - -TEST_F(HostResolverManagerDnsTest, EsniQuery_InvalidConfig) { - set_allow_fallback_to_proctask(false); - // Set empty DnsConfig. - InvalidateDnsConfig(); - - HostResolver::ResolveHostParameters parameters; - parameters.dns_query_type = DnsQueryType::ESNI; - - ResolveHostResponseHelper response(resolver_->CreateRequest( - HostPortPair("host", 108), NetworkIsolationKey(), NetLogWithSource(), - parameters, resolve_context_.get(), resolve_context_->host_cache())); - EXPECT_THAT(response.result_error(), IsError(ERR_DNS_CACHE_MISS)); -} - -TEST_F(HostResolverManagerDnsTest, EsniQuery_NonexistentDomain) { - // Setup fallback to confirm it is not used for non-address results. - set_allow_fallback_to_proctask(true); - proc_->AddRuleForAllFamilies("host", "192.168.1.102"); - proc_->SignalMultiple(1u); - - MockDnsClientRuleList rules; - rules.emplace_back("host", dns_protocol::kExperimentalTypeEsniDraft4, - false /* secure */, - MockDnsClientRule::Result(MockDnsClientRule::NODOMAIN), - false /* delay */); - - CreateResolver(); - UseMockDnsClient(CreateValidDnsConfig(), std::move(rules)); - - HostResolver::ResolveHostParameters parameters; - parameters.dns_query_type = DnsQueryType::ESNI; - - ResolveHostResponseHelper response(resolver_->CreateRequest( - HostPortPair("host", 108), NetworkIsolationKey(), NetLogWithSource(), - parameters, resolve_context_.get(), resolve_context_->host_cache())); - EXPECT_THAT(response.result_error(), IsError(ERR_NAME_NOT_RESOLVED)); - EXPECT_FALSE(response.request()->GetAddressResults()); - EXPECT_FALSE(response.request()->GetTextResults()); - EXPECT_FALSE(response.request()->GetHostnameResults()); - EXPECT_FALSE(response.request()->GetEsniResults()); -} - -TEST_F(HostResolverManagerDnsTest, EsniQuery_Failure) { - // Setup fallback to confirm it is not used for non-address results. - set_allow_fallback_to_proctask(true); - proc_->AddRuleForAllFamilies("host", "192.168.1.102"); - proc_->SignalMultiple(1u); - - MockDnsClientRuleList rules; - rules.emplace_back( - "host", dns_protocol::kExperimentalTypeEsniDraft4, false /* secure */, - MockDnsClientRule::Result(MockDnsClientRule::FAIL), false /* delay */); - - CreateResolver(); - UseMockDnsClient(CreateValidDnsConfig(), std::move(rules)); - - HostResolver::ResolveHostParameters parameters; - parameters.dns_query_type = DnsQueryType::ESNI; - - ResolveHostResponseHelper response(resolver_->CreateRequest( - HostPortPair("host", 108), NetworkIsolationKey(), NetLogWithSource(), - parameters, resolve_context_.get(), resolve_context_->host_cache())); - EXPECT_THAT(response.result_error(), IsError(ERR_NAME_NOT_RESOLVED)); - EXPECT_FALSE(response.request()->GetAddressResults()); - EXPECT_FALSE(response.request()->GetTextResults()); - EXPECT_FALSE(response.request()->GetHostnameResults()); - EXPECT_FALSE(response.request()->GetEsniResults()); -} - -TEST_F(HostResolverManagerDnsTest, EsniQuery_Timeout) { - // Setup fallback to confirm it is not used for non-address results. - set_allow_fallback_to_proctask(true); - proc_->AddRuleForAllFamilies("host", "192.168.1.102"); - proc_->SignalMultiple(1u); - - MockDnsClientRuleList rules; - rules.emplace_back( - "host", dns_protocol::kExperimentalTypeEsniDraft4, false /* secure */, - MockDnsClientRule::Result(MockDnsClientRule::TIMEOUT), false /* delay */); - - CreateResolver(); - UseMockDnsClient(CreateValidDnsConfig(), std::move(rules)); - - HostResolver::ResolveHostParameters parameters; - parameters.dns_query_type = DnsQueryType::ESNI; - - ResolveHostResponseHelper response(resolver_->CreateRequest( - HostPortPair("host", 108), NetworkIsolationKey(), NetLogWithSource(), - parameters, resolve_context_.get(), resolve_context_->host_cache())); - EXPECT_THAT(response.result_error(), IsError(ERR_DNS_TIMED_OUT)); - EXPECT_FALSE(response.request()->GetAddressResults()); - EXPECT_FALSE(response.request()->GetTextResults()); - EXPECT_FALSE(response.request()->GetHostnameResults()); - EXPECT_FALSE(response.request()->GetEsniResults()); -} - -TEST_F(HostResolverManagerDnsTest, EsniQuery_Empty) { - // Setup fallback to confirm it is not used for non-address results. - set_allow_fallback_to_proctask(true); - proc_->AddRuleForAllFamilies("host", "192.168.1.102"); - proc_->SignalMultiple(1u); - - MockDnsClientRuleList rules; - rules.emplace_back( - "host", dns_protocol::kExperimentalTypeEsniDraft4, false /* secure */, - MockDnsClientRule::Result(MockDnsClientRule::EMPTY), false /* delay */); - - CreateResolver(); - UseMockDnsClient(CreateValidDnsConfig(), std::move(rules)); - - HostResolver::ResolveHostParameters parameters; - parameters.dns_query_type = DnsQueryType::ESNI; - - ResolveHostResponseHelper response(resolver_->CreateRequest( - HostPortPair("host", 108), NetworkIsolationKey(), NetLogWithSource(), - parameters, resolve_context_.get(), resolve_context_->host_cache())); - EXPECT_THAT(response.result_error(), IsError(ERR_NAME_NOT_RESOLVED)); - EXPECT_FALSE(response.request()->GetAddressResults()); - EXPECT_FALSE(response.request()->GetTextResults()); - EXPECT_FALSE(response.request()->GetHostnameResults()); - EXPECT_FALSE(response.request()->GetEsniResults()); -} - -TEST_F(HostResolverManagerDnsTest, EsniQuery_Malformed) { - // Setup fallback to confirm it is not used for non-address results. - set_allow_fallback_to_proctask(true); - proc_->AddRuleForAllFamilies("host", "192.168.1.102"); - proc_->SignalMultiple(1u); - - MockDnsClientRuleList rules; - rules.emplace_back("host", dns_protocol::kExperimentalTypeEsniDraft4, - false /* secure */, - MockDnsClientRule::Result(MockDnsClientRule::MALFORMED), - false /* delay */); - - CreateResolver(); - UseMockDnsClient(CreateValidDnsConfig(), std::move(rules)); - - HostResolver::ResolveHostParameters parameters; - parameters.dns_query_type = DnsQueryType::ESNI; - - ResolveHostResponseHelper response(resolver_->CreateRequest( - HostPortPair("host", 108), NetworkIsolationKey(), NetLogWithSource(), - parameters, resolve_context_.get(), resolve_context_->host_cache())); - EXPECT_THAT(response.result_error(), IsError(ERR_DNS_MALFORMED_RESPONSE)); - EXPECT_FALSE(response.request()->GetAddressResults()); - EXPECT_FALSE(response.request()->GetTextResults()); - EXPECT_FALSE(response.request()->GetHostnameResults()); - EXPECT_FALSE(response.request()->GetEsniResults()); -} - -TEST_F(HostResolverManagerDnsTest, EsniQuery_MismatchedName) { - EsniContent content; - IPAddress address(1, 2, 3, 4); - std::string key = GenerateWellFormedEsniKeys("a"); - content.AddKeyForAddress(address, key); - - std::vector<EsniContent> esni_records = {content}; - - MockDnsClientRuleList rules; - rules.emplace_back("host", dns_protocol::kExperimentalTypeEsniDraft4, - false /* secure */, - MockDnsClientRule::Result(BuildTestDnsEsniResponse( - "host", std::move(esni_records), "not.host")), - false /* delay */); - - CreateResolver(); - UseMockDnsClient(CreateValidDnsConfig(), std::move(rules)); - - HostResolver::ResolveHostParameters parameters; - parameters.dns_query_type = DnsQueryType::ESNI; - - ResolveHostResponseHelper response(resolver_->CreateRequest( - HostPortPair("host", 108), NetworkIsolationKey(), NetLogWithSource(), - parameters, resolve_context_.get(), resolve_context_->host_cache())); - EXPECT_THAT(response.result_error(), IsError(ERR_DNS_MALFORMED_RESPONSE)); - EXPECT_FALSE(response.request()->GetAddressResults()); - EXPECT_FALSE(response.request()->GetTextResults()); - EXPECT_FALSE(response.request()->GetHostnameResults()); - EXPECT_FALSE(response.request()->GetEsniResults()); -} - -TEST_F(HostResolverManagerDnsTest, EsniQuery_WrongType) { - // Respond to an ESNI query with an A response. - MockDnsClientRuleList rules; - rules.emplace_back("host", dns_protocol::kExperimentalTypeEsniDraft4, - false /* secure */, - MockDnsClientRule::Result( - BuildTestDnsResponse("host", IPAddress(1, 2, 3, 4))), - false /* delay */); - - CreateResolver(); - UseMockDnsClient(CreateValidDnsConfig(), std::move(rules)); - - HostResolver::ResolveHostParameters parameters; - parameters.dns_query_type = DnsQueryType::ESNI; - - // Responses for the wrong type should be ignored. - ResolveHostResponseHelper response(resolver_->CreateRequest( - HostPortPair("ok", 108), NetworkIsolationKey(), NetLogWithSource(), - parameters, resolve_context_.get(), resolve_context_->host_cache())); - EXPECT_THAT(response.result_error(), IsError(ERR_NAME_NOT_RESOLVED)); - EXPECT_FALSE(response.request()->GetAddressResults()); - EXPECT_FALSE(response.request()->GetTextResults()); - EXPECT_FALSE(response.request()->GetHostnameResults()); - EXPECT_FALSE(response.request()->GetEsniResults()); -} - -// Same as EsniQuery except we specify DNS HostResolverSource instead of relying -// on automatic determination. Expect same results since DNS should be what we -// automatically determine, but some slightly different logic paths are -// involved. -TEST_F(HostResolverManagerDnsTest, EsniDnsQuery) { - EsniContent c1, c2, c3; - IPAddress a1(1, 2, 3, 4), a2(5, 6, 7, 8); - - const std::string kKey1 = GenerateWellFormedEsniKeys("a"); - const std::string kKey2 = GenerateWellFormedEsniKeys("b"); - const std::string kKey3 = GenerateWellFormedEsniKeys("c"); - - c1.AddKey(kKey1); - - c2.AddKeyForAddress(a1, kKey2); - c2.AddKeyForAddress(a2, kKey2); - - c3.AddKeyForAddress(a1, kKey3); - - std::vector<EsniContent> esni_records = {c1, c2, c3}; - - MockDnsClientRuleList rules; - rules.emplace_back("host", dns_protocol::kExperimentalTypeEsniDraft4, - false /* secure */, - MockDnsClientRule::Result(BuildTestDnsEsniResponse( - "host", std::move(esni_records))), - false /* delay */); - - CreateResolver(); - UseMockDnsClient(CreateValidDnsConfig(), std::move(rules)); - - HostResolver::ResolveHostParameters parameters; - parameters.source = HostResolverSource::DNS; - parameters.dns_query_type = DnsQueryType::ESNI; - - ResolveHostResponseHelper response(resolver_->CreateRequest( - HostPortPair("host", 108), NetworkIsolationKey(), NetLogWithSource(), - parameters, resolve_context_.get(), resolve_context_->host_cache())); - EXPECT_THAT(response.result_error(), IsOk()); - EXPECT_FALSE(response.request()->GetHostnameResults()); - EXPECT_FALSE(response.request()->GetTextResults()); - - // The multiple ESNI records should have been merged when parsing - // the results. - c1.MergeFrom(c2); - c1.MergeFrom(c3); - - // The ESNI records' addresses should have been merged into - // the address list. - ASSERT_TRUE(response.request()->GetAddressResults()); - EXPECT_THAT( - response.request()->GetAddressResults()->endpoints(), - testing::UnorderedElementsAre(IPEndPoint(a1, 108), IPEndPoint(a2, 108))); - - ASSERT_TRUE(response.request()->GetEsniResults().has_value()); - - // During aggregation of ESNI query results, we drop ESNI keys - // with no associated addresses, like key 1 here. (This is an implementation - // decision declining a "MAY" behavior from the spec.) So, we require that - // only keys 2 and 3 are surfaced. - EXPECT_THAT(response.request()->GetEsniResults()->keys(), - testing::UnorderedElementsAre(kKey2, kKey3)); - EXPECT_EQ(response.request()->GetEsniResults()->keys_for_addresses(), - c1.keys_for_addresses()); -} - // Test that a newly-registered ResolveContext is immediately usable with a DNS // configuration loaded before the context registration. TEST_F(HostResolverManagerDnsTest, @@ -9202,353 +9396,4 @@ TEST_F(HostResolverManagerDnsTest, resolver_->DeregisterResolveContext(&context); } -class HostResolverManagerEsniTest : public HostResolverManagerDnsTest { - public: - HostResolverManagerEsniTest() - : HostResolverManagerDnsTest( - base::test::TaskEnvironment::TimeSource::MOCK_TIME) { - scoped_feature_list_.InitAndEnableFeature(features::kRequestEsniDnsRecords); - } - - protected: - base::test::ScopedFeatureList scoped_feature_list_; - - // Adds a rule returning a collection of ESNI records such that - // - there is a lone key with no associated addresses - // - there is an address associated with multiple keys - // - there is a key associated with multiple addresses - // - // Returns a pair containing: - // (1) a single merged EsniContent object which should be contained in - // the eventual response. - // (2) the collection of IPEndPoints corresponding to the - // ESNI records' contained addresses; these are expected to - // be contained in the eventual response's address list (assuming - // no addresses are pruned by the address sorter, which will - // be the case in the test, because MockAddressSorter no-ops) - struct AddEsniRecordsRuleOptions { - bool secure = true, delay = false; - }; - std::pair<EsniContent, std::vector<IPEndPoint>> AddEsniRecordsRule( - base::StringPiece hostname, - AddEsniRecordsRuleOptions options, - MockDnsClientRuleList* rules) { - EsniContent c1, c2, c3; - IPAddress a1(1, 2, 3, 4); - IPAddress a2(5, 6, 7, 8); - - const std::string kKey1 = GenerateWellFormedEsniKeys("a"); - const std::string kKey2 = GenerateWellFormedEsniKeys("b"); - const std::string kKey3 = GenerateWellFormedEsniKeys("c"); - - c1.AddKey(kKey1); - - c2.AddKeyForAddress(a1, kKey2); - c2.AddKeyForAddress(a2, kKey2); - - c3.AddKeyForAddress(a1, kKey3); - - std::vector<EsniContent> esni_records = {c1, c2, c3}; - rules->emplace_back(std::string(hostname), - dns_protocol::kExperimentalTypeEsniDraft4, - options.secure, - MockDnsClientRule::Result(BuildTestDnsEsniResponse( - std::string(hostname), std::move(esni_records))), - options.delay); - - // Key 1 will be dropped because it corresponds to no addresses; - // section 4.2.2 of ESNI draft 4 gives implementors the option to associate - // these with all IP addresses received in concurrent A and AAAA responses, - // and we choose not to do this. - c2.MergeFrom(c3); - return std::make_pair( - c2, std::vector<IPEndPoint>{IPEndPoint(a1, 80), IPEndPoint(a2, 80)}); - } -}; - -// Check that resolving ESNI queries alongside A and AAAA queries -// results in a correct aggregation of addresses. -TEST_F(HostResolverManagerEsniTest, AggregatesResults) { - MockDnsClientRuleList rules; - - EsniContent esni_expectation; - std::vector<IPEndPoint> expected_addresses; - std::tie(esni_expectation, expected_addresses) = - AddEsniRecordsRule("host", AddEsniRecordsRuleOptions(), &rules); - - rules.emplace_back("host", dns_protocol::kTypeA, true /* secure */, - MockDnsClientRule::Result(MockDnsClientRule::OK), - false /* delay */); - rules.emplace_back("host", dns_protocol::kTypeAAAA, true /* secure */, - MockDnsClientRule::Result(MockDnsClientRule::OK), - false /* delay */); - // Even though the A and AAAA results' addresses won't have any - // associated ESNI keys, they should still be surfaced in GetAddressResults(). - expected_addresses.push_back(CreateExpected("127.0.0.1", 80)); - expected_addresses.push_back(CreateExpected("::1", 80)); - - CreateResolver(); - UseMockDnsClient(CreateValidDnsConfig(), std::move(rules)); - DnsConfigOverrides overrides; - overrides.secure_dns_mode = DnsConfig::SecureDnsMode::AUTOMATIC; - resolver_->SetDnsConfigOverrides(overrides); - - ResolveHostResponseHelper response(resolver_->CreateRequest( - HostPortPair("host", 80), NetworkIsolationKey(), NetLogWithSource(), - HostResolver::ResolveHostParameters(), resolve_context_.get(), - resolve_context_->host_cache())); - - ASSERT_THAT(response.result_error(), IsOk()); - EXPECT_THAT(response.request()->GetEsniResults(), - testing::Optional(testing::Eq(esni_expectation))); - // GetAddressResults() should surface addresses with and without - // associated ESNI keys. - ASSERT_THAT(response.request()->GetAddressResults()->endpoints(), - testing::UnorderedElementsAreArray(expected_addresses)); -} - -// Test that addresses with associated ESNI keys are placed -// first in the order provided to the address sorter. -// (This corresponds to the order of the address list in the results -// because MockAddressSorter's sort is a no-op.) -TEST_F(HostResolverManagerEsniTest, EsniAddressesFirstInOrder) { - MockDnsClientRuleList rules; - - EsniContent esni_expectation; - std::vector<IPEndPoint> esni_addresses; - std::tie(esni_expectation, esni_addresses) = - AddEsniRecordsRule("host", AddEsniRecordsRuleOptions(), &rules); - - rules.emplace_back("host", dns_protocol::kTypeA, true /* secure */, - MockDnsClientRule::Result(MockDnsClientRule::OK), - false /* delay */); - rules.emplace_back("host", dns_protocol::kTypeAAAA, true /* secure */, - MockDnsClientRule::Result(MockDnsClientRule::OK), - false /* delay */); - - CreateResolver(); - UseMockDnsClient(CreateValidDnsConfig(), std::move(rules)); - DnsConfigOverrides overrides; - overrides.secure_dns_mode = DnsConfig::SecureDnsMode::AUTOMATIC; - resolver_->SetDnsConfigOverrides(overrides); - - HostResolver::ResolveHostParameters parameters; - ResolveHostResponseHelper response(resolver_->CreateRequest( - HostPortPair("host", 80), NetworkIsolationKey(), NetLogWithSource(), - parameters, resolve_context_.get(), resolve_context_->host_cache())); - - // Check that the IP addresses with associated - // ESNI key objects occupy the initial entries of the - // address list returned by the DNS query. - ASSERT_THAT(response.result_error(), IsOk()); - ASSERT_TRUE(response.request()->GetAddressResults()); - const auto& result_addresses = - response.request()->GetAddressResults()->endpoints(); - for (const IPEndPoint& address_with_esni_keys : esni_addresses) { - int index = std::find(result_addresses.begin(), result_addresses.end(), - address_with_esni_keys) - - result_addresses.begin(); - - // Since this address has associated ESNI keys, it should be in - // the first esni_addresses.size() many entries of the result's - // address list. - ASSERT_TRUE(base::IsValueInRangeForNumericType<size_t>(index)); - EXPECT_LT(static_cast<size_t>(index), esni_addresses.size()); - } -} - -TEST_F(HostResolverManagerEsniTest, OnlyMakesRequestOverSecureDns) { - // Add some insecurely-accessible ESNI results alongside - // the default (insecurely-accessible) IPv4 and IPv6 results - // for the "ok" hostname. - MockDnsClientRuleList rules = CreateDefaultDnsRules(); - AddEsniRecordsRuleOptions options; - options.secure = false; - AddEsniRecordsRule("ok", options, &rules); - - CreateResolver(); - UseMockDnsClient(CreateValidDnsConfig(), std::move(rules)); - - ResolveHostResponseHelper response(resolver_->CreateRequest( - HostPortPair("ok", 80), NetworkIsolationKey(), NetLogWithSource(), - HostResolver::ResolveHostParameters(), resolve_context_.get(), - resolve_context_->host_cache())); - - ASSERT_THAT(response.result_error(), IsOk()); - - // Since the request wasn't secure, we shouldn't have - // queried for any ESNI results. - ASSERT_FALSE(response.request()->GetEsniResults()); -} - -// Make sure that ESNI queries don't get cancelled *before* the -// configured timeout, but do get cancelled after it, -// in the case where the absolute timeout dominates. -TEST_F(HostResolverManagerEsniTest, RespectsAbsoluteTimeout) { - // Add some delayed ESNI, IPv4, and IPv6 results - MockDnsClientRuleList rules = CreateDefaultDnsRules(); - AddEsniRecordsRuleOptions options; - options.delay = true; - AddEsniRecordsRule("host", options, &rules); - rules.emplace_back("host", dns_protocol::kTypeA, true /* secure */, - MockDnsClientRule::Result(MockDnsClientRule::OK), - true /* delay */); - rules.emplace_back("host", dns_protocol::kTypeAAAA, true /* secure */, - MockDnsClientRule::Result(MockDnsClientRule::OK), - true /* delay */); - - CreateResolver(); - UseMockDnsClient(CreateValidDnsConfig(), std::move(rules)); - DnsConfigOverrides overrides; - overrides.secure_dns_mode = DnsConfig::SecureDnsMode::AUTOMATIC; - resolver_->SetDnsConfigOverrides(overrides); - - ResolveHostResponseHelper response(resolver_->CreateRequest( - HostPortPair("host", 80), NetworkIsolationKey(), NetLogWithSource(), - HostResolver::ResolveHostParameters(), resolve_context_.get(), - resolve_context_->host_cache())); - - base::TimeDelta absolute_timeout = - features::EsniDnsMaxAbsoluteAdditionalWait(); - - // Let enough time pass during the A and AAAA transactions that the - // absolute timeout will be less than the relative timeout. - base::TimeDelta a_aaaa_elapsed = - 50 * (100.0 / features::kEsniDnsMaxRelativeAdditionalWaitPercent.Get()) * - absolute_timeout; - - FastForwardBy(a_aaaa_elapsed); - ASSERT_TRUE( - dns_client_->CompleteOneDelayedTransactionOfType(DnsQueryType::A)); - ASSERT_TRUE( - dns_client_->CompleteOneDelayedTransactionOfType(DnsQueryType::AAAA)); - - // Since the A and AAAA queries have only just completed, we shouldn't - // have timed out the ESNI query. - EXPECT_FALSE(response.complete()); - - // After half of the absolute timeout, the query should still be alive. - FastForwardBy(0.5 * absolute_timeout); - - // Since the absolute timeout has not yet elapsed, and it is shorter by - // design than the relative timeout, we shouldn't - // have timed out the ESNI transaction. - EXPECT_FALSE(response.complete()); - - // After (more than) the timeout has passed, we should have cancelled - // the ESNI transaction. - FastForwardBy(absolute_timeout); - ASSERT_THAT(response.result_error(), IsOk()); - - // Since we cancelled the transaction, we shouldn't have any ESNI results. - EXPECT_FALSE(response.request()->GetEsniResults()); -} - -// Make sure that ESNI queries don't get cancelled *before* the -// configured timeout, but do get cancelled after it, -// in the case where the relative timeout dominates. -TEST_F(HostResolverManagerEsniTest, RespectsRelativeTimeout) { - // Add some delayed ESNI, IPv4, and IPv6 results - MockDnsClientRuleList rules = CreateDefaultDnsRules(); - AddEsniRecordsRuleOptions options; - options.delay = true; - AddEsniRecordsRule("host", options, &rules); - rules.emplace_back("host", dns_protocol::kTypeA, true /* secure */, - MockDnsClientRule::Result(MockDnsClientRule::OK), - false /* delay */); - rules.emplace_back("host", dns_protocol::kTypeAAAA, true /* secure */, - MockDnsClientRule::Result(MockDnsClientRule::OK), - true /* delay */); - - CreateResolver(); - UseMockDnsClient(CreateValidDnsConfig(), std::move(rules)); - DnsConfigOverrides overrides; - overrides.secure_dns_mode = DnsConfig::SecureDnsMode::AUTOMATIC; - resolver_->SetDnsConfigOverrides(overrides); - - ResolveHostResponseHelper response(resolver_->CreateRequest( - HostPortPair("host", 80), NetworkIsolationKey(), NetLogWithSource(), - HostResolver::ResolveHostParameters(), resolve_context_.get(), - resolve_context_->host_cache())); - - // Let little enough time pass during the A and AAAA transactions that the - // relative timeout will be less than the absolute timeout. - base::TimeDelta a_aaaa_elapsed = - 0.05 * features::EsniDnsMaxAbsoluteAdditionalWait() * - (100 / features::kEsniDnsMaxRelativeAdditionalWaitPercent.Get()); - - // Since the A and AAAA queries haven't both completed yet, we shouldn't time - // out the ESNI query. - FastForwardBy(a_aaaa_elapsed); - - // Upon completing the AAAA transaction, the ESNI timer should start - ASSERT_TRUE( - dns_client_->CompleteOneDelayedTransactionOfType(DnsQueryType::AAAA)); - - base::TimeDelta relative_timeout = - 0.01 * features::kEsniDnsMaxRelativeAdditionalWaitPercent.Get() * - a_aaaa_elapsed; - - // After *less* than the relative timeout, the query shouldn't have concluded. - FastForwardBy(relative_timeout * 0.5); - - EXPECT_FALSE(response.complete()); - - // After more than the relative timeout, the query should conclude by aborting - // the ESNI query. - FastForwardBy(relative_timeout * 0.5); - - // The task should have completed with a cancelled ESNI query. - ASSERT_THAT(response.result_error(), IsOk()); - EXPECT_FALSE(response.request()->GetEsniResults()); - ASSERT_TRUE(response.request()->GetAddressResults()); - EXPECT_THAT(response.request()->GetAddressResults()->endpoints(), - testing::UnorderedElementsAre(CreateExpected("127.0.0.1", 80), - CreateExpected("::1", 80))); -} - -// Test that we still receive delayed A/AAAA records -// that arrive after a successful (non-delayed) ESNI transaction. -TEST_F(HostResolverManagerEsniTest, WaitsForSlowAccompanyingQueries) { - MockDnsClientRuleList rules; - - EsniContent esni_expectation; - std::vector<IPEndPoint> expected_addresses; - std::tie(esni_expectation, expected_addresses) = - AddEsniRecordsRule("host", AddEsniRecordsRuleOptions(), &rules); - - rules.emplace_back("host", dns_protocol::kTypeA, true /* secure */, - MockDnsClientRule::Result(MockDnsClientRule::OK), - true /* delay */); - expected_addresses.push_back(CreateExpected("127.0.0.1", 80)); - - rules.emplace_back("host", dns_protocol::kTypeAAAA, true /* secure */, - MockDnsClientRule::Result(MockDnsClientRule::OK), - true /* delay */); - expected_addresses.push_back(CreateExpected("::1", 80)); - - CreateResolver(); - UseMockDnsClient(CreateValidDnsConfig(), std::move(rules)); - DnsConfigOverrides overrides; - overrides.secure_dns_mode = DnsConfig::SecureDnsMode::AUTOMATIC; - resolver_->SetDnsConfigOverrides(overrides); - - ResolveHostResponseHelper response(resolver_->CreateRequest( - HostPortPair("host", 80), NetworkIsolationKey(), NetLogWithSource(), - HostResolver::ResolveHostParameters(), resolve_context_.get(), - resolve_context_->host_cache())); - - // Wait quite a long time. (If the timer were erroneously to have been - // started, it should expire by the end of this elapsed window.) - FastForwardBy(features::EsniDnsMaxAbsoluteAdditionalWait() * 10); - dns_client_->CompleteDelayedTransactions(); - - EXPECT_THAT(response.result_error(), IsOk()); - EXPECT_THAT(response.request()->GetEsniResults(), - testing::Optional(testing::Eq(esni_expectation))); - ASSERT_TRUE(response.request()->GetAddressResults()); - EXPECT_THAT(response.request()->GetAddressResults()->endpoints(), - testing::UnorderedElementsAreArray(expected_addresses)); -} - } // namespace net diff --git a/chromium/net/dns/host_resolver_mdns_listener_impl.cc b/chromium/net/dns/host_resolver_mdns_listener_impl.cc index 88102dff25e..066cc635774 100644 --- a/chromium/net/dns/host_resolver_mdns_listener_impl.cc +++ b/chromium/net/dns/host_resolver_mdns_listener_impl.cc @@ -73,7 +73,7 @@ void HostResolverMdnsListenerImpl::OnRecordUpdate( switch (query_type_) { case DnsQueryType::UNSPECIFIED: - case DnsQueryType::ESNI: + case DnsQueryType::INTEGRITY: NOTREACHED(); break; case DnsQueryType::A: diff --git a/chromium/net/dns/host_resolver_mdns_task.cc b/chromium/net/dns/host_resolver_mdns_task.cc index 551ab7ae25c..745b847eede 100644 --- a/chromium/net/dns/host_resolver_mdns_task.cc +++ b/chromium/net/dns/host_resolver_mdns_task.cc @@ -198,8 +198,8 @@ HostCache::Entry HostResolverMdnsTask::ParseResult( switch (query_type) { case DnsQueryType::UNSPECIFIED: // Should create two separate transactions with specified type. - case DnsQueryType::ESNI: - // ESNI queries are not expected to be useful in mDNS, so they're not + case DnsQueryType::INTEGRITY: + // INTEGRITY queries are not expected to be useful in mDNS, so they're not // supported. NOTREACHED(); return HostCache::Entry(ERR_FAILED, HostCache::Entry::SOURCE_UNKNOWN); diff --git a/chromium/net/dns/httpssvc_metrics.cc b/chromium/net/dns/httpssvc_metrics.cc new file mode 100644 index 00000000000..453e2a32ed2 --- /dev/null +++ b/chromium/net/dns/httpssvc_metrics.cc @@ -0,0 +1,254 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/dns/httpssvc_metrics.h" + +#include "base/feature_list.h" +#include "base/metrics/histogram.h" +#include "base/metrics/histogram_base.h" +#include "base/metrics/histogram_functions.h" +#include "base/notreached.h" +#include "base/strings/string_split.h" +#include "base/strings/string_util.h" +#include "net/base/features.h" +#include "net/dns/dns_util.h" +#include "net/dns/public/dns_protocol.h" + +namespace net { + +enum HttpssvcDnsRcode TranslateDnsRcodeForHttpssvcExperiment(uint8_t rcode) { + switch (rcode) { + case dns_protocol::kRcodeNOERROR: + return HttpssvcDnsRcode::kNoError; + case dns_protocol::kRcodeFORMERR: + return HttpssvcDnsRcode::kFormErr; + case dns_protocol::kRcodeSERVFAIL: + return HttpssvcDnsRcode::kServFail; + case dns_protocol::kRcodeNXDOMAIN: + return HttpssvcDnsRcode::kNxDomain; + case dns_protocol::kRcodeNOTIMP: + return HttpssvcDnsRcode::kNotImp; + case dns_protocol::kRcodeREFUSED: + return HttpssvcDnsRcode::kRefused; + default: + return HttpssvcDnsRcode::kUnrecognizedRcode; + } + NOTREACHED(); +} + +HttpssvcExperimentDomainCache::HttpssvcExperimentDomainCache() = default; +HttpssvcExperimentDomainCache::~HttpssvcExperimentDomainCache() = default; + +bool HttpssvcExperimentDomainCache::ListContainsDomain( + const std::string& domain_list, + base::StringPiece domain, + base::Optional<base::flat_set<std::string>>& in_out_cached_list) { + if (!in_out_cached_list) { + in_out_cached_list = base::SplitString( + domain_list, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); + } + return in_out_cached_list->find(domain) != in_out_cached_list->end(); +} + +bool HttpssvcExperimentDomainCache::IsExperimental(base::StringPiece domain) { + if (!base::FeatureList::IsEnabled(features::kDnsHttpssvc)) + return false; + return ListContainsDomain(features::kDnsHttpssvcExperimentDomains.Get(), + domain, experimental_list_); +} + +bool HttpssvcExperimentDomainCache::IsControl(base::StringPiece domain) { + std::vector<base::StringPiece> control_domains; + if (!base::FeatureList::IsEnabled(features::kDnsHttpssvc)) + return false; + if (features::kDnsHttpssvcControlDomainWildcard.Get()) + return !IsExperimental(domain); + return ListContainsDomain(features::kDnsHttpssvcControlDomains.Get(), domain, + control_list_); +} + +HttpssvcMetrics::HttpssvcMetrics(bool expect_intact) + : expect_intact_(expect_intact) {} + +HttpssvcMetrics::~HttpssvcMetrics() { + RecordIntegrityMetrics(); +} + +void HttpssvcMetrics::SaveForNonIntegrity( + base::Optional<std::string> new_doh_provider_id, + base::TimeDelta resolve_time, + enum HttpssvcDnsRcode rcode) { + set_doh_provider_id(new_doh_provider_id); + + non_integrity_resolve_times_.push_back(resolve_time); + + if (rcode != HttpssvcDnsRcode::kNoError) + disqualified_ = true; +} + +void HttpssvcMetrics::SaveNonIntegrityFailure() { + disqualified_ = true; +} + +void HttpssvcMetrics::SaveForIntegrity( + base::Optional<std::string> new_doh_provider_id, + enum HttpssvcDnsRcode rcode_integrity, + const std::vector<bool>& condensed_records, + base::TimeDelta integrity_resolve_time) { + DCHECK(!rcode_integrity_.has_value()); + set_doh_provider_id(new_doh_provider_id); + + rcode_integrity_ = rcode_integrity; + + num_integrity_records_ = condensed_records.size(); + + // We only record one "Integrity" sample per INTEGRITY query. In case + // multiple matching records are in present in the response, we + // combine their intactness values with logical AND. + const bool intact = + std::all_of(condensed_records.cbegin(), condensed_records.cend(), + [](bool b) { return b; }); + + DCHECK(!is_integrity_intact_.has_value()); + is_integrity_intact_ = intact; + + DCHECK(!integrity_resolve_time_.has_value()); + integrity_resolve_time_ = integrity_resolve_time; +} + +void HttpssvcMetrics::set_doh_provider_id( + base::Optional<std::string> new_doh_provider_id) { + // "Other" never gets updated. + if (doh_provider_id_.has_value() && *doh_provider_id_ == "Other") + return; + + // If provider IDs mismatch, downgrade the new provider ID to "Other". + if ((doh_provider_id_.has_value() && !new_doh_provider_id.has_value()) || + (doh_provider_id_.has_value() && new_doh_provider_id.has_value() && + *doh_provider_id_ != *new_doh_provider_id)) { + new_doh_provider_id = "Other"; + } + + doh_provider_id_ = new_doh_provider_id; +} + +std::string HttpssvcMetrics::BuildMetricName( + base::StringPiece leaf_name) const { + // Build shared pieces of the metric names. + const base::StringPiece expectation = + expect_intact_ ? "ExpectIntact" : "ExpectNoerror"; + const std::string provider_id = doh_provider_id_.value_or("Other"); + + // Example INTEGRITY metric name: + // Net.DNS.HTTPSSVC.RecordIntegrity.CleanBrowsingAdult.ExpectIntact.DnsRcode + return base::JoinString({"Net.DNS.HTTPSSVC.RecordIntegrity", + provider_id.c_str(), expectation, leaf_name}, + "."); +} + +void HttpssvcMetrics::RecordIntegrityMetrics() { + // The HTTPSSVC experiment and its feature param indicating INTEGRITY must + // both be enabled. + DCHECK(base::FeatureList::IsEnabled(features::kDnsHttpssvc)); + DCHECK(features::kDnsHttpssvcUseIntegrity.Get()); + + DCHECK(in_progress_); + in_progress_ = false; + + // We really have no metrics to record without |integrity_resolve_time_| and + // |non_integrity_resolve_times_|. If this HttpssvcMetrics is in an + // inconsistent state, disqualify any metrics from being recorded. + if (!integrity_resolve_time_.has_value() || + non_integrity_resolve_times_.empty()) { + disqualified_ = true; + } + if (disqualified_) + return; + + // Record the metrics that the "ExpectIntact" and "ExpectNoerror" branches + // have in common. + RecordIntegrityCommonMetrics(); + + if (expect_intact_) { + // Record metrics that are unique to the "ExpectIntact" branch. + RecordIntegrityExpectIntactMetrics(); + } else { + // Record metrics that are unique to the "ExpectNoerror" branch. + RecordIntegrityExpectNoerrorMetrics(); + } +} + +void HttpssvcMetrics::RecordIntegrityCommonMetrics() { + base::UmaHistogramMediumTimes(BuildMetricName("ResolveTimeIntegrityRecord"), + *integrity_resolve_time_); + + const std::string kMetricResolveTimeNonIntegrityRecord = + BuildMetricName("ResolveTimeNonIntegrityRecord"); + for (base::TimeDelta resolve_time_other : non_integrity_resolve_times_) { + base::UmaHistogramMediumTimes(kMetricResolveTimeNonIntegrityRecord, + resolve_time_other); + } + + // ResolveTimeRatio is the INTEGRITY resolve time divided by the slower of the + // A or AAAA resolve times. Arbitrarily choosing precision at two decimal + // places. + std::vector<base::TimeDelta>::iterator slowest_non_integrity_resolve = + std::max_element(non_integrity_resolve_times_.begin(), + non_integrity_resolve_times_.end()); + DCHECK(slowest_non_integrity_resolve != non_integrity_resolve_times_.end()); + + // Compute a percentage showing how much larger the INTEGRITY resolve time was + // compared to the slowest A or AAAA query. + // + // Computation happens on TimeDelta objects, which use CheckedNumeric. This + // will crash if the system clock leaps forward several hundred millennia + // (numeric_limits<int64_t>::max() microseconds ~= 292,000 years). + const int64_t resolve_time_percent = + (100 * *integrity_resolve_time_) / *slowest_non_integrity_resolve; + + // Scale the value of |resolve_time_percent| by dividing by |kPercentScale|. + // Sample values are bounded between 1 and 20. A recorded sample of 10 means + // that the INTEGRITY resolve time took 100% of the slower A/AAAA resolve + // time. A sample of 20 means that the INTEGRITY resolve time was 200% + // relative to the A/AAAA resolve time, twice as long. + constexpr int64_t kMaxRatio = 20; + constexpr int64_t kPercentScale = 10; + base::UmaHistogramExactLinear(BuildMetricName("ResolveTimeRatio"), + resolve_time_percent / kPercentScale, + kMaxRatio); +} + +void HttpssvcMetrics::RecordIntegrityExpectIntactMetrics() { + // Without |rocde_integrity_|, we can't make progress on any of these metrics. + DCHECK(rcode_integrity_.has_value()); + + // The ExpectIntact variant of the "DnsRcode" metric is only recorded when no + // records are received. + if (num_integrity_records_ == 0) { + base::UmaHistogramEnumeration(BuildMetricName("DnsRcode"), + *rcode_integrity_); + } + if (num_integrity_records_ > 0) { + if (*rcode_integrity_ == HttpssvcDnsRcode::kNoError) { + base::UmaHistogramBoolean(BuildMetricName("Integrity"), + is_integrity_intact_.value_or(false)); + } else if (*rcode_integrity_ != HttpssvcDnsRcode::kNoError) { + // Record boolean indicating whether we received an INTEGRITY record and + // an error simultaneously. + base::UmaHistogramBoolean(BuildMetricName("RecordWithError"), true); + } + } +} + +void HttpssvcMetrics::RecordIntegrityExpectNoerrorMetrics() { + if (rcode_integrity_.has_value()) { + base::UmaHistogramEnumeration(BuildMetricName("DnsRcode"), + *rcode_integrity_); + } + if (num_integrity_records_ > 0) { + base::UmaHistogramBoolean(BuildMetricName("RecordReceived"), true); + } +} + +} // namespace net diff --git a/chromium/net/dns/httpssvc_metrics.h b/chromium/net/dns/httpssvc_metrics.h new file mode 100644 index 00000000000..76e4795cafc --- /dev/null +++ b/chromium/net/dns/httpssvc_metrics.h @@ -0,0 +1,112 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NET_DNS_HTTPSSVC_METRICS_H_ +#define NET_DNS_HTTPSSVC_METRICS_H_ + +#include <string> +#include <vector> + +#include "base/containers/flat_set.h" +#include "base/optional.h" +#include "base/strings/string_piece_forward.h" +#include "base/time/time.h" +#include "net/base/net_export.h" + +namespace net { + +// These values are persisted to logs. Entries should not be renumbered and +// numeric values should never be reused. (See HttpssvcDnsRcode in +// tools/metrics/histograms/enums.xml.) +enum HttpssvcDnsRcode { + kTimedOut = 0, + kUnrecognizedRcode, + kMissingDnsResponse, + kNoError, + kFormErr, + kServFail, + kNxDomain, + kNotImp, + kRefused, + kMaxValue = kRefused, +}; + +// Helper that classifies domains as experimental, control, or other. Queries +// feature params and caches result to avoid repeated parsing. +class NET_EXPORT_PRIVATE HttpssvcExperimentDomainCache { + public: + HttpssvcExperimentDomainCache(); + ~HttpssvcExperimentDomainCache(); + bool IsExperimental(base::StringPiece domain); + bool IsControl(base::StringPiece domain); + + private: + bool ListContainsDomain( + const std::string& domain_list, + base::StringPiece domain, + base::Optional<base::flat_set<std::string>>& in_out_cached_list); + + base::Optional<base::flat_set<std::string>> experimental_list_; + base::Optional<base::flat_set<std::string>> control_list_; +}; + +// Translate an RCODE value to the |HttpssvcDnsRcode| enum, which is used for +// HTTPSSVC experimentation. The goal is to keep these values in a small, +// contiguous range in order to satisfy the UMA enumeration function's +// requirements. This function never returns |kTimedOut| |kUnrecognizedRcode|, +// or |kMissingDnsResponse|. +enum HttpssvcDnsRcode TranslateDnsRcodeForHttpssvcExperiment(uint8_t rcode); + +// Tool for aggregating HTTPSSVC and INTEGRITY metrics. Accumulates metrics via +// the Save* methods. Records metrics to UMA on destruction. +class NET_EXPORT_PRIVATE HttpssvcMetrics { + public: + explicit HttpssvcMetrics(bool expect_intact); + ~HttpssvcMetrics(); + HttpssvcMetrics(HttpssvcMetrics&) = delete; + HttpssvcMetrics(HttpssvcMetrics&&) = delete; + + // May be called many times. + void SaveForNonIntegrity(base::Optional<std::string> doh_provider_id, + base::TimeDelta resolve_time, + enum HttpssvcDnsRcode rcode); + + // Save the fact that the non-integrity queries failed. Prevents metrics from + // being recorded. + void SaveNonIntegrityFailure(); + + // Must only be called once. + void SaveForIntegrity(base::Optional<std::string> doh_provider_id, + enum HttpssvcDnsRcode rcode, + const std::vector<bool>& condensed_records, + base::TimeDelta integrity_resolve_time); + + private: + std::string BuildMetricName(base::StringPiece leaf_name) const; + + // Records all the aggregated metrics to UMA. + void RecordIntegrityMetrics(); + void RecordIntegrityCommonMetrics(); + void RecordIntegrityExpectIntactMetrics(); + void RecordIntegrityExpectNoerrorMetrics(); + + void set_doh_provider_id(base::Optional<std::string> doh_provider_id); + + // RecordIntegrityMetrics() will do nothing when |disqualified_| is true. + bool disqualified_ = false; + const bool expect_intact_; + bool in_progress_ = true; + base::Optional<std::string> doh_provider_id_; + base::Optional<enum HttpssvcDnsRcode> rcode_integrity_; + size_t num_integrity_records_ = 0; + base::Optional<bool> is_integrity_intact_; + // We never make multiple INTEGRITY queries per DnsTask, so we only need + // one TimeDelta for the INTEGRITY query. + base::Optional<base::TimeDelta> integrity_resolve_time_; + std::vector<base::TimeDelta> non_integrity_resolve_times_; +}; + +} // namespace net + +#endif // NET_DNS_HTTPSSVC_METRICS_H_ diff --git a/chromium/net/dns/httpssvc_metrics_unittest.cc b/chromium/net/dns/httpssvc_metrics_unittest.cc new file mode 100644 index 00000000000..1ce51cf7608 --- /dev/null +++ b/chromium/net/dns/httpssvc_metrics_unittest.cc @@ -0,0 +1,554 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/dns/httpssvc_metrics.h" + +#include <string> +#include <tuple> + +#include "base/feature_list.h" +#include "base/strings/strcat.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_util.h" +#include "base/test/metrics/histogram_tester.h" +#include "base/test/scoped_feature_list.h" +#include "net/base/features.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace net { + +// int: number of domains +// bool: extra leading comma +// bool: extra trailing comma +using DomainListQuirksTuple = std::tuple<int, bool, bool>; + +// bool: DnsHttpssvc feature is enabled +// bool: DnsHttpssvcUseIntegrity feature param +// bool: DnsHttpssvcUseHttpssvc feature param +// bool: DnsHttpssvcControlDomainWildcard feature param +using HttpssvcFeatureTuple = std::tuple<bool, bool, bool, bool>; + +// DomainListQuirksTuple: quirks for the experimental domain list. +// DomainListQuirksTuple: quirks for the control domain list. +// HttpssvcFeatureTuple: config for the whole DnsHttpssvc feature. +using ParsingTestParamTuple = std:: + tuple<DomainListQuirksTuple, DomainListQuirksTuple, HttpssvcFeatureTuple>; + +// bool: whether we are querying for an experimental domain or a control domain +// HttpssvcFeatureTuple: config for the whole DnsHttpssvc feature. +using MetricsTestParamTuple = std::tuple<bool, HttpssvcFeatureTuple>; + +// Create a comma-separated list of |domains| with the given |quirks|. +std::string FlattenDomainList(const std::vector<std::string>& domains, + DomainListQuirksTuple quirks) { + int num_domains; + bool leading_comma, trailing_comma; + std::tie(num_domains, leading_comma, trailing_comma) = quirks; + + CHECK_EQ(static_cast<size_t>(num_domains), domains.size()); + std::string flattened = base::JoinString(domains, ","); + if (leading_comma) + flattened.insert(flattened.begin(), ','); + if (trailing_comma) + flattened.push_back(','); + return flattened; +} + +// Intermediate representation constructed from test parameters. +struct HttpssvcFeatureConfig { + HttpssvcFeatureConfig() = default; + + explicit HttpssvcFeatureConfig(const HttpssvcFeatureTuple& feature_tuple, + base::StringPiece experiment_domains, + base::StringPiece control_domains) + : experiment_domains(experiment_domains.as_string()), + control_domains(control_domains.as_string()) { + std::tie(enabled, use_integrity, use_httpssvc, control_domain_wildcard) = + feature_tuple; + } + + void Apply(base::test::ScopedFeatureList* scoped_feature_list) const { + if (!enabled) { + scoped_feature_list->InitAndDisableFeature(features::kDnsHttpssvc); + return; + } + auto stringify = [](bool b) -> std::string { return b ? "true" : "false"; }; + scoped_feature_list->InitAndEnableFeatureWithParameters( + features::kDnsHttpssvc, + { + {"DnsHttpssvcUseHttpssvc", stringify(use_httpssvc)}, + {"DnsHttpssvcUseIntegrity", stringify(use_integrity)}, + {"DnsHttpssvcEnableQueryOverInsecure", "false"}, + {"DnsHttpssvcExperimentDomains", experiment_domains}, + {"DnsHttpssvcControlDomains", control_domains}, + {"DnsHttpssvcControlDomainWildcard", + stringify(control_domain_wildcard)}, + }); + } + + bool enabled = false; + bool use_integrity = false; + bool use_httpssvc = false; + bool control_domain_wildcard = false; + std::string experiment_domains; + std::string control_domains; +}; + +std::vector<std::string> GenerateDomainList(base::StringPiece label, int n) { + std::vector<std::string> domains; + for (int i = 0; i < n; i++) { + domains.push_back(base::StrCat( + {"domain", base::NumberToString(i), ".", label, ".example"})); + } + return domains; +} + +// Base for testing domain list parsing functions in +// net::features::dns_httpssvc_experiment. +class HttpssvcDomainParsingTest + : public ::testing::TestWithParam<ParsingTestParamTuple> { + public: + void SetUp() override { + DomainListQuirksTuple domain_quirks_experimental; + DomainListQuirksTuple domain_quirks_control; + HttpssvcFeatureTuple httpssvc_feature; + std::tie(domain_quirks_experimental, domain_quirks_control, + httpssvc_feature) = GetParam(); + + expected_experiment_domains_ = GenerateDomainList( + "experiment", std::get<0>(domain_quirks_experimental)); + expected_control_domains_ = + GenerateDomainList("control", std::get<0>(domain_quirks_control)); + + config_ = HttpssvcFeatureConfig( + httpssvc_feature, + FlattenDomainList(expected_experiment_domains_, + domain_quirks_experimental), + FlattenDomainList(expected_control_domains_, domain_quirks_control)); + config_.Apply(&scoped_feature_list_); + } + + const HttpssvcFeatureConfig& config() { return config_; } + + protected: + // The expected results of parsing the comma-separated domain lists in + // |experiment_domains| and |control_domains|, respectively. + std::vector<std::string> expected_experiment_domains_; + std::vector<std::string> expected_control_domains_; + + private: + HttpssvcFeatureConfig config_; + base::test::ScopedFeatureList scoped_feature_list_; +}; + +// This instantiation tests the domain list parser against various quirks, +// e.g. leading comma. +INSTANTIATE_TEST_SUITE_P( + HttpssvcMetricsTestDomainParsing, + HttpssvcDomainParsingTest, + testing::Combine( + // DomainListQuirksTuple for experimental domains. To fight back + // combinatorial explosion of tests, this tuple is pared down more than + // the one for control domains. This should not significantly hurt test + // coverage because |IsExperimentDomain| and |IsControlDomain| rely on a + // shared helper function. + testing::Combine(testing::Values(0, 1), + testing::Values(false), + testing::Values(false)), + // DomainListQuirksTuple for control domains. + testing::Combine(testing::Range(0, 3), + testing::Bool(), + testing::Bool()), + // HttpssvcFeatureTuple + testing::Combine( + testing::Bool() /* DnsHttpssvc feature enabled? */, + testing::Bool() /* DnsHttpssvcUseIntegrity */, + testing::Values(false) /* DnsHttpssvcUseHttpssvc */, + testing::Values(false) /* DnsHttpssvcControlDomainWildcard */))); + +// Base for testing the metrics collection code in |HttpssvcMetrics|. +class HttpssvcMetricsTest + : public ::testing::TestWithParam<MetricsTestParamTuple> { + public: + void SetUp() override { + HttpssvcFeatureTuple httpssvc_feature; + std::tie(querying_experimental_, httpssvc_feature) = GetParam(); + config_ = HttpssvcFeatureConfig(httpssvc_feature, "", ""); + config_.Apply(&scoped_feature_list_); + } + + std::string BuildMetricNamePrefix() const { + return base::StrCat( + {"Net.DNS.HTTPSSVC.RecordIntegrity.", doh_provider_, "."}); + } + + template <typename T> + void ExpectSample(base::StringPiece name, base::Optional<T> sample) const { + if (sample) + histo().ExpectUniqueSample(name, *sample, 1); + else + histo().ExpectTotalCount(name, 0); + } + + void ExpectSample(base::StringPiece name, + base::Optional<base::TimeDelta> sample) const { + base::Optional<int64_t> sample_ms; + if (sample) + sample_ms = {sample->InMilliseconds()}; + ExpectSample<int64_t>(name, sample_ms); + } + + void VerifyMetricsForExpectIntact( + base::Optional<HttpssvcDnsRcode> rcode, + base::Optional<bool> integrity, + base::Optional<bool> record_with_error, + base::Optional<base::TimeDelta> resolve_time_integrity, + base::Optional<base::TimeDelta> resolve_time_non_integrity, + base::Optional<int> resolve_time_ratio) const { + const std::string kPrefix = + base::StrCat({BuildMetricNamePrefix(), "ExpectIntact."}); + const std::string kMetricDnsRcode = base::StrCat({kPrefix, "DnsRcode"}); + const std::string kMetricIntegrity = base::StrCat({kPrefix, "Integrity"}); + const std::string kMetricRecordWithError = + base::StrCat({kPrefix, "RecordWithError"}); + const std::string kMetricResolveTimeIntegrity = + base::StrCat({kPrefix, "ResolveTimeIntegrityRecord"}); + const std::string kMetricResolveTimeNonIntegrity = + base::StrCat({kPrefix, "ResolveTimeNonIntegrityRecord"}); + const std::string kMetricResolveTimeRatio = + base::StrCat({kPrefix, "ResolveTimeRatio"}); + + ExpectSample(kMetricDnsRcode, rcode); + ExpectSample(kMetricIntegrity, integrity); + ExpectSample(kMetricRecordWithError, record_with_error); + ExpectSample(kMetricResolveTimeIntegrity, resolve_time_integrity); + ExpectSample(kMetricResolveTimeNonIntegrity, resolve_time_non_integrity); + ExpectSample(kMetricResolveTimeRatio, resolve_time_ratio); + } + + void VerifyMetricsForExpectNoerror( + base::Optional<HttpssvcDnsRcode> rcode, + base::Optional<int> record_received, + base::Optional<base::TimeDelta> resolve_time_integrity, + base::Optional<base::TimeDelta> resolve_time_non_integrity, + base::Optional<int> resolve_time_ratio) const { + const std::string kPrefix = + base::StrCat({BuildMetricNamePrefix(), "ExpectNoerror."}); + const std::string kMetricDnsRcode = base::StrCat({kPrefix, "DnsRcode"}); + const std::string kMetricRecordReceived = + base::StrCat({kPrefix, "RecordReceived"}); + const std::string kMetricResolveTimeIntegrity = + base::StrCat({kPrefix, "ResolveTimeIntegrityRecord"}); + const std::string kMetricResolveTimeNonIntegrity = + base::StrCat({kPrefix, "ResolveTimeNonIntegrityRecord"}); + const std::string kMetricResolveTimeRatio = + base::StrCat({kPrefix, "ResolveTimeRatio"}); + + ExpectSample(kMetricDnsRcode, rcode); + ExpectSample(kMetricRecordReceived, record_received); + ExpectSample(kMetricResolveTimeIntegrity, resolve_time_integrity); + ExpectSample(kMetricResolveTimeNonIntegrity, resolve_time_non_integrity); + ExpectSample(kMetricResolveTimeRatio, resolve_time_ratio); + } + + void VerifyMetricsForExpectIntact() { + VerifyMetricsForExpectIntact(base::nullopt, base::nullopt, base::nullopt, + base::nullopt, base::nullopt, base::nullopt); + } + + void VerifyMetricsForExpectNoerror() { + VerifyMetricsForExpectNoerror(base::nullopt, base::nullopt, base::nullopt, + base::nullopt, base::nullopt); + } + + const base::HistogramTester& histo() const { return histogram_; } + const HttpssvcFeatureConfig& config() const { return config_; } + + protected: + bool querying_experimental_; + + private: + HttpssvcFeatureConfig config_; + base::test::ScopedFeatureList scoped_feature_list_; + base::HistogramTester histogram_; + std::string doh_provider_ = "Other"; +}; + +// This instantiation focuses on whether the correct metrics are recorded. The +// domain list parser is already tested against encoding quirks in +// |HttpssvcMetricsTestDomainParsing|, so we fix the quirks at false. +INSTANTIATE_TEST_SUITE_P( + HttpssvcMetricsTestSimple, + HttpssvcMetricsTest, + testing::Combine( + // Whether we are querying an experimental domain. + testing::Bool(), + // HttpssvcFeatureTuple + testing::Combine( + testing::Values(true) /* DnsHttpssvc feature enabled? */, + testing::Values(true) /* DnsHttpssvcUseIntegrity */, + testing::Values(false) /* DnsHttpssvcUseHttpssvc */, + testing::Values(false) /* DnsHttpssvcControlDomainWildcard */))); + +TEST_P(HttpssvcDomainParsingTest, ParseFeatureParamIntegrityDomains) { + HttpssvcExperimentDomainCache domain_cache; + + // We are not testing this feature param yet. + CHECK(!config().use_httpssvc); + + const std::string kReservedDomain = "neither.example"; + EXPECT_FALSE(domain_cache.IsExperimental(kReservedDomain)); + EXPECT_EQ(domain_cache.IsControl(kReservedDomain), + config().enabled && config().control_domain_wildcard); + + // If |config().use_integrity| is true, then we expect all domains in + // |expected_experiment_domains_| to be experimental (same goes for + // control domains). Otherwise, no domain should be considered experimental or + // control. + + if (!config().enabled) { + // When the HTTPSSVC feature is disabled, no domain should be considered + // experimental or control. + for (const std::string& experiment_domain : expected_experiment_domains_) { + EXPECT_FALSE(domain_cache.IsExperimental(experiment_domain)); + EXPECT_FALSE(domain_cache.IsControl(experiment_domain)); + } + for (const std::string& control_domain : expected_control_domains_) { + EXPECT_FALSE(domain_cache.IsExperimental(control_domain)); + EXPECT_FALSE(domain_cache.IsControl(control_domain)); + } + } else if (config().use_integrity) { + for (const std::string& experiment_domain : expected_experiment_domains_) { + EXPECT_TRUE(domain_cache.IsExperimental(experiment_domain)); + EXPECT_FALSE(domain_cache.IsControl(experiment_domain)); + } + for (const std::string& control_domain : expected_control_domains_) { + EXPECT_FALSE(domain_cache.IsExperimental(control_domain)); + EXPECT_TRUE(domain_cache.IsControl(control_domain)); + } + return; + } +} + +// Only record metrics for a non-integrity query. +TEST_P(HttpssvcMetricsTest, AddressAndIntegrityMissing) { + if (!config().enabled || !config().use_integrity) { + VerifyMetricsForExpectIntact(); + VerifyMetricsForExpectNoerror(); + return; + } + const base::TimeDelta kResolveTime = base::TimeDelta::FromMilliseconds(10); + base::Optional<HttpssvcMetrics> metrics(querying_experimental_); + metrics->SaveForNonIntegrity(base::nullopt, kResolveTime, + HttpssvcDnsRcode::kNoError); + metrics.reset(); // Record the metrics to UMA. + + VerifyMetricsForExpectIntact(); + VerifyMetricsForExpectNoerror(); +} + +TEST_P(HttpssvcMetricsTest, AddressAndIntegrityIntact) { + if (!config().enabled || !config().use_integrity) { + VerifyMetricsForExpectIntact(); + VerifyMetricsForExpectNoerror(); + return; + } + const base::TimeDelta kResolveTime = base::TimeDelta::FromMilliseconds(10); + const base::TimeDelta kResolveTimeIntegrity = + base::TimeDelta::FromMilliseconds(15); + base::Optional<HttpssvcMetrics> metrics(querying_experimental_); + metrics->SaveForIntegrity(base::nullopt, HttpssvcDnsRcode::kNoError, {true}, + kResolveTimeIntegrity); + metrics->SaveForNonIntegrity(base::nullopt, kResolveTime, + HttpssvcDnsRcode::kNoError); + metrics.reset(); // Record the metrics to UMA. + + if (querying_experimental_) { + VerifyMetricsForExpectIntact( + base::nullopt /* rcode */, {true} /* integrity */, + base::nullopt /* record_with_error */, + {kResolveTimeIntegrity} /* resolve_time_integrity */, + {kResolveTime} /* resolve_time_non_integrity */, + {15} /* resolve_time_ratio */); + + VerifyMetricsForExpectNoerror(); + return; + } + + VerifyMetricsForExpectIntact(); + + VerifyMetricsForExpectNoerror( + {HttpssvcDnsRcode::kNoError} /* rcode */, {1} /* record_received */, + {kResolveTimeIntegrity} /* resolve_time_integrity */, + {kResolveTime} /* resolve_time_non_integrity */, + {15} /* resolve_time_ratio */); +} + +// This test simulates an INTEGRITY response that includes no INTEGRITY records, +// but does have an error value for the RCODE. +TEST_P(HttpssvcMetricsTest, AddressAndIntegrityMissingWithRcode) { + if (!config().enabled || !config().use_integrity) { + VerifyMetricsForExpectIntact(); + VerifyMetricsForExpectNoerror(); + return; + } + const base::TimeDelta kResolveTime = base::TimeDelta::FromMilliseconds(10); + const base::TimeDelta kResolveTimeIntegrity = + base::TimeDelta::FromMilliseconds(15); + + base::Optional<HttpssvcMetrics> metrics(querying_experimental_); + metrics->SaveForIntegrity(base::nullopt, HttpssvcDnsRcode::kNxDomain, {}, + kResolveTimeIntegrity); + metrics->SaveForNonIntegrity(base::nullopt, kResolveTime, + HttpssvcDnsRcode::kNoError); + metrics.reset(); // Record the metrics to UMA. + + if (querying_experimental_) { + VerifyMetricsForExpectIntact( + {HttpssvcDnsRcode::kNxDomain} /* rcode */, + base::nullopt /* integrity */, base::nullopt /* record_with_error */, + {kResolveTimeIntegrity} /* resolve_time_integrity */, + {kResolveTime} /* resolve_time_non_integrity */, + {15} /* resolve_time_ratio */); + + VerifyMetricsForExpectNoerror(); + return; + } + + VerifyMetricsForExpectIntact(); + + VerifyMetricsForExpectNoerror( + {HttpssvcDnsRcode::kNxDomain} /* rcode */, + base::nullopt /* record_received */, + {kResolveTimeIntegrity} /* resolve_time_integrity */, + {kResolveTime} /* resolve_time_non_integrity */, + {15} /* resolve_time_ratio */); +} + +// This test simulates an INTEGRITY response that includes an intact INTEGRITY +// record, but also has an error RCODE. +TEST_P(HttpssvcMetricsTest, AddressAndIntegrityIntactWithRcode) { + if (!config().enabled || !config().use_integrity) { + VerifyMetricsForExpectIntact(); + VerifyMetricsForExpectNoerror(); + return; + } + + const base::TimeDelta kResolveTime = base::TimeDelta::FromMilliseconds(10); + const base::TimeDelta kResolveTimeIntegrity = + base::TimeDelta::FromMilliseconds(15); + + base::Optional<HttpssvcMetrics> metrics(querying_experimental_); + metrics->SaveForIntegrity(base::nullopt, HttpssvcDnsRcode::kNxDomain, {true}, + kResolveTimeIntegrity); + metrics->SaveForNonIntegrity(base::nullopt, kResolveTime, + HttpssvcDnsRcode::kNoError); + metrics.reset(); // Record the metrics to UMA. + + if (querying_experimental_) { + VerifyMetricsForExpectIntact( + // "DnsRcode" metric is omitted because we received an INTEGRITY record. + base::nullopt /* rcode */, + // "Integrity" metric is omitted because the RCODE is not NOERROR. + base::nullopt /* integrity */, {true} /* record_with_error */, + {kResolveTimeIntegrity} /* resolve_time_integrity */, + {kResolveTime} /* resolve_time_non_integrity */, + {15} /* resolve_time_ratio */); + + VerifyMetricsForExpectNoerror(); + return; + } + + VerifyMetricsForExpectIntact(); + + VerifyMetricsForExpectNoerror( + {HttpssvcDnsRcode::kNxDomain} /* rcode */, {true} /* record_received */, + {kResolveTimeIntegrity} /* resolve_time_integrity */, + {kResolveTime} /* resolve_time_non_integrity */, + {15} /* resolve_time_ratio */); +} + +// This test simulates an INTEGRITY response that includes a mangled INTEGRITY +// record *and* has an error RCODE. +TEST_P(HttpssvcMetricsTest, AddressAndIntegrityMangledWithRcode) { + if (!config().enabled || !config().use_integrity) { + VerifyMetricsForExpectIntact(); + VerifyMetricsForExpectNoerror(); + return; + } + const base::TimeDelta kResolveTime = base::TimeDelta::FromMilliseconds(10); + const base::TimeDelta kResolveTimeIntegrity = + base::TimeDelta::FromMilliseconds(15); + base::Optional<HttpssvcMetrics> metrics(querying_experimental_); + metrics->SaveForIntegrity(base::nullopt, HttpssvcDnsRcode::kNxDomain, {false}, + kResolveTimeIntegrity); + metrics->SaveForNonIntegrity(base::nullopt, kResolveTime, + HttpssvcDnsRcode::kNoError); + metrics.reset(); // Record the metrics to UMA. + + if (querying_experimental_) { + VerifyMetricsForExpectIntact( + // "DnsRcode" metric is omitted because we received an INTEGRITY record. + base::nullopt /* rcode */, + // "Integrity" metric is omitted because the RCODE is not NOERROR. + base::nullopt /* integrity */, {true} /* record_with_error */, + {kResolveTimeIntegrity} /* resolve_time_integrity */, + {kResolveTime} /* resolve_time_non_integrity */, + {15} /* resolve_time_ratio */); + + VerifyMetricsForExpectNoerror(); + return; + } + + VerifyMetricsForExpectIntact(); + + VerifyMetricsForExpectNoerror( + {HttpssvcDnsRcode::kNxDomain} /* rcode */, {true} /* record_received */, + {kResolveTimeIntegrity} /* resolve_time_integrity */, + {kResolveTime} /* resolve_time_non_integrity */, + {15} /* resolve_time_ratio */); +} + +// This test simulates successful address queries and an INTEGRITY query that +// timed out. +TEST_P(HttpssvcMetricsTest, AddressAndIntegrityTimedOut) { + if (!config().enabled || !config().use_integrity) { + VerifyMetricsForExpectIntact(); + VerifyMetricsForExpectNoerror(); + return; + } + const base::TimeDelta kResolveTime = base::TimeDelta::FromMilliseconds(10); + const base::TimeDelta kResolveTimeIntegrity = + base::TimeDelta::FromMilliseconds(15); + base::Optional<HttpssvcMetrics> metrics(querying_experimental_); + metrics->SaveForIntegrity(base::nullopt, HttpssvcDnsRcode::kTimedOut, {}, + kResolveTimeIntegrity); + metrics->SaveForNonIntegrity(base::nullopt, kResolveTime, + HttpssvcDnsRcode::kNoError); + metrics.reset(); // Record the metrics to UMA. + + if (querying_experimental_) { + VerifyMetricsForExpectIntact( + {HttpssvcDnsRcode::kTimedOut} /* rcode */, + // "Integrity" metric is omitted because the RCODE is not NOERROR. + base::nullopt /* integrity */, base::nullopt /* record_with_error */, + {kResolveTimeIntegrity} /* resolve_time_integrity */, + {kResolveTime} /* resolve_time_non_integrity */, + {15} /* resolve_time_ratio */); + + VerifyMetricsForExpectNoerror(); + return; + } + + VerifyMetricsForExpectIntact(); + + VerifyMetricsForExpectNoerror( + {HttpssvcDnsRcode::kTimedOut} /* rcode */, + base::nullopt /* record_received */, + {kResolveTimeIntegrity} /* resolve_time_integrity */, + {kResolveTime} /* resolve_time_non_integrity */, + {15} /* resolve_time_ratio */); +} + +} // namespace net diff --git a/chromium/net/dns/mock_host_resolver.cc b/chromium/net/dns/mock_host_resolver.cc index d66b8e4a1fb..e0a23ae727b 100644 --- a/chromium/net/dns/mock_host_resolver.cc +++ b/chromium/net/dns/mock_host_resolver.cc @@ -139,12 +139,6 @@ class MockHostResolverBase::RequestImpl return *nullopt_result; } - const base::Optional<EsniContent>& GetEsniResults() const override { - DCHECK(complete_); - static const base::NoDestructor<base::Optional<EsniContent>> nullopt_result; - return *nullopt_result; - } - net::ResolveErrorInfo GetResolveErrorInfo() const override { DCHECK(complete_); return resolve_error_info_; @@ -1028,10 +1022,6 @@ class HangingHostResolver::RequestImpl IMMEDIATE_CRASH(); } - const base::Optional<EsniContent>& GetEsniResults() const override { - IMMEDIATE_CRASH(); - } - net::ResolveErrorInfo GetResolveErrorInfo() const override { IMMEDIATE_CRASH(); } diff --git a/chromium/net/dns/public/BUILD.gn b/chromium/net/dns/public/BUILD.gn index 04f2a9b57b3..832312ddeee 100644 --- a/chromium/net/dns/public/BUILD.gn +++ b/chromium/net/dns/public/BUILD.gn @@ -19,8 +19,8 @@ source_set("public") { "dns_protocol.h", "dns_query_type.cc", "dns_query_type.h", - "doh_provider_list.cc", - "doh_provider_list.h", + "doh_provider_entry.cc", + "doh_provider_entry.h", "resolve_error_info.cc", "resolve_error_info.h", "util.cc", @@ -35,7 +35,7 @@ source_set("public") { source_set("tests") { testonly = true sources = [ - "doh_provider_list_unittest.cc", + "doh_provider_entry_unittest.cc", "util_unittest.cc", ] diff --git a/chromium/net/dns/public/dns_protocol.h b/chromium/net/dns/public/dns_protocol.h index ea9112feb00..c77dbaa7cd4 100644 --- a/chromium/net/dns/public/dns_protocol.h +++ b/chromium/net/dns/public/dns_protocol.h @@ -153,11 +153,6 @@ static const uint16_t kTypeANY = 255; // Experimental DNS record types pending IANA assignment. // -// Record type proposed for TLS Encrypted Server Name Indication -// (ESNI, draft 4) records: -// https://tools.ietf.org/html/draft-ietf-tls-esni-04#section-8.3 -static const uint16_t kExperimentalTypeEsniDraft4 = 65439; - // The INTEGRITY RR type exists purely for measuring how the DNS ecosystem // handles new RR types. // https://docs.google.com/document/d/14eCqVyT_3MSj7ydqNFl1Yl0yg1fs6g24qmYUUdi5V-k/edit?usp=sharing diff --git a/chromium/net/dns/public/dns_query_type.h b/chromium/net/dns/public/dns_query_type.h index 7d407a62d01..ecc61ea597d 100644 --- a/chromium/net/dns/public/dns_query_type.h +++ b/chromium/net/dns/public/dns_query_type.h @@ -20,14 +20,15 @@ enum class DnsQueryType { TXT, PTR, SRV, - ESNI, - MAX = ESNI + INTEGRITY, + MAX = INTEGRITY }; const DnsQueryType kDnsQueryTypes[] = { DnsQueryType::UNSPECIFIED, DnsQueryType::A, DnsQueryType::AAAA, DnsQueryType::TXT, DnsQueryType::PTR, DnsQueryType::SRV, - DnsQueryType::ESNI}; + DnsQueryType::INTEGRITY, +}; static_assert(base::size(kDnsQueryTypes) == static_cast<unsigned>(DnsQueryType::MAX) + 1, diff --git a/chromium/net/dns/public/doh_provider_list.cc b/chromium/net/dns/public/doh_provider_entry.cc index b5b2a50ef89..0422c8c6a7a 100644 --- a/chromium/net/dns/public/doh_provider_list.cc +++ b/chromium/net/dns/public/doh_provider_entry.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "net/dns/public/doh_provider_list.h" +#include "net/dns/public/doh_provider_entry.h" #include <utility> @@ -12,54 +12,28 @@ namespace net { -DohProviderEntry::DohProviderEntry( - std::string provider, - base::Optional<DohProviderIdForHistogram> provider_id_for_histogram, - std::set<std::string> ip_strs, - std::set<std::string> dns_over_tls_hostnames, - std::string dns_over_https_template, - std::string ui_name, - std::string privacy_policy, - bool display_globally, - std::set<std::string> display_countries) - : provider(std::move(provider)), - provider_id_for_histogram(std::move(provider_id_for_histogram)), - dns_over_tls_hostnames(std::move(dns_over_tls_hostnames)), - dns_over_https_template(std::move(dns_over_https_template)), - ui_name(std::move(ui_name)), - privacy_policy(std::move(privacy_policy)), - display_globally(display_globally), - display_countries(std::move(display_countries)) { - DCHECK(!this->dns_over_https_template.empty()); - DCHECK(dns_util::IsValidDohTemplate(this->dns_over_https_template, - nullptr /* server_method */)); +namespace { - DCHECK(!display_globally || this->display_countries.empty()); - if (display_globally || !this->display_countries.empty()) { - DCHECK(!this->ui_name.empty()); - DCHECK(!this->privacy_policy.empty()); - DCHECK(this->provider_id_for_histogram.has_value()); - } - for (const auto& display_country : this->display_countries) { - DCHECK_EQ(2u, display_country.size()); - } - for (const std::string& ip_str : ip_strs) { +std::set<IPAddress> ParseIPs(const std::set<base::StringPiece>& ip_strs) { + std::set<IPAddress> ip_addresses; + for (base::StringPiece ip_str : ip_strs) { IPAddress ip_address; bool success = ip_address.AssignFromIPLiteral(ip_str); DCHECK(success); - ip_addresses.insert(ip_address); + ip_addresses.insert(std::move(ip_address)); } + return ip_addresses; } -DohProviderEntry::DohProviderEntry(const DohProviderEntry& other) = default; -DohProviderEntry::~DohProviderEntry() = default; +} // namespace -const std::vector<DohProviderEntry>& GetDohProviderList() { +// static +const DohProviderEntry::List& DohProviderEntry::GetList() { // The provider names in these entries should be kept in sync with the // DohProviderId histogram suffix list in // tools/metrics/histograms/histograms.xml. - static const base::NoDestructor<std::vector<DohProviderEntry>> providers{{ - DohProviderEntry( + static const base::NoDestructor<DohProviderEntry::List> providers{{ + new DohProviderEntry( "CleanBrowsingAdult", base::nullopt /* provider_id_for_histogram */, {"185.228.168.10", "185.228.169.11", "2a0d:2a00:1::1", "2a0d:2a00:2::1"}, @@ -67,7 +41,7 @@ const std::vector<DohProviderEntry>& GetDohProviderList() { "https://doh.cleanbrowsing.org/doh/adult-filter{?dns}", "" /* ui_name */, "" /* privacy_policy */, false /* display_globally */, {} /* display_countries */), - DohProviderEntry( + new DohProviderEntry( "CleanBrowsingFamily", DohProviderIdForHistogram::kCleanBrowsingFamily, {"185.228.168.168", "185.228.169.168", @@ -77,7 +51,7 @@ const std::vector<DohProviderEntry>& GetDohProviderList() { "CleanBrowsing (Family Filter)" /* ui_name */, "https://cleanbrowsing.org/privacy" /* privacy_policy */, true /* display_globally */, {} /* display_countries */), - DohProviderEntry( + new DohProviderEntry( "CleanBrowsingSecure", base::nullopt /* provider_id_for_histogram */, {"185.228.168.9", "185.228.169.9", "2a0d:2a00:1::2", "2a0d:2a00:2::2"}, @@ -85,7 +59,7 @@ const std::vector<DohProviderEntry>& GetDohProviderList() { "https://doh.cleanbrowsing.org/doh/security-filter{?dns}", "" /* ui_name */, "" /* privacy_policy */, false /* display_globally */, {} /* display_countries */), - DohProviderEntry( + new DohProviderEntry( "Cloudflare", DohProviderIdForHistogram::kCloudflare, {"1.1.1.1", "1.0.0.1", "2606:4700:4700::1111", "2606:4700:4700::1001"}, @@ -96,63 +70,64 @@ const std::vector<DohProviderEntry>& GetDohProviderList() { "https://developers.cloudflare.com/1.1.1.1/privacy/" "public-dns-resolver/" /* privacy_policy */, true /* display_globally */, {} /* display_countries */), - DohProviderEntry("Comcast", base::nullopt /* provider_id_for_histogram */, - {"75.75.75.75", "75.75.76.76", "2001:558:feed::1", - "2001:558:feed::2"}, - {"dot.xfinity.com"} /* dns_over_tls_hostnames */, - "https://doh.xfinity.com/dns-query{?dns}", - "" /* ui_name */, "" /* privacy_policy */, - false /* display_globally */, - {} /* display_countries */), - DohProviderEntry("Cznic", base::nullopt /* provider_id_for_histogram */, - {"185.43.135.1", "2001:148f:fffe::1"}, - {"odvr.nic.cz"} /* dns_over_tls_hostnames */, - "https://odvr.nic.cz/doh", "" /* ui_name */, - "" /* privacy_policy */, false /* display_globally */, - {} /* display_countries */), + new DohProviderEntry( + "Comcast", base::nullopt /* provider_id_for_histogram */, + {"75.75.75.75", "75.75.76.76", "2001:558:feed::1", + "2001:558:feed::2"}, + {"dot.xfinity.com"} /* dns_over_tls_hostnames */, + "https://doh.xfinity.com/dns-query{?dns}", "" /* ui_name */, + "" /* privacy_policy */, false /* display_globally */, + {} /* display_countries */), + new DohProviderEntry( + "Cznic", base::nullopt /* provider_id_for_histogram */, + {"185.43.135.1", "2001:148f:fffe::1"}, + {"odvr.nic.cz"} /* dns_over_tls_hostnames */, + "https://odvr.nic.cz/doh", "" /* ui_name */, "" /* privacy_policy */, + false /* display_globally */, {} /* display_countries */), // Note: DNS.SB has separate entries for autoupgrade and settings UI to // allow the extra |no_ecs| parameter for autoupgrade. This parameter // disables EDNS Client Subnet (ECS) handling in order to match the // behavior of the upgraded-from classic DNS server. - DohProviderEntry( + new DohProviderEntry( "Dnssb", base::nullopt /* provider_id_for_histogram */, {"185.222.222.222", "185.184.222.222", "2a09::", "2a09::1"}, {"dns.sb"} /* dns_over_tls_hostnames */, "https://doh.dns.sb/dns-query?no_ecs=true{&dns}", "" /* ui_name */, "" /* privacy_policy */, false /* display_globally */, {} /* display_countries */), - DohProviderEntry( + new DohProviderEntry( "DnssbUserSelected", DohProviderIdForHistogram::kDnsSb, {} /* ip_strs */, {} /* dns_over_tls_hostnames */, "https://doh.dns.sb/dns-query{?dns}", "DNS.SB" /* ui_name */, "https://dns.sb/privacy/" /* privacy_policy */, false /* display_globally */, {"EE", "DE"} /* display_countries */), - DohProviderEntry("Google", DohProviderIdForHistogram::kGoogle, - {"8.8.8.8", "8.8.4.4", "2001:4860:4860::8888", - "2001:4860:4860::8844"}, - {"dns.google", "dns.google.com", - "8888.google"} /* dns_over_tls_hostnames */, - "https://dns.google/dns-query{?dns}", - "Google (Public DNS)" /* ui_name */, - "https://developers.google.com/speed/public-dns/" - "privacy" /* privacy_policy */, - true /* display_globally */, {} /* display_countries */), - DohProviderEntry("Iij", DohProviderIdForHistogram::kIij, {} /* ip_strs */, - {} /* dns_over_tls_hostnames */, - "https://public.dns.iij.jp/dns-query", - "IIJ (Public DNS)" /* ui_name */, - "https://public.dns.iij.jp/" /* privacy_policy */, - false /* display_globally */, - {"JP"} /* display_countries */), - DohProviderEntry("OpenDNS", base::nullopt /* provider_id_for_histogram */, - {"208.67.222.222", "208.67.220.220", "2620:119:35::35", - "2620:119:53::53"}, - {""} /* dns_over_tls_hostnames */, - "https://doh.opendns.com/dns-query{?dns}", - "" /* ui_name */, "" /* privacy_policy */, - false /* display_globally */, - {} /* display_countries */), - DohProviderEntry( + new DohProviderEntry("Google", DohProviderIdForHistogram::kGoogle, + {"8.8.8.8", "8.8.4.4", "2001:4860:4860::8888", + "2001:4860:4860::8844"}, + {"dns.google", "dns.google.com", + "8888.google"} /* dns_over_tls_hostnames */, + "https://dns.google/dns-query{?dns}", + "Google (Public DNS)" /* ui_name */, + "https://developers.google.com/speed/public-dns/" + "privacy" /* privacy_policy */, + true /* display_globally */, + {} /* display_countries */), + new DohProviderEntry("Iij", DohProviderIdForHistogram::kIij, + {} /* ip_strs */, {} /* dns_over_tls_hostnames */, + "https://public.dns.iij.jp/dns-query", + "IIJ (Public DNS)" /* ui_name */, + "https://public.dns.iij.jp/" /* privacy_policy */, + false /* display_globally */, + {"JP"} /* display_countries */), + new DohProviderEntry( + "OpenDNS", base::nullopt /* provider_id_for_histogram */, + {"208.67.222.222", "208.67.220.220", "2620:119:35::35", + "2620:119:53::53"}, + {""} /* dns_over_tls_hostnames */, + "https://doh.opendns.com/dns-query{?dns}", "" /* ui_name */, + "" /* privacy_policy */, false /* display_globally */, + {} /* display_countries */), + new DohProviderEntry( "OpenDNSFamily", base::nullopt /* provider_id_for_histogram */, {"208.67.222.123", "208.67.220.123", "2620:119:35::123", "2620:119:53::123"}, @@ -160,36 +135,94 @@ const std::vector<DohProviderEntry>& GetDohProviderList() { "https://doh.familyshield.opendns.com/dns-query{?dns}", "" /* ui_name */, "" /* privacy_policy */, false /* display_globally */, {} /* display_countries */), - DohProviderEntry( + new DohProviderEntry( "Quad9Cdn", base::nullopt /* provider_id_for_histogram */, {"9.9.9.11", "149.112.112.11", "2620:fe::11", "2620:fe::fe:11"}, {"dns11.quad9.net"} /* dns_over_tls_hostnames */, "https://dns11.quad9.net/dns-query", "" /* ui_name */, "" /* privacy_policy */, false /* display_globally */, {} /* display_countries */), - DohProviderEntry( + new DohProviderEntry( "Quad9Insecure", base::nullopt /* provider_id_for_histogram */, {"9.9.9.10", "149.112.112.10", "2620:fe::10", "2620:fe::fe:10"}, {"dns10.quad9.net"} /* dns_over_tls_hostnames */, "https://dns10.quad9.net/dns-query", "" /* ui_name */, "" /* privacy_policy */, false /* display_globally */, {} /* display_countries */), - DohProviderEntry( + new DohProviderEntry( "Quad9Secure", DohProviderIdForHistogram::kQuad9Secure, {"9.9.9.9", "149.112.112.112", "2620:fe::fe", "2620:fe::9"}, {"dns.quad9.net", "dns9.quad9.net"} /* dns_over_tls_hostnames */, "https://dns.quad9.net/dns-query", "Quad9 (9.9.9.9)" /* ui_name */, "https://www.quad9.net/home/privacy/" /* privacy_policy */, true /* display_globally */, {} /* display_countries */), - DohProviderEntry("Switch", base::nullopt /* provider_id_for_histogram */, - {"130.59.31.251", "130.59.31.248", "2001:620:0:ff::2", - "2001:620:0:ff::3"}, - {"dns.switch.ch"} /* dns_over_tls_hostnames */, - "https://dns.switch.ch/dns-query", "" /* ui_name */, - "" /* privacy_policy */, false /* display_globally */, - {} /* display_countries */), + new DohProviderEntry( + "Switch", base::nullopt /* provider_id_for_histogram */, + {"130.59.31.251", "130.59.31.248", "2001:620:0:ff::2", + "2001:620:0:ff::3"}, + {"dns.switch.ch"} /* dns_over_tls_hostnames */, + "https://dns.switch.ch/dns-query", "" /* ui_name */, + "" /* privacy_policy */, false /* display_globally */, + {} /* display_countries */), }}; return *providers; } +// static +DohProviderEntry DohProviderEntry::ConstructForTesting( + std::string provider, + base::Optional<DohProviderIdForHistogram> provider_id_for_histogram, + std::set<base::StringPiece> ip_strs, + std::set<std::string> dns_over_tls_hostnames, + std::string dns_over_https_template, + std::string ui_name, + std::string privacy_policy, + bool display_globally, + std::set<std::string> display_countries) { + return DohProviderEntry(provider, provider_id_for_histogram, ip_strs, + dns_over_tls_hostnames, dns_over_https_template, + ui_name, privacy_policy, display_globally, + display_countries); +} + +DohProviderEntry::DohProviderEntry(DohProviderEntry&& other) = default; +DohProviderEntry& DohProviderEntry::operator=(DohProviderEntry&& other) = + default; + +DohProviderEntry::~DohProviderEntry() = default; + +DohProviderEntry::DohProviderEntry( + std::string provider, + base::Optional<DohProviderIdForHistogram> provider_id_for_histogram, + std::set<base::StringPiece> ip_strs, + std::set<std::string> dns_over_tls_hostnames, + std::string dns_over_https_template, + std::string ui_name, + std::string privacy_policy, + bool display_globally, + std::set<std::string> display_countries) + : provider(std::move(provider)), + provider_id_for_histogram(std::move(provider_id_for_histogram)), + ip_addresses(ParseIPs(ip_strs)), + dns_over_tls_hostnames(std::move(dns_over_tls_hostnames)), + dns_over_https_template(std::move(dns_over_https_template)), + ui_name(std::move(ui_name)), + privacy_policy(std::move(privacy_policy)), + display_globally(display_globally), + display_countries(std::move(display_countries)) { + DCHECK(!this->dns_over_https_template.empty()); + DCHECK(dns_util::IsValidDohTemplate(this->dns_over_https_template, + nullptr /* server_method */)); + + DCHECK(!display_globally || this->display_countries.empty()); + if (display_globally || !this->display_countries.empty()) { + DCHECK(!this->ui_name.empty()); + DCHECK(!this->privacy_policy.empty()); + DCHECK(this->provider_id_for_histogram.has_value()); + } + for (const auto& display_country : this->display_countries) { + DCHECK_EQ(2u, display_country.size()); + } +} + } // namespace net diff --git a/chromium/net/dns/public/doh_provider_list.h b/chromium/net/dns/public/doh_provider_entry.h index 5b3050874a3..150ea48bef5 100644 --- a/chromium/net/dns/public/doh_provider_list.h +++ b/chromium/net/dns/public/doh_provider_entry.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef NET_DNS_PUBLIC_DOH_PROVIDER_LIST_H_ -#define NET_DNS_PUBLIC_DOH_PROVIDER_LIST_H_ +#ifndef NET_DNS_PUBLIC_DOH_PROVIDER_ENTRY_H_ +#define NET_DNS_PUBLIC_DOH_PROVIDER_ENTRY_H_ #include <set> #include <string> @@ -41,37 +41,56 @@ enum class DohProviderIdForHistogram { // codes, if any, where the entry is eligible for being displayed in the // dropdown menu. struct NET_EXPORT DohProviderEntry { - DohProviderEntry( + public: + using List = std::vector<const DohProviderEntry*>; + + std::string provider; + // A provider_id_for_histogram is required for entries that are intended to + // be visible in the UI. + base::Optional<DohProviderIdForHistogram> provider_id_for_histogram; + std::set<IPAddress> ip_addresses; + std::set<std::string> dns_over_tls_hostnames; + std::string dns_over_https_template; + std::string ui_name; + std::string privacy_policy; + bool display_globally; + std::set<std::string> display_countries; + + // Returns the full list of DoH providers. A subset of this list may be used + // to support upgrade in automatic mode or to populate the dropdown menu for + // secure mode. + static const List& GetList(); + + static DohProviderEntry ConstructForTesting( std::string provider, base::Optional<DohProviderIdForHistogram> provider_id_for_histogram, - std::set<std::string> ip_strs, + std::set<base::StringPiece> ip_strs, std::set<std::string> dns_over_tls_hostnames, std::string dns_over_https_template, std::string ui_name, std::string privacy_policy, bool display_globally, std::set<std::string> display_countries); - DohProviderEntry(const DohProviderEntry& other); + + // Entries are move-only. This allows tests to construct a List but ensures + // that |const DohProviderEntry*| is a safe type for application code. + DohProviderEntry(DohProviderEntry&& other); + DohProviderEntry& operator=(DohProviderEntry&& other); ~DohProviderEntry(); - const std::string provider; - // A provider_id_for_histogram is required for entries that are intended to - // be visible in the UI. - const base::Optional<DohProviderIdForHistogram> provider_id_for_histogram; - std::set<IPAddress> ip_addresses; - const std::set<std::string> dns_over_tls_hostnames; - const std::string dns_over_https_template; - const std::string ui_name; - const std::string privacy_policy; - bool display_globally; - std::set<std::string> display_countries; + private: + DohProviderEntry( + std::string provider, + base::Optional<DohProviderIdForHistogram> provider_id_for_histogram, + std::set<base::StringPiece> ip_strs, + std::set<std::string> dns_over_tls_hostnames, + std::string dns_over_https_template, + std::string ui_name, + std::string privacy_policy, + bool display_globally, + std::set<std::string> display_countries); }; -// Returns the full list of DoH providers. A subset of this list may be used -// to support upgrade in automatic mode or to populate the dropdown menu for -// secure mode. -NET_EXPORT const std::vector<DohProviderEntry>& GetDohProviderList(); - } // namespace net -#endif // NET_DNS_PUBLIC_DOH_PROVIDER_LIST_H_ +#endif // NET_DNS_PUBLIC_DOH_PROVIDER_ENTRY_H_ diff --git a/chromium/net/dns/public/doh_provider_list_unittest.cc b/chromium/net/dns/public/doh_provider_entry_unittest.cc index 60750e6d86a..e5cf5b79cf5 100644 --- a/chromium/net/dns/public/doh_provider_list_unittest.cc +++ b/chromium/net/dns/public/doh_provider_entry_unittest.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "net/dns/public/doh_provider_list.h" +#include "net/dns/public/doh_provider_entry.h" #include "testing/gtest/include/gtest/gtest.h" @@ -10,7 +10,7 @@ namespace net { namespace { TEST(DohProviderListTest, GetDohProviderList) { - const std::vector<DohProviderEntry>& list = GetDohProviderList(); + const DohProviderEntry::List& list = DohProviderEntry::GetList(); EXPECT_FALSE(list.empty()); } diff --git a/chromium/net/dns/record_parsed.cc b/chromium/net/dns/record_parsed.cc index 1ca18d8d22c..23c2f2eb4bc 100644 --- a/chromium/net/dns/record_parsed.cc +++ b/chromium/net/dns/record_parsed.cc @@ -62,9 +62,6 @@ std::unique_ptr<const RecordParsed> RecordParsed::CreateFrom( case OptRecordRdata::kType: rdata = OptRecordRdata::Create(record.rdata, *parser); break; - case EsniRecordRdata::kType: - rdata = EsniRecordRdata::Create(record.rdata, *parser); - break; case IntegrityRecordRdata::kType: rdata = IntegrityRecordRdata::Create(record.rdata); break; diff --git a/chromium/net/dns/record_rdata.cc b/chromium/net/dns/record_rdata.cc index 74200808b57..08d89d4fc15 100644 --- a/chromium/net/dns/record_rdata.cc +++ b/chromium/net/dns/record_rdata.cc @@ -18,88 +18,12 @@ namespace net { -namespace { - -// Helper function for parsing ESNI (TLS 1.3 Encrypted -// Server Name Indication, draft 4) RDATA. -// -// Precondition: |reader| points to the beginning of an -// incoming ESNI-type RecordRdata's data -// -// If the ESNIRecord contains a well-formed -// ESNIKeys field, advances |reader| immediately past the field -// and returns true. Otherwise, returns false. -WARN_UNUSED_RESULT bool AdvancePastEsniKeysField( - base::BigEndianReader* reader) { - DCHECK(reader); - - // Skip |esni_keys.version|. - if (!reader->Skip(2)) - return false; - - // Within esni_keys, skip |public_name|, - // |keys|, and |cipher_suites|. - base::StringPiece piece_for_skipping; - for (int i = 0; i < 3; ++i) { - if (!reader->ReadU16LengthPrefixed(&piece_for_skipping)) - return false; - } - - // Skip the |esni_keys.padded_length| field. - if (!reader->Skip(2)) - return false; - - // Skip the |esni_keys.extensions| field. - return reader->ReadU16LengthPrefixed(&piece_for_skipping); -} - -// Parses a single ESNI address set, appending the addresses to |out|. -WARN_UNUSED_RESULT bool ParseEsniAddressSet(base::StringPiece address_set, - std::vector<IPAddress>* out) { - DCHECK(out); - - IPAddressBytes address_bytes; - base::BigEndianReader address_set_reader(address_set.data(), - address_set.size()); - while (address_set_reader.remaining()) { - // enum AddressType, section 4.2.1 of ESNI draft 4 - // values: 4 (IPv4), 6 (IPv6) - uint8_t address_type = 0; - if (!address_set_reader.ReadU8(&address_type)) - return false; - - switch (address_type) { - case 4: { - address_bytes.Resize(IPAddress::kIPv4AddressSize); - break; - } - case 6: { - address_bytes.Resize(IPAddress::kIPv6AddressSize); - break; - } - default: // invalid address type - return false; - } - if (!address_set_reader.ReadBytes(address_bytes.data(), - address_bytes.size())) - return false; - out->emplace_back(address_bytes); - } - return true; -} - -} // namespace - static const size_t kSrvRecordMinimumSize = 6; -// Source: https://tools.ietf.org/html/draft-ietf-tls-esni-04, section 4.1 -// (This isn't necessarily a tight bound, but it doesn't need to be: -// |HasValidSize| is just used for sanity-check validation.) -// - ESNIKeys field: 8 bytes of length prefixes, 4 bytes of mandatory u16 -// fields, >=7 bytes of length-prefixed fields' contents -// - ESNIRecord field = ESNIKeys field + 2 bytes for |dns_extensions|'s -// length prefix -static const size_t kEsniDraft4MinimumSize = 21; +// The simplest INTEGRITY record is a U16-length-prefixed nonce (containing zero +// bytes) followed by its SHA256 digest. +static constexpr size_t kIntegrityMinimumSize = + sizeof(uint16_t) + IntegrityRecordRdata::kDigestLen; bool RecordRdata::HasValidSize(const base::StringPiece& data, uint16_t type) { switch (type) { @@ -109,8 +33,8 @@ bool RecordRdata::HasValidSize(const base::StringPiece& data, uint16_t type) { return data.size() == IPAddress::kIPv4AddressSize; case dns_protocol::kTypeAAAA: return data.size() == IPAddress::kIPv6AddressSize; - case dns_protocol::kExperimentalTypeEsniDraft4: - return data.size() >= kEsniDraft4MinimumSize; + case dns_protocol::kExperimentalTypeIntegrity: + return data.size() >= kIntegrityMinimumSize; case dns_protocol::kTypeCNAME: case dns_protocol::kTypePTR: case dns_protocol::kTypeTXT: @@ -449,72 +373,6 @@ bool OptRecordRdata::Opt::operator==(const OptRecordRdata::Opt& other) const { return code_ == other.code_ && data_ == other.data_; } -EsniRecordRdata::EsniRecordRdata() = default; - -EsniRecordRdata::~EsniRecordRdata() = default; - -// static -std::unique_ptr<EsniRecordRdata> EsniRecordRdata::Create( - base::StringPiece data, - const DnsRecordParser& parser) { - base::BigEndianReader reader(data.data(), data.size()); - - // TODO: Once BoringSSL CL 37704 lands, replace - // this with Boring's SSL_parse_esni_record, - // which does the same thing. - if (!AdvancePastEsniKeysField(&reader)) - return nullptr; - - size_t esni_keys_len = reader.ptr() - data.data(); - - base::StringPiece dns_extensions; - if (!reader.ReadU16LengthPrefixed(&dns_extensions) || reader.remaining() > 0) - return nullptr; - - // Check defensively that we're not about to read OOB. - CHECK_LT(esni_keys_len, data.size()); - auto rdata = base::WrapUnique(new EsniRecordRdata); - rdata->esni_keys_ = std::string(data.begin(), esni_keys_len); - - base::BigEndianReader dns_extensions_reader(dns_extensions.data(), - dns_extensions.size()); - if (dns_extensions_reader.remaining() == 0) - return rdata; - - // ESNI Draft 4 only permits one extension type, address_set, - // so reject if we see any other extension type. - uint16_t dns_extension_type = 0; - if (!dns_extensions_reader.ReadU16(&dns_extension_type) || - dns_extension_type != kAddressSetExtensionType) - return nullptr; - - base::StringPiece address_set; - if (!dns_extensions_reader.ReadU16LengthPrefixed(&address_set) || - !ParseEsniAddressSet(address_set, &rdata->addresses_)) - return nullptr; - - // In TLS, it's forbidden to send the same extension more than once in an - // extension block; assuming that the same restriction applies here, the - // record is ill-formed if any bytes follow the first (and only) extension. - if (dns_extensions_reader.remaining() > 0) - return nullptr; - - return rdata; -} - -uint16_t EsniRecordRdata::Type() const { - return EsniRecordRdata::kType; -} - -bool EsniRecordRdata::IsEqual(const RecordRdata* other) const { - if (other->Type() != Type()) - return false; - const EsniRecordRdata* esni_other = - static_cast<const EsniRecordRdata*>(other); - return esni_keys_ == esni_other->esni_keys_ && - addresses_ == esni_other->addresses_; -} - IntegrityRecordRdata::IntegrityRecordRdata(Nonce nonce) : nonce_(std::move(nonce)), digest_(Hash(nonce_)), is_intact_(true) {} diff --git a/chromium/net/dns/record_rdata.h b/chromium/net/dns/record_rdata.h index 42d7c1c6111..d652eb7e7ab 100644 --- a/chromium/net/dns/record_rdata.h +++ b/chromium/net/dns/record_rdata.h @@ -11,8 +11,8 @@ #include <string> #include <vector> +#include "base/check_op.h" #include "base/compiler_specific.h" -#include "base/logging.h" #include "base/macros.h" #include "base/optional.h" #include "base/strings/string_piece.h" @@ -269,49 +269,6 @@ class NET_EXPORT_PRIVATE OptRecordRdata : public RecordRdata { DISALLOW_COPY_AND_ASSIGN(OptRecordRdata); }; -// TLS 1.3 Encrypted Server Name Indication -// record format (https://tools.ietf.org/id/draft-ietf-tls-esni-04.txt) -// struct { -// ESNIKeys esni_keys; // see spec -// Extension dns_extensions<0..2 ^ 16 - 1>; -// } ESNIRecord; -class NET_EXPORT EsniRecordRdata : public RecordRdata { - public: - static constexpr uint16_t kType = dns_protocol::kExperimentalTypeEsniDraft4; - static constexpr uint16_t kAddressSetExtensionType = 0x1001u; - - ~EsniRecordRdata() override; - - // Parsing an ESNIRecord Rdata succeeds when all of the following hold: - // 1. The esni_keys field is well-formed. - // 2. The dns_extensions field is well-formed and, additionally, valid - // in the sense that its enum members have values allowed by the spec. - // 3. The Rdata field contains no data beyond the ESNIKeys and, optionally, - // one DNS extension of type address_set. - static std::unique_ptr<EsniRecordRdata> Create(base::StringPiece data, - const DnsRecordParser& parser); - - // Two EsniRecordRdatas compare equal if their ESNIKeys fields agree - // and their address sets contain the same addresses in the same order. - bool IsEqual(const RecordRdata* other) const override; - uint16_t Type() const override; - - // Returns the ESNIKeys field of the record. This is an opaque bitstring - // passed to the SSL library. - base::StringPiece esni_keys() const { return esni_keys_; } - - // Returns the IP addresses parsed from the address_set DNS extension, if any. - const std::vector<IPAddress>& addresses() const { return addresses_; } - - private: - EsniRecordRdata(); - - std::string esni_keys_; - std::vector<IPAddress> addresses_; - - DISALLOW_COPY_AND_ASSIGN(EsniRecordRdata); -}; - // This class parses and serializes the INTEGRITY DNS record. // // This RR was invented for a preliminary HTTPSSVC experiment. See the public diff --git a/chromium/net/dns/record_rdata_unittest.cc b/chromium/net/dns/record_rdata_unittest.cc index c70e674a2d9..88f4c2bd96f 100644 --- a/chromium/net/dns/record_rdata_unittest.cc +++ b/chromium/net/dns/record_rdata_unittest.cc @@ -136,472 +136,6 @@ TEST(RecordRdataTest, ParseCnameRecord) { ASSERT_TRUE(record_obj->IsEqual(record_obj.get())); } -// Appends a well-formed ESNIKeys struct to the stream owned by "writer". -// Returns the length, in bytes, of this struct, or 0 on error. -// -// (There is no ambiguity in the return value because a well-formed -// ESNIKeys struct has positive length.) -void AppendWellFormedEsniKeys(base::BigEndianWriter* writer) { - CHECK(writer); - writer->WriteBytes(kWellFormedEsniKeys, kWellFormedEsniKeysSize); -} - -// This helper checks |keys| against the well-formed sample ESNIKeys -// struct; it's necessary because we can't implicitly convert -// kWellFormedEsniKeys to a StringPiece (it's a byte array, not a -// null-terminated string). -void ExpectMatchesSampleKeys(base::StringPiece keys) { - EXPECT_EQ(keys, - base::StringPiece(kWellFormedEsniKeys, kWellFormedEsniKeysSize)); -} - -// Appends an IP address in network byte order, prepended by one byte -// containing its version number, to |*serialized_addresses|. Appends -// the corresponding IPAddress object to |*address_objects|. -void AppendAnotherIPAddress(std::vector<uint8_t>* serialized_addresses, - std::vector<IPAddress>* address_objects, - int ip_version) { - CHECK(serialized_addresses); - CHECK(address_objects); - - // To make the addresses vary, but in a deterministic manner, assign octets - // in increasing order as they're requested, potentially eventually wrapping - // to 0. - static uint8_t next_octet; - - CHECK(ip_version == 4 || ip_version == 6); - const int address_num_bytes = ip_version == 4 ? 4 : 16; - - std::vector<uint8_t> address_bytes; - for (int i = 0; i < address_num_bytes; ++i) - address_bytes.push_back(next_octet++); - IPAddress address(address_bytes.data(), address_num_bytes); - - serialized_addresses->push_back(ip_version); - serialized_addresses->insert(serialized_addresses->end(), - address_bytes.begin(), address_bytes.end()); - address_objects->push_back(address); -} - -// Writes a dns_extensions ESNIRecord block containing given the address -// set to |writer|. This involves: -// - writing the 16-bit length prefix for the dns_extensions block -// - writing the 16-bit extension type (0x1001 "address_set") -// - writing the 16-bit length prefix for the address set extension -// - writing the extension itself -void AppendDnsExtensionsBlock(base::BigEndianWriter* writer, - const std::vector<uint8_t>& address_list) { - CHECK(writer); - // 2 bytes for the DNS extension type - writer->WriteU16(4 + - address_list.size()); // length of the dns_extensions field - writer->WriteU16(EsniRecordRdata::kAddressSetExtensionType); - writer->WriteU16(address_list.size()); // length of the address set - writer->WriteBytes(address_list.data(), address_list.size()); -} - -// Test parsing a well-formed ESNI record with no DNS extensions. -TEST(RecordRdataTest, ParseEsniRecordNoExtensions) { - char record[10000] = {}; - base::BigEndianWriter writer(record, sizeof(record)); - AppendWellFormedEsniKeys(&writer); - - writer.WriteU16(0); // dns_extensions length - - auto record_size = writer.ptr() - record; - DnsRecordParser parser(record, record_size, 0 /* offset */); - - std::unique_ptr<EsniRecordRdata> record_obj = - EsniRecordRdata::Create(std::string(record, record_size), parser); - ASSERT_THAT(record_obj, NotNull()); - EXPECT_TRUE(record_obj->IsEqual(record_obj.get())); - EXPECT_EQ(record_obj->esni_keys(), - std::string(kWellFormedEsniKeys, kWellFormedEsniKeysSize)); - EXPECT_EQ(record_obj->Type(), dns_protocol::kExperimentalTypeEsniDraft4); -} - -// Test parsing a well-formed ESNI record bearing an address_set extension -// containing a single IPv4 address. -TEST(RecordRdataTest, ParseEsniRecordOneIPv4Address) { - // ESNI record: - // well-formed ESNI keys - // extensions length - // extension - char record[10000] = {}; - base::BigEndianWriter writer(record, sizeof(record)); - AppendWellFormedEsniKeys(&writer); - - std::vector<uint8_t> address_list; - std::vector<IPAddress> addresses_for_validation; - - AppendAnotherIPAddress(&address_list, &addresses_for_validation, - 4 /* ip_version */); - - AppendDnsExtensionsBlock(&writer, address_list); - - auto record_size = writer.ptr() - record; - DnsRecordParser parser(record, record_size, 0 /* offset */); - - std::unique_ptr<EsniRecordRdata> record_obj = - EsniRecordRdata::Create(std::string(record, record_size), parser); - ASSERT_THAT(record_obj, NotNull()); - - const auto& addresses = record_obj->addresses(); - - EXPECT_EQ(addresses, addresses_for_validation); - - EXPECT_TRUE(record_obj->IsEqual(record_obj.get())); - ExpectMatchesSampleKeys(record_obj->esni_keys()); -} - -// Test parsing a well-formed ESNI record bearing an address_set extension -// containing a single IPv6 address. -TEST(RecordRdataTest, ParseEsniRecordOneIPv6Address) { - // ESNI record: - // well-formed ESNI keys - // extensions length - // extension - char record[10000] = {}; - base::BigEndianWriter writer(record, sizeof(record)); - AppendWellFormedEsniKeys(&writer); - - std::vector<uint8_t> address_list; - std::vector<IPAddress> addresses_for_validation; - - AppendAnotherIPAddress(&address_list, &addresses_for_validation, - 6 /* ip_version */); - - AppendDnsExtensionsBlock(&writer, address_list); - - auto record_size = writer.ptr() - record; - DnsRecordParser parser(record, record_size, 0 /* offset */); - - std::unique_ptr<EsniRecordRdata> record_obj = - EsniRecordRdata::Create(std::string(record, record_size), parser); - ASSERT_THAT(record_obj, NotNull()); - - const auto& addresses = record_obj->addresses(); - - EXPECT_EQ(addresses, addresses_for_validation); - - EXPECT_TRUE(record_obj->IsEqual(record_obj.get())); - ExpectMatchesSampleKeys(record_obj->esni_keys()); -} - -// Test parsing a well-formed ESNI record bearing an address_set extension -// containing several IPv4 and IPv6 addresses. -TEST(RecordRdataTest, ParseEsniRecordManyAddresses) { - // ESNI record: - // well-formed ESNI keys - // extensions length - // extension - char record[10000] = {}; - base::BigEndianWriter writer(record, sizeof(record)); - AppendWellFormedEsniKeys(&writer); - - std::vector<uint8_t> address_list; - std::vector<IPAddress> addresses_for_validation; - - for (int i = 0; i < 100; ++i) - AppendAnotherIPAddress(&address_list, &addresses_for_validation, - (i % 3) ? 4 : 6 /* ip_version */); - - AppendDnsExtensionsBlock(&writer, address_list); - - auto record_size = writer.ptr() - record; - DnsRecordParser parser(record, record_size, 0 /* offset */); - - std::unique_ptr<EsniRecordRdata> record_obj = - EsniRecordRdata::Create(std::string(record, record_size), parser); - ASSERT_THAT(record_obj, NotNull()); - - const auto& addresses = record_obj->addresses(); - - EXPECT_EQ(addresses, addresses_for_validation); - - EXPECT_TRUE(record_obj->IsEqual(record_obj.get())); - ExpectMatchesSampleKeys(record_obj->esni_keys()); -} - -// Test that we correctly reject a record with an ill-formed ESNI keys field. -// -// This test makes sure that the //net-side record parser is able -// correctly to handle the case where an external ESNI keys validation -// subroutine reports that the keys are ill-formed; because this validation -// will eventually be performed by BoringSSL once the corresponding -// BSSL code lands, it's out of scope here to exercise the -// validation logic itself. -TEST(RecordRdataTest, EsniMalformedRecord_InvalidEsniKeys) { - char record[10000] = {}; - base::BigEndianWriter writer(record, sizeof(record)); - - // Oops! This otherwise well-formed ESNIKeys struct is missing its - // final byte, and the reader contains no content after this incomplete - // struct. - const char ill_formed_esni_keys[] = { - 0xff, 0x3, 0x0, 0x0, 0x0, 0x24, 0x0, 0x1d, 0x0, 0x20, - 0xed, 0xed, 0xc8, 0x68, 0xc1, 0x71, 0xd6, 0x9e, 0xa9, 0xf0, - 0xa2, 0xc9, 0xf5, 0xa9, 0xdc, 0xcf, 0xf9, 0xb8, 0xed, 0x15, - 0x5c, 0xc4, 0x5a, 0xec, 0x6f, 0xb2, 0x86, 0x14, 0xb7, 0x71, - 0x1b, 0x7c, 0x0, 0x2, 0x13, 0x1, 0x1, 0x4, 0x0}; - writer.WriteBytes(ill_formed_esni_keys, sizeof(ill_formed_esni_keys)); - - auto record_size = writer.ptr() - record; - DnsRecordParser parser(record, record_size, 0 /* offset */); - std::unique_ptr<EsniRecordRdata> record_obj = - EsniRecordRdata::Create(std::string(record, record_size), parser); - - ASSERT_THAT(record_obj, IsNull()); -} - -// Test that an empty address_set extension is correctly accepted. -TEST(RecordRdataTest, ParseEsniRecord_EmptyAddressSet) { - char record[10000] = {}; - base::BigEndianWriter writer(record, sizeof(record)); - AppendWellFormedEsniKeys(&writer); - - writer.WriteU16(4); // length of the dns_extensions field - writer.WriteU16(EsniRecordRdata::kAddressSetExtensionType); - writer.WriteU16(0); // length of the (empty) address_set extension - - auto record_size = writer.ptr() - record; - DnsRecordParser parser(record, record_size, 0 /* offset */); - std::unique_ptr<EsniRecordRdata> record_obj = - EsniRecordRdata::Create(std::string(record, record_size), parser); - - ASSERT_THAT(record_obj, NotNull()); -} - -// Test that we correctly reject a record invalid due to having extra -// data within its dns_extensions block but after its last extension. -TEST(RecordRdataTest, EsniMalformedRecord_TrailingDataWithinDnsExtensions) { - char record[10000] = {}; - base::BigEndianWriter writer(record, sizeof(record)); - AppendWellFormedEsniKeys(&writer); - - writer.WriteU16(5); // length of the dns_extensions field - writer.WriteU16(EsniRecordRdata::kAddressSetExtensionType); - writer.WriteU16(0); // length of the (empty) address_set extension - - // Pad the otherwise-valid extensions block with one byte of garbage. - writer.WriteBytes(&"a", 1); - - auto record_size = writer.ptr() - record; - DnsRecordParser parser(record, record_size, 0 /* offset */); - std::unique_ptr<EsniRecordRdata> record_obj = - EsniRecordRdata::Create(std::string(record, record_size), parser); - - ASSERT_THAT(record_obj, IsNull()); -} - -// Test that we correctly reject a record with two well-formed -// DNS extensions (only one extension of each type is permitted). -TEST(RecordRdataTest, EsniMalformedRecord_TooManyExtensions) { - char record[10000] = {}; - base::BigEndianWriter writer(record, sizeof(record)); - AppendWellFormedEsniKeys(&writer); - - writer.WriteU16(8); // length of the dns_extensions field - writer.WriteU16(EsniRecordRdata::kAddressSetExtensionType); - writer.WriteU16(0); // length of the (empty) address_set extension - // Write another (empty, but completely valid on its own) extension, - // rendering the record invalid. - writer.WriteU16(EsniRecordRdata::kAddressSetExtensionType); - writer.WriteU16(0); - - auto record_size = writer.ptr() - record; - DnsRecordParser parser(record, record_size, 0 /* offset */); - std::unique_ptr<EsniRecordRdata> record_obj = - EsniRecordRdata::Create(std::string(record, record_size), parser); - - ASSERT_THAT(record_obj, IsNull()); -} - -// Test that an ESNIRecord with an extension of invalid type -// is correctly rejected. -TEST(RecordRdataTest, EsniMalformedRecord_InvalidExtensionType) { - char record[10000] = {}; - base::BigEndianWriter writer(record, sizeof(record)); - AppendWellFormedEsniKeys(&writer); - - // 2 bytes for the DNS extension type - writer.WriteU16(2); // length of the dns_extensions field - writer.WriteU16(0xdead); // invalid address type - - auto record_size = writer.ptr() - record; - DnsRecordParser parser(record, record_size, 0 /* offset */); - std::unique_ptr<EsniRecordRdata> record_obj = - EsniRecordRdata::Create(std::string(record, record_size), parser); - - ASSERT_THAT(record_obj, IsNull()); -} - -// Test that an address_set extension missing a length field -// is correctly rejected. -TEST(RecordRdataTest, EsniMalformedRecord_MalformedAddressSetLength) { - char record[10000] = {}; - base::BigEndianWriter writer(record, sizeof(record)); - AppendWellFormedEsniKeys(&writer); - - // 3 bytes: 2 for the DNS extension type, and one for our - // too-short address_set length - writer.WriteU16(3); // length of the dns_extensions field - writer.WriteU16(EsniRecordRdata::kAddressSetExtensionType); - // oops! need two bytes for the address length - writer.WriteU8(57); - - auto record_size = writer.ptr() - record; - DnsRecordParser parser(record, record_size, 0 /* offset */); - std::unique_ptr<EsniRecordRdata> record_obj = - EsniRecordRdata::Create(std::string(record, record_size), parser); - - ASSERT_THAT(record_obj, IsNull()); -} - -// Test that an ESNI record with malformed dns_extensions length is -// correctly rejected. -TEST(RecordRdataTest, EsniMalformedRecord_MalformedDnsExtensionsLength) { - char record[10000] = {}; - base::BigEndianWriter writer(record, sizeof(record)); - AppendWellFormedEsniKeys(&writer); - - // Oops! Length field of dns_extensions should be 2 bytes. - writer.WriteU8(57); - - auto record_size = writer.ptr() - record; - DnsRecordParser parser(record, record_size, 0 /* offset */); - std::unique_ptr<EsniRecordRdata> record_obj = - EsniRecordRdata::Create(std::string(record, record_size), parser); - - ASSERT_THAT(record_obj, IsNull()); -} - -// Test that an ESNI record with invalid dns_extensions length is -// correctly rejected. -TEST(RecordRdataTest, EsniMalformedRecord_BadDnsExtensionsLength) { - char record[10000] = {}; - base::BigEndianWriter writer(record, sizeof(record)); - AppendWellFormedEsniKeys(&writer); - - // Length-prepend the dns_extensions field with value 5, even though - // the extensions object will have length 4 (two U16's): this should - // make the record be rejected as malformed. - writer.WriteU16(5); - writer.WriteU16(EsniRecordRdata::kAddressSetExtensionType); - writer.WriteU16(0); // length of the address_set extension - - auto record_size = writer.ptr() - record; - DnsRecordParser parser(record, record_size, 0 /* offset */); - std::unique_ptr<EsniRecordRdata> record_obj = - EsniRecordRdata::Create(std::string(record, record_size), parser); - - ASSERT_THAT(record_obj, IsNull()); -} - -// Test that an ESNI record with invalid address_set extension length is -// correctly rejected. -TEST(RecordRdataTest, EsniMalformedRecord_BadAddressSetLength) { - char record[10000] = {}; - base::BigEndianWriter writer(record, sizeof(record)); - AppendWellFormedEsniKeys(&writer); - - writer.WriteU16(4); // 2 bytes for each of the U16s to be written - writer.WriteU16(EsniRecordRdata::kAddressSetExtensionType); - // Oops! Length-prepending the empty address_set field with the value 1. - writer.WriteU16(1); - - auto record_size = writer.ptr() - record; - DnsRecordParser parser(record, record_size, 0 /* offset */); - std::unique_ptr<EsniRecordRdata> record_obj = - EsniRecordRdata::Create(std::string(record, record_size), parser); - - ASSERT_THAT(record_obj, IsNull()); -} - -// Test that an ESNI record with an address_set entry of bad address -// type is correctly rejected. -TEST(RecordRdataTest, EsniMalformedRecord_InvalidAddressType) { - char record[10000] = {}; - base::BigEndianWriter writer(record, sizeof(record)); - AppendWellFormedEsniKeys(&writer); - - writer.WriteU16(9); // dns_extensions length: two U16's and a 5-byte address - writer.WriteU16(EsniRecordRdata::kAddressSetExtensionType); - - std::vector<uint8_t> address_list; - IPAddress ipv4; - ASSERT_TRUE(net::ParseURLHostnameToAddress("192.168.1.1", &ipv4)); - address_list.push_back(5); // Oops! "5" isn't a valid AddressType. - std::copy(ipv4.bytes().begin(), ipv4.bytes().end(), - std::back_inserter(address_list)); - - writer.WriteU16(address_list.size()); - writer.WriteBytes(address_list.data(), address_list.size()); - - auto record_size = writer.ptr() - record; - DnsRecordParser parser(record, record_size, 0 /* offset */); - std::unique_ptr<EsniRecordRdata> record_obj = - EsniRecordRdata::Create(std::string(record, record_size), parser); - - ASSERT_THAT(record_obj, IsNull()); -} - -// Test that an ESNI record with an address_set entry of bad address -// type is correctly rejected. -TEST(RecordRdataTest, EsniMalformedRecord_NotEnoughAddressData_IPv4) { - char record[10000] = {}; - base::BigEndianWriter writer(record, sizeof(record)); - AppendWellFormedEsniKeys(&writer); - - std::vector<uint8_t> address_list; - std::vector<IPAddress> addresses_for_validation_unused; - AppendAnotherIPAddress(&address_list, &addresses_for_validation_unused, 4); - - // dns_extensions length: 2 bytes for address type, 2 for address_set length - // Subtract 1 because we're deliberately writing one byte too few for the - // purposes of this test. - writer.WriteU16(address_list.size() - 1 + 4); - writer.WriteU16(EsniRecordRdata::kAddressSetExtensionType); - writer.WriteU16(address_list.size() - 1); - // oops! missing the last byte of our IPv4 address - writer.WriteBytes(address_list.data(), address_list.size() - 1); - - auto record_size = writer.ptr() - record; - DnsRecordParser parser(record, record_size, 0 /* offset */); - std::unique_ptr<EsniRecordRdata> record_obj = - EsniRecordRdata::Create(std::string(record, record_size), parser); - - ASSERT_THAT(record_obj, IsNull()); -} - -// Test that an ESNI record with an address_set entry of bad address -// type is correctly rejected. -TEST(RecordRdataTest, EsniMalformedRecord_NotEnoughAddressData_IPv6) { - char record[10000] = {}; - base::BigEndianWriter writer(record, sizeof(record)); - AppendWellFormedEsniKeys(&writer); - - std::vector<uint8_t> address_list; - std::vector<IPAddress> addresses_for_validation_unused; - AppendAnotherIPAddress(&address_list, &addresses_for_validation_unused, 6); - - // dns_extensions length: 2 bytes for address type, 2 for address_set length - // Subtract 1 because we're deliberately writing one byte too few for the - // purposes of this test. - writer.WriteU16(address_list.size() - 1 + 4); - writer.WriteU16(EsniRecordRdata::kAddressSetExtensionType); - writer.WriteU16(address_list.size() - 1); - // oops! missing the last byte of our IPv6 address - writer.WriteBytes(address_list.data(), address_list.size() - 1); - - auto record_size = writer.ptr() - record; - DnsRecordParser parser(record, record_size, 0 /* offset */); - std::unique_ptr<EsniRecordRdata> record_obj = - EsniRecordRdata::Create(std::string(record, record_size), parser); - - ASSERT_THAT(record_obj, IsNull()); -} - TEST(RecordRdataTest, ParsePtrRecord) { // These are just the rdata portions of the DNS records, rather than complete // records, but it works well enough for this test. diff --git a/chromium/net/dns/resolve_context.cc b/chromium/net/dns/resolve_context.cc index fd7f7c6f17f..3b15cf320ec 100644 --- a/chromium/net/dns/resolve_context.cc +++ b/chromium/net/dns/resolve_context.cc @@ -7,7 +7,6 @@ #include <algorithm> #include <cstdlib> #include <limits> -#include <string> #include <utility> #include "base/check_op.h" @@ -15,6 +14,7 @@ #include "base/metrics/histogram.h" #include "base/metrics/histogram_base.h" #include "base/metrics/histogram_functions.h" +#include "base/metrics/histogram_macros.h" #include "base/metrics/sample_vector.h" #include "base/no_destructor.h" #include "base/numerics/safe_conversions.h" @@ -150,10 +150,27 @@ size_t ResolveContext::NumAvailableDohServers(const DnsSession* session) const { void ResolveContext::RecordServerFailure(size_t server_index, bool is_doh_server, + int rv, const DnsSession* session) { + DCHECK(rv != OK && rv != ERR_NAME_NOT_RESOLVED && rv != ERR_IO_PENDING); + if (!IsCurrentSession(session)) return; + // "FailureError" metric is only recorded for secure queries. + if (is_doh_server) { + std::string query_type = + GetQueryTypeForUma(server_index, true /* is_doh_server */, session); + DCHECK_NE(query_type, "Insecure"); + std::string provider_id = + GetDohProviderIdForUma(server_index, true /* is_doh_server */, session); + + base::UmaHistogramSparse( + base::StringPrintf("Net.DNS.DnsTransaction.%s.%s.FailureError", + query_type.c_str(), provider_id.c_str()), + std::abs(rv)); + } + size_t num_available_doh_servers_before = NumAvailableDohServers(session); ServerStats* stats = GetServerStats(server_index, is_doh_server); @@ -200,10 +217,11 @@ void ResolveContext::RecordRtt(size_t server_index, if (!IsCurrentSession(session)) return; - RecordRttForUma(server_index, is_doh_server, rtt, rv, session); - ServerStats* stats = GetServerStats(server_index, is_doh_server); + base::TimeDelta base_timeout = NextTimeoutHelper(stats, 0 /* num_backoffs */); + RecordRttForUma(server_index, is_doh_server, rtt, rv, base_timeout, session); + // RTT values shouldn't be less than 0, but it shouldn't cause a crash if // they are anyway, so clip to 0. See https://crbug.com/753568. if (rtt < base::TimeDelta()) @@ -367,43 +385,71 @@ void ResolveContext::RecordRttForUma(size_t server_index, bool is_doh_server, base::TimeDelta rtt, int rv, + base::TimeDelta base_timeout, const DnsSession* session) { DCHECK(IsCurrentSession(session)); - std::string query_type; - std::string provider_id; - if (is_doh_server) { - // Secure queries are validated if the DoH server state is available. - if (GetDohServerAvailability(server_index, session)) - query_type = "SecureValidated"; - else - query_type = "SecureNotValidated"; - provider_id = GetDohProviderIdForHistogramFromDohConfig( - current_session_->config().dns_over_https_servers[server_index]); - } else { - query_type = "Insecure"; - provider_id = GetDohProviderIdForHistogramFromNameserver( - current_session_->config().nameservers[server_index]); - } + std::string query_type = + GetQueryTypeForUma(server_index, is_doh_server, session); + std::string provider_id = + GetDohProviderIdForUma(server_index, is_doh_server, session); + if (rv == OK || rv == ERR_NAME_NOT_RESOLVED) { base::UmaHistogramMediumTimes( base::StringPrintf("Net.DNS.DnsTransaction.%s.%s.SuccessTime", query_type.c_str(), provider_id.c_str()), rtt); + if (query_type == "SecureValidated") { + DCHECK(is_doh_server); + + // Only for SecureValidated requests, record the ratio between successful + // RTT and the base timeout for the server. Note that RTT could be much + // longer than the timeout as previous attempts are often allowed to + // continue in parallel with new attempts made by the transaction. Scale + // the ratio up by 10 for sub-integer granularity. + // TODO(crbug.com/1105138): Remove after determining good timeout logic. + int timeout_ratio = 10 * rtt / base_timeout; + UMA_HISTOGRAM_COUNTS_1000( + "Net.DNS.DnsTransaction.SecureValidated.SuccessTimeoutRatio", + timeout_ratio); + } } else { base::UmaHistogramMediumTimes( base::StringPrintf("Net.DNS.DnsTransaction.%s.%s.FailureTime", query_type.c_str(), provider_id.c_str()), rtt); - if (is_doh_server) { - base::UmaHistogramSparse( - base::StringPrintf("Net.DNS.DnsTransaction.%s.%s.FailureError", - query_type.c_str(), provider_id.c_str()), - std::abs(rv)); - } } } +std::string ResolveContext::GetQueryTypeForUma(size_t server_index, + bool is_doh_server, + const DnsSession* session) { + DCHECK(IsCurrentSession(session)); + + if (!is_doh_server) + return "Insecure"; + + // Secure queries are validated if the DoH server state is available. + if (GetDohServerAvailability(server_index, session)) + return "SecureValidated"; + + return "SecureNotValidated"; +} + +std::string ResolveContext::GetDohProviderIdForUma(size_t server_index, + bool is_doh_server, + const DnsSession* session) { + DCHECK(IsCurrentSession(session)); + + if (is_doh_server) { + return GetDohProviderIdForHistogramFromDohConfig( + session->config().dns_over_https_servers[server_index]); + } + + return GetDohProviderIdForHistogramFromNameserver( + session->config().nameservers[server_index]); +} + void ResolveContext::NotifyDohStatusObserversOfSessionChanged() { for (auto& observer : doh_status_observers_) observer.OnSessionChanged(); diff --git a/chromium/net/dns/resolve_context.h b/chromium/net/dns/resolve_context.h index 8b3ec4fd388..bcbac646da5 100644 --- a/chromium/net/dns/resolve_context.h +++ b/chromium/net/dns/resolve_context.h @@ -6,6 +6,7 @@ #define NET_DNS_RESOLVE_CONTEXT_H_ #include <memory> +#include <string> #include <vector> #include "base/memory/weak_ptr.h" @@ -92,9 +93,12 @@ class NET_EXPORT_PRIVATE ResolveContext : public base::CheckedObserver { // Record that server failed to respond (due to SRV_FAIL or timeout). If // |is_doh_server| and the number of failures has surpassed a threshold, // sets the DoH probe state to unavailable. Noop if |session| is not the - // current session. + // current session. Should only be called with with server failure |rv|s, + // not eg OK, ERR_NAME_NOT_RESOLVED (which at the transaction level is + // expected to be nxdomain), or ERR_IO_PENDING. void RecordServerFailure(size_t server_index, bool is_doh_server, + int rv, const DnsSession* session); // Record that server responded successfully. Noop if |session| is not the @@ -199,7 +203,14 @@ class NET_EXPORT_PRIVATE ResolveContext : public base::CheckedObserver { bool is_doh_server, base::TimeDelta rtt, int rv, + base::TimeDelta base_timeout, const DnsSession* session); + std::string GetQueryTypeForUma(size_t server_index, + bool is_doh_server, + const DnsSession* session); + std::string GetDohProviderIdForUma(size_t server_index, + bool is_doh_server, + const DnsSession* session); void NotifyDohStatusObserversOfSessionChanged(); void NotifyDohStatusObserversOfUnavailable(bool network_change); diff --git a/chromium/net/dns/resolve_context_unittest.cc b/chromium/net/dns/resolve_context_unittest.cc index 4701feff6db..5de6a10e3f3 100644 --- a/chromium/net/dns/resolve_context_unittest.cc +++ b/chromium/net/dns/resolve_context_unittest.cc @@ -197,7 +197,7 @@ TEST_F(ResolveContextTest, DohServerAvailability_DifferentSession) { ASSERT_TRUE(context.GetDohServerAvailability(1u, session2.get())); for (int i = 0; i < ResolveContext::kAutomaticModeFailureLimit; ++i) { context.RecordServerFailure(1u /* server_index */, true /* is_doh_server */, - session1.get()); + ERR_FAILED, session1.get()); } EXPECT_TRUE(context.GetDohServerAvailability(1u, session2.get())); } @@ -300,7 +300,7 @@ TEST_F(ResolveContextTest, DohServerAvailabilityNotification) { for (int i = 0; i < ResolveContext::kAutomaticModeFailureLimit; ++i) { ASSERT_EQ(2u, context.NumAvailableDohServers(session.get())); context.RecordServerFailure(0u /* server_index */, true /* is_doh_server */, - session.get()); + ERR_FAILED, session.get()); base::RunLoop().RunUntilIdle(); // Notifications are async. EXPECT_EQ(1, config_observer.dns_changed_calls()); } @@ -313,7 +313,7 @@ TEST_F(ResolveContextTest, DohServerAvailabilityNotification) { EXPECT_EQ(1, config_observer.dns_changed_calls()); context.RecordServerFailure(1u /* server_index */, true /* is_doh_server */, - session.get()); + ERR_FAILED, session.get()); } ASSERT_EQ(0u, context.NumAvailableDohServers(session.get())); base::RunLoop().RunUntilIdle(); // Notifications are async. @@ -418,7 +418,8 @@ TEST_F(ResolveContextTest, Failures_Consecutive) { EXPECT_EQ(classic_itr->GetNextAttemptIndex(), 1u); context.RecordServerFailure(1u /* server_index */, - false /* is_doh_server */, session.get()); + false /* is_doh_server */, ERR_FAILED, + session.get()); } { @@ -464,7 +465,8 @@ TEST_F(ResolveContextTest, Failures_NonConsecutive) { EXPECT_EQ(classic_itr->GetNextAttemptIndex(), 1u); context.RecordServerFailure(1u /* server_index */, - false /* is_doh_server */, session.get()); + false /* is_doh_server */, ERR_FAILED, + session.get()); } { @@ -491,7 +493,7 @@ TEST_F(ResolveContextTest, Failures_NonConsecutive) { // Expect server stay preferred through non-consecutive failures. context.RecordServerFailure(1u /* server_index */, false /* is_doh_server */, - session.get()); + ERR_FAILED, session.get()); { std::unique_ptr<DnsServerIterator> classic_itr = context.GetClassicDnsIterator(session->config(), session.get()); @@ -518,7 +520,8 @@ TEST_F(ResolveContextTest, Failures_NoSession) { EXPECT_FALSE(classic_itr->AttemptAvailable()); context.RecordServerFailure(1u /* server_index */, - false /* is_doh_server */, session.get()); + false /* is_doh_server */, ERR_FAILED, + session.get()); } std::unique_ptr<DnsServerIterator> classic_itr = context.GetClassicDnsIterator(session->config(), session.get()); @@ -551,7 +554,8 @@ TEST_F(ResolveContextTest, Failures_DifferentSession) { EXPECT_EQ(classic_itr->GetNextAttemptIndex(), 1u); context.RecordServerFailure(1u /* server_index */, - false /* is_doh_server */, session1.get()); + false /* is_doh_server */, ERR_FAILED, + session1.get()); } std::unique_ptr<DnsServerIterator> classic_itr = context.GetClassicDnsIterator(session2->config(), session2.get()); @@ -586,9 +590,11 @@ TEST_F(ResolveContextTest, TwoFailures) { EXPECT_EQ(classic_itr->GetNextAttemptIndex(), 2u); context.RecordServerFailure(0u /* server_index */, - false /* is_doh_server */, session.get()); + false /* is_doh_server */, ERR_FAILED, + session.get()); context.RecordServerFailure(1u /* server_index */, - false /* is_doh_server */, session.get()); + false /* is_doh_server */, ERR_FAILED, + session.get()); } { std::unique_ptr<DnsServerIterator> classic_itr = @@ -661,7 +667,7 @@ TEST_F(ResolveContextTest, DohFailures_Consecutive) { EXPECT_EQ(1u, context.NumAvailableDohServers(session.get())); EXPECT_EQ(0, observer.server_unavailable_notifications()); context.RecordServerFailure(1u /* server_index */, true /* is_doh_server */, - session.get()); + ERR_FAILED, session.get()); } std::unique_ptr<DnsServerIterator> doh_itr = context.GetDohIterator( session->config(), DnsConfig::SecureDnsMode::AUTOMATIC, session.get()); @@ -696,7 +702,7 @@ TEST_F(ResolveContextTest, DohFailures_NonConsecutive) { EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 1u); EXPECT_EQ(1u, context.NumAvailableDohServers(session.get())); context.RecordServerFailure(1u /* server_index */, true /* is_doh_server */, - session.get()); + ERR_FAILED, session.get()); } { std::unique_ptr<DnsServerIterator> doh_itr = context.GetDohIterator( @@ -721,7 +727,7 @@ TEST_F(ResolveContextTest, DohFailures_NonConsecutive) { // Expect a single additional failure should not make a DoH server unavailable // because the success resets failure tracking. context.RecordServerFailure(1u /* server_index */, true /* is_doh_server */, - session.get()); + ERR_FAILED, session.get()); { std::unique_ptr<DnsServerIterator> doh_itr = context.GetDohIterator( session->config(), DnsConfig::SecureDnsMode::AUTOMATIC, session.get()); @@ -752,7 +758,7 @@ TEST_F(ResolveContextTest, DohFailures_SuccessAfterFailures) { for (size_t i = 0; i < ResolveContext::kAutomaticModeFailureLimit; i++) { context.RecordServerFailure(1u /* server_index */, true /* is_doh_server */, - session.get()); + ERR_FAILED, session.get()); } ASSERT_EQ(0u, context.NumAvailableDohServers(session.get())); EXPECT_EQ(1, observer.server_unavailable_notifications()); @@ -787,7 +793,7 @@ TEST_F(ResolveContextTest, DohFailures_NoSession) { for (size_t i = 0; i < ResolveContext::kAutomaticModeFailureLimit; i++) { EXPECT_EQ(0u, context.NumAvailableDohServers(session.get())); context.RecordServerFailure(1u /* server_index */, true /* is_doh_server */, - session.get()); + ERR_FAILED, session.get()); } EXPECT_EQ(0u, context.NumAvailableDohServers(session.get())); } @@ -814,7 +820,7 @@ TEST_F(ResolveContextTest, DohFailures_DifferentSession) { for (size_t i = 0; i < ResolveContext::kAutomaticModeFailureLimit; i++) { EXPECT_EQ(1u, context.NumAvailableDohServers(session2.get())); context.RecordServerFailure(1u /* server_index */, true /* is_doh_server */, - session1.get()); + ERR_FAILED, session1.get()); } EXPECT_EQ(1u, context.NumAvailableDohServers(session2.get())); } @@ -849,9 +855,9 @@ TEST_F(ResolveContextTest, TwoDohFailures) { EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 2u); context.RecordServerFailure(0u /* server_index */, true /* is_doh_server */, - session.get()); + ERR_FAILED, session.get()); context.RecordServerFailure(1u /* server_index */, true /* is_doh_server */, - session.get()); + ERR_FAILED, session.get()); } std::unique_ptr<DnsServerIterator> doh_itr = context.GetDohIterator( diff --git a/chromium/net/dns/test_dns_config_service.h b/chromium/net/dns/test_dns_config_service.h index 3b61c361c6c..1b63ec766f6 100644 --- a/chromium/net/dns/test_dns_config_service.h +++ b/chromium/net/dns/test_dns_config_service.h @@ -7,7 +7,7 @@ #include <utility> -#include "base/logging.h" +#include "base/check.h" #include "base/optional.h" #include "net/dns/dns_config_service.h" diff --git a/chromium/net/docs/bug-triage-labels.md b/chromium/net/docs/bug-triage-labels.md index d32cde11826..1a9724e9221 100644 --- a/chromium/net/docs/bug-triage-labels.md +++ b/chromium/net/docs/bug-triage-labels.md @@ -10,22 +10,11 @@ that die in the SSL negotiation phase, in particular, this is often the correct component. -* **Internals>Network>DataProxy** - - Flywheel / the Data Reduction Proxy. Issues require "Reduce Data Usage" be - turned on. Proxy URL is [https://proxy.googlezip.net:443](#), with - [http://compress.googlezip.net:80](#) as a fallback. Currently Android and - iOS only. - * **Internals>Network>Cache** The cache is the layer that handles most range request logic (Though range requests may also be issued by the PDF plugin, XHRs, or other components). -* **Internals>Network>SPDY** - - Covers HTTP2 as well. - * **Internals>Network>HTTP** Typically not used. Unclear what it covers, and there's no specific HTTP diff --git a/chromium/net/docs/bug-triage-suggested-workflow.md b/chromium/net/docs/bug-triage-suggested-workflow.md deleted file mode 100644 index 4807c72b95a..00000000000 --- a/chromium/net/docs/bug-triage-suggested-workflow.md +++ /dev/null @@ -1,112 +0,0 @@ -# Chrome Network Bug Triage : Suggested Workflow - -[TOC] - -## Identifying unlabeled network bugs on the tracker - -* Look at new unconfirmed bugs since noon PST on the last triager's rotation. - [Use this issue tracker - query](https://bugs.chromium.org/p/chromium/issues/list?q=status%3Aunconfirmed&sort=-id&num=1000). - -* Read the title of the bug. - -* If a bug looks like it might be network related, middle click (or - command-click on OSX) to open it in a new tab. - -* If a user provides a crash ID for a crasher for a bug that could be - net-related, see the [internal instructions on dealing with a crash ID](https://goto.google.com/network_triage_internal#dealing-with-a-crash-id) - -* If network causes are possible, ask for a net-export log (If it's not a - browser crash) and attach the most specific internals-network label that's - applicable. If there isn't an applicable narrower component, a clear owner - for the issue, or there are multiple possibilities, attach the - Internals>Network component and proceed with further investigation. - -* If non-network causes also seem possible, attach those components as well. - -## Investigating component=Internals>Network bugs - -* Note that you may want to investigate Needs-Feedback bugs first, as - that may result in some bugs being added to this list. - -* It's recommended that while on triage duty, you subscribe to the - Internals>Network component (but not its subcomponents). To do this, go - to the issue tracker and then click "Saved Queries". - Add a query with these settings: - * Saved query name: Network Bug Triage - * Project: chromium - * Query: component=Internals>Network - * Subscription options: Notify Immediately - -* Look through unconfirmed and untriaged component=Internals>Network bugs, - prioritizing those updated within the last week. [Use this issue tracker - query](https://bugs.chromium.org/p/chromium/issues/list?can=2&q=component%3DInternals%3ENetwork+status%3AUnconfirmed,Untriaged+-label:Needs-Feedback&sort=-modified). - -* If more information is needed from the reporter, ask for it and add the - Needs-Feedback label. - -* While investigating a new issue, change the status to Untriaged. - -* If a bug is a potential security issue (Allows for code execution from remote - site, allows crossing security boundaries, unchecked array bounds, etc) mark - it Type-Bug-Security. If it has privacy implication (History, cookies - discoverable by an entity that shouldn't be able to do so, incognito state - being saved in memory or on disk beyond the lifetime of incognito tabs, etc), - mark it with component Privacy. - -* For bugs that already have a more specific network component, go ahead and - remove the Internals>Network component to get them off the next triager's - radar and move on. - -* Try to figure out if it's really a network bug. See common non-network - components section for description of common components for issues incorrectly - tagged as Internals>Network. - -* If it's not, attach appropriate labels/components and go no further. - -* If it may be a network bug, attach additional possibly relevant component if - any, and continue investigating. Once you either determine it's a - non-network bug, or figure out accurate more specific network components, your - job is done, though you should still ask for a net-export dump if it seems - likely to be useful. - -* Note that Chrome-OS-specific network-related code (Captive portal detection, - connectivity detection, login, etc) may not all have appropriate more - specific subcomponents, but are not in areas handled by the network stack - team. Just make sure those have the OS-Chrome label, and any more specific - labels if applicable, and then move on. - -* Gather data and investigate. - * Remember to add the Needs-Feedback label whenever waiting for the user to - respond with more information, and remove it when not waiting on the - user. - * Try to reproduce locally. If you can, and it's a regression, use - src/tools/bisect-builds.py to figure out when it regressed. - * Ask more data from the user as needed (net-export dumps, repro case, - crash ID from chrome://crashes, run tests, etc). - * If asking for a chrome://net-export dump, provide this link: - https://sites.google.com/a/chromium.org/dev/for-testers/providing-network-details. - -* Try to figure out what's going on, and which more specific network component - is most appropriate. - -* If it's a regression, browse through the git history of relevant files to try - and figure out when it regressed. CC authors / primary reviewers of any - strongly suspect CLs. - -* If you are having trouble with an issue, particularly for help understanding - net-export logs, email the public net-dev@chromium.org list for help - debugging. If it's a crasher, or for some other reason discussion needs to - be done in private, see [internal documentation for details](https://goto.google.com/network_triage_internal#getting-help-with-a-bug) - -* If it appears to be a bug in the unowned core of the network stack (i.e. no - subcomponent applies, or only the Internals>Network>HTTP subcomponent - applies, and there's no clear owner), try to figure out the exact cause. - -## Crashes - -For guidance on crashes see the internal documentation: - -* [Dealing with a crash ID](https://goto.google.com/network_triage_internal#dealing-with-a-crash-id) -* [Looking for new crashers](https://goto.google.com/network_triage_internal#looking-for-new-crashers) -* [Investigating crashers](https://goto.google.com/network_triage_internal#investigating-crashers) diff --git a/chromium/net/docs/bug-triage.md b/chromium/net/docs/bug-triage.md index 25348795d97..ab02bbe8ff8 100644 --- a/chromium/net/docs/bug-triage.md +++ b/chromium/net/docs/bug-triage.md @@ -1,115 +1,96 @@ # Chrome Network Bug Triage -The Chrome network team uses a two day bug triage rotation. The main goals are -to identify and label new network bugs, and investigate network bugs when no -label seems suitable. +The Chrome network team uses a two day bug triage rotation. The goal is to +review outstanding issues and keep things moving forward. The rotation is time +based rather than objective based. Sheriffs are expected to spend the majority +of their two days working on bug triage/investigation. + +## 1. Review untriaged bugs + +Look through [this list of untriaged +bugs](https://bugs.chromium.org/p/chromium/issues/list?sort=pri%20-stars%20-opened&q=component%3AInternals%3ENetwork%20status%3Aunconfirmed%2Cuntriaged%20-component%3AInternals%3ENetwork%3ECookies%20-component%3AInternals%3ENetwork%3EDNS%20-component%3AInternals%3ENetwork%3ECookies%20-component%3AInternals%3ENetwork%3ECertificate%20-component%3AInternals%3ENetwork%3EReportingAndNEL%20-component%3AInternals%3ENetwork%3EDataUse%20-component%3AInternals%3ENetwork%3EEV%20-component%3AInternals%3ENetwork%3EDataProxy%20-component%3AInternals%3ENetwork%3ECertTrans%20-component%3AInternals%3ENetwork%3ENetworkQuality%20-component%3AInternals%3ENetwork%3EDoH%20-component%3AInternals%3ENetwork%3ENetInfo%20-component%3AInternals%3ENetwork%3EVPN%20-Needs%3DFeedback). + +* Go through them in the given order (top to bottom). + The link sorts them by priority and then recency. +* The goal is to move them out of the untriaged bug queue and give them a priority. + +For each bug try to: + +* Remove the `Internals>Network` component if it belongs elsewhere +* Dupe it against an existing bug +* Close it `WontFix` if appropriate +* Give the bug a priority. Refer to [this (internal) document for guidelines](https://goto.google.com/xnzwn) +* If the bug is a potential security issue (Allows for code execution from remote + site, allows crossing security boundaries, unchecked array bounds, etc) mark + it `Type-Bug-Security`. +* If the bug has privacy implications mark it with component `Privacy`. +* Mark it as a feature request or task if appropriate +* Ask the reporter to narrow down regressions, possibly by using + [bisect-builds-py](https://www.chromium.org/developers/bisect-builds-py). To + view suspicious changelists in a regression window, you can use the Change Log + form on [OmahaProxy](https://omahaproxy.appspot.com/) +* CC others who may be able to help +* Mark it as `Needs-Feedback` and request more information if needed. +* Request a NetLog that captures the problem. You can paste this on the bug: + ``` + Please collect and attach a chrome://net-export log. + Instructions can be found here: + https://chromium.org/for-testers/providing-network-details + ``` +* If a NetLog was provided, try to spend a bit of time reviewing it. See + [crash-course-in-net-internals.md](crash-course-in-net-internals.md) for an + introduction. +* Move to a subcomponent of `Internals>Network` if appropriate. See + [bug-triage-labels.md](bug-triage-labels.md) for an overview of the components. +* If the bug is a crash, see [internal: Dealing with a crash + ID](https://goto.google.com/network_triage_internal#dealing-with-a-crash-id) +and [internal: Investigating +crashers](https://goto.google.com/network_triage_internal#investigating-crashers) + +## 2. Follow-up on issues with the Needs-Feedback label + +Look through [this list of Needs=Feedback +bugs](https://bugs.chromium.org/p/chromium/issues/list?sort=pri%20-modified&q=component%3AInternals%3ENetwork%20Needs%3DFeedback%20-component%3AInternals%3ENetwork%3ECookies%20-component%3AInternals%3ENetwork%3EDNS%20-component%3AInternals%3ENetwork%3ECookies%20-component%3AInternals%3ENetwork%3ECertificate%20-component%3AInternals%3ENetwork%3EReportingAndNEL%20-component%3AInternals%3ENetwork%3EDataUse%20-component%3AInternals%3ENetwork%3EEV%20-component%3AInternals%3ENetwork%3EDataProxy%20-component%3AInternals%3ENetwork%3ECertTrans%20-component%3AInternals%3ENetwork%3ENetworkQuality%20-component%3AInternals%3ENetwork%3EDoH%20-component%3AInternals%3ENetwork%3ENetInfo%20-component%3AInternals%3ENetwork%3EVPN). + +* Go through them in the given order (top to bottom). + The link sorts them by priority and then recency. +* If the requested feedback was provided, review the new information and repeat + the same steps as (1) to re-triage based on the new information. +* If the bug had the `Needs-Feedback` label for over a week and the + feedback needed to make progress was not yet provided, archive the bug. + +## 3. (Optional) Look through crash reports + +Top crashes will already be entered into the bug system by a different process, +so will be handled by the triage steps above. + +However if you have time to look through lower threshold crashes, see +[internal: Looking for new crashers](https://goto.google.com/network_triage_internal#looking-for-new-crashers) + +## 4. Send out a sheriff report + +On the final day of your rotation, send a brief summary to net-dev@chromium.org +detailing any interesting or concerning trends. Do not discuss any restricted +bugs on the public mailing list. ## Management -Owners for the network bug triage rotation can find instructions on -generating and modifying shifts -[here (internal-only)](https://goto.google.com/pflvb). - -## Responsibilities - -### Required, in rough order of priority: -* Identify new network bugs on the tracker. -* Investigate recent `Internals>Network` issues with no subcomponent. -* Follow up on `Needs-Feedback` issues for all network components. -* Identify and file bugs for significant new crashers. - -### Best effort, also in rough priority order: -* Investigate unowned and owned-but-forgotten net/ crashers. -* Investigate old bugs. -* Close obsolete bugs. - -All of the above is to be done on each rotation. These responsibilities should -be tracked, and anything left undone at the end of a rotation should be handed -off to the next triager. The downside to passing along bug investigations like -this is each new triager has to get back up to speed on bugs the previous -triager was investigating. The upside is that triagers don't get stuck -investigating issues after their time after their rotation, and it results in a -uniform, predictable two day commitment for all triagers. - -## Details - -### Required: - -* Identify new network bugs on the bug tracker, looking at [this issue tracker - query](https://bugs.chromium.org/p/chromium/issues/list?q=status%3Aunconfirmed+-commentby=425761728072-pa1bs18esuhp2cp2qfa1u9vb6p1v6kfu@developer.gserviceaccount.com&sort=-id&num=1000). - - * All Unconfirmed issues filed during your triage rotation should be scanned - for suspected network bugs, a network component assigned and a - chrome://net-export/ log requested. Suggested text: "Please collect and - attach a chrome://net-export log. Instructions can be found here: - https://chromium.org/for-testers/providing-network-details". - A link to the instructions appears on net-export, for easy reference. - When asking for a log or more details, attach the Needs-Feedback label. - - * A triager is responsible for looking at bugs reported from noon PST / - 3:00 pm EST of the last day of the previous triager's rotation until the - same time on the last day of their rotation. - -* Investigate [Unconfirmed / Untriaged Internals>Network issues that don't belong to a more specific network component](https://bugs.chromium.org/p/chromium/issues/list?can=2&q=component%3DInternals%3ENetwork+status%3AUnconfirmed,Untriaged+-label:Needs-Feedback&sort=-modified), - prioritizing the most recent issues, ones with the most responsive reporters, - and major crashers. This will generally take up the majority of your time as - triager. Continue digging until you can do one of the following: - - * Mark it as `WontFix` (working as intended, obsolete issue) or a - duplicate. - - * Mark it as a feature request. +* Your rotation will appear in Google Calendar as two days. You are expected to + work on it full-time (as best you can) during those calendar days, during your + ordinary working hours. - * Mark it as `Needs-Feedback`. +* Google Calendar [google.com_52n2p39ad82hah9v7j26vek830@group.calendar.google.com](https://calendar.google.com/calendar/embed?src=google.com_52n2p39ad82hah9v7j26vek830%40group.calendar.google.com&ctz=America%2FLos_Angeles) - * Remove the `Internals>Network` component, replacing it with at least one - more specific network component or non-network component. Replacing the - `Internals>Network` component gets it off the next triager's radar, and - in front of someone more familiar with the relevant code. Note that - due to the way the bug report wizard works, a lot of bugs incorrectly end - up with the network component. - - * The issue is assigned to an appropriate owner. Make sure to mark it as - "assigned" so the next triager doesn't run into it. - - * If there is no more specific component for a bug, it should be - investigated by the triager until we have a good understanding of the - cause of the problem, and some idea how it should be fixed, at which point - its status should be set to Available. Future triagers should ignore bugs - with this status, unless investigating stale bugs. - -* Follow up on [Needs-Feedback issues for all components owned by the network stack team](https://bugs.chromium.org/p/chromium/issues/list?q=component%3AInternals%3ENetwork+-component%3AInternals%3ENetwork%3EDataProxy+-component%3AInternals%3ENetwork%3EDataUse+-component%3AInternals%3ENetwork%3EVPN+Needs%3DFeedback&sort=-modified). - - * Remove label once feedback is provided. Continue to investigate, if - the previous section applies. - - * If the `Needs-Feedback` label has been present for one week, ping the - reporter. - - * Archive after two weeks with no feedback, telling users to file a new - bug if they still have the issue, with the requested information, unless - the reporter indicates they'll provide data when they can. In that case, - use your own judgment for further pings or archiving. - -* Identify significant new crashes. See [internal documentation](https://goto.google.com/network_triage_internal#looking-for-new-crashers). - -### Best Effort (As you have time): - -* Investigate old bugs, and bugs associated with `Internals>Network` - subcomponents. - -* Investigate unowned and owned but forgotten net/ crashers that are still - occurring (As indicated by - [go/chromenetcrash](https://goto.google.com/chromenetcrash)), prioritizing - frequent and long standing crashers. - -* Close obsolete bugs. +* Owners for the network bug triage rotation can find instructions on +generating and modifying shifts +[here (internal-only)](https://goto.google.com/pflvb). -See [bug-triage-suggested-workflow.md](bug-triage-suggested-workflow.md) for -suggested workflows. +* An overview of bug trends can be seen on [Chromium + Dashboard](https://chromiumdash.appspot.com/components/Internals/Network?project=Chromium) -See [bug-triage-labels.md](bug-triage-labels.md) for labeling tips for network -and non-network bugs. +* There is also an [internal dashboard with bug trends for Web + Platform](https://goto.google.com/vufyq) that includes network issues. -See [crash-course-in-net-internals.md](crash-course-in-net-internals.md) for -some help on getting started with chrome://net-internals debugging. +* The issue tracker doesn't track any official mappings between components and + OWNERS. This [internal document](https://goto.google.com/kojfj) enumerates + the known owners for subcomponents. diff --git a/chromium/net/docs/certificate_lifetimes.md b/chromium/net/docs/certificate_lifetimes.md new file mode 100644 index 00000000000..ee413ef9157 --- /dev/null +++ b/chromium/net/docs/certificate_lifetimes.md @@ -0,0 +1,78 @@ +# Certificate Lifetimes + +As part of our ongoing commitment to ensuring users’ security, Google is +reducing the maximum allowed lifetimes of TLS certificates. + +## Upcoming Changes + +Beginning with Chrome 85, TLS server certificates issued on or after +2020-09-01 00:00:00 UTC will be required to have a validity period of 398 days +or less. This will only apply to TLS server certificates from CAs that are +trusted in a default installation of Google Chrome, commonly known as +"publicly trusted CAs", and will not apply to locally-operated CAs that have +been manually configured. + +Certificates that do not comply with this requirement will not work, and may +cause webpages to fail to load or to render incorrectly. + +If a certificate that does not comply with this requirement is issued by a CA +trusted in a default installation of Google Chrome, this will be treated as a +failure to comply with the security policies necessary to being a trusted CA, +and may result in the removal of trust of that CA’s certificates. + +## Technical Details + +* A certificate will be impacted by this restriction if either the notBefore + of the certificate is on or after 2020-09-01 00:00:00 UTC, or if the first + precertificate logged by the CA to a Certificate Transparency Log that is + qualified at time of issuance is on or after this date. +* The validity period of a certificate is defined within RFC 5280, Section + 4.1.2.5, as "the period of time from notBefore through notAfter, inclusive." +* 398 days is measured with a day being equal to 86,400 seconds. Any time + greater than this indicates an additional day of validity. +* To avoid the risk of misissuance, such as due to leap seconds or + CA-configured randomization, CAs SHOULD issue such server certificates with + validity periods of 397 days or less. + +## Frequently Asked Questions + +* Does this apply to locally-operated CAs, such as those used within + enterprises that use enterprise-configured configured CAs? + * No. This only applies to the set of CAs that are trusted by default by + Google Chrome, and not CAs that are operated by an enterprise and that + have no certification paths to CAs that are trusted by default. +* Is there an enterprise policy to disable this enforcement? + * No. These changes are transparent and do not offer an enterprise control + to override, as they only apply to so-called "publicly trusted" CAs. + Enterprises that wish to have certificates with validity periods longer + than 398 days may do so by using a locally-operated CA that does not have + any certification paths up to a publicly trusted CA. +* Does this mean I have to replace my existing certificates? + * No. This requirement only applies to new certificate issuance on or after + 2020-09-01 00:00:00 UTC. Existing certificates whose validity period + exceeds 398 days will continue to work, while new certificates must comply + with these new requirements, such as when they are renewed or replaced. +* Will this make certificates more expensive? + * As with past changes to the maximum certificate lifetimes, many CAs have + committed to providing additional certificates, as needed by the shortened + maximum lifetime, at no additional cost. +* What will happen if a certificate is issued that does not meet these + requirements? + * Google Chrome will reject such certificates as having too long a validity + period, consistent with existing validity-period based enforcement. + Additionally, such certificates will be treated as a critical security + failure by the CA, and may result in further action taken on the CA that + may affect how current or future certificates from that CA function. + Chromium-based browsers will have this enforcement enabled by default, and + will need to modify the source to disable this. +* What are other browsers doing? + * Apple previously announced this change for versions of iOS, iPadOS, macOS, + tvOS, and watchOS, as documented at + https://support.apple.com/en-us/HT211025, which will apply to all + applications, and not just those of Safari. This certificate lifetime + requirement is fully interoperable with Apple’s requirements. + + Microsoft, Mozilla, Opera, and 360 have previously indicated their support + for these requirements, although have not yet made announcements at the + time of this post (2020-06-22). Other browsers, including those browsers + based on Chromium, may provide additional guidance or clarification. diff --git a/chromium/net/docs/net-log.md b/chromium/net/docs/net-log.md index 4097bc87a1d..ebf7ceee681 100644 --- a/chromium/net/docs/net-log.md +++ b/chromium/net/docs/net-log.md @@ -69,10 +69,9 @@ That said, changing core events may have consequences for external consumers of NetLogs, which rely on the structure and parameters to events for pretty printing and log analysis. -The [NetLog -viewer](https://chromium.googlesource.com/catapult/+/master/netlog_viewer/) for -instance pretty prints certain parameters based on their names, and the event -name that added them. +The [NetLog viewer](https://netlog-viewer.appspot.com/) for instance pretty +prints certain parameters based on their names, and the event name that added +them. ### Example 1 diff --git a/chromium/net/extras/sqlite/sqlite_persistent_cookie_store.cc b/chromium/net/extras/sqlite/sqlite_persistent_cookie_store.cc index 26ed5f2ad0d..474db6ecaa0 100644 --- a/chromium/net/extras/sqlite/sqlite_persistent_cookie_store.cc +++ b/chromium/net/extras/sqlite/sqlite_persistent_cookie_store.cc @@ -77,20 +77,10 @@ enum CookieCommitProblem { COOKIE_COMMIT_PROBLEM_ADD = 1, COOKIE_COMMIT_PROBLEM_UPDATE_ACCESS = 2, COOKIE_COMMIT_PROBLEM_DELETE = 3, + COOKIE_COMMIT_PROBLEM_TRANSACTION_COMMIT = 4, COOKIE_COMMIT_PROBLEM_LAST_ENTRY }; -// Used to report a histogram on status of cookie commit to disk. -// -// Please do not reorder or remove entries. New entries must be added to the -// end of the list, just before BACKING_STORE_RESULTS_LAST_ENTRY. -enum BackingStoreResults { - BACKING_STORE_RESULTS_SUCCESS = 0, - BACKING_STORE_RESULTS_FAILURE = 1, - BACKING_STORE_RESULTS_MIXED = 2, - BACKING_STORE_RESULTS_LAST_ENTRY -}; - void RecordCookieLoadProblem(CookieLoadProblem event) { UMA_HISTOGRAM_ENUMERATION("Cookie.LoadProblem", event, COOKIE_LOAD_PROBLEM_LAST_ENTRY); @@ -1221,7 +1211,6 @@ void SQLitePersistentCookieStore::Backend::DoCommit() { if (!transaction.Begin()) return; - bool trouble = false; for (auto& kv : ops) { for (std::unique_ptr<PendingOperation>& po_entry : kv.second) { // Free the cookies as we commit them to the database. @@ -1237,7 +1226,6 @@ void SQLitePersistentCookieStore::Backend::DoCommit() { if (!crypto_->EncryptString(po->cc().Value(), &encrypted_value)) { DLOG(WARNING) << "Could not encrypt a cookie, skipping add."; RecordCookieCommitProblem(COOKIE_COMMIT_PROBLEM_ENCRYPT_FAILED); - trouble = true; continue; } add_smt.BindCString(3, ""); // value @@ -1263,7 +1251,6 @@ void SQLitePersistentCookieStore::Backend::DoCommit() { if (!add_smt.Run()) { DLOG(WARNING) << "Could not add a cookie to the DB."; RecordCookieCommitProblem(COOKIE_COMMIT_PROBLEM_ADD); - trouble = true; } break; @@ -1278,7 +1265,6 @@ void SQLitePersistentCookieStore::Backend::DoCommit() { DLOG(WARNING) << "Could not update cookie last access time in the DB."; RecordCookieCommitProblem(COOKIE_COMMIT_PROBLEM_UPDATE_ACCESS); - trouble = true; } break; @@ -1290,7 +1276,6 @@ void SQLitePersistentCookieStore::Backend::DoCommit() { if (!del_smt.Run()) { DLOG(WARNING) << "Could not delete a cookie from the DB."; RecordCookieCommitProblem(COOKIE_COMMIT_PROBLEM_DELETE); - trouble = true; } break; @@ -1300,13 +1285,10 @@ void SQLitePersistentCookieStore::Backend::DoCommit() { } } } - bool succeeded = transaction.Commit(); - UMA_HISTOGRAM_ENUMERATION("Cookie.BackingStoreUpdateResults", - succeeded - ? (trouble ? BACKING_STORE_RESULTS_MIXED - : BACKING_STORE_RESULTS_SUCCESS) - : BACKING_STORE_RESULTS_FAILURE, - BACKING_STORE_RESULTS_LAST_ENTRY); + bool commit_ok = transaction.Commit(); + if (!commit_ok) { + RecordCookieCommitProblem(COOKIE_COMMIT_PROBLEM_TRANSACTION_COMMIT); + } } size_t SQLitePersistentCookieStore::Backend::GetQueueLengthForTesting() { diff --git a/chromium/net/extras/sqlite/sqlite_persistent_cookie_store_unittest.cc b/chromium/net/extras/sqlite/sqlite_persistent_cookie_store_unittest.cc index 7555e39ea88..79fa984d105 100644 --- a/chromium/net/extras/sqlite/sqlite_persistent_cookie_store_unittest.cc +++ b/chromium/net/extras/sqlite/sqlite_persistent_cookie_store_unittest.cc @@ -31,6 +31,7 @@ #include "net/base/test_completion_callback.h" #include "net/cookies/canonical_cookie.h" #include "net/cookies/cookie_constants.h" +#include "net/cookies/cookie_inclusion_status.h" #include "net/cookies/cookie_store_test_callbacks.h" #include "net/extras/sqlite/cookie_crypto_delegate.h" #include "net/log/net_log_capture_mode.h" @@ -1273,16 +1274,14 @@ TEST_F(SQLitePersistentCookieStoreTest, KeyInconsistency) { cookie_scheme_callback1.MakeCallback()); cookie_scheme_callback1.WaitUntilDone(); EXPECT_TRUE(cookie_scheme_callback1.result()); - ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus> - set_cookie_callback; + ResultSavingCookieCallback<CookieInclusionStatus> set_cookie_callback; GURL ftp_url("ftp://subdomain.ftperiffic.com/page/"); auto cookie = CanonicalCookie::Create(ftp_url, "A=B; max-age=3600", base::Time::Now(), base::nullopt /* server_time */); cookie_monster->SetCanonicalCookieAsync( std::move(cookie), ftp_url, CookieOptions::MakeAllInclusive(), - base::BindOnce(&ResultSavingCookieCallback< - CanonicalCookie::CookieInclusionStatus>::Run, + base::BindOnce(&ResultSavingCookieCallback<CookieInclusionStatus>::Run, base::Unretained(&set_cookie_callback))); set_cookie_callback.WaitUntilDone(); EXPECT_TRUE(set_cookie_callback.result().IsInclude()); @@ -1290,16 +1289,14 @@ TEST_F(SQLitePersistentCookieStoreTest, KeyInconsistency) { // Also insert a whole bunch of cookies to slow down the background loading of // all the cookies. for (int i = 0; i < 50; ++i) { - ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus> - set_cookie_callback2; + ResultSavingCookieCallback<CookieInclusionStatus> set_cookie_callback2; GURL url(base::StringPrintf("http://example%d.com/", i)); auto canonical_cookie = CanonicalCookie::Create(url, "A=B; max-age=3600", base::Time::Now(), base::nullopt /* server_time */); cookie_monster->SetCanonicalCookieAsync( std::move(canonical_cookie), url, CookieOptions::MakeAllInclusive(), - base::BindOnce(&ResultSavingCookieCallback< - CanonicalCookie::CookieInclusionStatus>::Run, + base::BindOnce(&ResultSavingCookieCallback<CookieInclusionStatus>::Run, base::Unretained(&set_cookie_callback2))); set_cookie_callback2.WaitUntilDone(); EXPECT_TRUE(set_cookie_callback2.result().IsInclude()); @@ -1347,16 +1344,14 @@ TEST_F(SQLitePersistentCookieStoreTest, OpsIfInitFailed) { std::unique_ptr<CookieMonster> cookie_monster = std::make_unique<CookieMonster>(store_.get(), nullptr); - ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus> - set_cookie_callback; + ResultSavingCookieCallback<CookieInclusionStatus> set_cookie_callback; GURL url("http://www.example.com/"); auto cookie = CanonicalCookie::Create(url, "A=B; max-age=3600", base::Time::Now(), base::nullopt /* server_time */); cookie_monster->SetCanonicalCookieAsync( std::move(cookie), url, CookieOptions::MakeAllInclusive(), - base::BindOnce(&ResultSavingCookieCallback< - CanonicalCookie::CookieInclusionStatus>::Run, + base::BindOnce(&ResultSavingCookieCallback<CookieInclusionStatus>::Run, base::Unretained(&set_cookie_callback))); set_cookie_callback.WaitUntilDone(); EXPECT_TRUE(set_cookie_callback.result().IsInclude()); diff --git a/chromium/net/extras/sqlite/sqlite_persistent_reporting_and_nel_store.cc b/chromium/net/extras/sqlite/sqlite_persistent_reporting_and_nel_store.cc index 55d28e49413..c4fbb1e586d 100644 --- a/chromium/net/extras/sqlite/sqlite_persistent_reporting_and_nel_store.cc +++ b/chromium/net/extras/sqlite/sqlite_persistent_reporting_and_nel_store.cc @@ -582,8 +582,6 @@ bool SQLitePersistentReportingAndNelStore::Backend::CreateDatabaseSchema() { base::Optional<int> SQLitePersistentReportingAndNelStore::Backend::DoMigrateDatabaseSchema() { int cur_version = meta_table()->GetVersionNumber(); - if (cur_version != 1) - return base::nullopt; // Future database upgrade statements go here. diff --git a/chromium/net/extras/sqlite/sqlite_persistent_reporting_and_nel_store_unittest.cc b/chromium/net/extras/sqlite/sqlite_persistent_reporting_and_nel_store_unittest.cc index 1faaac6612e..aed51b9a5d7 100644 --- a/chromium/net/extras/sqlite/sqlite_persistent_reporting_and_nel_store_unittest.cc +++ b/chromium/net/extras/sqlite/sqlite_persistent_reporting_and_nel_store_unittest.cc @@ -16,12 +16,15 @@ #include "base/task/post_task.h" #include "base/task/thread_pool.h" #include "base/test/bind_test_util.h" +#include "base/test/metrics/histogram_tester.h" #include "base/test/simple_test_clock.h" #include "base/threading/thread_restrictions.h" #include "base/threading/thread_task_runner_handle.h" #include "net/network_error_logging/network_error_logging_service.h" #include "net/reporting/reporting_test_util.h" #include "net/test/test_with_task_environment.h" +#include "sql/database.h" +#include "sql/meta_table.h" #include "testing/gtest/include/gtest/gtest.h" namespace net { @@ -199,8 +202,7 @@ class SQLitePersistentReportingAndNelStoreTest info.priority = priority; info.weight = weight; ReportingEndpoint endpoint( - ReportingEndpointGroupKey(NetworkIsolationKey::Todo(), origin, - group_name), + ReportingEndpointGroupKey(NetworkIsolationKey(), origin, group_name), std::move(info)); return endpoint; } @@ -212,8 +214,7 @@ class SQLitePersistentReportingAndNelStoreTest OriginSubdomains include_subdomains = OriginSubdomains::DEFAULT, base::Time expires = kExpires) { return CachedReportingEndpointGroup( - ReportingEndpointGroupKey(NetworkIsolationKey::Todo(), origin, - group_name), + ReportingEndpointGroupKey(NetworkIsolationKey(), origin, group_name), include_subdomains, expires, last_used); } @@ -237,6 +238,72 @@ TEST_F(SQLitePersistentReportingAndNelStoreTest, CreateDBAndTables) { EXPECT_NE(std::string::npos, contents.find("reporting_endpoint_groups")); } +TEST_F(SQLitePersistentReportingAndNelStoreTest, TestInvalidMetaTableRecovery) { + CreateStore(); + InitializeStore(); + base::Time now = base::Time::Now(); + NetworkErrorLoggingService::NelPolicy policy1 = + MakeNelPolicy(url::Origin::Create(GURL("https://www.foo.test")), now); + store_->AddNelPolicy(policy1); + + // Close and reopen the database. + DestroyStore(); + CreateStore(); + + // Load the stored policy. + std::vector<NetworkErrorLoggingService::NelPolicy> policies; + LoadNelPolicies(&policies); + ASSERT_EQ(1u, policies.size()); + EXPECT_EQ(policy1.origin, policies[0].origin); + EXPECT_EQ(policy1.received_ip_address, policies[0].received_ip_address); + EXPECT_EQ(policy1.report_to, policies[0].report_to); + EXPECT_TRUE(WithinOneMicrosecond(policy1.expires, policies[0].expires)); + EXPECT_EQ(policy1.include_subdomains, policies[0].include_subdomains); + EXPECT_EQ(policy1.success_fraction, policies[0].success_fraction); + EXPECT_EQ(policy1.failure_fraction, policies[0].failure_fraction); + EXPECT_TRUE(WithinOneMicrosecond(policy1.last_used, policies[0].last_used)); + DestroyStore(); + policies.clear(); + + // Now corrupt the meta table. + { + sql::Database db; + ASSERT_TRUE( + db.Open(temp_dir_.GetPath().Append(kReportingAndNELStoreFilename))); + sql::MetaTable meta_table; + meta_table.Init(&db, 1, 1); + ASSERT_TRUE(db.Execute("DELETE FROM meta")); + db.Close(); + } + + base::HistogramTester hist_tester; + + // Upon loading, the database should be reset to a good, blank state. + CreateStore(); + LoadNelPolicies(&policies); + ASSERT_EQ(0U, policies.size()); + + hist_tester.ExpectUniqueSample("ReportingAndNEL.CorruptMetaTable", 1, 1); + + // Verify that, after, recovery, the database persists properly. + NetworkErrorLoggingService::NelPolicy policy2 = + MakeNelPolicy(url::Origin::Create(GURL("https://www.bar.test")), now); + store_->AddNelPolicy(policy2); + DestroyStore(); + + CreateStore(); + LoadNelPolicies(&policies); + ASSERT_EQ(1u, policies.size()); + EXPECT_EQ(policy2.origin, policies[0].origin); + EXPECT_EQ(policy2.received_ip_address, policies[0].received_ip_address); + EXPECT_EQ(policy2.report_to, policies[0].report_to); + EXPECT_TRUE(WithinOneMicrosecond(policy2.expires, policies[0].expires)); + EXPECT_EQ(policy2.include_subdomains, policies[0].include_subdomains); + EXPECT_EQ(policy2.success_fraction, policies[0].success_fraction); + EXPECT_EQ(policy2.failure_fraction, policies[0].failure_fraction); + EXPECT_TRUE(WithinOneMicrosecond(policy2.last_used, policies[0].last_used)); +} + TEST_F(SQLitePersistentReportingAndNelStoreTest, PersistNelPolicy) { CreateStore(); InitializeStore(); diff --git a/chromium/net/http/alternative_service.cc b/chromium/net/http/alternative_service.cc index 56273b992fc..e43ce7d71f2 100644 --- a/chromium/net/http/alternative_service.cc +++ b/chromium/net/http/alternative_service.cc @@ -47,13 +47,14 @@ quic::ParsedQuicVersion ParsedQuicVersionFromAlpn( if (AlpnForVersion(version) == str) return version; } - return {quic::PROTOCOL_UNSUPPORTED, quic::QUIC_VERSION_UNSUPPORTED}; + return quic::ParsedQuicVersion::Unsupported(); } } // anonymous namespace void HistogramAlternateProtocolUsage(AlternateProtocolUsage usage, - bool proxy_server_used) { + bool proxy_server_used, + bool is_google_host) { if (proxy_server_used) { DCHECK_LE(usage, ALTERNATE_PROTOCOL_USAGE_LOST_RACE); LOCAL_HISTOGRAM_ENUMERATION("Net.QuicAlternativeProxy.Usage", @@ -62,6 +63,10 @@ void HistogramAlternateProtocolUsage(AlternateProtocolUsage usage, } else { UMA_HISTOGRAM_ENUMERATION("Net.AlternateProtocolUsage", usage, ALTERNATE_PROTOCOL_USAGE_MAX); + if (is_google_host) { + UMA_HISTOGRAM_ENUMERATION("Net.AlternateProtocolUsageGoogle", usage, + ALTERNATE_PROTOCOL_USAGE_MAX); + } } } @@ -201,8 +206,7 @@ AlternativeServiceInfoVector ProcessAlternativeServices( } else if (!IsAlternateProtocolValid(protocol)) { quic::ParsedQuicVersion version = ParsedQuicVersionFromAlpn( alternative_service_entry.protocol_id, supported_quic_versions); - if (version.handshake_protocol == quic::PROTOCOL_UNSUPPORTED || - version.transport_version == quic::QUIC_VERSION_UNSUPPORTED) { + if (version == quic::ParsedQuicVersion::Unsupported()) { continue; } protocol = kProtoQUIC; diff --git a/chromium/net/http/alternative_service.h b/chromium/net/http/alternative_service.h index aaf32b77779..eaaae3e6f8f 100644 --- a/chromium/net/http/alternative_service.h +++ b/chromium/net/http/alternative_service.h @@ -41,7 +41,8 @@ enum AlternateProtocolUsage { // Log a histogram to reflect |usage|. NET_EXPORT void HistogramAlternateProtocolUsage(AlternateProtocolUsage usage, - bool proxy_server_used); + bool proxy_server_used, + bool is_google_host); enum BrokenAlternateProtocolLocation { BROKEN_ALTERNATE_PROTOCOL_LOCATION_HTTP_STREAM_FACTORY_JOB = 0, diff --git a/chromium/net/http/failing_http_transaction_factory.cc b/chromium/net/http/failing_http_transaction_factory.cc deleted file mode 100644 index 7f367a8d38e..00000000000 --- a/chromium/net/http/failing_http_transaction_factory.cc +++ /dev/null @@ -1,211 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/http/failing_http_transaction_factory.h" - -#include <stdint.h> - -#include <utility> - -#include "base/bind.h" -#include "base/check_op.h" -#include "base/compiler_specific.h" -#include "base/location.h" -#include "base/notreached.h" -#include "base/single_thread_task_runner.h" -#include "base/threading/thread_task_runner_handle.h" -#include "net/base/completion_once_callback.h" -#include "net/base/load_timing_info.h" -#include "net/base/net_error_details.h" -#include "net/http/http_response_info.h" -#include "net/socket/connection_attempts.h" - -namespace net { - -class AuthCredentials; -class HttpRequestHeaders; -class IOBuffer; -class NetLogWithSource; -class SSLPrivateKey; -class X509Certificate; - -namespace { - -// A simple class to interpose between the cache and network http layers. -// These transactions can be generated by the FailingHttpTransactionFactory -// to test interactions between cache and network. -class FailingHttpTransaction : public HttpTransaction { - public: - explicit FailingHttpTransaction(Error error); - ~FailingHttpTransaction() override; - - // HttpTransaction - int Start(const HttpRequestInfo* request_info, - CompletionOnceCallback callback, - const NetLogWithSource& net_log) override; - int RestartIgnoringLastError(CompletionOnceCallback callback) override; - int RestartWithCertificate(scoped_refptr<X509Certificate> client_cert, - scoped_refptr<SSLPrivateKey> client_private_key, - CompletionOnceCallback callback) override; - int RestartWithAuth(const AuthCredentials& credentials, - CompletionOnceCallback callback) override; - bool IsReadyToRestartForAuth() override; - int Read(IOBuffer* buf, - int buf_len, - CompletionOnceCallback callback) override; - void StopCaching() override; - int64_t GetTotalReceivedBytes() const override; - int64_t GetTotalSentBytes() const override; - void DoneReading() override; - const HttpResponseInfo* GetResponseInfo() const override; - LoadState GetLoadState() const override; - void SetQuicServerInfo(QuicServerInfo* quic_server_info) override; - bool GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const override; - bool GetRemoteEndpoint(IPEndPoint* endpoint) const override; - void PopulateNetErrorDetails(NetErrorDetails* details) const override; - void SetPriority(RequestPriority priority) override; - void SetWebSocketHandshakeStreamCreateHelper( - WebSocketHandshakeStreamBase::CreateHelper* create_helper) override; - void SetBeforeNetworkStartCallback( - const BeforeNetworkStartCallback& callback) override; - int ResumeNetworkStart() override; - void GetConnectionAttempts(ConnectionAttempts* out) const override; - void SetRequestHeadersCallback(RequestHeadersCallback) override {} - void SetResponseHeadersCallback(ResponseHeadersCallback) override {} - - private: - Error error_; - HttpResponseInfo response_; -}; - -FailingHttpTransaction::FailingHttpTransaction(Error error) : error_(error) { - DCHECK_LT(error, OK); -} - -FailingHttpTransaction::~FailingHttpTransaction() = default; - -int FailingHttpTransaction::Start(const HttpRequestInfo* request_info, - CompletionOnceCallback callback, - const NetLogWithSource& net_log) { - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(std::move(callback), error_)); - return ERR_IO_PENDING; -} - -int FailingHttpTransaction::RestartIgnoringLastError( - CompletionOnceCallback callback) { - return ERR_FAILED; -} - -int FailingHttpTransaction::RestartWithCertificate( - scoped_refptr<X509Certificate> client_cert, - scoped_refptr<SSLPrivateKey> client_private_key, - CompletionOnceCallback callback) { - return ERR_FAILED; -} - -int FailingHttpTransaction::RestartWithAuth(const AuthCredentials& credentials, - CompletionOnceCallback callback) { - return ERR_FAILED; -} - -bool FailingHttpTransaction::IsReadyToRestartForAuth() { - return false; -} - -int FailingHttpTransaction::Read(IOBuffer* buf, - int buf_len, - CompletionOnceCallback callback) { - NOTREACHED(); - return ERR_FAILED; -} - -void FailingHttpTransaction::StopCaching() {} - -int64_t FailingHttpTransaction::GetTotalReceivedBytes() const { - return 0; -} - -int64_t FailingHttpTransaction::GetTotalSentBytes() const { - return 0; -} - -void FailingHttpTransaction::DoneReading() { - NOTREACHED(); -} - -const HttpResponseInfo* FailingHttpTransaction::GetResponseInfo() const { - return &response_; -} - -LoadState FailingHttpTransaction::GetLoadState() const { - return LOAD_STATE_IDLE; -} - -void FailingHttpTransaction::SetQuicServerInfo( - QuicServerInfo* quic_server_info) { -} - -bool FailingHttpTransaction::GetLoadTimingInfo( - LoadTimingInfo* load_timing_info) const { - return false; -} - -bool FailingHttpTransaction::GetRemoteEndpoint(IPEndPoint* endpoint) const { - return false; -} - -void FailingHttpTransaction::PopulateNetErrorDetails( - NetErrorDetails* /*details*/) const { - return; -} - -void FailingHttpTransaction::SetPriority(RequestPriority priority) {} - -void FailingHttpTransaction::SetWebSocketHandshakeStreamCreateHelper( - WebSocketHandshakeStreamBase::CreateHelper* create_helper) { - NOTREACHED(); -} - -void FailingHttpTransaction::SetBeforeNetworkStartCallback( - const BeforeNetworkStartCallback& callback) { -} - -int FailingHttpTransaction::ResumeNetworkStart() { - NOTREACHED(); - return ERR_FAILED; -} - -void FailingHttpTransaction::GetConnectionAttempts( - ConnectionAttempts* out) const { - NOTIMPLEMENTED(); -} - -} // namespace - -FailingHttpTransactionFactory::FailingHttpTransactionFactory( - HttpNetworkSession* session, - Error error) : session_(session), error_(error) { - DCHECK_LT(error, OK); -} - -FailingHttpTransactionFactory::~FailingHttpTransactionFactory() = default; - -// HttpTransactionFactory: -int FailingHttpTransactionFactory::CreateTransaction( - RequestPriority priority, - std::unique_ptr<HttpTransaction>* trans) { - trans->reset(new FailingHttpTransaction(error_)); - return OK; -} - -HttpCache* FailingHttpTransactionFactory::GetCache() { - return nullptr; -} - -HttpNetworkSession* FailingHttpTransactionFactory::GetSession() { - return session_; -} - -} // namespace net diff --git a/chromium/net/http/failing_http_transaction_factory.h b/chromium/net/http/failing_http_transaction_factory.h deleted file mode 100644 index 0830d57c1a6..00000000000 --- a/chromium/net/http/failing_http_transaction_factory.h +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_HTTP_FAILING_HTTP_TRANSACTION_FACTORY_H_ -#define NET_HTTP_FAILING_HTTP_TRANSACTION_FACTORY_H_ - -#include <memory> - -#include "net/base/net_errors.h" -#include "net/base/net_export.h" -#include "net/base/request_priority.h" -#include "net/http/http_transaction.h" -#include "net/http/http_transaction_factory.h" - -namespace net { - -class HttpCache; -class HttpNetworkSession; - -// Creates transactions that always (asynchronously) return a specified -// error. The error is returned asynchronously, just after the transaction is -// started. -class NET_EXPORT FailingHttpTransactionFactory : public HttpTransactionFactory { - public: - // The caller must guarantee that |session| outlives this object. - FailingHttpTransactionFactory(HttpNetworkSession* session, Error error); - ~FailingHttpTransactionFactory() override; - - // HttpTransactionFactory: - int CreateTransaction(RequestPriority priority, - std::unique_ptr<HttpTransaction>* trans) override; - HttpCache* GetCache() override; - HttpNetworkSession* GetSession() override; - - private: - HttpNetworkSession* session_; - Error error_; -}; - -} // namespace net - -#endif // NET_HTTP_FAILING_HTTP_TRANSACTION_FACTORY_H_ diff --git a/chromium/net/http/http_auth.cc b/chromium/net/http/http_auth.cc index 57d4c9029ef..986f0330f7e 100644 --- a/chromium/net/http/http_auth.cc +++ b/chromium/net/http/http_auth.cc @@ -37,6 +37,7 @@ void HttpAuth::ChooseBestChallenge( HttpAuthHandlerFactory* http_auth_handler_factory, const HttpResponseHeaders& response_headers, const SSLInfo& ssl_info, + const NetworkIsolationKey& network_isolation_key, Target target, const GURL& origin, const std::set<Scheme>& disabled_schemes, @@ -54,7 +55,8 @@ void HttpAuth::ChooseBestChallenge( while (response_headers.EnumerateHeader(&iter, header_name, &cur_challenge)) { std::unique_ptr<HttpAuthHandler> cur; int rv = http_auth_handler_factory->CreateAuthHandlerFromString( - cur_challenge, target, ssl_info, origin, net_log, host_resolver, &cur); + cur_challenge, target, ssl_info, network_isolation_key, origin, net_log, + host_resolver, &cur); if (rv != OK) { VLOG(1) << "Unable to create AuthHandler. Status: " << ErrorToString(rv) << " Challenge: " << cur_challenge; diff --git a/chromium/net/http/http_auth.h b/chromium/net/http/http_auth.h index 622015423a9..78b46f3ff2c 100644 --- a/chromium/net/http/http_auth.h +++ b/chromium/net/http/http_auth.h @@ -173,6 +173,7 @@ class NET_EXPORT_PRIVATE HttpAuth { HttpAuthHandlerFactory* http_auth_handler_factory, const HttpResponseHeaders& response_headers, const SSLInfo& ssl_info, + const NetworkIsolationKey& network_isolation_key, Target target, const GURL& origin, const std::set<Scheme>& disabled_schemes, diff --git a/chromium/net/http/http_auth_controller.cc b/chromium/net/http/http_auth_controller.cc index 1ef08d8c87a..fc335665bc1 100644 --- a/chromium/net/http/http_auth_controller.cc +++ b/chromium/net/http/http_auth_controller.cc @@ -231,8 +231,8 @@ bool HttpAuthController::SelectPreemptiveAuth( std::unique_ptr<HttpAuthHandler> handler_preemptive; int rv_create = http_auth_handler_factory_->CreatePreemptiveAuthHandlerFromString( - entry->auth_challenge(), target_, auth_origin_, - entry->IncrementNonceCount(), net_log_, host_resolver_, + entry->auth_challenge(), target_, network_isolation_key_, + auth_origin_, entry->IncrementNonceCount(), net_log_, host_resolver_, &handler_preemptive); if (rv_create != OK) return false; @@ -328,9 +328,10 @@ int HttpAuthController::HandleAuthChallenge( do { if (!handler_.get() && can_send_auth) { // Find the best authentication challenge that we support. - HttpAuth::ChooseBestChallenge( - http_auth_handler_factory_, *headers, ssl_info, target_, auth_origin_, - disabled_schemes_, net_log_, host_resolver_, &handler_); + HttpAuth::ChooseBestChallenge(http_auth_handler_factory_, *headers, + ssl_info, network_isolation_key_, target_, + auth_origin_, disabled_schemes_, net_log_, + host_resolver_, &handler_); if (handler_.get()) HistogramAuthEvent(handler_.get(), AUTH_EVENT_START); } diff --git a/chromium/net/http/http_auth_controller_unittest.cc b/chromium/net/http/http_auth_controller_unittest.cc index 1f78cacf18d..a6dc2f86c12 100644 --- a/chromium/net/http/http_auth_controller_unittest.cc +++ b/chromium/net/http/http_auth_controller_unittest.cc @@ -183,8 +183,9 @@ TEST(HttpAuthControllerTest, NoExplicitCredentialsAllowed) { protected: bool Init(HttpAuthChallengeTokenizer* challenge, - const SSLInfo& ssl_info) override { - HttpAuthHandlerMock::Init(challenge, ssl_info); + const SSLInfo& ssl_info, + const NetworkIsolationKey& network_isolation_key) override { + HttpAuthHandlerMock::Init(challenge, ssl_info, network_isolation_key); set_allows_default_credentials(true); set_allows_explicit_credentials(false); set_connection_based(true); diff --git a/chromium/net/http/http_auth_handler.cc b/chromium/net/http/http_auth_handler.cc index b62f870a755..4d2164e47df 100644 --- a/chromium/net/http/http_auth_handler.cc +++ b/chromium/net/http/http_auth_handler.cc @@ -25,11 +25,13 @@ HttpAuthHandler::HttpAuthHandler() HttpAuthHandler::~HttpAuthHandler() = default; -bool HttpAuthHandler::InitFromChallenge(HttpAuthChallengeTokenizer* challenge, - HttpAuth::Target target, - const SSLInfo& ssl_info, - const GURL& origin, - const NetLogWithSource& net_log) { +bool HttpAuthHandler::InitFromChallenge( + HttpAuthChallengeTokenizer* challenge, + HttpAuth::Target target, + const SSLInfo& ssl_info, + const NetworkIsolationKey& network_isolation_key, + const GURL& origin, + const NetLogWithSource& net_log) { origin_ = origin; target_ = target; score_ = -1; @@ -38,7 +40,7 @@ bool HttpAuthHandler::InitFromChallenge(HttpAuthChallengeTokenizer* challenge, auth_challenge_ = challenge->challenge_text(); net_log_.BeginEvent(NetLogEventType::AUTH_HANDLER_INIT); - bool ok = Init(challenge, ssl_info); + bool ok = Init(challenge, ssl_info, network_isolation_key); net_log_.AddEntryWithBoolParams(NetLogEventType::AUTH_HANDLER_INIT, NetLogEventPhase::END, "succeeded", ok); diff --git a/chromium/net/http/http_auth_handler.h b/chromium/net/http/http_auth_handler.h index c8d3b9f4761..1a17af7a43f 100644 --- a/chromium/net/http/http_auth_handler.h +++ b/chromium/net/http/http_auth_handler.h @@ -15,6 +15,7 @@ namespace net { +class NetworkIsolationKey; class HttpAuthChallengeTokenizer; struct HttpRequestInfo; class SSLInfo; @@ -43,10 +44,13 @@ class NET_EXPORT_PRIVATE HttpAuthHandler { // |target| and |origin| are both stored for later use, and are not part of // the initial challenge. // |ssl_info| must be valid if the underlying connection used a certificate. + // |network_isolation_key| the NetworkIsolationKey associated with the + // challenge. Used for host resolutions, if any are needed. // |net_log| to be used for logging. bool InitFromChallenge(HttpAuthChallengeTokenizer* challenge, HttpAuth::Target target, const SSLInfo& ssl_info, + const NetworkIsolationKey& network_isolation_key, const GURL& origin, const NetLogWithSource& net_log); @@ -178,10 +182,13 @@ class NET_EXPORT_PRIVATE HttpAuthHandler { // If the request was sent over an encrypted connection, |ssl_info| is valid // and describes the connection. // + // NetworkIsolationKey is the NetworkIsolationKey associated with the request. + // // Implementations are expected to initialize the following members: // scheme_, realm_, score_, properties_ virtual bool Init(HttpAuthChallengeTokenizer* challenge, - const SSLInfo& ssl_info) = 0; + const SSLInfo& ssl_info, + const NetworkIsolationKey& network_isolation_key) = 0; // |GenerateAuthTokenImpl()} is the auth-scheme specific implementation // of generating the next auth token. Callers should use |GenerateAuthToken()| diff --git a/chromium/net/http/http_auth_handler_basic.cc b/chromium/net/http/http_auth_handler_basic.cc index 696aaf0e8dc..4692c02b248 100644 --- a/chromium/net/http/http_auth_handler_basic.cc +++ b/chromium/net/http/http_auth_handler_basic.cc @@ -55,8 +55,10 @@ bool ParseRealm(const HttpAuthChallengeTokenizer& tokenizer, } // namespace -bool HttpAuthHandlerBasic::Init(HttpAuthChallengeTokenizer* challenge, - const SSLInfo& ssl_info) { +bool HttpAuthHandlerBasic::Init( + HttpAuthChallengeTokenizer* challenge, + const SSLInfo& ssl_info, + const NetworkIsolationKey& network_isolation_key) { auth_scheme_ = HttpAuth::AUTH_SCHEME_BASIC; score_ = 1; properties_ = 0; @@ -111,6 +113,7 @@ int HttpAuthHandlerBasic::Factory::CreateAuthHandler( HttpAuthChallengeTokenizer* challenge, HttpAuth::Target target, const SSLInfo& ssl_info, + const NetworkIsolationKey& network_isolation_key, const GURL& origin, CreateReason reason, int digest_nonce_count, @@ -120,9 +123,10 @@ int HttpAuthHandlerBasic::Factory::CreateAuthHandler( // TODO(cbentzel): Move towards model of parsing in the factory // method and only constructing when valid. std::unique_ptr<HttpAuthHandler> tmp_handler(new HttpAuthHandlerBasic()); - if (!tmp_handler->InitFromChallenge(challenge, target, ssl_info, origin, - net_log)) + if (!tmp_handler->InitFromChallenge(challenge, target, ssl_info, + network_isolation_key, origin, net_log)) { return ERR_INVALID_RESPONSE; + } handler->swap(tmp_handler); return OK; } diff --git a/chromium/net/http/http_auth_handler_basic.h b/chromium/net/http/http_auth_handler_basic.h index 6f4a00950a0..8042182b315 100644 --- a/chromium/net/http/http_auth_handler_basic.h +++ b/chromium/net/http/http_auth_handler_basic.h @@ -26,6 +26,7 @@ class NET_EXPORT_PRIVATE HttpAuthHandlerBasic : public HttpAuthHandler { int CreateAuthHandler(HttpAuthChallengeTokenizer* challenge, HttpAuth::Target target, const SSLInfo& ssl_info, + const NetworkIsolationKey& network_isolation_key, const GURL& origin, CreateReason reason, int digest_nonce_count, @@ -37,7 +38,8 @@ class NET_EXPORT_PRIVATE HttpAuthHandlerBasic : public HttpAuthHandler { private: // HttpAuthHandler bool Init(HttpAuthChallengeTokenizer* challenge, - const SSLInfo& ssl_info) override; + const SSLInfo& ssl_info, + const NetworkIsolationKey& network_isolation_key) override; int GenerateAuthTokenImpl(const AuthCredentials* credentials, const HttpRequestInfo* request, CompletionOnceCallback callback, diff --git a/chromium/net/http/http_auth_handler_basic_fuzzer.cc b/chromium/net/http/http_auth_handler_basic_fuzzer.cc index 5c1b7b24993..498452e96ab 100644 --- a/chromium/net/http/http_auth_handler_basic_fuzzer.cc +++ b/chromium/net/http/http_auth_handler_basic_fuzzer.cc @@ -5,6 +5,7 @@ #include <memory> #include <string> +#include "net/base/network_isolation_key.h" #include "net/dns/mock_host_resolver.h" #include "net/http/http_auth_handler.h" #include "net/http/http_auth_handler_basic.h" @@ -23,8 +24,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { std::unique_ptr<net::HttpAuthHandler> basic; net::HttpAuthHandlerBasic::Factory factory; - factory.CreateAuthHandlerFromString( - challenge, net::HttpAuth::AUTH_SERVER, null_ssl_info, origin, - net::NetLogWithSource(), host_resolver.get(), &basic); + factory.CreateAuthHandlerFromString(challenge, net::HttpAuth::AUTH_SERVER, + null_ssl_info, net::NetworkIsolationKey(), + origin, net::NetLogWithSource(), + host_resolver.get(), &basic); return 0; } diff --git a/chromium/net/http/http_auth_handler_basic_unittest.cc b/chromium/net/http/http_auth_handler_basic_unittest.cc index f2c80e641bd..9754d230684 100644 --- a/chromium/net/http/http_auth_handler_basic_unittest.cc +++ b/chromium/net/http/http_auth_handler_basic_unittest.cc @@ -11,6 +11,7 @@ #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "net/base/net_errors.h" +#include "net/base/network_isolation_key.h" #include "net/base/test_completion_callback.h" #include "net/dns/mock_host_resolver.h" #include "net/http/http_auth_challenge_tokenizer.h" @@ -47,8 +48,9 @@ TEST(HttpAuthHandlerBasicTest, GenerateAuthToken) { auto host_resolver = std::make_unique<MockHostResolver>(); std::unique_ptr<HttpAuthHandler> basic; EXPECT_EQ(OK, factory.CreateAuthHandlerFromString( - challenge, HttpAuth::AUTH_SERVER, null_ssl_info, origin, - NetLogWithSource(), host_resolver.get(), &basic)); + challenge, HttpAuth::AUTH_SERVER, null_ssl_info, + NetworkIsolationKey(), origin, NetLogWithSource(), + host_resolver.get(), &basic)); AuthCredentials credentials(base::ASCIIToUTF16(tests[i].username), base::ASCIIToUTF16(tests[i].password)); HttpRequestInfo request_info; @@ -103,7 +105,8 @@ TEST(HttpAuthHandlerBasicTest, HandleAnotherChallenge) { std::unique_ptr<HttpAuthHandler> basic; EXPECT_EQ(OK, factory.CreateAuthHandlerFromString( tests[0].challenge, HttpAuth::AUTH_SERVER, null_ssl_info, - origin, NetLogWithSource(), host_resolver.get(), &basic)); + NetworkIsolationKey(), origin, NetLogWithSource(), + host_resolver.get(), &basic)); for (size_t i = 0; i < base::size(tests); ++i) { std::string challenge(tests[i].challenge); @@ -204,8 +207,8 @@ TEST(HttpAuthHandlerBasicTest, InitFromChallenge) { auto host_resolver = std::make_unique<MockHostResolver>(); std::unique_ptr<HttpAuthHandler> basic; int rv = factory.CreateAuthHandlerFromString( - challenge, HttpAuth::AUTH_SERVER, null_ssl_info, origin, - NetLogWithSource(), host_resolver.get(), &basic); + challenge, HttpAuth::AUTH_SERVER, null_ssl_info, NetworkIsolationKey(), + origin, NetLogWithSource(), host_resolver.get(), &basic); EXPECT_EQ(tests[i].expected_rv, rv); if (rv == OK) EXPECT_EQ(tests[i].expected_realm, basic->realm()); diff --git a/chromium/net/http/http_auth_handler_digest.cc b/chromium/net/http/http_auth_handler_digest.cc index 64c2f6de57d..71289867729 100644 --- a/chromium/net/http/http_auth_handler_digest.cc +++ b/chromium/net/http/http_auth_handler_digest.cc @@ -92,6 +92,7 @@ int HttpAuthHandlerDigest::Factory::CreateAuthHandler( HttpAuthChallengeTokenizer* challenge, HttpAuth::Target target, const SSLInfo& ssl_info, + const NetworkIsolationKey& network_isolation_key, const GURL& origin, CreateReason reason, int digest_nonce_count, @@ -102,15 +103,18 @@ int HttpAuthHandlerDigest::Factory::CreateAuthHandler( // method and only constructing when valid. std::unique_ptr<HttpAuthHandler> tmp_handler( new HttpAuthHandlerDigest(digest_nonce_count, nonce_generator_.get())); - if (!tmp_handler->InitFromChallenge(challenge, target, ssl_info, origin, - net_log)) + if (!tmp_handler->InitFromChallenge(challenge, target, ssl_info, + network_isolation_key, origin, net_log)) { return ERR_INVALID_RESPONSE; + } handler->swap(tmp_handler); return OK; } -bool HttpAuthHandlerDigest::Init(HttpAuthChallengeTokenizer* challenge, - const SSLInfo& ssl_info) { +bool HttpAuthHandlerDigest::Init( + HttpAuthChallengeTokenizer* challenge, + const SSLInfo& ssl_info, + const NetworkIsolationKey& network_isolation_key) { return ParseChallenge(challenge); } diff --git a/chromium/net/http/http_auth_handler_digest.h b/chromium/net/http/http_auth_handler_digest.h index b4f847d721b..b8688ceb905 100644 --- a/chromium/net/http/http_auth_handler_digest.h +++ b/chromium/net/http/http_auth_handler_digest.h @@ -70,6 +70,7 @@ class NET_EXPORT_PRIVATE HttpAuthHandlerDigest : public HttpAuthHandler { int CreateAuthHandler(HttpAuthChallengeTokenizer* challenge, HttpAuth::Target target, const SSLInfo& ssl_info, + const NetworkIsolationKey& network_isolation_key, const GURL& origin, CreateReason reason, int digest_nonce_count, @@ -84,7 +85,8 @@ class NET_EXPORT_PRIVATE HttpAuthHandlerDigest : public HttpAuthHandler { private: // HttpAuthHandler bool Init(HttpAuthChallengeTokenizer* challenge, - const SSLInfo& ssl_info) override; + const SSLInfo& ssl_info, + const NetworkIsolationKey& network_isolation_key) override; int GenerateAuthTokenImpl(const AuthCredentials* credentials, const HttpRequestInfo* request, CompletionOnceCallback callback, diff --git a/chromium/net/http/http_auth_handler_digest_fuzzer.cc b/chromium/net/http/http_auth_handler_digest_fuzzer.cc index caaf1fd8c39..20e452bd11d 100644 --- a/chromium/net/http/http_auth_handler_digest_fuzzer.cc +++ b/chromium/net/http/http_auth_handler_digest_fuzzer.cc @@ -7,6 +7,7 @@ #include <memory> #include <string> +#include "net/base/network_isolation_key.h" #include "net/dns/mock_host_resolver.h" #include "net/http/http_auth_challenge_tokenizer.h" #include "net/http/http_auth_handler.h" @@ -28,9 +29,10 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { std::unique_ptr<net::HttpAuthHandler> handler; net::HttpAuthHandlerDigest::Factory factory; - factory.CreateAuthHandlerFromString( - challenge, net::HttpAuth::AUTH_SERVER, null_ssl_info, origin, - net::NetLogWithSource(), host_resolver.get(), &handler); + factory.CreateAuthHandlerFromString(challenge, net::HttpAuth::AUTH_SERVER, + null_ssl_info, net::NetworkIsolationKey(), + origin, net::NetLogWithSource(), + host_resolver.get(), &handler); if (handler) { auto followup = "Digest " + data_provider.ConsumeRemainingBytesAsString(); diff --git a/chromium/net/http/http_auth_handler_digest_unittest.cc b/chromium/net/http/http_auth_handler_digest_unittest.cc index f13ae108886..200508ba908 100644 --- a/chromium/net/http/http_auth_handler_digest_unittest.cc +++ b/chromium/net/http/http_auth_handler_digest_unittest.cc @@ -8,6 +8,7 @@ #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "net/base/net_errors.h" +#include "net/base/network_isolation_key.h" #include "net/base/test_completion_callback.h" #include "net/dns/mock_host_resolver.h" #include "net/http/http_auth_challenge_tokenizer.h" @@ -64,8 +65,9 @@ bool RespondToChallenge(HttpAuth::Target target, SSLInfo null_ssl_info; GURL url_origin(target == HttpAuth::AUTH_SERVER ? request_url : proxy_name); int rv_create = factory->CreateAuthHandlerFromString( - challenge, target, null_ssl_info, url_origin.GetOrigin(), - NetLogWithSource(), host_resolver.get(), &handler); + challenge, target, null_ssl_info, NetworkIsolationKey(), + url_origin.GetOrigin(), NetLogWithSource(), host_resolver.get(), + &handler); if (rv_create != OK || handler.get() == nullptr) { ADD_FAILURE() << "Unable to create auth handler."; return false; @@ -366,8 +368,9 @@ TEST(HttpAuthHandlerDigestTest, ParseChallenge) { auto host_resolver = std::make_unique<MockHostResolver>(); std::unique_ptr<HttpAuthHandler> handler; int rv = factory->CreateAuthHandlerFromString( - tests[i].challenge, HttpAuth::AUTH_SERVER, null_ssl_info, origin, - NetLogWithSource(), host_resolver.get(), &handler); + tests[i].challenge, HttpAuth::AUTH_SERVER, null_ssl_info, + NetworkIsolationKey(), origin, NetLogWithSource(), host_resolver.get(), + &handler); if (tests[i].parsed_success) { EXPECT_THAT(rv, IsOk()); } else { @@ -531,8 +534,9 @@ TEST(HttpAuthHandlerDigestTest, AssembleCredentials) { auto host_resolver = std::make_unique<MockHostResolver>(); std::unique_ptr<HttpAuthHandler> handler; int rv = factory->CreateAuthHandlerFromString( - tests[i].challenge, HttpAuth::AUTH_SERVER, null_ssl_info, origin, - NetLogWithSource(), host_resolver.get(), &handler); + tests[i].challenge, HttpAuth::AUTH_SERVER, null_ssl_info, + NetworkIsolationKey(), origin, NetLogWithSource(), host_resolver.get(), + &handler); EXPECT_THAT(rv, IsOk()); ASSERT_TRUE(handler != nullptr); @@ -561,8 +565,9 @@ TEST(HttpAuthHandlerDigest, HandleAnotherChallenge) { GURL origin("intranet.google.com"); SSLInfo null_ssl_info; int rv = factory->CreateAuthHandlerFromString( - default_challenge, HttpAuth::AUTH_SERVER, null_ssl_info, origin, - NetLogWithSource(), host_resolver.get(), &handler); + default_challenge, HttpAuth::AUTH_SERVER, null_ssl_info, + NetworkIsolationKey(), origin, NetLogWithSource(), host_resolver.get(), + &handler); EXPECT_THAT(rv, IsOk()); ASSERT_TRUE(handler.get() != nullptr); HttpAuthChallengeTokenizer tok_default(default_challenge.begin(), diff --git a/chromium/net/http/http_auth_handler_factory.cc b/chromium/net/http/http_auth_handler_factory.cc index 05a7a8c21a8..c5d50949623 100644 --- a/chromium/net/http/http_auth_handler_factory.cc +++ b/chromium/net/http/http_auth_handler_factory.cc @@ -32,18 +32,21 @@ int HttpAuthHandlerFactory::CreateAuthHandlerFromString( const std::string& challenge, HttpAuth::Target target, const SSLInfo& ssl_info, + const NetworkIsolationKey& network_isolation_key, const GURL& origin, const NetLogWithSource& net_log, HostResolver* host_resolver, std::unique_ptr<HttpAuthHandler>* handler) { HttpAuthChallengeTokenizer props(challenge.begin(), challenge.end()); - return CreateAuthHandler(&props, target, ssl_info, origin, CREATE_CHALLENGE, - 1, net_log, host_resolver, handler); + return CreateAuthHandler(&props, target, ssl_info, network_isolation_key, + origin, CREATE_CHALLENGE, 1, net_log, host_resolver, + handler); } int HttpAuthHandlerFactory::CreatePreemptiveAuthHandlerFromString( const std::string& challenge, HttpAuth::Target target, + const NetworkIsolationKey& network_isolation_key, const GURL& origin, int digest_nonce_count, const NetLogWithSource& net_log, @@ -51,9 +54,9 @@ int HttpAuthHandlerFactory::CreatePreemptiveAuthHandlerFromString( std::unique_ptr<HttpAuthHandler>* handler) { HttpAuthChallengeTokenizer props(challenge.begin(), challenge.end()); SSLInfo null_ssl_info; - return CreateAuthHandler(&props, target, null_ssl_info, origin, - CREATE_PREEMPTIVE, digest_nonce_count, net_log, - host_resolver, handler); + return CreateAuthHandler(&props, target, null_ssl_info, network_isolation_key, + origin, CREATE_PREEMPTIVE, digest_nonce_count, + net_log, host_resolver, handler); } namespace { @@ -194,6 +197,7 @@ int HttpAuthHandlerRegistryFactory::CreateAuthHandler( HttpAuthChallengeTokenizer* challenge, HttpAuth::Target target, const SSLInfo& ssl_info, + const NetworkIsolationKey& network_isolation_key, const GURL& origin, CreateReason reason, int digest_nonce_count, @@ -211,9 +215,9 @@ int HttpAuthHandlerRegistryFactory::CreateAuthHandler( return ERR_UNSUPPORTED_AUTH_SCHEME; } DCHECK(it->second); - return it->second->CreateAuthHandler(challenge, target, ssl_info, origin, - reason, digest_nonce_count, net_log, - host_resolver, handler); + return it->second->CreateAuthHandler( + challenge, target, ssl_info, network_isolation_key, origin, reason, + digest_nonce_count, net_log, host_resolver, handler); } } // namespace net diff --git a/chromium/net/http/http_auth_handler_factory.h b/chromium/net/http/http_auth_handler_factory.h index c38a368fe3d..aeba0b8429f 100644 --- a/chromium/net/http/http_auth_handler_factory.h +++ b/chromium/net/http/http_auth_handler_factory.h @@ -28,6 +28,7 @@ class HttpAuthHandler; class HttpAuthHandlerRegistryFactory; class HttpAuthPreferences; class NetLogWithSource; +class NetworkIsolationKey; // An HttpAuthHandlerFactory is used to create HttpAuthHandler objects. // The HttpAuthHandlerFactory object _must_ outlive any of the HttpAuthHandler @@ -90,28 +91,32 @@ class NET_EXPORT HttpAuthHandlerFactory { // scheme is used and the factory was created with // |negotiate_disable_cname_lookup| false, |host_resolver| must not be null, // and it must remain valid for the lifetime of the created |handler|. - virtual int CreateAuthHandler(HttpAuthChallengeTokenizer* challenge, - HttpAuth::Target target, - const SSLInfo& ssl_info, - const GURL& origin, - CreateReason create_reason, - int digest_nonce_count, - const NetLogWithSource& net_log, - HostResolver* host_resolver, - std::unique_ptr<HttpAuthHandler>* handler) = 0; + virtual int CreateAuthHandler( + HttpAuthChallengeTokenizer* challenge, + HttpAuth::Target target, + const SSLInfo& ssl_info, + const NetworkIsolationKey& network_isolation_key, + const GURL& origin, + CreateReason create_reason, + int digest_nonce_count, + const NetLogWithSource& net_log, + HostResolver* host_resolver, + std::unique_ptr<HttpAuthHandler>* handler) = 0; // Creates an HTTP authentication handler based on the authentication // challenge string |challenge|. // This is a convenience function which creates a ChallengeTokenizer for // |challenge| and calls |CreateAuthHandler|. See |CreateAuthHandler| for // more details on return values. - int CreateAuthHandlerFromString(const std::string& challenge, - HttpAuth::Target target, - const SSLInfo& ssl_info, - const GURL& origin, - const NetLogWithSource& net_log, - HostResolver* host_resolver, - std::unique_ptr<HttpAuthHandler>* handler); + int CreateAuthHandlerFromString( + const std::string& challenge, + HttpAuth::Target target, + const SSLInfo& ssl_info, + const NetworkIsolationKey& network_isolation_key, + const GURL& origin, + const NetLogWithSource& net_log, + HostResolver* host_resolver, + std::unique_ptr<HttpAuthHandler>* handler); // Creates an HTTP authentication handler based on the authentication // challenge string |challenge|. @@ -121,6 +126,7 @@ class NET_EXPORT HttpAuthHandlerFactory { int CreatePreemptiveAuthHandlerFromString( const std::string& challenge, HttpAuth::Target target, + const NetworkIsolationKey& network_isolation_key, const GURL& origin, int digest_nonce_count, const NetLogWithSource& net_log, @@ -219,6 +225,7 @@ class NET_EXPORT HttpAuthHandlerRegistryFactory int CreateAuthHandler(HttpAuthChallengeTokenizer* challenge, HttpAuth::Target target, const SSLInfo& ssl_info, + const NetworkIsolationKey& network_isolation_key, const GURL& origin, CreateReason reason, int digest_nonce_count, diff --git a/chromium/net/http/http_auth_handler_factory_unittest.cc b/chromium/net/http/http_auth_handler_factory_unittest.cc index 0a99c6fec8c..7b1d0f3f3bc 100644 --- a/chromium/net/http/http_auth_handler_factory_unittest.cc +++ b/chromium/net/http/http_auth_handler_factory_unittest.cc @@ -8,6 +8,7 @@ #include "build/build_config.h" #include "net/base/net_errors.h" +#include "net/base/network_isolation_key.h" #include "net/dns/host_resolver.h" #include "net/dns/mock_host_resolver.h" #include "net/http/http_auth_handler.h" @@ -37,6 +38,7 @@ class MockHttpAuthHandlerFactory : public HttpAuthHandlerFactory { int CreateAuthHandler(HttpAuthChallengeTokenizer* challenge, HttpAuth::Target target, const SSLInfo& ssl_info, + const NetworkIsolationKey& network_isolation_key, const GURL& origin, CreateReason reason, int nonce_count, @@ -73,49 +75,57 @@ TEST(HttpAuthHandlerFactoryTest, RegistryFactory) { std::unique_ptr<HttpAuthHandler> handler; // No schemes should be supported in the beginning. - EXPECT_EQ(ERR_UNSUPPORTED_AUTH_SCHEME, - registry_factory.CreateAuthHandlerFromString( - "Basic", HttpAuth::AUTH_SERVER, null_ssl_info, gurl, - NetLogWithSource(), host_resovler.get(), &handler)); + EXPECT_EQ( + ERR_UNSUPPORTED_AUTH_SCHEME, + registry_factory.CreateAuthHandlerFromString( + "Basic", HttpAuth::AUTH_SERVER, null_ssl_info, NetworkIsolationKey(), + gurl, NetLogWithSource(), host_resovler.get(), &handler)); // Test what happens with a single scheme. registry_factory.RegisterSchemeFactory("Basic", mock_factory_basic); - EXPECT_EQ(kBasicReturnCode, - registry_factory.CreateAuthHandlerFromString( - "Basic", HttpAuth::AUTH_SERVER, null_ssl_info, gurl, - NetLogWithSource(), host_resovler.get(), &handler)); - EXPECT_EQ(ERR_UNSUPPORTED_AUTH_SCHEME, - registry_factory.CreateAuthHandlerFromString( - "Digest", HttpAuth::AUTH_SERVER, null_ssl_info, gurl, - NetLogWithSource(), host_resovler.get(), &handler)); + EXPECT_EQ( + kBasicReturnCode, + registry_factory.CreateAuthHandlerFromString( + "Basic", HttpAuth::AUTH_SERVER, null_ssl_info, NetworkIsolationKey(), + gurl, NetLogWithSource(), host_resovler.get(), &handler)); + EXPECT_EQ( + ERR_UNSUPPORTED_AUTH_SCHEME, + registry_factory.CreateAuthHandlerFromString( + "Digest", HttpAuth::AUTH_SERVER, null_ssl_info, NetworkIsolationKey(), + gurl, NetLogWithSource(), host_resovler.get(), &handler)); // Test multiple schemes registry_factory.RegisterSchemeFactory("Digest", mock_factory_digest); - EXPECT_EQ(kBasicReturnCode, - registry_factory.CreateAuthHandlerFromString( - "Basic", HttpAuth::AUTH_SERVER, null_ssl_info, gurl, - NetLogWithSource(), host_resovler.get(), &handler)); - EXPECT_EQ(kDigestReturnCode, - registry_factory.CreateAuthHandlerFromString( - "Digest", HttpAuth::AUTH_SERVER, null_ssl_info, gurl, - NetLogWithSource(), host_resovler.get(), &handler)); + EXPECT_EQ( + kBasicReturnCode, + registry_factory.CreateAuthHandlerFromString( + "Basic", HttpAuth::AUTH_SERVER, null_ssl_info, NetworkIsolationKey(), + gurl, NetLogWithSource(), host_resovler.get(), &handler)); + EXPECT_EQ( + kDigestReturnCode, + registry_factory.CreateAuthHandlerFromString( + "Digest", HttpAuth::AUTH_SERVER, null_ssl_info, NetworkIsolationKey(), + gurl, NetLogWithSource(), host_resovler.get(), &handler)); // Test case-insensitivity - EXPECT_EQ(kBasicReturnCode, - registry_factory.CreateAuthHandlerFromString( - "basic", HttpAuth::AUTH_SERVER, null_ssl_info, gurl, - NetLogWithSource(), host_resovler.get(), &handler)); + EXPECT_EQ( + kBasicReturnCode, + registry_factory.CreateAuthHandlerFromString( + "basic", HttpAuth::AUTH_SERVER, null_ssl_info, NetworkIsolationKey(), + gurl, NetLogWithSource(), host_resovler.get(), &handler)); // Test replacement of existing auth scheme registry_factory.RegisterSchemeFactory("Digest", mock_factory_digest_replace); - EXPECT_EQ(kBasicReturnCode, - registry_factory.CreateAuthHandlerFromString( - "Basic", HttpAuth::AUTH_SERVER, null_ssl_info, gurl, - NetLogWithSource(), host_resovler.get(), &handler)); - EXPECT_EQ(kDigestReturnCodeReplace, - registry_factory.CreateAuthHandlerFromString( - "Digest", HttpAuth::AUTH_SERVER, null_ssl_info, gurl, - NetLogWithSource(), host_resovler.get(), &handler)); + EXPECT_EQ( + kBasicReturnCode, + registry_factory.CreateAuthHandlerFromString( + "Basic", HttpAuth::AUTH_SERVER, null_ssl_info, NetworkIsolationKey(), + gurl, NetLogWithSource(), host_resovler.get(), &handler)); + EXPECT_EQ( + kDigestReturnCodeReplace, + registry_factory.CreateAuthHandlerFromString( + "Digest", HttpAuth::AUTH_SERVER, null_ssl_info, NetworkIsolationKey(), + gurl, NetLogWithSource(), host_resovler.get(), &handler)); } TEST(HttpAuthHandlerFactoryTest, DefaultFactory) { @@ -132,7 +142,8 @@ TEST(HttpAuthHandlerFactoryTest, DefaultFactory) { std::unique_ptr<HttpAuthHandler> handler; int rv = http_auth_handler_factory->CreateAuthHandlerFromString( "Basic realm=\"FooBar\"", HttpAuth::AUTH_SERVER, null_ssl_info, - server_origin, NetLogWithSource(), host_resolver.get(), &handler); + NetworkIsolationKey(), server_origin, NetLogWithSource(), + host_resolver.get(), &handler); EXPECT_THAT(rv, IsOk()); ASSERT_FALSE(handler.get() == nullptr); EXPECT_EQ(HttpAuth::AUTH_SCHEME_BASIC, handler->auth_scheme()); @@ -145,7 +156,8 @@ TEST(HttpAuthHandlerFactoryTest, DefaultFactory) { std::unique_ptr<HttpAuthHandler> handler; int rv = http_auth_handler_factory->CreateAuthHandlerFromString( "UNSUPPORTED realm=\"FooBar\"", HttpAuth::AUTH_SERVER, null_ssl_info, - server_origin, NetLogWithSource(), host_resolver.get(), &handler); + NetworkIsolationKey(), server_origin, NetLogWithSource(), + host_resolver.get(), &handler); EXPECT_THAT(rv, IsError(ERR_UNSUPPORTED_AUTH_SCHEME)); EXPECT_TRUE(handler.get() == nullptr); } @@ -153,8 +165,8 @@ TEST(HttpAuthHandlerFactoryTest, DefaultFactory) { std::unique_ptr<HttpAuthHandler> handler; int rv = http_auth_handler_factory->CreateAuthHandlerFromString( "Digest realm=\"FooBar\", nonce=\"xyz\"", HttpAuth::AUTH_PROXY, - null_ssl_info, proxy_origin, NetLogWithSource(), host_resolver.get(), - &handler); + null_ssl_info, NetworkIsolationKey(), proxy_origin, NetLogWithSource(), + host_resolver.get(), &handler); EXPECT_THAT(rv, IsOk()); ASSERT_FALSE(handler.get() == nullptr); EXPECT_EQ(HttpAuth::AUTH_SCHEME_DIGEST, handler->auth_scheme()); @@ -166,8 +178,8 @@ TEST(HttpAuthHandlerFactoryTest, DefaultFactory) { { std::unique_ptr<HttpAuthHandler> handler; int rv = http_auth_handler_factory->CreateAuthHandlerFromString( - "NTLM", HttpAuth::AUTH_SERVER, null_ssl_info, server_origin, - NetLogWithSource(), host_resolver.get(), &handler); + "NTLM", HttpAuth::AUTH_SERVER, null_ssl_info, NetworkIsolationKey(), + server_origin, NetLogWithSource(), host_resolver.get(), &handler); EXPECT_THAT(rv, IsOk()); ASSERT_FALSE(handler.get() == nullptr); EXPECT_EQ(HttpAuth::AUTH_SCHEME_NTLM, handler->auth_scheme()); @@ -179,8 +191,9 @@ TEST(HttpAuthHandlerFactoryTest, DefaultFactory) { { std::unique_ptr<HttpAuthHandler> handler; int rv = http_auth_handler_factory->CreateAuthHandlerFromString( - "Negotiate", HttpAuth::AUTH_SERVER, null_ssl_info, server_origin, - NetLogWithSource(), host_resolver.get(), &handler); + "Negotiate", HttpAuth::AUTH_SERVER, null_ssl_info, + NetworkIsolationKey(), server_origin, NetLogWithSource(), + host_resolver.get(), &handler); // Note the default factory doesn't support Kerberos on Android #if BUILDFLAG(USE_KERBEROS) && !defined(OS_ANDROID) EXPECT_THAT(rv, IsOk()); diff --git a/chromium/net/http/http_auth_handler_mock.cc b/chromium/net/http/http_auth_handler_mock.cc index dd3000d5b65..951b0d49e12 100644 --- a/chromium/net/http/http_auth_handler_mock.cc +++ b/chromium/net/http/http_auth_handler_mock.cc @@ -70,8 +70,10 @@ bool HttpAuthHandlerMock::AllowsExplicitCredentials() { return allows_explicit_credentials_; } -bool HttpAuthHandlerMock::Init(HttpAuthChallengeTokenizer* challenge, - const SSLInfo& ssl_info) { +bool HttpAuthHandlerMock::Init( + HttpAuthChallengeTokenizer* challenge, + const SSLInfo& ssl_info, + const NetworkIsolationKey& network_isolation_key) { EXPECT_EQ(State::WAIT_FOR_INIT, state_); state_ = State::WAIT_FOR_GENERATE_AUTH_TOKEN; auth_scheme_ = HttpAuth::AUTH_SCHEME_MOCK; @@ -161,6 +163,7 @@ int HttpAuthHandlerMock::Factory::CreateAuthHandler( HttpAuthChallengeTokenizer* challenge, HttpAuth::Target target, const SSLInfo& ssl_info, + const NetworkIsolationKey& network_isolation_key, const GURL& origin, CreateReason reason, int nonce_count, @@ -174,9 +177,10 @@ int HttpAuthHandlerMock::Factory::CreateAuthHandler( std::vector<std::unique_ptr<HttpAuthHandler>>& handlers = handlers_[target]; handlers.erase(handlers.begin()); if (do_init_from_challenge_ && - !tmp_handler->InitFromChallenge(challenge, target, ssl_info, origin, - net_log)) + !tmp_handler->InitFromChallenge(challenge, target, ssl_info, + network_isolation_key, origin, net_log)) { return ERR_INVALID_RESPONSE; + } handler->swap(tmp_handler); return OK; } diff --git a/chromium/net/http/http_auth_handler_mock.h b/chromium/net/http/http_auth_handler_mock.h index 5e7e32c82f1..e44388bcf83 100644 --- a/chromium/net/http/http_auth_handler_mock.h +++ b/chromium/net/http/http_auth_handler_mock.h @@ -46,6 +46,7 @@ class HttpAuthHandlerMock : public HttpAuthHandler { int CreateAuthHandler(HttpAuthChallengeTokenizer* challenge, HttpAuth::Target target, const SSLInfo& ssl_info, + const NetworkIsolationKey& network_isolation_key, const GURL& origin, CreateReason reason, int nonce_count, @@ -90,7 +91,8 @@ class HttpAuthHandlerMock : public HttpAuthHandler { bool AllowsDefaultCredentials() override; bool AllowsExplicitCredentials() override; bool Init(HttpAuthChallengeTokenizer* challenge, - const SSLInfo& ssl_info) override; + const SSLInfo& ssl_info, + const NetworkIsolationKey& network_isolation_key) override; int GenerateAuthTokenImpl(const AuthCredentials* credentials, const HttpRequestInfo* request, CompletionOnceCallback callback, diff --git a/chromium/net/http/http_auth_handler_negotiate.cc b/chromium/net/http/http_auth_handler_negotiate.cc index e6efffe07e7..281e62f6185 100644 --- a/chromium/net/http/http_auth_handler_negotiate.cc +++ b/chromium/net/http/http_auth_handler_negotiate.cc @@ -86,6 +86,7 @@ int HttpAuthHandlerNegotiate::Factory::CreateAuthHandler( HttpAuthChallengeTokenizer* challenge, HttpAuth::Target target, const SSLInfo& ssl_info, + const NetworkIsolationKey& network_isolation_key, const GURL& origin, CreateReason reason, int digest_nonce_count, @@ -131,9 +132,10 @@ int HttpAuthHandlerNegotiate::Factory::CreateAuthHandler( negotiate_auth_system_factory_), http_auth_preferences(), host_resolver)); #endif - if (!tmp_handler->InitFromChallenge(challenge, target, ssl_info, origin, - net_log)) + if (!tmp_handler->InitFromChallenge(challenge, target, ssl_info, + network_isolation_key, origin, net_log)) { return ERR_INVALID_RESPONSE; + } handler->swap(tmp_handler); return OK; } @@ -171,8 +173,11 @@ bool HttpAuthHandlerNegotiate::AllowsExplicitCredentials() { // The Negotiate challenge header looks like: // WWW-Authenticate: NEGOTIATE auth-data -bool HttpAuthHandlerNegotiate::Init(HttpAuthChallengeTokenizer* challenge, - const SSLInfo& ssl_info) { +bool HttpAuthHandlerNegotiate::Init( + HttpAuthChallengeTokenizer* challenge, + const SSLInfo& ssl_info, + const NetworkIsolationKey& network_isolation_key) { + network_isolation_key_ = network_isolation_key; #if defined(OS_POSIX) if (!auth_system_->Init(net_log())) { VLOG(1) << "can't initialize GSSAPI library"; @@ -341,8 +346,9 @@ int HttpAuthHandlerNegotiate::DoResolveCanonicalName() { // TODO(cbentzel): Add reverse DNS lookup for numeric addresses. HostResolver::ResolveHostParameters parameters; parameters.include_canonical_name = true; - resolve_host_request_ = resolver_->CreateRequest( - HostPortPair(origin_.host(), 0), net_log(), parameters); + resolve_host_request_ = + resolver_->CreateRequest(HostPortPair(origin_.host(), 0), + network_isolation_key_, net_log(), parameters); return resolve_host_request_->Start(base::BindOnce( &HttpAuthHandlerNegotiate::OnIOComplete, base::Unretained(this))); } diff --git a/chromium/net/http/http_auth_handler_negotiate.h b/chromium/net/http/http_auth_handler_negotiate.h index e9c98d1c1ff..651e4a61522 100644 --- a/chromium/net/http/http_auth_handler_negotiate.h +++ b/chromium/net/http/http_auth_handler_negotiate.h @@ -12,6 +12,7 @@ #include "build/build_config.h" #include "net/base/completion_once_callback.h" #include "net/base/net_export.h" +#include "net/base/network_isolation_key.h" #include "net/dns/host_resolver.h" #include "net/http/http_auth_handler.h" #include "net/http/http_auth_handler_factory.h" @@ -63,6 +64,7 @@ class NET_EXPORT_PRIVATE HttpAuthHandlerNegotiate : public HttpAuthHandler { int CreateAuthHandler(HttpAuthChallengeTokenizer* challenge, HttpAuth::Target target, const SSLInfo& ssl_info, + const NetworkIsolationKey& network_isolation_key, const GURL& origin, CreateReason reason, int digest_nonce_count, @@ -94,7 +96,8 @@ class NET_EXPORT_PRIVATE HttpAuthHandlerNegotiate : public HttpAuthHandler { protected: // HttpAuthHandler bool Init(HttpAuthChallengeTokenizer* challenge, - const SSLInfo& ssl_info) override; + const SSLInfo& ssl_info, + const NetworkIsolationKey& network_isolation_key) override; int GenerateAuthTokenImpl(const AuthCredentials* credentials, const HttpRequestInfo* request, CompletionOnceCallback callback, @@ -126,6 +129,8 @@ class NET_EXPORT_PRIVATE HttpAuthHandlerNegotiate : public HttpAuthHandler { std::unique_ptr<HttpAuthMechanism> auth_system_; HostResolver* const resolver_; + NetworkIsolationKey network_isolation_key_; + // Members which are needed for DNS lookup + SPN. std::unique_ptr<HostResolver::ResolveHostRequest> resolve_host_request_; diff --git a/chromium/net/http/http_auth_handler_negotiate_unittest.cc b/chromium/net/http/http_auth_handler_negotiate_unittest.cc index a94c5e40dd5..40f80012da0 100644 --- a/chromium/net/http/http_auth_handler_negotiate_unittest.cc +++ b/chromium/net/http/http_auth_handler_negotiate_unittest.cc @@ -12,7 +12,9 @@ #include "base/stl_util.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" +#include "base/test/scoped_feature_list.h" #include "build/build_config.h" +#include "net/base/features.h" #include "net/base/net_errors.h" #include "net/base/test_completion_callback.h" #include "net/dns/mock_host_resolver.h" @@ -53,12 +55,15 @@ class HttpAuthHandlerNegotiateTest : public PlatformTest, public WithTaskEnvironment { public: void SetUp() override { + scoped_feature_list_.InitAndEnableFeature( + features::kSplitHostCacheByNetworkIsolationKey); + network_isolation_key_ = NetworkIsolationKey::CreateTransient(); #if defined(OS_WIN) auth_library_ = new MockAuthLibrary(const_cast<wchar_t*>(NEGOSSP_NAME)); #else auth_library_ = new MockAuthLibrary(); #endif - resolver_.reset(new MockHostResolver()); + resolver_ = std::make_unique<MockCachingHostResolver>(); resolver_->rules_map()[HostResolverSource::ANY]->AddIPLiteralRule( "alias", "10.0.0.2", "canonical.example.com"); @@ -227,8 +232,9 @@ class HttpAuthHandlerNegotiateTest : public PlatformTest, std::unique_ptr<HttpAuthHandler> generic_handler; SSLInfo null_ssl_info; int rv = factory_->CreateAuthHandlerFromString( - "Negotiate", HttpAuth::AUTH_SERVER, null_ssl_info, gurl, - NetLogWithSource(), resolver_.get(), &generic_handler); + "Negotiate", HttpAuth::AUTH_SERVER, null_ssl_info, + network_isolation_key(), gurl, NetLogWithSource(), resolver_.get(), + &generic_handler); if (rv != OK) return rv; HttpAuthHandlerNegotiate* negotiate_handler = @@ -238,12 +244,20 @@ class HttpAuthHandlerNegotiateTest : public PlatformTest, } MockAuthLibrary* AuthLibrary() { return auth_library_; } - MockHostResolver* resolver() { return resolver_.get(); } + MockCachingHostResolver* resolver() { return resolver_.get(); } MockAllowHttpAuthPreferences* http_auth_preferences() { return http_auth_preferences_.get(); } + const NetworkIsolationKey& network_isolation_key() const { + return network_isolation_key_; + } + private: + base::test::ScopedFeatureList scoped_feature_list_; + + NetworkIsolationKey network_isolation_key_; + #if defined(OS_WIN) std::unique_ptr<SecPkgInfoW> security_package_; #endif @@ -251,7 +265,7 @@ class HttpAuthHandlerNegotiateTest : public PlatformTest, // can't be a scoped pointer to it since the tests need access when they set // up the mocks after passing ownership. MockAuthLibrary* auth_library_; - std::unique_ptr<MockHostResolver> resolver_; + std::unique_ptr<MockCachingHostResolver> resolver_; std::unique_ptr<MockAllowHttpAuthPreferences> http_auth_preferences_; std::unique_ptr<HttpAuthHandlerNegotiate::Factory> factory_; }; @@ -314,8 +328,8 @@ TEST_F(HttpAuthHandlerNegotiateTest, DisableCnameNonstandardPort) { TEST_F(HttpAuthHandlerNegotiateTest, CnameSync) { SetupMocks(AuthLibrary()); std::unique_ptr<HttpAuthHandlerNegotiate> auth_handler; - EXPECT_EQ(OK, CreateHandler( - false, false, true, "http://alias:500", &auth_handler)); + const std::string url_string = "http://alias:500"; + EXPECT_EQ(OK, CreateHandler(false, false, true, url_string, &auth_handler)); ASSERT_TRUE(auth_handler.get() != nullptr); TestCompletionCallback callback; HttpRequestInfo request_info; @@ -327,13 +341,35 @@ TEST_F(HttpAuthHandlerNegotiateTest, CnameSync) { #else EXPECT_EQ("HTTP@canonical.example.com", auth_handler->spn_for_testing()); #endif + + // Make sure a cache-only lookup with the wrong NetworkIsolationKey (an empty + // one) fails, to make sure the right NetworkIsolationKey was used. + HostPortPair host_port_pair = HostPortPair::FromURL(GURL(url_string)); + HostResolver::ResolveHostParameters resolve_params; + resolve_params.include_canonical_name = true; + resolve_params.source = HostResolverSource::LOCAL_ONLY; + std::unique_ptr<HostResolver::ResolveHostRequest> host_request1 = + resolver()->CreateRequest(host_port_pair, NetworkIsolationKey(), + NetLogWithSource(), resolve_params); + TestCompletionCallback callback2; + int result = host_request1->Start(callback2.callback()); + EXPECT_EQ(ERR_NAME_NOT_RESOLVED, callback2.GetResult(result)); + + // Make sure a cache-only lookup with the same NetworkIsolationKey succeeds, + // to make sure the right NetworkIsolationKey was used. + std::unique_ptr<HostResolver::ResolveHostRequest> host_request2 = + resolver()->CreateRequest(host_port_pair, network_isolation_key(), + NetLogWithSource(), resolve_params); + TestCompletionCallback callback3; + result = host_request2->Start(callback3.callback()); + EXPECT_EQ(OK, callback3.GetResult(result)); } TEST_F(HttpAuthHandlerNegotiateTest, CnameAsync) { SetupMocks(AuthLibrary()); std::unique_ptr<HttpAuthHandlerNegotiate> auth_handler; - EXPECT_EQ(OK, CreateHandler( - false, false, false, "http://alias:500", &auth_handler)); + const std::string url_string = "http://alias:500"; + EXPECT_EQ(OK, CreateHandler(false, false, false, url_string, &auth_handler)); ASSERT_TRUE(auth_handler.get() != nullptr); TestCompletionCallback callback; HttpRequestInfo request_info; @@ -347,6 +383,28 @@ TEST_F(HttpAuthHandlerNegotiateTest, CnameAsync) { #else EXPECT_EQ("HTTP@canonical.example.com", auth_handler->spn_for_testing()); #endif + + // Make sure a cache-only lookup with the wrong NetworkIsolationKey (an empty + // one) fails, to make sure the right NetworkIsolationKey was used. + HostPortPair host_port_pair = HostPortPair::FromURL(GURL(url_string)); + HostResolver::ResolveHostParameters resolve_params; + resolve_params.include_canonical_name = true; + resolve_params.source = HostResolverSource::LOCAL_ONLY; + std::unique_ptr<HostResolver::ResolveHostRequest> host_request1 = + resolver()->CreateRequest(host_port_pair, NetworkIsolationKey(), + NetLogWithSource(), resolve_params); + TestCompletionCallback callback2; + int result = host_request1->Start(callback2.callback()); + EXPECT_EQ(ERR_NAME_NOT_RESOLVED, callback2.GetResult(result)); + + // Make sure a cache-only lookup with the same NetworkIsolationKey succeeds, + // to make sure the right NetworkIsolationKey was used. + std::unique_ptr<HostResolver::ResolveHostRequest> host_request2 = + resolver()->CreateRequest(host_port_pair, network_isolation_key(), + NetLogWithSource(), resolve_params); + TestCompletionCallback callback3; + result = host_request2->Start(callback3.callback()); + EXPECT_EQ(OK, callback3.GetResult(result)); } #if defined(OS_POSIX) @@ -397,8 +455,8 @@ TEST_F(HttpAuthHandlerNegotiateTest, MissingGSSAPI) { GURL gurl("http://www.example.com"); std::unique_ptr<HttpAuthHandler> generic_handler; int rv = negotiate_factory->CreateAuthHandlerFromString( - "Negotiate", HttpAuth::AUTH_SERVER, SSLInfo(), gurl, NetLogWithSource(), - resolver(), &generic_handler); + "Negotiate", HttpAuth::AUTH_SERVER, SSLInfo(), NetworkIsolationKey(), + gurl, NetLogWithSource(), resolver(), &generic_handler); EXPECT_THAT(rv, IsError(ERR_UNSUPPORTED_AUTH_SCHEME)); EXPECT_TRUE(generic_handler.get() == nullptr); } @@ -470,8 +528,9 @@ TEST_F(HttpAuthHandlerNegotiateTest, OverrideAuthSystem) { GURL gurl("http://www.example.com"); std::unique_ptr<HttpAuthHandler> handler; EXPECT_EQ(OK, negotiate_factory->CreateAuthHandlerFromString( - "Negotiate", HttpAuth::AUTH_SERVER, SSLInfo(), gurl, - NetLogWithSource(), resolver(), &handler)); + "Negotiate", HttpAuth::AUTH_SERVER, SSLInfo(), + NetworkIsolationKey(), gurl, NetLogWithSource(), resolver(), + &handler)); EXPECT_TRUE(handler); TestCompletionCallback callback; diff --git a/chromium/net/http/http_auth_handler_ntlm.cc b/chromium/net/http/http_auth_handler_ntlm.cc index 1433411a8dd..5ea166db493 100644 --- a/chromium/net/http/http_auth_handler_ntlm.cc +++ b/chromium/net/http/http_auth_handler_ntlm.cc @@ -15,8 +15,10 @@ HttpAuthHandlerNTLM::Factory::Factory() = default; HttpAuthHandlerNTLM::Factory::~Factory() = default; -bool HttpAuthHandlerNTLM::Init(HttpAuthChallengeTokenizer* tok, - const SSLInfo& ssl_info) { +bool HttpAuthHandlerNTLM::Init( + HttpAuthChallengeTokenizer* tok, + const SSLInfo& ssl_info, + const NetworkIsolationKey& network_isolation_key) { auth_scheme_ = HttpAuth::AUTH_SCHEME_NTLM; score_ = 3; properties_ = ENCRYPTS_IDENTITY | IS_CONNECTION_BASED; diff --git a/chromium/net/http/http_auth_handler_ntlm.h b/chromium/net/http/http_auth_handler_ntlm.h index 34ce35e1290..ce7ed585507 100644 --- a/chromium/net/http/http_auth_handler_ntlm.h +++ b/chromium/net/http/http_auth_handler_ntlm.h @@ -51,6 +51,7 @@ class NET_EXPORT_PRIVATE HttpAuthHandlerNTLM : public HttpAuthHandler { int CreateAuthHandler(HttpAuthChallengeTokenizer* challenge, HttpAuth::Target target, const SSLInfo& ssl_info, + const NetworkIsolationKey& network_isolation_key, const GURL& origin, CreateReason reason, int digest_nonce_count, @@ -90,7 +91,9 @@ class NET_EXPORT_PRIVATE HttpAuthHandlerNTLM : public HttpAuthHandler { protected: // HttpAuthHandler - bool Init(HttpAuthChallengeTokenizer* tok, const SSLInfo& ssl_info) override; + bool Init(HttpAuthChallengeTokenizer* tok, + const SSLInfo& ssl_info, + const NetworkIsolationKey& network_isolation_key) override; int GenerateAuthTokenImpl(const AuthCredentials* credentials, const HttpRequestInfo* request, CompletionOnceCallback callback, diff --git a/chromium/net/http/http_auth_handler_ntlm_portable.cc b/chromium/net/http/http_auth_handler_ntlm_portable.cc index 484565d97c8..5f932f99826 100644 --- a/chromium/net/http/http_auth_handler_ntlm_portable.cc +++ b/chromium/net/http/http_auth_handler_ntlm_portable.cc @@ -15,6 +15,7 @@ int HttpAuthHandlerNTLM::Factory::CreateAuthHandler( HttpAuthChallengeTokenizer* challenge, HttpAuth::Target target, const SSLInfo& ssl_info, + const NetworkIsolationKey& network_isolation_key, const GURL& origin, CreateReason reason, int digest_nonce_count, @@ -29,8 +30,8 @@ int HttpAuthHandlerNTLM::Factory::CreateAuthHandler( // of NTLM. std::unique_ptr<HttpAuthHandler> tmp_handler( new HttpAuthHandlerNTLM(http_auth_preferences())); - if (!tmp_handler->InitFromChallenge(challenge, target, ssl_info, origin, - net_log)) + if (!tmp_handler->InitFromChallenge(challenge, target, ssl_info, + network_isolation_key, origin, net_log)) return ERR_INVALID_RESPONSE; handler->swap(tmp_handler); return OK; diff --git a/chromium/net/http/http_auth_handler_ntlm_portable_unittest.cc b/chromium/net/http/http_auth_handler_ntlm_portable_unittest.cc index 009e0fd7e03..473134ec2eb 100644 --- a/chromium/net/http/http_auth_handler_ntlm_portable_unittest.cc +++ b/chromium/net/http/http_auth_handler_ntlm_portable_unittest.cc @@ -10,6 +10,7 @@ #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" +#include "net/base/network_isolation_key.h" #include "net/base/test_completion_callback.h" #include "net/dns/mock_host_resolver.h" #include "net/http/http_auth_challenge_tokenizer.h" @@ -52,8 +53,8 @@ class HttpAuthHandlerNtlmPortableTest : public PlatformTest { SSLInfo null_ssl_info; return factory_->CreateAuthHandlerFromString( - "NTLM", HttpAuth::AUTH_SERVER, null_ssl_info, gurl, NetLogWithSource(), - nullptr, &auth_handler_); + "NTLM", HttpAuth::AUTH_SERVER, null_ssl_info, NetworkIsolationKey(), + gurl, NetLogWithSource(), nullptr, &auth_handler_); } std::string CreateNtlmAuthHeader(base::span<const uint8_t> buffer) { diff --git a/chromium/net/http/http_auth_handler_ntlm_win.cc b/chromium/net/http/http_auth_handler_ntlm_win.cc index 26b48a7a10c..0fdae59ace3 100644 --- a/chromium/net/http/http_auth_handler_ntlm_win.cc +++ b/chromium/net/http/http_auth_handler_ntlm_win.cc @@ -22,6 +22,7 @@ int HttpAuthHandlerNTLM::Factory::CreateAuthHandler( HttpAuthChallengeTokenizer* challenge, HttpAuth::Target target, const SSLInfo& ssl_info, + const NetworkIsolationKey& network_isolation_key, const GURL& origin, CreateReason reason, int digest_nonce_count, @@ -34,8 +35,8 @@ int HttpAuthHandlerNTLM::Factory::CreateAuthHandler( // method and only constructing when valid. std::unique_ptr<HttpAuthHandler> tmp_handler( new HttpAuthHandlerNTLM(sspi_library_.get(), http_auth_preferences())); - if (!tmp_handler->InitFromChallenge(challenge, target, ssl_info, origin, - net_log)) + if (!tmp_handler->InitFromChallenge(challenge, target, ssl_info, + network_isolation_key, origin, net_log)) return ERR_INVALID_RESPONSE; handler->swap(tmp_handler); return OK; diff --git a/chromium/net/http/http_auth_handler_unittest.cc b/chromium/net/http/http_auth_handler_unittest.cc index fed58146ca8..da80db140f0 100644 --- a/chromium/net/http/http_auth_handler_unittest.cc +++ b/chromium/net/http/http_auth_handler_unittest.cc @@ -8,6 +8,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/test/task_environment.h" #include "net/base/net_errors.h" +#include "net/base/network_isolation_key.h" #include "net/base/test_completion_callback.h" #include "net/http/http_auth_challenge_tokenizer.h" #include "net/http/http_auth_handler_mock.h" @@ -42,7 +43,8 @@ TEST(HttpAuthHandlerTest, NetLog) { // call after GenerateAuthToken() is expected and does not result in // AUTHORIZATION_RESULT_REJECT. mock_handler.set_connection_based(true); - mock_handler.InitFromChallenge(&tokenizer, target, SSLInfo(), origin, + mock_handler.InitFromChallenge(&tokenizer, target, SSLInfo(), + NetworkIsolationKey(), origin, test_net_log.bound()); mock_handler.SetGenerateExpectation(async, OK); mock_handler.GenerateAuthToken(&credentials, &request, diff --git a/chromium/net/http/http_auth_sspi_win.cc b/chromium/net/http/http_auth_sspi_win.cc index 5e11b9ff147..0716b6e99e9 100644 --- a/chromium/net/http/http_auth_sspi_win.cc +++ b/chromium/net/http/http_auth_sspi_win.cc @@ -547,7 +547,12 @@ int HttpAuthSSPI::GetNextSecurityToken(const std::string& spn, if (delegation_type_ != DelegationType::kNone) context_flags |= (ISC_REQ_DELEGATE | ISC_REQ_MUTUAL_AUTH); - net_log.BeginEvent(NetLogEventType::AUTH_LIBRARY_INIT_SEC_CTX); + net_log.BeginEvent(NetLogEventType::AUTH_LIBRARY_INIT_SEC_CTX, [&] { + base::Value params{base::Value::Type::DICTIONARY}; + params.SetStringKey("spn", spn); + params.SetKey("flags", ContextFlagsToValue(context_flags)); + return params; + }); // This returns a token that is passed to the remote server. DWORD context_attributes = 0; diff --git a/chromium/net/http/http_auth_sspi_win_unittest.cc b/chromium/net/http/http_auth_sspi_win_unittest.cc index 09ddf1d6593..bad9b9ba25c 100644 --- a/chromium/net/http/http_auth_sspi_win_unittest.cc +++ b/chromium/net/http/http_auth_sspi_win_unittest.cc @@ -260,6 +260,18 @@ TEST(HttpAuthSSPITest, GenerateAuthToken_FullHandshake_AmbientCreds_Logging) { expected = base::JSONReader::Read(R"( { + "flags": { + "delegated": false, + "mutual": false, + "value": "0x00000000" + }, + "spn": "HTTP/intranet.google.com" + } + )"); + EXPECT_EQ(expected, entries[0].params); + + expected = base::JSONReader::Read(R"( + { "context": { "authority": "Dodgy Server", "flags": { diff --git a/chromium/net/http/http_auth_unittest.cc b/chromium/net/http/http_auth_unittest.cc index 39e32e5dbf2..059385e9a6a 100644 --- a/chromium/net/http/http_auth_unittest.cc +++ b/chromium/net/http/http_auth_unittest.cc @@ -13,6 +13,7 @@ #include "base/strings/string_util.h" #include "build/build_config.h" #include "net/base/net_errors.h" +#include "net/base/network_isolation_key.h" #include "net/dns/mock_host_resolver.h" #include "net/http/http_auth_challenge_tokenizer.h" #include "net/http/http_auth_filter.h" @@ -41,9 +42,9 @@ std::unique_ptr<HttpAuthHandlerMock> CreateMockHandler(bool connection_based) { challenge_text.end()); GURL origin("www.example.com"); SSLInfo null_ssl_info; - EXPECT_TRUE(auth_handler->InitFromChallenge(&challenge, HttpAuth::AUTH_SERVER, - null_ssl_info, origin, - NetLogWithSource())); + EXPECT_TRUE(auth_handler->InitFromChallenge( + &challenge, HttpAuth::AUTH_SERVER, null_ssl_info, NetworkIsolationKey(), + origin, NetLogWithSource())); return auth_handler; } @@ -140,10 +141,10 @@ TEST(HttpAuthTest, ChooseBestChallenge) { SSLInfo null_ssl_info; std::unique_ptr<HttpAuthHandler> handler; - HttpAuth::ChooseBestChallenge(http_auth_handler_factory.get(), *headers, - null_ssl_info, HttpAuth::AUTH_SERVER, origin, - disabled_schemes, NetLogWithSource(), - host_resolver.get(), &handler); + HttpAuth::ChooseBestChallenge( + http_auth_handler_factory.get(), *headers, null_ssl_info, + NetworkIsolationKey(), HttpAuth::AUTH_SERVER, origin, disabled_schemes, + NetLogWithSource(), host_resolver.get(), &handler); if (handler.get()) { EXPECT_EQ(tests[i].challenge_scheme, handler->auth_scheme()); diff --git a/chromium/net/http/http_basic_stream.cc b/chromium/net/http/http_basic_stream.cc index b2bb7fd1958..085b1fe7fbf 100644 --- a/chromium/net/http/http_basic_stream.cc +++ b/chromium/net/http/http_basic_stream.cc @@ -138,6 +138,7 @@ bool HttpBasicStream::GetLoadTimingInfo( } load_timing_info->receive_headers_start = parser()->response_start_time(); + load_timing_info->first_early_hints_time = parser()->first_early_hints_time(); return true; } diff --git a/chromium/net/http/http_cache_transaction.cc b/chromium/net/http/http_cache_transaction.cc index ad6e626898d..a4afd4bc42a 100644 --- a/chromium/net/http/http_cache_transaction.cc +++ b/chromium/net/http/http_cache_transaction.cc @@ -2709,11 +2709,12 @@ ValidationType HttpCache::Transaction::RequiresValidation() { if (effective_load_flags_ & LOAD_SKIP_CACHE_VALIDATION) return VALIDATION_NONE; + TimeDelta response_time_in_cache = + cache_->clock_->Now() - response_.response_time; if (response_.unused_since_prefetch && !(effective_load_flags_ & LOAD_PREFETCH) && - response_.headers->GetCurrentAge( - response_.request_time, response_.response_time, - cache_->clock_->Now()) < TimeDelta::FromMinutes(kPrefetchReuseMins)) { + (response_time_in_cache < TimeDelta::FromMinutes(kPrefetchReuseMins)) && + (response_time_in_cache >= TimeDelta())) { // The first use of a resource after prefetch within a short window skips // validation. return VALIDATION_NONE; diff --git a/chromium/net/http/http_network_session.cc b/chromium/net/http/http_network_session.cc index d5283730314..bce0e10597c 100644 --- a/chromium/net/http/http_network_session.cc +++ b/chromium/net/http/http_network_session.cc @@ -209,9 +209,9 @@ HttpNetworkSession::HttpNetworkSession(const Params& params, context.quic_context->params()->max_server_configs_stored_in_properties); if (!params_.disable_idle_sockets_close_on_memory_pressure) { - memory_pressure_listener_.reset( - new base::MemoryPressureListener(base::BindRepeating( - &HttpNetworkSession::OnMemoryPressure, base::Unretained(this)))); + memory_pressure_listener_ = std::make_unique<base::MemoryPressureListener>( + FROM_HERE, base::BindRepeating(&HttpNetworkSession::OnMemoryPressure, + base::Unretained(this))); } } diff --git a/chromium/net/http/http_network_session.h b/chromium/net/http/http_network_session.h index 92530037564..c39cfddec9a 100644 --- a/chromium/net/http/http_network_session.h +++ b/chromium/net/http/http_network_session.h @@ -115,7 +115,7 @@ class NET_EXPORT HttpNetworkSession { // logic from hiding broken servers. spdy::SettingsMap http2_settings; // If set, an HTTP/2 frame with a reserved frame type will be sent after - // every HEADERS and SETTINGS frame. See + // every HTTP/2 SETTINGS frame and before every HTTP/2 DATA frame. // https://tools.ietf.org/html/draft-bishop-httpbis-grease-00. // The same frame will be sent out on all connections to prevent the retry // logic from hiding broken servers. diff --git a/chromium/net/http/http_network_transaction.cc b/chromium/net/http/http_network_transaction.cc index 22a18a35871..64b249b6b72 100644 --- a/chromium/net/http/http_network_transaction.cc +++ b/chromium/net/http/http_network_transaction.cc @@ -1312,21 +1312,15 @@ void HttpNetworkTransaction::ProcessReportToHeader() { return; ReportingService* service = session_->reporting_service(); - if (!service) { - ReportingHeaderParser::RecordHeaderDiscardedForNoReportingService(); + if (!service) return; - } // Only accept Report-To headers on HTTPS connections that have no // certificate errors. - if (!response_.ssl_info.is_valid()) { - ReportingHeaderParser::RecordHeaderDiscardedForInvalidSSLInfo(); + if (!response_.ssl_info.is_valid()) return; - } - if (IsCertStatusError(response_.ssl_info.cert_status)) { - ReportingHeaderParser::RecordHeaderDiscardedForCertStatusError(); + if (IsCertStatusError(response_.ssl_info.cert_status)) return; - } service->ProcessHeader(url_.GetOrigin(), value); } @@ -1340,11 +1334,8 @@ void HttpNetworkTransaction::ProcessNetworkErrorLoggingHeader() { NetworkErrorLoggingService* service = session_->network_error_logging_service(); - if (!service) { - NetworkErrorLoggingService:: - RecordHeaderDiscardedForNoNetworkErrorLoggingService(); + if (!service) return; - } // Don't accept NEL headers received via a proxy, because the IP address of // the destination server is not known. @@ -1353,19 +1344,13 @@ void HttpNetworkTransaction::ProcessNetworkErrorLoggingHeader() { // Only accept NEL headers on HTTPS connections that have no certificate // errors. - if (!response_.ssl_info.is_valid()) { - NetworkErrorLoggingService::RecordHeaderDiscardedForInvalidSSLInfo(); - return; - } - if (IsCertStatusError(response_.ssl_info.cert_status)) { - NetworkErrorLoggingService::RecordHeaderDiscardedForCertStatusError(); + if (!response_.ssl_info.is_valid() || + IsCertStatusError(response_.ssl_info.cert_status)) { return; } - if (remote_endpoint_.address().empty()) { - NetworkErrorLoggingService::RecordHeaderDiscardedForMissingRemoteEndpoint(); + if (remote_endpoint_.address().empty()) return; - } service->OnHeader(url::Origin::Create(url_), remote_endpoint_.address(), value); diff --git a/chromium/net/http/http_network_transaction_unittest.cc b/chromium/net/http/http_network_transaction_unittest.cc index 86d5348164e..b01179e007e 100644 --- a/chromium/net/http/http_network_transaction_unittest.cc +++ b/chromium/net/http/http_network_transaction_unittest.cc @@ -15269,8 +15269,8 @@ TEST_F(HttpNetworkTransactionTest, GenerateAuthToken) { HttpAuthChallengeTokenizer tokenizer(auth_challenge.begin(), auth_challenge.end()); auth_handler->InitFromChallenge(&tokenizer, HttpAuth::AUTH_PROXY, - empty_ssl_info, origin, - NetLogWithSource()); + empty_ssl_info, NetworkIsolationKey(), + origin, NetLogWithSource()); auth_handler->SetGenerateExpectation( test_config.proxy_auth_timing == AUTH_ASYNC, n == 0 ? test_config.first_generate_proxy_token_rv : OK); @@ -15284,8 +15284,8 @@ TEST_F(HttpNetworkTransactionTest, GenerateAuthToken) { HttpAuthChallengeTokenizer tokenizer(auth_challenge.begin(), auth_challenge.end()); auth_handler->InitFromChallenge(&tokenizer, HttpAuth::AUTH_SERVER, - empty_ssl_info, origin, - NetLogWithSource()); + empty_ssl_info, NetworkIsolationKey(), + origin, NetLogWithSource()); auth_handler->SetGenerateExpectation( test_config.server_auth_timing == AUTH_ASYNC, test_config.first_generate_server_token_rv); @@ -15297,8 +15297,8 @@ TEST_F(HttpNetworkTransactionTest, GenerateAuthToken) { std::unique_ptr<HttpAuthHandlerMock> second_handler = std::make_unique<HttpAuthHandlerMock>(); second_handler->InitFromChallenge(&tokenizer, HttpAuth::AUTH_SERVER, - empty_ssl_info, origin, - NetLogWithSource()); + empty_ssl_info, NetworkIsolationKey(), + origin, NetLogWithSource()); second_handler->SetGenerateExpectation(true, OK); auth_factory->AddMockHandler(second_handler.release(), HttpAuth::AUTH_SERVER); @@ -15413,7 +15413,8 @@ TEST_F(HttpNetworkTransactionTest, MultiRoundAuth) { auth_challenge.end()); SSLInfo empty_ssl_info; auth_handler->InitFromChallenge(&tokenizer, HttpAuth::AUTH_SERVER, - empty_ssl_info, origin, NetLogWithSource()); + empty_ssl_info, NetworkIsolationKey(), origin, + NetLogWithSource()); auth_factory->AddMockHandler(auth_handler, HttpAuth::AUTH_SERVER); int rv = OK; @@ -19438,21 +19439,15 @@ class HttpNetworkTransactionReportingTest : public HttpNetworkTransactionTest { TEST_F(HttpNetworkTransactionReportingTest, DontProcessReportToHeaderNoService) { - base::HistogramTester histograms; clear_reporting_service(); RequestPolicy(); - histograms.ExpectBucketCount( - ReportingHeaderParser::kHeaderOutcomeHistogram, - ReportingHeaderParser::HeaderOutcome::DISCARDED_NO_REPORTING_SERVICE, 1); + // No crash. } TEST_F(HttpNetworkTransactionReportingTest, DontProcessReportToHeaderHttp) { - base::HistogramTester histograms; url_ = "http://www.example.org/"; RequestPolicy(); - histograms.ExpectBucketCount( - ReportingHeaderParser::kHeaderOutcomeHistogram, - ReportingHeaderParser::HeaderOutcome::DISCARDED_INVALID_SSL_INFO, 1); + EXPECT_EQ(0u, reporting_context()->cache()->GetEndpointCount()); } TEST_F(HttpNetworkTransactionReportingTest, ProcessReportToHeaderHttps) { @@ -19469,12 +19464,9 @@ TEST_F(HttpNetworkTransactionReportingTest, ProcessReportToHeaderHttps) { TEST_F(HttpNetworkTransactionReportingTest, DontProcessReportToHeaderInvalidHttps) { - base::HistogramTester histograms; CertStatus cert_status = CERT_STATUS_COMMON_NAME_INVALID; RequestPolicy(cert_status); - histograms.ExpectBucketCount( - ReportingHeaderParser::kHeaderOutcomeHistogram, - ReportingHeaderParser::HeaderOutcome::DISCARDED_CERT_STATUS_ERROR, 1); + EXPECT_EQ(0u, reporting_context()->cache()->GetEndpointCount()); } #endif // BUILDFLAG(ENABLE_REPORTING) @@ -19593,25 +19585,17 @@ class HttpNetworkTransactionNetworkErrorLoggingTest TEST_F(HttpNetworkTransactionNetworkErrorLoggingTest, DontProcessNelHeaderNoService) { - base::HistogramTester histograms; clear_network_error_logging_service(); RequestPolicy(); - histograms.ExpectBucketCount( - NetworkErrorLoggingService::kHeaderOutcomeHistogram, - NetworkErrorLoggingService::HeaderOutcome:: - DISCARDED_NO_NETWORK_ERROR_LOGGING_SERVICE, - 1); + // No crash. } TEST_F(HttpNetworkTransactionNetworkErrorLoggingTest, DontProcessNelHeaderHttp) { - base::HistogramTester histograms; url_ = "http://www.example.org/"; request_.url = GURL(url_); RequestPolicy(); - histograms.ExpectBucketCount( - NetworkErrorLoggingService::kHeaderOutcomeHistogram, - NetworkErrorLoggingService::HeaderOutcome::DISCARDED_INVALID_SSL_INFO, 1); + EXPECT_EQ(0u, network_error_logging_service()->headers().size()); } // Don't set NEL policies received on a proxied connection. @@ -19690,13 +19674,9 @@ TEST_F(HttpNetworkTransactionNetworkErrorLoggingTest, ProcessNelHeaderHttps) { TEST_F(HttpNetworkTransactionNetworkErrorLoggingTest, DontProcessNelHeaderInvalidHttps) { - base::HistogramTester histograms; CertStatus cert_status = CERT_STATUS_COMMON_NAME_INVALID; RequestPolicy(cert_status); - histograms.ExpectBucketCount( - NetworkErrorLoggingService::kHeaderOutcomeHistogram, - NetworkErrorLoggingService::HeaderOutcome::DISCARDED_CERT_STATUS_ERROR, - 1); + EXPECT_EQ(0u, network_error_logging_service()->headers().size()); } TEST_F(HttpNetworkTransactionNetworkErrorLoggingTest, CreateReportSuccess) { diff --git a/chromium/net/http/http_proxy_connect_job.h b/chromium/net/http/http_proxy_connect_job.h index dac631fbe46..07b2627327a 100644 --- a/chromium/net/http/http_proxy_connect_job.h +++ b/chromium/net/http/http_proxy_connect_job.h @@ -40,8 +40,7 @@ class QuicStreamRequest; // HttpProxySocketParams only needs the socket params for one of the proxy // types. The other param must be NULL. When using an HTTP proxy, // |transport_params| must be set. When using an HTTPS proxy or QUIC proxy, -// |ssl_params| must be set. Also, if using a QUIC proxy, |quic_version| must -// not be quic::QUIC_VERSION_UNSUPPORTED. +// |ssl_params| must be set. class NET_EXPORT_PRIVATE HttpProxySocketParams : public base::RefCounted<HttpProxySocketParams> { public: diff --git a/chromium/net/http/http_request_headers.cc b/chromium/net/http/http_request_headers.cc index d0aa57c2ba7..35ede841aa9 100644 --- a/chromium/net/http/http_request_headers.cc +++ b/chromium/net/http/http_request_headers.cc @@ -7,6 +7,7 @@ #include <utility> #include "base/logging.h" +#include "base/notreached.h" #include "base/strings/strcat.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" diff --git a/chromium/net/http/http_response_info.cc b/chromium/net/http/http_response_info.cc index 0c31a131cdf..f1adaf13ecd 100644 --- a/chromium/net/http/http_response_info.cc +++ b/chromium/net/http/http_response_info.cc @@ -162,6 +162,8 @@ HttpResponseInfo::ConnectionInfoCoarse HttpResponseInfo::ConnectionInfoToCoarse( case CONNECTION_INFO_QUIC_999: case CONNECTION_INFO_QUIC_DRAFT_25: case CONNECTION_INFO_QUIC_DRAFT_27: + case CONNECTION_INFO_QUIC_DRAFT_28: + case CONNECTION_INFO_QUIC_DRAFT_29: return CONNECTION_INFO_COARSE_QUIC; case CONNECTION_INFO_UNKNOWN: @@ -497,6 +499,8 @@ bool HttpResponseInfo::DidUseQuic() const { case CONNECTION_INFO_QUIC_999: case CONNECTION_INFO_QUIC_DRAFT_25: case CONNECTION_INFO_QUIC_DRAFT_27: + case CONNECTION_INFO_QUIC_DRAFT_28: + case CONNECTION_INFO_QUIC_DRAFT_29: return true; case NUM_OF_CONNECTION_INFOS: NOTREACHED(); @@ -579,6 +583,10 @@ std::string HttpResponseInfo::ConnectionInfoToString( return "h3-25"; case CONNECTION_INFO_QUIC_DRAFT_27: return "h3-27"; + case CONNECTION_INFO_QUIC_DRAFT_28: + return "h3-28"; + case CONNECTION_INFO_QUIC_DRAFT_29: + return "h3-29"; case CONNECTION_INFO_QUIC_T099: return "h3-T099"; case CONNECTION_INFO_HTTP0_9: diff --git a/chromium/net/http/http_response_info.h b/chromium/net/http/http_response_info.h index 445dd63b696..f878369a720 100644 --- a/chromium/net/http/http_response_info.h +++ b/chromium/net/http/http_response_info.h @@ -73,6 +73,8 @@ class NET_EXPORT HttpResponseInfo { CONNECTION_INFO_QUIC_T099 = 34, CONNECTION_INFO_QUIC_DRAFT_25 = 35, CONNECTION_INFO_QUIC_DRAFT_27 = 36, + CONNECTION_INFO_QUIC_DRAFT_28 = 37, + CONNECTION_INFO_QUIC_DRAFT_29 = 38, NUM_OF_CONNECTION_INFOS, }; diff --git a/chromium/net/http/http_server_properties.cc b/chromium/net/http/http_server_properties.cc index da1bf8335e9..cce79cafb0c 100644 --- a/chromium/net/http/http_server_properties.cc +++ b/chromium/net/http/http_server_properties.cc @@ -18,6 +18,7 @@ #include "base/time/default_tick_clock.h" #include "base/values.h" #include "net/base/features.h" +#include "net/base/url_util.h" #include "net/http/http_network_session.h" #include "net/http/http_server_properties_manager.h" #include "net/socket/ssl_client_socket.h" @@ -871,7 +872,7 @@ void HttpServerProperties::SetAlternativeServicesInternal( // before the first completes. In this case, only one of the jobs // would reach this code, whereas all of them should should have. HistogramAlternateProtocolUsage(ALTERNATE_PROTOCOL_USAGE_MAPPING_MISSING, - false); + false, IsGoogleHost(origin.host())); } // If this host ends with a canonical suffix, then set it as the diff --git a/chromium/net/http/http_server_properties_manager.cc b/chromium/net/http/http_server_properties_manager.cc index fd30463050d..00fb6ee099b 100644 --- a/chromium/net/http/http_server_properties_manager.cc +++ b/chromium/net/http/http_server_properties_manager.cc @@ -529,7 +529,7 @@ bool HttpServerPropertiesManager::ParseAlternativeServiceInfoDictOfServer( } // Advertised versions list is optional. - // It is only used for PROTOCOL_QUIC_CRYPTO versions. + // It is only used for versions that use the legacy Google AltSvc format. if (dict.HasKey(kAdvertisedVersionsKey)) { const base::ListValue* versions_list = nullptr; if (!dict.GetListWithoutPathExpansion(kAdvertisedVersionsKey, @@ -546,15 +546,15 @@ bool HttpServerPropertiesManager::ParseAlternativeServiceInfoDictOfServer( << server_str; return false; } - if (!quic::ParsedQuicVersionIsValid( - quic::PROTOCOL_QUIC_CRYPTO, - quic::QuicTransportVersion(version))) { - // This version is not valid, this can happen if we've deprecated - // a version that used to be valid. - continue; + for (const quic::ParsedQuicVersion& supported : + quic::AllSupportedVersions()) { + if (supported.UsesQuicCrypto() && + supported.SupportsGoogleAltSvcFormat() && + static_cast<int>(supported.transport_version) == version) { + advertised_versions.push_back(supported); + break; + } } - advertised_versions.push_back(quic::ParsedQuicVersion( - quic::PROTOCOL_QUIC_CRYPTO, quic::QuicTransportVersion(version))); } alternative_service_info->set_advertised_versions(advertised_versions); } diff --git a/chromium/net/http/http_server_properties_manager_unittest.cc b/chromium/net/http/http_server_properties_manager_unittest.cc index ab1cd3a3c49..792231248ab 100644 --- a/chromium/net/http/http_server_properties_manager_unittest.cc +++ b/chromium/net/http/http_server_properties_manager_unittest.cc @@ -1481,10 +1481,7 @@ TEST_F(HttpServerPropertiesManagerTest, PersistAdvertisedVersionsToPref) { base::Time expiration1; ASSERT_TRUE(base::Time::FromUTCString("2036-12-01 10:00:00", &expiration1)); quic::ParsedQuicVersionVector advertised_versions = { - quic::ParsedQuicVersion(quic::PROTOCOL_QUIC_CRYPTO, - quic::QUIC_VERSION_46), - quic::ParsedQuicVersion(quic::PROTOCOL_QUIC_CRYPTO, - quic::QUIC_VERSION_43)}; + quic::ParsedQuicVersion::Q046(), quic::ParsedQuicVersion::Q043()}; alternative_service_info_vector.push_back( AlternativeServiceInfo::CreateQuicAlternativeServiceInfo( quic_alternative_service1, expiration1, advertised_versions)); @@ -1543,7 +1540,7 @@ TEST_F(HttpServerPropertiesManagerTest, PersistAdvertisedVersionsToPref) { "\"isolation\":[]," "\"server\":\"https://www.google.com:80\"}," "{\"alternative_service\":[{" - "\"advertised_versions\":[46],\"expiration\":\"9223372036854775807\"," + "\"advertised_versions\":[50],\"expiration\":\"9223372036854775807\"," "\"host\":\"foo.google.com\",\"port\":444,\"protocol_str\":\"quic\"}]," "\"isolation\":[]," "\"network_stats\":{\"srtt\":42}," @@ -1606,12 +1603,8 @@ TEST_F(HttpServerPropertiesManagerTest, ReadAdvertisedVersionsFromPref) { const quic::ParsedQuicVersionVector loaded_advertised_versions = alternative_service_info_vector[1].advertised_versions(); EXPECT_EQ(2u, loaded_advertised_versions.size()); - EXPECT_EQ(quic::ParsedQuicVersion(quic::PROTOCOL_QUIC_CRYPTO, - quic::QUIC_VERSION_43), - loaded_advertised_versions[0]); - EXPECT_EQ(quic::ParsedQuicVersion(quic::PROTOCOL_QUIC_CRYPTO, - quic::QUIC_VERSION_46), - loaded_advertised_versions[1]); + EXPECT_EQ(quic::ParsedQuicVersion::Q043(), loaded_advertised_versions[0]); + EXPECT_EQ(quic::ParsedQuicVersion::Q046(), loaded_advertised_versions[1]); // No other fields should have been populated. server_info.alternative_services.reset(); @@ -1626,8 +1619,7 @@ TEST_F(HttpServerPropertiesManagerTest, // #1: Set alternate protocol. AlternativeServiceInfoVector alternative_service_info_vector; - // Quic alternative service set with a single QUIC version: - // quic::QUIC_VERSION_46. + // Quic alternative service set with a single QUIC version: Q046. AlternativeService quic_alternative_service1(kProtoQUIC, "", 443); base::Time expiration1; ASSERT_TRUE(base::Time::FromUTCString("2036-12-01 10:00:00", &expiration1)); @@ -1660,7 +1652,7 @@ TEST_F(HttpServerPropertiesManagerTest, "\"server_id\":\"https://mail.google.com:80\"," "\"server_info\":\"quic_server_info1\"}]," "\"servers\":[" - "{\"alternative_service\":[{\"advertised_versions\":[46]," + "{\"alternative_service\":[{\"advertised_versions\":[50]," "\"expiration\":\"13756212000000000\",\"port\":443," "\"protocol_str\":\"quic\"}]," "\"isolation\":[]," @@ -1680,10 +1672,7 @@ TEST_F(HttpServerPropertiesManagerTest, AlternativeServiceInfoVector alternative_service_info_vector_2; // Quic alternative service set with two advertised QUIC versions. quic::ParsedQuicVersionVector advertised_versions = { - quic::ParsedQuicVersion(quic::PROTOCOL_QUIC_CRYPTO, - quic::QUIC_VERSION_46), - quic::ParsedQuicVersion(quic::PROTOCOL_QUIC_CRYPTO, - quic::QUIC_VERSION_43)}; + quic::ParsedQuicVersion::Q046(), quic::ParsedQuicVersion::Q043()}; alternative_service_info_vector_2.push_back( AlternativeServiceInfo::CreateQuicAlternativeServiceInfo( quic_alternative_service1, expiration1, advertised_versions)); @@ -1718,10 +1707,7 @@ TEST_F(HttpServerPropertiesManagerTest, AlternativeServiceInfoVector alternative_service_info_vector_3; // A same set of QUIC versions but listed in a different order. quic::ParsedQuicVersionVector advertised_versions_2 = { - quic::ParsedQuicVersion(quic::PROTOCOL_QUIC_CRYPTO, - quic::QUIC_VERSION_43), - quic::ParsedQuicVersion(quic::PROTOCOL_QUIC_CRYPTO, - quic::QUIC_VERSION_46)}; + quic::ParsedQuicVersion::Q043(), quic::ParsedQuicVersion::Q046()}; alternative_service_info_vector_3.push_back( AlternativeServiceInfo::CreateQuicAlternativeServiceInfo( quic_alternative_service1, expiration1, advertised_versions_2)); diff --git a/chromium/net/http/http_stream_factory_job.cc b/chromium/net/http/http_stream_factory_job.cc index b2a42a4bdfa..10b862d5d47 100644 --- a/chromium/net/http/http_stream_factory_job.cc +++ b/chromium/net/http/http_stream_factory_job.cc @@ -175,7 +175,7 @@ HttpStreamFactory::Job::Job(Delegate* delegate, // The Job is forced to use QUIC without a designated version, try the // preferred QUIC version that is supported by default. - if (quic_version_ == quic::UnsupportedQuicVersion() && + if (quic_version_ == quic::ParsedQuicVersion::Unsupported() && ShouldForceQuic(session, destination, origin_url, proxy_info, using_ssl_)) { quic_version_ = @@ -183,7 +183,7 @@ HttpStreamFactory::Job::Job(Delegate* delegate, } if (using_quic_) - DCHECK_NE(quic_version_, quic::UnsupportedQuicVersion()); + DCHECK_NE(quic_version_, quic::ParsedQuicVersion::Unsupported()); DCHECK(session); if (alternative_protocol != kProtoUnknown) { @@ -1103,6 +1103,10 @@ int HttpStreamFactory::Job::DoCreateStream() { ->CreateBasicStream(std::move(connection_), using_proxy, session_->websocket_endpoint_lock_manager()); } else { + if (request_info_.upload_data_stream && + !request_info_.upload_data_stream->AllowHTTP1()) { + return ERR_H2_OR_QUIC_REQUIRED; + } stream_ = std::make_unique<HttpBasicStream>(std::move(connection_), using_proxy); } @@ -1292,7 +1296,7 @@ HttpStreamFactory::JobFactory::CreateMainJob( return std::make_unique<HttpStreamFactory::Job>( delegate, job_type, session, request_info, priority, proxy_info, server_ssl_config, proxy_ssl_config, destination, origin_url, - kProtoUnknown, quic::UnsupportedQuicVersion(), ProxyServer(), + kProtoUnknown, quic::ParsedQuicVersion::Unsupported(), ProxyServer(), is_websocket, enable_ip_based_pooling, net_log); } @@ -1339,8 +1343,8 @@ HttpStreamFactory::JobFactory::CreateAltProxyJob( return std::make_unique<HttpStreamFactory::Job>( delegate, job_type, session, request_info, priority, proxy_info, server_ssl_config, proxy_ssl_config, destination, origin_url, - kProtoUnknown, quic::UnsupportedQuicVersion(), alternative_proxy_server, - is_websocket, enable_ip_based_pooling, net_log); + kProtoUnknown, quic::ParsedQuicVersion::Unsupported(), + alternative_proxy_server, is_websocket, enable_ip_based_pooling, net_log); } bool HttpStreamFactory::Job::ShouldThrottleConnectForSpdy() const { diff --git a/chromium/net/http/http_stream_factory_job.h b/chromium/net/http/http_stream_factory_job.h index 7ab4e170b00..ee43e1eac99 100644 --- a/chromium/net/http/http_stream_factory_job.h +++ b/chromium/net/http/http_stream_factory_job.h @@ -193,6 +193,7 @@ class HttpStreamFactory::Job void SetPriority(RequestPriority priority); + const GURL& origin_url() const { return origin_url_; } RequestPriority priority() const { return priority_; } bool was_alpn_negotiated() const; NextProto negotiated_protocol() const; diff --git a/chromium/net/http/http_stream_factory_job_controller.cc b/chromium/net/http/http_stream_factory_job_controller.cc index b99d74823a0..9c0b0baea43 100644 --- a/chromium/net/http/http_stream_factory_job_controller.cc +++ b/chromium/net/http/http_stream_factory_job_controller.cc @@ -17,6 +17,7 @@ #include "base/values.h" #include "net/base/host_mapping_rules.h" #include "net/base/load_flags.h" +#include "net/base/url_util.h" #include "net/http/bidirectional_stream_impl.h" #include "net/http/transport_security_state.h" #include "net/log/net_log.h" @@ -672,11 +673,11 @@ int HttpStreamFactory::JobController::DoCreateJobs() { alternative_service_info_ = GetAlternativeServiceInfoFor(request_info_, delegate_, stream_type_); } - quic::ParsedQuicVersion quic_version = quic::UnsupportedQuicVersion(); + quic::ParsedQuicVersion quic_version = quic::ParsedQuicVersion::Unsupported(); if (alternative_service_info_.protocol() == kProtoQUIC) { quic_version = SelectQuicVersion(alternative_service_info_.advertised_versions()); - DCHECK_NE(quic_version, quic::UnsupportedQuicVersion()); + DCHECK_NE(quic_version, quic::ParsedQuicVersion::Unsupported()); } if (is_preconnect_) { @@ -1014,7 +1015,8 @@ HttpStreamFactory::JobController::GetAlternativeServiceInfoInternal( if (!is_any_broken) { // Only log the broken alternative service once per request. is_any_broken = true; - HistogramAlternateProtocolUsage(ALTERNATE_PROTOCOL_USAGE_BROKEN, false); + HistogramAlternateProtocolUsage(ALTERNATE_PROTOCOL_USAGE_BROKEN, false, + HasGoogleHost(original_url)); } continue; } @@ -1060,7 +1062,7 @@ HttpStreamFactory::JobController::GetAlternativeServiceInfoInternal( // If there is no QUIC version in the advertised versions that is // supported, ignore this entry. if (SelectQuicVersion(alternative_service_info.advertised_versions()) == - quic::UnsupportedQuicVersion()) + quic::ParsedQuicVersion::Unsupported()) continue; // Check whether there is an existing QUIC session to use for this origin. @@ -1106,13 +1108,13 @@ quic::ParsedQuicVersion HttpStreamFactory::JobController::SelectQuicVersion( for (const quic::ParsedQuicVersion& advertised : advertised_versions) { for (const quic::ParsedQuicVersion& supported : supported_versions) { if (supported == advertised) { - DCHECK_NE(quic::UnsupportedQuicVersion(), supported); + DCHECK_NE(quic::ParsedQuicVersion::Unsupported(), supported); return supported; } } } - return quic::UnsupportedQuicVersion(); + return quic::ParsedQuicVersion::Unsupported(); } bool HttpStreamFactory::JobController::ShouldCreateAlternativeProxyServerJob( @@ -1170,22 +1172,23 @@ void HttpStreamFactory::JobController::ReportAlternateProtocolUsage( bool proxy_server_used = alternative_job_->alternative_proxy_server().is_quic(); + bool is_google_host = HasGoogleHost(job->origin_url()); if (job == main_job_.get()) { HistogramAlternateProtocolUsage(ALTERNATE_PROTOCOL_USAGE_LOST_RACE, - proxy_server_used); + proxy_server_used, is_google_host); return; } DCHECK_EQ(alternative_job_.get(), job); if (job->using_existing_quic_session()) { HistogramAlternateProtocolUsage(ALTERNATE_PROTOCOL_USAGE_NO_RACE, - proxy_server_used); + proxy_server_used, is_google_host); return; } HistogramAlternateProtocolUsage(ALTERNATE_PROTOCOL_USAGE_WON_RACE, - proxy_server_used); + proxy_server_used, is_google_host); } bool HttpStreamFactory::JobController::IsJobOrphaned(Job* job) const { diff --git a/chromium/net/http/http_stream_factory_job_controller.h b/chromium/net/http/http_stream_factory_job_controller.h index bad49ec4b4b..ee7bf05e525 100644 --- a/chromium/net/http/http_stream_factory_job_controller.h +++ b/chromium/net/http/http_stream_factory_job_controller.h @@ -253,7 +253,7 @@ class HttpStreamFactory::JobController // Returns the first quic::ParsedQuicVersion that has been advertised in // |advertised_versions| and is supported, following the order of // |advertised_versions|. If no mutually supported version is found, - // quic::UnsupportedQuicVersion() will be returned. + // quic::ParsedQuicVersion::Unsupported() will be returned. quic::ParsedQuicVersion SelectQuicVersion( const quic::ParsedQuicVersionVector& advertised_versions); diff --git a/chromium/net/http/http_stream_factory_job_controller_unittest.cc b/chromium/net/http/http_stream_factory_job_controller_unittest.cc index 0c4ef067abd..c58ac8abdc3 100644 --- a/chromium/net/http/http_stream_factory_job_controller_unittest.cc +++ b/chromium/net/http/http_stream_factory_job_controller_unittest.cc @@ -873,7 +873,7 @@ TEST_F(HttpStreamFactoryJobControllerTest, base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1); session_->http_server_properties()->SetQuicAlternativeService( server, NetworkIsolationKey(), alternative_service, expiration, - {quic::UnsupportedQuicVersion()}); + {quic::ParsedQuicVersion::Unsupported()}); request_ = job_controller_->Start(&request_delegate_, nullptr, net_log_.bound(), @@ -3286,14 +3286,14 @@ TEST_F(HttpStreamFactoryJobControllerTest, GetAlternativeServiceInfoFor) { EXPECT_EQ(supported_versions, alt_svc_info.advertised_versions()); quic::ParsedQuicVersion unsupported_version_1 = - quic::UnsupportedQuicVersion(); + quic::ParsedQuicVersion::Unsupported(); quic::ParsedQuicVersion unsupported_version_2 = - quic::UnsupportedQuicVersion(); + quic::ParsedQuicVersion::Unsupported(); for (const quic::ParsedQuicVersion& version : quic::AllSupportedVersions()) { if (std::find(supported_versions.begin(), supported_versions.end(), version) != supported_versions.end()) continue; - if (unsupported_version_1 == quic::UnsupportedQuicVersion()) { + if (unsupported_version_1 == quic::ParsedQuicVersion::Unsupported()) { unsupported_version_1 = version; continue; } @@ -3374,9 +3374,7 @@ TEST_F(HttpStreamFactoryJobControllerTest, "h3-Q046=\":443\"; ma=2592000," "h3-Q043=\":443\"; ma=2592000," "h3-T050=\":443\"; ma=2592000", - quic::ParsedQuicVersion(quic::PROTOCOL_QUIC_CRYPTO, - quic::QUIC_VERSION_46), - quic::AllSupportedVersions()); + quic::ParsedQuicVersion::Q046(), quic::AllSupportedVersions()); } TEST_F(HttpStreamFactoryJobControllerTest, @@ -3389,23 +3387,16 @@ TEST_F(HttpStreamFactoryJobControllerTest, "h3-Q043=\":443\"; ma=2592000," "h3-T050=\":443\"; ma=2592000," "quic=\":443\"; ma=2592000; v=\"46,43\"", - quic::ParsedQuicVersion(quic::PROTOCOL_QUIC_CRYPTO, - quic::QUIC_VERSION_50), - quic::AllSupportedVersions()); + quic::ParsedQuicVersion::Q050(), quic::AllSupportedVersions()); } TEST_F(HttpStreamFactoryJobControllerTest, AltSvcVersionSelectionWithInverseOrderingOldFormat) { // Server prefers Q043 but client prefers Q046. TestAltSvcVersionSelection( - "quic=\":443\"; ma=2592000; v=\"43,46\"", - quic::ParsedQuicVersion(quic::PROTOCOL_QUIC_CRYPTO, - quic::QUIC_VERSION_43), - quic::ParsedQuicVersionVector{ - quic::ParsedQuicVersion(quic::PROTOCOL_QUIC_CRYPTO, - quic::QUIC_VERSION_46), - quic::ParsedQuicVersion(quic::PROTOCOL_QUIC_CRYPTO, - quic::QUIC_VERSION_43)}); + "quic=\":443\"; ma=2592000; v=\"43,46\"", quic::ParsedQuicVersion::Q043(), + quic::ParsedQuicVersionVector{quic::ParsedQuicVersion::Q046(), + quic::ParsedQuicVersion::Q043()}); } TEST_F(HttpStreamFactoryJobControllerTest, @@ -3414,13 +3405,19 @@ TEST_F(HttpStreamFactoryJobControllerTest, TestAltSvcVersionSelection( "h3-Q043=\":443\"; ma=2592000," "h3-Q046=\":443\"; ma=2592000", - quic::ParsedQuicVersion(quic::PROTOCOL_QUIC_CRYPTO, - quic::QUIC_VERSION_43), - quic::ParsedQuicVersionVector{ - quic::ParsedQuicVersion(quic::PROTOCOL_QUIC_CRYPTO, - quic::QUIC_VERSION_46), - quic::ParsedQuicVersion(quic::PROTOCOL_QUIC_CRYPTO, - quic::QUIC_VERSION_43)}); + quic::ParsedQuicVersion::Q043(), + quic::ParsedQuicVersionVector{quic::ParsedQuicVersion::Q046(), + quic::ParsedQuicVersion::Q043()}); +} + +TEST_F(HttpStreamFactoryJobControllerTest, + AltSvcVersionSelectionWithInvalidOldFormat) { + // Q043 can use the old format but Q050 cannot. Make sure the client ignores + // Q050 even though it is preferred. + TestAltSvcVersionSelection( + "quic=\":443\"; ma=2592000; v=\"50,43\"", quic::ParsedQuicVersion::Q043(), + quic::ParsedQuicVersionVector{quic::ParsedQuicVersion::Q050(), + quic::ParsedQuicVersion::Q043()}); } // Tests that if HttpNetworkSession has a non-empty QUIC host allowlist, diff --git a/chromium/net/http/http_stream_factory_test_util.cc b/chromium/net/http/http_stream_factory_test_util.cc index 1e898ceb5c2..e9ae6319cb8 100644 --- a/chromium/net/http/http_stream_factory_test_util.cc +++ b/chromium/net/http/http_stream_factory_test_util.cc @@ -80,7 +80,7 @@ std::unique_ptr<HttpStreamFactory::Job> TestJobFactory::CreateMainJob( auto main_job = std::make_unique<MockHttpStreamFactoryJob>( delegate, job_type, session, request_info, priority, proxy_info, SSLConfig(), SSLConfig(), destination, origin_url, kProtoUnknown, - quic::UnsupportedQuicVersion(), ProxyServer(), is_websocket, + quic::ParsedQuicVersion::Unsupported(), ProxyServer(), is_websocket, enable_ip_based_pooling, net_log); // Keep raw pointer to Job but pass ownership. @@ -135,8 +135,8 @@ std::unique_ptr<HttpStreamFactory::Job> TestJobFactory::CreateAltProxyJob( auto alternative_job = std::make_unique<MockHttpStreamFactoryJob>( delegate, job_type, session, request_info, priority, proxy_info, SSLConfig(), SSLConfig(), destination, origin_url, kProtoUnknown, - quic::UnsupportedQuicVersion(), alternative_proxy_server, is_websocket, - enable_ip_based_pooling, net_log); + quic::ParsedQuicVersion::Unsupported(), alternative_proxy_server, + is_websocket, enable_ip_based_pooling, net_log); // Keep raw pointer to Job but pass ownership. alternative_job_ = alternative_job.get(); diff --git a/chromium/net/http/http_stream_factory_unittest.cc b/chromium/net/http/http_stream_factory_unittest.cc index 756599802f7..0ddf2a4aa70 100644 --- a/chromium/net/http/http_stream_factory_unittest.cc +++ b/chromium/net/http/http_stream_factory_unittest.cc @@ -2199,15 +2199,39 @@ TEST_F(HttpStreamFactoryTest, RequestBidirectionalStreamImpl) { EXPECT_TRUE(waiter.used_proxy_info().is_direct()); } +struct TestParams { + quic::ParsedQuicVersion version; + bool client_headers_include_h2_stream_dependency; +}; + +// Used by ::testing::PrintToStringParamName(). +std::string PrintToString(const TestParams& p) { + return quiche::QuicheStrCat( + ParsedQuicVersionToString(p.version), "_", + (p.client_headers_include_h2_stream_dependency ? "" : "No"), + "Dependency"); +} + +std::vector<TestParams> GetTestParams() { + std::vector<TestParams> params; + quic::ParsedQuicVersionVector all_supported_versions = + quic::AllSupportedVersions(); + for (const auto& version : all_supported_versions) { + params.push_back(TestParams{version, false}); + params.push_back(TestParams{version, true}); + } + return params; +} + class HttpStreamFactoryBidirectionalQuicTest : public TestWithTaskEnvironment, - public ::testing::WithParamInterface< - std::tuple<quic::ParsedQuicVersion, bool>> { + public ::testing::WithParamInterface<TestParams> { protected: HttpStreamFactoryBidirectionalQuicTest() : default_url_(kDefaultUrl), - version_(std::get<0>(GetParam())), - client_headers_include_h2_stream_dependency_(std::get<1>(GetParam())), + version_(GetParam().version), + client_headers_include_h2_stream_dependency_( + GetParam().client_headers_include_h2_stream_dependency), client_packet_maker_(version_, quic::QuicUtils::CreateRandomConnectionId( quic_context_.random_generator()), @@ -2227,9 +2251,7 @@ class HttpStreamFactoryBidirectionalQuicTest ssl_config_service_(new SSLConfigServiceDefaults) { FLAGS_quic_enable_http3_grease_randomness = false; quic_context_.AdvanceTime(quic::QuicTime::Delta::FromMilliseconds(20)); - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3) { - quic::QuicEnableVersion(version_); - } + quic::QuicEnableVersion(version_); } void TearDown() override { session_.reset(); } @@ -2327,11 +2349,10 @@ class HttpStreamFactoryBidirectionalQuicTest HttpNetworkSession::Params params_; }; -INSTANTIATE_TEST_SUITE_P( - VersionIncludeStreamDependencySequence, - HttpStreamFactoryBidirectionalQuicTest, - ::testing::Combine(::testing::ValuesIn(quic::AllSupportedVersions()), - ::testing::Bool())); +INSTANTIATE_TEST_SUITE_P(VersionIncludeStreamDependencySequence, + HttpStreamFactoryBidirectionalQuicTest, + ::testing::ValuesIn(GetTestParams()), + ::testing::PrintToStringParamName()); TEST_P(HttpStreamFactoryBidirectionalQuicTest, RequestBidirectionalStreamImplQuicAlternative) { @@ -3452,10 +3473,10 @@ TEST_F(ProcessAlternativeServicesTest, ProcessAltSvcClear) { EXPECT_TRUE(alternatives.empty()); } -TEST_F(ProcessAlternativeServicesTest, ProcessAltSvcQuic) { +TEST_F(ProcessAlternativeServicesTest, ProcessAltSvcQuicOldFormat) { quic::ParsedQuicVersionVector versions_with_quic_handshake; for (const auto& version : quic::AllSupportedVersions()) { - if (version.handshake_protocol == quic::PROTOCOL_QUIC_CRYPTO) { + if (version.UsesQuicCrypto() && version.SupportsGoogleAltSvcFormat()) { versions_with_quic_handshake.push_back(version); } } @@ -3471,7 +3492,7 @@ TEST_F(ProcessAlternativeServicesTest, ProcessAltSvcQuic) { scoped_refptr<HttpResponseHeaders> headers( base::MakeRefCounted<HttpResponseHeaders>("")); - headers->AddHeader("alt-svc", "quic=\":443\"; v=\"99,50,49,48,47,46,43,39\""); + headers->AddHeader("alt-svc", "quic=\":443\"; v=\"46,43\""); session_->http_stream_factory()->ProcessAlternativeServices( session_.get(), network_isolation_key, headers.get(), origin); @@ -3493,9 +3514,10 @@ TEST_F(ProcessAlternativeServicesTest, ProcessAltSvcQuic) { // Regression test for https://crbug.com/1044694. TEST_F(ProcessAlternativeServicesTest, AltSvcQuicDoesNotSupportTLSHandshake) { // In this example, QUIC v50 is only supported with TLS handshake. + // Note that this test only covers the Google-specific AltSvc format + // which is now deprecated. quic_context_.params()->supported_versions = { - {quic::PROTOCOL_QUIC_CRYPTO, quic::QUIC_VERSION_49}, - {quic::PROTOCOL_TLS1_3, quic::QUIC_VERSION_50}}; + quic::ParsedQuicVersion::Q043(), quic::ParsedQuicVersion::T050()}; session_ = std::make_unique<HttpNetworkSession>(session_params_, session_context_); url::SchemeHostPort origin(url::kHttpsScheme, "example.com", 443); @@ -3504,10 +3526,9 @@ TEST_F(ProcessAlternativeServicesTest, AltSvcQuicDoesNotSupportTLSHandshake) { url::Origin::Create(GURL("https://example.com")), url::Origin::Create(GURL("https://example.com"))); - // Alt-Svc header only refers to PROTOCOL_QUIC_CRYPTO handshake. scoped_refptr<HttpResponseHeaders> headers( base::MakeRefCounted<HttpResponseHeaders>("")); - headers->AddHeader("alt-svc", "quic=\":443\"; v=\"50,49\""); + headers->AddHeader("alt-svc", "quic=\":443\"; v=\"50,43\""); session_->http_stream_factory()->ProcessAlternativeServices( session_.get(), network_isolation_key, headers.get(), origin); @@ -3519,11 +3540,9 @@ TEST_F(ProcessAlternativeServicesTest, AltSvcQuicDoesNotSupportTLSHandshake) { EXPECT_EQ(kProtoQUIC, alternatives[0].protocol()); EXPECT_EQ(HostPortPair("example.com", 443), alternatives[0].host_port_pair()); EXPECT_EQ(1u, alternatives[0].advertised_versions().size()); - // Q049 and T050 are supported. Q049 and Q050 are advertised in the Alt-Svc - // header. Therefore only Q049 is parsed. - quic::ParsedQuicVersion expected_advertised_version = { - quic::PROTOCOL_QUIC_CRYPTO, quic::QUIC_VERSION_49}; - EXPECT_EQ(expected_advertised_version, + // Q043 and T050 are supported. Q043 and Q050 are advertised in the Alt-Svc + // header. Therefore only Q043 is parsed. + EXPECT_EQ(quic::ParsedQuicVersion::Q043(), alternatives[0].advertised_versions()[0]); } @@ -3541,24 +3560,16 @@ TEST_F(ProcessAlternativeServicesTest, ProcessAltSvcQuicIetf) { base::MakeRefCounted<HttpResponseHeaders>("")); headers->AddHeader("alt-svc", "h3-27=\":443\"," - "h3-25=\":443\"," "h3-Q050=\":443\"," - "h3-Q049=\":443\"," - "h3-Q048=\":443\"," - "h3-Q047=\":443\"," - "h3-Q043=\":443\"," - "h3-Q039=\":443\""); + "h3-Q043=\":443\""); session_->http_stream_factory()->ProcessAlternativeServices( session_.get(), network_isolation_key, headers.get(), origin); quic::ParsedQuicVersionVector versions = { - {quic::PROTOCOL_TLS1_3, quic::QUIC_VERSION_IETF_DRAFT_27}, - {quic::PROTOCOL_TLS1_3, quic::QUIC_VERSION_IETF_DRAFT_25}, - {quic::PROTOCOL_QUIC_CRYPTO, quic::QUIC_VERSION_50}, - {quic::PROTOCOL_QUIC_CRYPTO, quic::QUIC_VERSION_49}, - {quic::PROTOCOL_QUIC_CRYPTO, quic::QUIC_VERSION_48}, - {quic::PROTOCOL_QUIC_CRYPTO, quic::QUIC_VERSION_43}, + quic::ParsedQuicVersion::Draft27(), + quic::ParsedQuicVersion::Q050(), + quic::ParsedQuicVersion::Q043(), }; AlternativeServiceInfoVector alternatives = http_server_properties_.GetAlternativeServiceInfos(origin, diff --git a/chromium/net/http/http_stream_parser.cc b/chromium/net/http/http_stream_parser.cc index c25ddf7029e..81b874031c0 100644 --- a/chromium/net/http/http_stream_parser.cc +++ b/chromium/net/http/http_stream_parser.cc @@ -922,6 +922,12 @@ int HttpStreamParser::HandleReadHeaderResult(int result) { // tunnel. response_header_start_offset_ = std::string::npos; response_body_length_ = -1; + // Record the timing of the 103 Early Hints response for the experiment + // (https://crbug.com/1093693). + if (response_->headers->response_code() == 103 && + first_early_hints_time_.is_null()) { + first_early_hints_time_ = response_start_time_; + } // Now waiting for the second set of headers to be read. } else { // Only set keep-alive based on final set of headers. diff --git a/chromium/net/http/http_stream_parser.h b/chromium/net/http/http_stream_parser.h index 2b5c2f0aeb7..0e773168272 100644 --- a/chromium/net/http/http_stream_parser.h +++ b/chromium/net/http/http_stream_parser.h @@ -95,6 +95,7 @@ class NET_EXPORT_PRIVATE HttpStreamParser { int64_t sent_bytes() const { return sent_bytes_; } base::TimeTicks response_start_time() { return response_start_time_; } + base::TimeTicks first_early_hints_time() { return first_early_hints_time_; } void GetSSLInfo(SSLInfo* ssl_info); @@ -241,6 +242,9 @@ class NET_EXPORT_PRIVATE HttpStreamParser { // parsed. base::TimeTicks response_start_time_; + // Time at which the first 103 Early Hints response is received. + base::TimeTicks first_early_hints_time_; + // Indicates the content length. If this value is less than zero // (and chunked_decoder_ is null), then we must read until the server // closes the connection. diff --git a/chromium/net/http/http_stream_parser_unittest.cc b/chromium/net/http/http_stream_parser_unittest.cc index 15c02611158..4dfad48917f 100644 --- a/chromium/net/http/http_stream_parser_unittest.cc +++ b/chromium/net/http/http_stream_parser_unittest.cc @@ -1680,6 +1680,39 @@ TEST(HttpStreamParser, ReceivedBytesIncludesContinueHeader) { EXPECT_EQ(response_size, get_runner.parser()->received_bytes()); } +// Test that "early hints" HTTP header is counted as "received_bytes". +// 103 Early Hints hasn't been implemented yet and should be ignored, but we +// collect timing information for the experiment (https://crbug.com/1093693). +TEST(HttpStreamParser, EarlyHints) { + std::string status103 = "HTTP/1.1 103 Early Hints\r\n\r\n"; + std::string headers = + "HTTP/1.1 200 OK\r\n" + "Content-Length: 7\r\n\r\n"; + int64_t headers_size = status103.size() + headers.size(); + std::string body = "content"; + std::string response = headers + body; + + SimpleGetRunner get_runner; + get_runner.AddRead(status103); + get_runner.AddRead(response); + get_runner.SetupParserAndSendRequest(); + get_runner.ReadHeaders(); + EXPECT_EQ(103, get_runner.response_info()->headers->response_code()); + int64_t status103_size = status103.size(); + EXPECT_EQ(status103_size, get_runner.parser()->received_bytes()); + get_runner.ReadHeaders(); + EXPECT_EQ(200, get_runner.response_info()->headers->response_code()); + EXPECT_EQ(headers_size, get_runner.parser()->received_bytes()); + int64_t response_size = headers_size + body.size(); + int body_size = body.size(); + int read_lengths[] = {body_size, 0}; + get_runner.ReadBody(body_size, read_lengths); + EXPECT_EQ(response_size, get_runner.parser()->received_bytes()); + + // Make sure the timing of the Early Hints response is captured. + EXPECT_FALSE(get_runner.parser()->first_early_hints_time().is_null()); +} + // Test that an HttpStreamParser can be read from after it's received headers // and data structures owned by its owner have been deleted. This happens // when a ResponseBodyDrainer is used. diff --git a/chromium/net/http/structured_headers.cc b/chromium/net/http/structured_headers.cc index 7d5c9218bd6..ab37791e526 100644 --- a/chromium/net/http/structured_headers.cc +++ b/chromium/net/http/structured_headers.cc @@ -12,6 +12,7 @@ #include "base/containers/flat_set.h" #include "base/containers/span.h" #include "base/logging.h" +#include "base/notreached.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" diff --git a/chromium/net/http/test_upload_data_stream_not_allow_http1.cc b/chromium/net/http/test_upload_data_stream_not_allow_http1.cc new file mode 100644 index 00000000000..5fc9f8a00b6 --- /dev/null +++ b/chromium/net/http/test_upload_data_stream_not_allow_http1.cc @@ -0,0 +1,32 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/http/test_upload_data_stream_not_allow_http1.h" + +#include "net/base/io_buffer.h" +#include "net/base/net_errors.h" + +namespace net { + +bool UploadDataStreamNotAllowHTTP1::AllowHTTP1() const { + return false; +} + +int UploadDataStreamNotAllowHTTP1::InitInternal(const NetLogWithSource&) { + return net::OK; +} + +int UploadDataStreamNotAllowHTTP1::ReadInternal(IOBuffer* buf, int buf_len) { + const size_t bytes_to_read = + std::min(content_.length(), static_cast<size_t>(buf_len)); + memcpy(buf->data(), content_.c_str(), bytes_to_read); + content_ = content_.substr(bytes_to_read); + if (!content_.length()) + SetIsFinalChunk(); + return bytes_to_read; +} + +void UploadDataStreamNotAllowHTTP1::ResetInternal() {} + +} // namespace net
\ No newline at end of file diff --git a/chromium/net/http/test_upload_data_stream_not_allow_http1.h b/chromium/net/http/test_upload_data_stream_not_allow_http1.h new file mode 100644 index 00000000000..50d33f6c807 --- /dev/null +++ b/chromium/net/http/test_upload_data_stream_not_allow_http1.h @@ -0,0 +1,33 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NET_HTTP_TEST_UPLOAD_DATA_STREAM_NOT_ALLOW_HTTP1_H_ +#define NET_HTTP_TEST_UPLOAD_DATA_STREAM_NOT_ALLOW_HTTP1_H_ + +#include "net/base/upload_data_stream.h" + +namespace net { + +// UploadDataStreamNotAllowHTTP1 simply disallows HTTP/1 and uploads content. +class UploadDataStreamNotAllowHTTP1 : public UploadDataStream { + public: + explicit UploadDataStreamNotAllowHTTP1(const std::string& content) + : UploadDataStream(true, 0), content_(content) {} + UploadDataStreamNotAllowHTTP1(const UploadDataStreamNotAllowHTTP1&) = delete; + UploadDataStreamNotAllowHTTP1& operator=( + const UploadDataStreamNotAllowHTTP1&) = delete; + + bool AllowHTTP1() const override; + + private: + int InitInternal(const NetLogWithSource& net_log) override; + int ReadInternal(IOBuffer* buf, int buf_len) override; + void ResetInternal() override; + + std::string content_; +}; + +} // namespace net + +#endif // NET_HTTP_TEST_UPLOAD_DATA_STREAM_NOT_ALLOW_HTTP1_H_
\ No newline at end of file diff --git a/chromium/net/http/transport_security_persister.cc b/chromium/net/http/transport_security_persister.cc index ce625c788b1..137c09f5ff1 100644 --- a/chromium/net/http/transport_security_persister.cc +++ b/chromium/net/http/transport_security_persister.cc @@ -15,11 +15,14 @@ #include "base/json/json_reader.h" #include "base/json/json_writer.h" #include "base/location.h" +#include "base/metrics/histogram_macros.h" #include "base/sequenced_task_runner.h" #include "base/task_runner_util.h" #include "base/threading/thread_task_runner_handle.h" #include "base/values.h" #include "crypto/sha2.h" +#include "net/base/features.h" +#include "net/base/network_isolation_key.h" #include "net/cert/x509_certificate.h" #include "net/http/transport_security_state.h" @@ -47,24 +50,50 @@ std::string ExternalStringToHashedDomain(const std::string& external) { return out; } -const char kIncludeSubdomains[] = "include_subdomains"; +// Version 2 of the on-disk format consists of a single JSON object. The +// top-level dictionary has "version", "sts", and "expect_ct" entries. The first +// is an integer, the latter two are unordered lists of dictionaries, each +// representing cached data for a single host. + +// Stored in serialized dictionary values to distinguish incompatible versions. +// Version 1 is distinguished by the lack of an integer version value. +const char kVersionKey[] = "version"; +const int kCurrentVersionValue = 2; + +// Keys in top level serialized dictionary, for lists of STS and Expect-CT +// entries, respectively. +const char kSTSKey[] = "sts"; +const char kExpectCTKey[] = "expect_ct"; + +// Hostname entry, used in serialized STS and Expect-CT dictionaries. Value is +// produced by passing hashed hostname strings to +// HashedDomainToExternalString(). +const char kHostname[] = "host"; + +// Key values in serialized STS entries. const char kStsIncludeSubdomains[] = "sts_include_subdomains"; -const char kMode[] = "mode"; +const char kStsObserved[] = "sts_observed"; const char kExpiry[] = "expiry"; +const char kMode[] = "mode"; + +// Values for "mode" used in serialized STS entries. const char kForceHTTPS[] = "force-https"; -const char kStrict[] = "strict"; const char kDefault[] = "default"; -const char kPinningOnly[] = "pinning-only"; -const char kCreated[] = "created"; -const char kStsObserved[] = "sts_observed"; -// The keys below are contained in a subdictionary keyed as -// |kExpectCTSubdictionary|. -const char kExpectCTSubdictionary[] = "expect_ct"; -const char kExpectCTExpiry[] = "expect_ct_expiry"; + +// Key names in serialized Expect-CT entries. +const char kNetworkIsolationKey[] = "nik"; const char kExpectCTObserved[] = "expect_ct_observed"; +const char kExpectCTExpiry[] = "expect_ct_expiry"; const char kExpectCTEnforce[] = "expect_ct_enforce"; const char kExpectCTReportUri[] = "expect_ct_report_uri"; +// Obsolete values in older STS entries. +const char kIncludeSubdomains[] = "include_subdomains"; +const char kStrict[] = "strict"; +const char kPinningOnly[] = "pinning-only"; +const char kCreated[] = "created"; +const char kExpectCTSubdictionary[] = "expect_ct"; + std::string LoadState(const base::FilePath& path) { std::string result; if (!base::ReadFileToString(path, &result)) { @@ -78,104 +107,201 @@ bool IsDynamicExpectCTEnabled() { TransportSecurityState::kDynamicExpectCTFeature); } -// Populates |host| with default values for the STS states. -// These default values represent "null" states and are only useful to keep -// the entries in the resulting JSON consistent. The deserializer will ignore -// "null" states. -// TODO(davidben): This can be removed when the STS and Expect-CT states are -// stored independently on disk. https://crbug.com/470295 -void PopulateEntryWithDefaults(base::DictionaryValue* host) { - host->Clear(); - - // STS default values. - host->SetBoolean(kStsIncludeSubdomains, false); - host->SetDouble(kStsObserved, 0.0); - host->SetDouble(kExpiry, 0.0); - host->SetString(kMode, kDefault); -} +// Serializes STS data from |state| to a Value. +base::Value SerializeSTSData(const TransportSecurityState* state) { + base::Value sts_list(base::Value::Type::LIST); -// Serializes STS data from |state| into |toplevel|. Any existing state in -// |toplevel| for each item is overwritten. -void SerializeSTSData(TransportSecurityState* state, - base::DictionaryValue* toplevel) { TransportSecurityState::STSStateIterator sts_iterator(*state); for (; sts_iterator.HasNext(); sts_iterator.Advance()) { - const std::string& hostname = sts_iterator.hostname(); const TransportSecurityState::STSState& sts_state = sts_iterator.domain_state(); - const std::string key = HashedDomainToExternalString(hostname); - std::unique_ptr<base::DictionaryValue> serialized( - new base::DictionaryValue); - PopulateEntryWithDefaults(serialized.get()); - - serialized->SetBoolean(kStsIncludeSubdomains, sts_state.include_subdomains); - serialized->SetDouble(kStsObserved, sts_state.last_observed.ToDoubleT()); - serialized->SetDouble(kExpiry, sts_state.expiry.ToDoubleT()); + base::Value serialized(base::Value::Type::DICTIONARY); + serialized.SetStringKey( + kHostname, HashedDomainToExternalString(sts_iterator.hostname())); + serialized.SetBoolKey(kStsIncludeSubdomains, sts_state.include_subdomains); + serialized.SetDoubleKey(kStsObserved, sts_state.last_observed.ToDoubleT()); + serialized.SetDoubleKey(kExpiry, sts_state.expiry.ToDoubleT()); switch (sts_state.upgrade_mode) { case TransportSecurityState::STSState::MODE_FORCE_HTTPS: - serialized->SetString(kMode, kForceHTTPS); + serialized.SetStringKey(kMode, kForceHTTPS); break; case TransportSecurityState::STSState::MODE_DEFAULT: - serialized->SetString(kMode, kDefault); + serialized.SetStringKey(kMode, kDefault); break; - default: - NOTREACHED() << "STSState with unknown mode"; - continue; } - toplevel->Set(key, std::move(serialized)); + sts_list.Append(std::move(serialized)); } + return sts_list; } -// Serializes Expect-CT data from |state| into |toplevel|. For each Expect-CT -// item in |state|, if |toplevel| already contains an item for that hostname, -// the item is updated to include a subdictionary with key -// |kExpectCTSubdictionary|; otherwise an item is created for that hostname with -// a |kExpectCTSubdictionary| subdictionary. -void SerializeExpectCTData(TransportSecurityState* state, - base::DictionaryValue* toplevel) { - if (!IsDynamicExpectCTEnabled()) +// Deserializes STS data from a Value created by the above method. +void DeserializeSTSData(const base::Value& sts_list, + TransportSecurityState* state) { + if (!sts_list.is_list()) return; + + base::Time current_time(base::Time::Now()); + + for (const base::Value& sts_entry : sts_list.GetList()) { + if (!sts_entry.is_dict()) + continue; + + const std::string* hostname = sts_entry.FindStringKey(kHostname); + base::Optional<bool> sts_include_subdomains = + sts_entry.FindBoolKey(kStsIncludeSubdomains); + base::Optional<double> sts_observed = sts_entry.FindDoubleKey(kStsObserved); + base::Optional<double> expiry = sts_entry.FindDoubleKey(kExpiry); + const std::string* mode = sts_entry.FindStringKey(kMode); + + if (!hostname || !sts_include_subdomains.has_value() || + !sts_observed.has_value() || !expiry.has_value() || !mode) { + continue; + } + + TransportSecurityState::STSState sts_state; + sts_state.include_subdomains = *sts_include_subdomains; + sts_state.last_observed = base::Time::FromDoubleT(*sts_observed); + sts_state.expiry = base::Time::FromDoubleT(*expiry); + + if (*mode == kForceHTTPS) { + sts_state.upgrade_mode = + TransportSecurityState::STSState::MODE_FORCE_HTTPS; + } else if (*mode == kDefault) { + sts_state.upgrade_mode = TransportSecurityState::STSState::MODE_DEFAULT; + } else { + continue; + } + + if (sts_state.expiry < current_time || !sts_state.ShouldUpgradeToSSL()) + continue; + + std::string hashed = ExternalStringToHashedDomain(*hostname); + if (hashed.empty()) + continue; + + state->AddOrUpdateEnabledSTSHosts(hashed, sts_state); + } +} + +// Serializes Expect-CT data from |state| to a Value. +base::Value SerializeExpectCTData(TransportSecurityState* state) { + base::Value ct_list(base::Value::Type::LIST); + + if (!IsDynamicExpectCTEnabled()) + return ct_list; + TransportSecurityState::ExpectCTStateIterator expect_ct_iterator(*state); for (; expect_ct_iterator.HasNext(); expect_ct_iterator.Advance()) { - const std::string& hostname = expect_ct_iterator.hostname(); const TransportSecurityState::ExpectCTState& expect_ct_state = expect_ct_iterator.domain_state(); - // See if the current |hostname| already has STS state and, if so, - // update that entry. - const std::string key = HashedDomainToExternalString(hostname); - base::DictionaryValue* serialized = nullptr; - if (!toplevel->GetDictionary(key, &serialized)) { - std::unique_ptr<base::DictionaryValue> serialized_scoped( - new base::DictionaryValue); - serialized = serialized_scoped.get(); - PopulateEntryWithDefaults(serialized); - toplevel->Set(key, std::move(serialized_scoped)); + base::DictionaryValue ct_entry; + + base::Value network_isolation_key_value; + // Don't serialize entries with transient NetworkIsolationKeys. + if (!expect_ct_iterator.network_isolation_key().ToValue( + &network_isolation_key_value)) { + continue; + } + ct_entry.SetKey(kNetworkIsolationKey, + std::move(network_isolation_key_value)); + + ct_entry.SetStringKey( + kHostname, HashedDomainToExternalString(expect_ct_iterator.hostname())); + ct_entry.SetDoubleKey(kExpectCTObserved, + expect_ct_state.last_observed.ToDoubleT()); + ct_entry.SetDoubleKey(kExpectCTExpiry, expect_ct_state.expiry.ToDoubleT()); + ct_entry.SetBoolKey(kExpectCTEnforce, expect_ct_state.enforce); + ct_entry.SetStringKey(kExpectCTReportUri, + expect_ct_state.report_uri.spec()); + + ct_list.Append(std::move(ct_entry)); + } + + return ct_list; +} + +// Deserializes Expect-CT data from a Value created by the above method. +void DeserializeExpectCTData(const base::Value& ct_list, + TransportSecurityState* state) { + if (!ct_list.is_list()) + return; + bool partition_by_nik = base::FeatureList::IsEnabled( + features::kPartitionExpectCTStateByNetworkIsolationKey); + + const base::Time current_time(base::Time::Now()); + + for (const base::Value& ct_entry : ct_list.GetList()) { + if (!ct_entry.is_dict()) + continue; + + const std::string* hostname = ct_entry.FindStringKey(kHostname); + const base::Value* network_isolation_key_value = + ct_entry.FindKey(kNetworkIsolationKey); + base::Optional<double> expect_ct_last_observed = + ct_entry.FindDoubleKey(kExpectCTObserved); + base::Optional<double> expect_ct_expiry = + ct_entry.FindDoubleKey(kExpectCTExpiry); + base::Optional<bool> expect_ct_enforce = + ct_entry.FindBoolKey(kExpectCTEnforce); + const std::string* expect_ct_report_uri = + ct_entry.FindStringKey(kExpectCTReportUri); + + if (!hostname || !network_isolation_key_value || + !expect_ct_last_observed.has_value() || !expect_ct_expiry.has_value() || + !expect_ct_enforce.has_value() || !expect_ct_report_uri) { + continue; } - std::unique_ptr<base::DictionaryValue> expect_ct_subdictionary( - new base::DictionaryValue()); - expect_ct_subdictionary->SetDouble( - kExpectCTObserved, expect_ct_state.last_observed.ToDoubleT()); - expect_ct_subdictionary->SetDouble(kExpectCTExpiry, - expect_ct_state.expiry.ToDoubleT()); - expect_ct_subdictionary->SetBoolean(kExpectCTEnforce, - expect_ct_state.enforce); - expect_ct_subdictionary->SetString(kExpectCTReportUri, - expect_ct_state.report_uri.spec()); - serialized->Set(kExpectCTSubdictionary, std::move(expect_ct_subdictionary)); + TransportSecurityState::ExpectCTState expect_ct_state; + expect_ct_state.last_observed = + base::Time::FromDoubleT(*expect_ct_last_observed); + expect_ct_state.expiry = base::Time::FromDoubleT(*expect_ct_expiry); + expect_ct_state.enforce = *expect_ct_enforce; + + GURL report_uri(*expect_ct_report_uri); + if (report_uri.is_valid()) + expect_ct_state.report_uri = report_uri; + + if (expect_ct_state.expiry < current_time || + (!expect_ct_state.enforce && expect_ct_state.report_uri.is_empty())) { + continue; + } + + std::string hashed = ExternalStringToHashedDomain(*hostname); + if (hashed.empty()) + continue; + + NetworkIsolationKey network_isolation_key; + if (!NetworkIsolationKey::FromValue(*network_isolation_key_value, + &network_isolation_key)) { + continue; + } + + // If Expect-CT is not being partitioned by NetworkIsolationKey, but + // |network_isolation_key| is not empty, drop the entry, to avoid ambiguity + // and favor entries that were saved with an empty NetworkIsolationKey. + if (!partition_by_nik && !network_isolation_key.IsEmpty()) + continue; + + state->AddOrUpdateEnabledExpectCTHosts(hashed, network_isolation_key, + expect_ct_state); } } -// Populates |state| with the values in the |kExpectCTSubdictionary| -// subdictionary in |parsed|. Returns false if |parsed| is malformed -// (e.g. missing a required Expect-CT key) and true otherwise. Note that true -// does not necessarily mean that Expect-CT state was present in |parsed|. -bool DeserializeExpectCTState(const base::DictionaryValue* parsed, - TransportSecurityState::ExpectCTState* state) { +// Handles deserializing |kExpectCTSubdictionary| in dictionaries that use the +// obsolete format. Populates |state| with the values from the Expect-CT +// subdictionary in |parsed|. Returns false if |parsed| is malformed (e.g. +// missing a required Expect-CT key) and true otherwise. Note that true does not +// necessarily mean that Expect-CT state was present in |parsed|. +// +// TODO(mmenke): Remove once the obsolete format is no longer supported. +bool DeserializeObsoleteExpectCTState( + const base::DictionaryValue* parsed, + TransportSecurityState::ExpectCTState* state) { const base::DictionaryValue* expect_ct_subdictionary; if (!parsed->GetDictionary(kExpectCTSubdictionary, &expect_ct_subdictionary)) { @@ -275,39 +401,75 @@ void TransportSecurityPersister::OnWriteFinished(base::OnceClosure callback) { bool TransportSecurityPersister::SerializeData(std::string* output) { DCHECK(foreground_runner_->RunsTasksInCurrentSequence()); - base::DictionaryValue toplevel; - - // TODO(davidben): Fix the serialization format by splitting the on-disk - // representation of the STS and Expect-CT states. https://crbug.com/470295. - SerializeSTSData(transport_security_state_, &toplevel); - SerializeExpectCTData(transport_security_state_, &toplevel); + base::Value toplevel(base::Value::Type::DICTIONARY); + toplevel.SetIntKey(kVersionKey, kCurrentVersionValue); + toplevel.SetKey(kSTSKey, SerializeSTSData(transport_security_state_)); + toplevel.SetKey(kExpectCTKey, + SerializeExpectCTData(transport_security_state_)); - base::JSONWriter::WriteWithOptions( - toplevel, base::JSONWriter::OPTIONS_PRETTY_PRINT, output); + base::JSONWriter::Write(toplevel, output); return true; } bool TransportSecurityPersister::LoadEntries(const std::string& serialized, - bool* dirty) { + bool* data_in_old_format) { DCHECK(foreground_runner_->RunsTasksInCurrentSequence()); transport_security_state_->ClearDynamicData(); - return Deserialize(serialized, dirty, transport_security_state_); + return Deserialize(serialized, data_in_old_format, transport_security_state_); } -// static bool TransportSecurityPersister::Deserialize(const std::string& serialized, - bool* dirty, + bool* data_in_old_format, TransportSecurityState* state) { - std::unique_ptr<base::Value> value = - base::JSONReader::ReadDeprecated(serialized); - base::DictionaryValue* dict_value = nullptr; - if (!value.get() || !value->GetAsDictionary(&dict_value)) + *data_in_old_format = false; + base::Optional<base::Value> value = base::JSONReader::Read(serialized); + if (!value || !value->is_dict()) return false; + // Old dictionaries don't have a version number, so try the obsolete format if + // there's no integer version number. + base::Optional<int> version = value->FindIntKey(kVersionKey); + if (!version) { + bool dirty_unused = false; + bool success = DeserializeObsoleteData(*value, &dirty_unused, state); + // If successfully loaded data from a file in the old format, need to + // overwrite the file with the newer format. + *data_in_old_format = success; + return success; + } + + if (*version != kCurrentVersionValue) + return false; + + base::Value* sts_value = value->FindKey(kSTSKey); + if (sts_value) + DeserializeSTSData(*sts_value, state); + + base::Value* expect_ct_value = value->FindKey(kExpectCTKey); + if (expect_ct_value) + DeserializeExpectCTData(*expect_ct_value, state); + + UMA_HISTOGRAM_CUSTOM_COUNTS("Net.ExpectCT.EntriesOnLoad", + state->num_expect_ct_entries(), 1 /* min */, + 2000 /* max */, 40 /* buckets */); + return true; +} + +bool TransportSecurityPersister::DeserializeObsoleteData( + const base::Value& value, + bool* dirty, + TransportSecurityState* state) { const base::Time current_time(base::Time::Now()); bool dirtied = false; + const base::DictionaryValue* dict_value = nullptr; + int rv = value.GetAsDictionary(&dict_value); + // The one caller ensures |value| is of Value::Type::DICTIONARY already, + // though it doesn't extract a DictionaryValue*, since that is the deprecated + // way to use dictionaries. + DCHECK(rv); + for (base::DictionaryValue::Iterator i(*dict_value); !i.IsAtEnd(); i.Advance()) { const base::DictionaryValue* parsed = nullptr; @@ -367,7 +529,7 @@ bool TransportSecurityPersister::Deserialize(const std::string& serialized, sts_state.last_observed = base::Time::Now(); } - if (!DeserializeExpectCTState(parsed, &expect_ct_state)) { + if (!DeserializeObsoleteExpectCTState(parsed, &expect_ct_state)) { continue; } @@ -394,8 +556,11 @@ bool TransportSecurityPersister::Deserialize(const std::string& serialized, // We only register entries that have actual state. if (has_sts) state->AddOrUpdateEnabledSTSHosts(hashed, sts_state); - if (has_expect_ct) - state->AddOrUpdateEnabledExpectCTHosts(hashed, expect_ct_state); + if (has_expect_ct) { + // Use empty NetworkIsolationKeys for old data. + state->AddOrUpdateEnabledExpectCTHosts(hashed, NetworkIsolationKey(), + expect_ct_state); + } } *dirty = dirtied; @@ -408,12 +573,10 @@ void TransportSecurityPersister::CompleteLoad(const std::string& state) { if (state.empty()) return; - bool dirty = false; - if (!LoadEntries(state, &dirty)) { - LOG(ERROR) << "Failed to deserialize state: " << state; + bool data_in_old_format = false; + if (!LoadEntries(state, &data_in_old_format)) return; - } - if (dirty) + if (data_in_old_format) StateIsDirty(transport_security_state_); } diff --git a/chromium/net/http/transport_security_persister.h b/chromium/net/http/transport_security_persister.h index a7a92839c32..9d6be48f3b6 100644 --- a/chromium/net/http/transport_security_persister.h +++ b/chromium/net/http/transport_security_persister.h @@ -45,6 +45,7 @@ namespace base { class SequencedTaskRunner; +class Value; } namespace net { @@ -107,20 +108,27 @@ class NET_EXPORT TransportSecurityPersister // Clears any existing non-static entries, and then re-populates // |transport_security_state_|. // - // Sets |*dirty| to true if the new state differs from the persisted - // state; false otherwise. - bool LoadEntries(const std::string& serialized, bool* dirty); + // Sets |*data_in_old_format| to true if the loaded data is in an older format + // and should be overwritten with data in the newest format. + bool LoadEntries(const std::string& serialized, bool* data_in_old_format); private: // Populates |state| from the JSON string |serialized|. Returns true if // all entries were parsed and deserialized correctly. // - // Sets |*dirty| to true if the new state differs from the persisted - // state; false otherwise. + // Sets |*data_in_old_format| to true if the old data is in the old file + // format and needs to be overwritten with data in the newer format; false + // otherwise. static bool Deserialize(const std::string& serialized, - bool* dirty, + bool* data_in_old_format, TransportSecurityState* state); + // Used internally by Deserialize() to handle older dictionaries. + // TODO(https://crbug.com/1086975): This should be removed in Chrome 88. + static bool DeserializeObsoleteData(const base::Value& value, + bool* dirty, + TransportSecurityState* state); + void CompleteLoad(const std::string& state); void OnWriteFinished(base::OnceClosure callback); diff --git a/chromium/net/http/transport_security_persister_unittest.cc b/chromium/net/http/transport_security_persister_unittest.cc index db952591974..c9a893bcfe9 100644 --- a/chromium/net/http/transport_security_persister_unittest.cc +++ b/chromium/net/http/transport_security_persister_unittest.cc @@ -16,9 +16,13 @@ #include "base/run_loop.h" #include "base/test/scoped_feature_list.h" #include "base/threading/thread_task_runner_handle.h" +#include "net/base/features.h" +#include "net/base/network_isolation_key.h" #include "net/http/transport_security_state.h" #include "net/test/test_with_task_environment.h" #include "testing/gtest/include/gtest/gtest.h" +#include "url/gurl.h" +#include "url/origin.h" namespace net { @@ -26,9 +30,19 @@ namespace { const char kReportUri[] = "http://www.example.test/report"; -class TransportSecurityPersisterTest : public TestWithTaskEnvironment { +// The bool indicates whether kPartitionExpectCTStateByNetworkIsolationKey +// should be enabled. +class TransportSecurityPersisterTest : public ::testing::TestWithParam<bool>, + public WithTaskEnvironment { public: - TransportSecurityPersisterTest() = default; + TransportSecurityPersisterTest() + : WithTaskEnvironment( + base::test::TaskEnvironment::TimeSource::MOCK_TIME) { + // Mock out time so that entries with hard-coded json data can be + // successfully loaded. Use a large enough value that dynamically created + // entries have at least somewhat interesting expiration times. + FastForwardBy(base::TimeDelta::FromDays(3660)); + } ~TransportSecurityPersisterTest() override { EXPECT_TRUE(base::MessageLoopCurrentForIO::IsSet()); @@ -42,23 +56,36 @@ class TransportSecurityPersisterTest : public TestWithTaskEnvironment { base::ThreadPool::CreateSequencedTaskRunner( {base::MayBlock(), base::TaskPriority::BEST_EFFORT, base::TaskShutdownBehavior::BLOCK_SHUTDOWN})); + // This feature is used in initializing |state_|. + if (partition_expect_ct_state()) { + feature_list_.InitAndEnableFeature( + features::kPartitionExpectCTStateByNetworkIsolationKey); + } else { + feature_list_.InitAndDisableFeature( + features::kPartitionExpectCTStateByNetworkIsolationKey); + } + state_ = std::make_unique<TransportSecurityState>(); persister_ = std::make_unique<TransportSecurityPersister>( - &state_, temp_dir_.GetPath(), std::move(background_runner)); + state_.get(), temp_dir_.GetPath(), std::move(background_runner)); } + bool partition_expect_ct_state() const { return GetParam(); } + protected: base::ScopedTempDir temp_dir_; - TransportSecurityState state_; + base::test::ScopedFeatureList feature_list_; + std::unique_ptr<TransportSecurityState> state_; std::unique_ptr<TransportSecurityPersister> persister_; }; +INSTANTIATE_TEST_SUITE_P(All, TransportSecurityPersisterTest, testing::Bool()); + // Tests that LoadEntries() clears existing non-static entries. -TEST_F(TransportSecurityPersisterTest, LoadEntriesClearsExistingState) { +TEST_P(TransportSecurityPersisterTest, LoadEntriesClearsExistingState) { base::test::ScopedFeatureList feature_list; feature_list.InitAndEnableFeature( TransportSecurityState::kDynamicExpectCTFeature); - std::string output; - bool dirty; + bool data_in_old_format; TransportSecurityState::STSState sts_state; TransportSecurityState::ExpectCTState expect_ct_state; @@ -66,63 +93,65 @@ TEST_F(TransportSecurityPersisterTest, LoadEntriesClearsExistingState) { const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000); static const char kYahooDomain[] = "yahoo.com"; - EXPECT_FALSE(state_.GetDynamicSTSState(kYahooDomain, &sts_state, nullptr)); + EXPECT_FALSE(state_->GetDynamicSTSState(kYahooDomain, &sts_state)); - state_.AddHSTS(kYahooDomain, expiry, false /* include subdomains */); - state_.AddExpectCT(kYahooDomain, expiry, true /* enforce */, GURL()); + state_->AddHSTS(kYahooDomain, expiry, false /* include subdomains */); + state_->AddExpectCT(kYahooDomain, expiry, true /* enforce */, GURL(), + NetworkIsolationKey()); - EXPECT_TRUE(state_.GetDynamicSTSState(kYahooDomain, &sts_state, nullptr)); - EXPECT_TRUE(state_.GetDynamicExpectCTState(kYahooDomain, &expect_ct_state)); + EXPECT_TRUE(state_->GetDynamicSTSState(kYahooDomain, &sts_state)); + EXPECT_TRUE(state_->GetDynamicExpectCTState( + kYahooDomain, NetworkIsolationKey(), &expect_ct_state)); - EXPECT_TRUE(persister_->LoadEntries("{}", &dirty)); - EXPECT_FALSE(dirty); + EXPECT_TRUE(persister_->LoadEntries("{\"version\":2}", &data_in_old_format)); + EXPECT_FALSE(data_in_old_format); - EXPECT_FALSE(state_.GetDynamicSTSState(kYahooDomain, &sts_state, nullptr)); - EXPECT_FALSE(state_.GetDynamicExpectCTState(kYahooDomain, &expect_ct_state)); + EXPECT_FALSE(state_->GetDynamicSTSState(kYahooDomain, &sts_state)); + EXPECT_FALSE(state_->GetDynamicExpectCTState( + kYahooDomain, NetworkIsolationKey(), &expect_ct_state)); } -TEST_F(TransportSecurityPersisterTest, SerializeData1) { +TEST_P(TransportSecurityPersisterTest, SerializeData1) { std::string output; - bool dirty; + bool data_in_old_format; EXPECT_TRUE(persister_->SerializeData(&output)); - EXPECT_TRUE(persister_->LoadEntries(output, &dirty)); - EXPECT_FALSE(dirty); + EXPECT_TRUE(persister_->LoadEntries(output, &data_in_old_format)); + EXPECT_FALSE(data_in_old_format); } -TEST_F(TransportSecurityPersisterTest, SerializeData2) { +TEST_P(TransportSecurityPersisterTest, SerializeData2) { TransportSecurityState::STSState sts_state; const base::Time current_time(base::Time::Now()); const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000); static const char kYahooDomain[] = "yahoo.com"; - EXPECT_FALSE(state_.GetDynamicSTSState(kYahooDomain, &sts_state, nullptr)); + EXPECT_FALSE(state_->GetDynamicSTSState(kYahooDomain, &sts_state)); bool include_subdomains = true; - state_.AddHSTS(kYahooDomain, expiry, include_subdomains); + state_->AddHSTS(kYahooDomain, expiry, include_subdomains); std::string output; - bool dirty; + bool data_in_old_format; EXPECT_TRUE(persister_->SerializeData(&output)); - EXPECT_TRUE(persister_->LoadEntries(output, &dirty)); + EXPECT_TRUE(persister_->LoadEntries(output, &data_in_old_format)); + EXPECT_FALSE(data_in_old_format); - EXPECT_TRUE(state_.GetDynamicSTSState(kYahooDomain, &sts_state, nullptr)); + EXPECT_TRUE(state_->GetDynamicSTSState(kYahooDomain, &sts_state)); EXPECT_EQ(sts_state.upgrade_mode, TransportSecurityState::STSState::MODE_FORCE_HTTPS); - EXPECT_TRUE(state_.GetDynamicSTSState("foo.yahoo.com", &sts_state, nullptr)); + EXPECT_TRUE(state_->GetDynamicSTSState("foo.yahoo.com", &sts_state)); EXPECT_EQ(sts_state.upgrade_mode, TransportSecurityState::STSState::MODE_FORCE_HTTPS); - EXPECT_TRUE( - state_.GetDynamicSTSState("foo.bar.yahoo.com", &sts_state, nullptr)); + EXPECT_TRUE(state_->GetDynamicSTSState("foo.bar.yahoo.com", &sts_state)); EXPECT_EQ(sts_state.upgrade_mode, TransportSecurityState::STSState::MODE_FORCE_HTTPS); - EXPECT_TRUE( - state_.GetDynamicSTSState("foo.bar.baz.yahoo.com", &sts_state, nullptr)); + EXPECT_TRUE(state_->GetDynamicSTSState("foo.bar.baz.yahoo.com", &sts_state)); EXPECT_EQ(sts_state.upgrade_mode, TransportSecurityState::STSState::MODE_FORCE_HTTPS); } -TEST_F(TransportSecurityPersisterTest, SerializeData3) { +TEST_P(TransportSecurityPersisterTest, SerializeData3) { base::test::ScopedFeatureList feature_list; feature_list.InitAndEnableFeature( TransportSecurityState::kDynamicExpectCTFeature); @@ -131,26 +160,27 @@ TEST_F(TransportSecurityPersisterTest, SerializeData3) { base::Time expiry = base::Time::Now() + base::TimeDelta::FromSeconds(1000); bool include_subdomains = false; - state_.AddHSTS("www.example.com", expiry, include_subdomains); - state_.AddExpectCT("www.example.com", expiry, true /* enforce */, GURL()); + state_->AddHSTS("www.example.com", expiry, include_subdomains); + state_->AddExpectCT("www.example.com", expiry, true /* enforce */, GURL(), + NetworkIsolationKey()); // Add another entry. expiry = base::Time::Now() + base::TimeDelta::FromSeconds(3000); - state_.AddHSTS("www.example.net", expiry, include_subdomains); - state_.AddExpectCT("www.example.net", expiry, false /* enforce */, - report_uri); + state_->AddHSTS("www.example.net", expiry, include_subdomains); + state_->AddExpectCT("www.example.net", expiry, false /* enforce */, + report_uri, NetworkIsolationKey()); // Save a copy of everything. std::set<std::string> sts_saved; - TransportSecurityState::STSStateIterator sts_iter(state_); + TransportSecurityState::STSStateIterator sts_iter(*state_); while (sts_iter.HasNext()) { sts_saved.insert(sts_iter.hostname()); sts_iter.Advance(); } std::set<std::string> expect_ct_saved; - TransportSecurityState::ExpectCTStateIterator expect_ct_iter(state_); + TransportSecurityState::ExpectCTStateIterator expect_ct_iter(*state_); while (expect_ct_iter.HasNext()) { expect_ct_saved.insert(expect_ct_iter.hostname()); expect_ct_iter.Advance(); @@ -161,7 +191,7 @@ TEST_F(TransportSecurityPersisterTest, SerializeData3) { // Persist the data to the file. base::RunLoop run_loop; - persister_->WriteNow(&state_, run_loop.QuitClosure()); + persister_->WriteNow(state_.get(), run_loop.QuitClosure()); run_loop.Run(); // Read the data back. @@ -169,13 +199,13 @@ TEST_F(TransportSecurityPersisterTest, SerializeData3) { std::string persisted; EXPECT_TRUE(base::ReadFileToString(path, &persisted)); EXPECT_EQ(persisted, serialized); - bool dirty; - EXPECT_TRUE(persister_->LoadEntries(persisted, &dirty)); - EXPECT_FALSE(dirty); + bool data_in_old_format; + EXPECT_TRUE(persister_->LoadEntries(persisted, &data_in_old_format)); + EXPECT_FALSE(data_in_old_format); // Check that states are the same as saved. size_t count = 0; - TransportSecurityState::STSStateIterator sts_iter2(state_); + TransportSecurityState::STSStateIterator sts_iter2(*state_); while (sts_iter2.HasNext()) { count++; sts_iter2.Advance(); @@ -183,7 +213,7 @@ TEST_F(TransportSecurityPersisterTest, SerializeData3) { EXPECT_EQ(count, sts_saved.size()); count = 0; - TransportSecurityState::ExpectCTStateIterator expect_ct_iter2(state_); + TransportSecurityState::ExpectCTStateIterator expect_ct_iter2(*state_); while (expect_ct_iter2.HasNext()) { count++; expect_ct_iter2.Advance(); @@ -191,24 +221,130 @@ TEST_F(TransportSecurityPersisterTest, SerializeData3) { EXPECT_EQ(count, expect_ct_saved.size()); } -TEST_F(TransportSecurityPersisterTest, SerializeDataOld) { +TEST_P(TransportSecurityPersisterTest, DeserializeBadData) { + bool data_in_old_format; + EXPECT_FALSE(persister_->LoadEntries("", &data_in_old_format)); + EXPECT_FALSE(persister_->LoadEntries("Foopy", &data_in_old_format)); + EXPECT_FALSE(persister_->LoadEntries("15", &data_in_old_format)); + EXPECT_FALSE(persister_->LoadEntries("[15]", &data_in_old_format)); + EXPECT_FALSE(persister_->LoadEntries("{\"version\":1}", &data_in_old_format)); +} + +TEST_P(TransportSecurityPersisterTest, DeserializeDataOldWithoutCreationDate) { + const char kDomain[] = "example.test"; + // This is an old-style piece of transport state JSON, which has no creation // date. - std::string output = + const std::string kInput = "{ " - "\"NiyD+3J1r6z1wjl2n1ALBu94Zj9OsEAMo0kCN8js0Uk=\": {" + "\"G0EywIek2XnIhLrUjaK4TrHBT1+2TcixDVRXwM3/CCo=\": {" "\"expiry\": 1266815027.983453, " "\"include_subdomains\": false, " "\"mode\": \"strict\" " "}" "}"; - bool dirty; - EXPECT_TRUE(persister_->LoadEntries(output, &dirty)); - EXPECT_TRUE(dirty); + bool data_in_old_format; + EXPECT_TRUE(persister_->LoadEntries(kInput, &data_in_old_format)); + EXPECT_TRUE(data_in_old_format); + + TransportSecurityState::STSState sts_state; + EXPECT_TRUE(state_->GetDynamicSTSState(kDomain, &sts_state)); + EXPECT_EQ(kDomain, sts_state.domain); + EXPECT_FALSE(sts_state.include_subdomains); + EXPECT_EQ(TransportSecurityState::STSState::MODE_FORCE_HTTPS, + sts_state.upgrade_mode); +} + +TEST_P(TransportSecurityPersisterTest, DeserializeDataOldMergedDictionary) { + const char kStsDomain[] = "sts.test"; + const char kExpectCTDomain[] = "expect_ct.test"; + const GURL kExpectCTReportUri = GURL("https://expect_ct.test/report_uri"); + const char kBothDomain[] = "both.test"; + + // This is an old-style piece of transport state JSON, which uses a single + // unversioned host-keyed dictionary of merged ExpectCT and HSTS data. + const std::string kInput = + "{" + " \"CxLbri+JPdi5pZ8/a/2rjyzq+IYs07WJJ1yxjB4Lpw0=\": {" + " \"expect_ct\": {" + " \"expect_ct_enforce\": true," + " \"expect_ct_expiry\": 1590512843.283966," + " \"expect_ct_observed\": 1590511843.284064," + " \"expect_ct_report_uri\": \"https://expect_ct.test/report_uri\"" + " }," + " \"expiry\": 0.0," + " \"mode\": \"default\"," + " \"sts_include_subdomains\": false," + " \"sts_observed\": 0.0" + " }," + " \"DkgjGShIBmYtgJcJf5lfX3rTr2S6dqyF+O8IAgjuleE=\": {" + " \"expiry\": 1590512843.283966," + " \"mode\": \"force-https\"," + " \"sts_include_subdomains\": false," + " \"sts_observed\": 1590511843.284025" + " }," + " \"M5lkNV3JBeoPMlKrTOKRYT+mrUsZCS5eoQWsc9/r1MU=\": {" + " \"expect_ct\": {" + " \"expect_ct_enforce\": true," + " \"expect_ct_expiry\": 1590512843.283966," + " \"expect_ct_observed\": 1590511843.284098," + " \"expect_ct_report_uri\": \"\"" + " }," + " \"expiry\": 1590512843.283966," + " \"mode\": \"force-https\"," + " \"sts_include_subdomains\": true," + " \"sts_observed\": 1590511843.284091" + " }" + "}"; + + bool data_in_old_format; + EXPECT_TRUE(persister_->LoadEntries(kInput, &data_in_old_format)); + EXPECT_TRUE(data_in_old_format); + + // kStsDomain should only have HSTS information. + TransportSecurityState::STSState sts_state; + EXPECT_TRUE(state_->GetDynamicSTSState(kStsDomain, &sts_state)); + EXPECT_EQ(kStsDomain, sts_state.domain); + EXPECT_FALSE(sts_state.include_subdomains); + EXPECT_EQ(TransportSecurityState::STSState::MODE_FORCE_HTTPS, + sts_state.upgrade_mode); + EXPECT_LT(base::Time::Now(), sts_state.last_observed); + EXPECT_LT(sts_state.last_observed, sts_state.expiry); + TransportSecurityState::ExpectCTState expect_ct_state; + EXPECT_FALSE(state_->GetDynamicExpectCTState( + kStsDomain, NetworkIsolationKey(), &expect_ct_state)); + + // kExpectCTDomain should only have HSTS information. + sts_state = TransportSecurityState::STSState(); + EXPECT_FALSE(state_->GetDynamicSTSState(kExpectCTDomain, &sts_state)); + expect_ct_state = TransportSecurityState::ExpectCTState(); + EXPECT_TRUE(state_->GetDynamicExpectCTState( + kExpectCTDomain, NetworkIsolationKey(), &expect_ct_state)); + EXPECT_EQ(kExpectCTReportUri, expect_ct_state.report_uri); + EXPECT_TRUE(expect_ct_state.enforce); + EXPECT_LT(base::Time::Now(), expect_ct_state.last_observed); + EXPECT_LT(expect_ct_state.last_observed, expect_ct_state.expiry); + + // kBothDomain should have HSTS and ExpectCT information. + sts_state = TransportSecurityState::STSState(); + EXPECT_TRUE(state_->GetDynamicSTSState(kBothDomain, &sts_state)); + EXPECT_EQ(kBothDomain, sts_state.domain); + EXPECT_TRUE(sts_state.include_subdomains); + EXPECT_EQ(TransportSecurityState::STSState::MODE_FORCE_HTTPS, + sts_state.upgrade_mode); + EXPECT_LT(base::Time::Now(), sts_state.last_observed); + EXPECT_LT(sts_state.last_observed, sts_state.expiry); + expect_ct_state = TransportSecurityState::ExpectCTState(); + EXPECT_TRUE(state_->GetDynamicExpectCTState( + kBothDomain, NetworkIsolationKey(), &expect_ct_state)); + EXPECT_TRUE(expect_ct_state.report_uri.is_empty()); + EXPECT_TRUE(expect_ct_state.enforce); + EXPECT_LT(base::Time::Now(), expect_ct_state.last_observed); + EXPECT_LT(expect_ct_state.last_observed, expect_ct_state.expiry); } // Tests that dynamic Expect-CT state is serialized and deserialized correctly. -TEST_F(TransportSecurityPersisterTest, ExpectCT) { +TEST_P(TransportSecurityPersisterTest, ExpectCT) { base::test::ScopedFeatureList feature_list; feature_list.InitAndEnableFeature( TransportSecurityState::kDynamicExpectCTFeature); @@ -216,32 +352,35 @@ TEST_F(TransportSecurityPersisterTest, ExpectCT) { TransportSecurityState::ExpectCTState expect_ct_state; static const char kTestDomain[] = "example.test"; - EXPECT_FALSE(state_.GetDynamicExpectCTState(kTestDomain, &expect_ct_state)); + EXPECT_FALSE(state_->GetDynamicExpectCTState( + kTestDomain, NetworkIsolationKey(), &expect_ct_state)); const base::Time current_time(base::Time::Now()); const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000); - state_.AddExpectCT(kTestDomain, expiry, true /* enforce */, GURL()); + state_->AddExpectCT(kTestDomain, expiry, true /* enforce */, GURL(), + NetworkIsolationKey()); std::string serialized; EXPECT_TRUE(persister_->SerializeData(&serialized)); - bool dirty; + bool data_in_old_format; // LoadEntries() clears existing dynamic data before loading entries from // |serialized|. - EXPECT_TRUE(persister_->LoadEntries(serialized, &dirty)); + EXPECT_TRUE(persister_->LoadEntries(serialized, &data_in_old_format)); TransportSecurityState::ExpectCTState new_expect_ct_state; - EXPECT_TRUE( - state_.GetDynamicExpectCTState(kTestDomain, &new_expect_ct_state)); + EXPECT_TRUE(state_->GetDynamicExpectCTState( + kTestDomain, NetworkIsolationKey(), &new_expect_ct_state)); EXPECT_TRUE(new_expect_ct_state.enforce); EXPECT_TRUE(new_expect_ct_state.report_uri.is_empty()); EXPECT_EQ(expiry, new_expect_ct_state.expiry); // Update the state for the domain and check that it is // serialized/deserialized correctly. - state_.AddExpectCT(kTestDomain, expiry, false /* enforce */, report_uri); + state_->AddExpectCT(kTestDomain, expiry, false /* enforce */, report_uri, + NetworkIsolationKey()); EXPECT_TRUE(persister_->SerializeData(&serialized)); - EXPECT_TRUE(persister_->LoadEntries(serialized, &dirty)); - EXPECT_TRUE( - state_.GetDynamicExpectCTState(kTestDomain, &new_expect_ct_state)); + EXPECT_TRUE(persister_->LoadEntries(serialized, &data_in_old_format)); + EXPECT_TRUE(state_->GetDynamicExpectCTState( + kTestDomain, NetworkIsolationKey(), &new_expect_ct_state)); EXPECT_FALSE(new_expect_ct_state.enforce); EXPECT_EQ(report_uri, new_expect_ct_state.report_uri); EXPECT_EQ(expiry, new_expect_ct_state.expiry); @@ -249,7 +388,7 @@ TEST_F(TransportSecurityPersisterTest, ExpectCT) { // Tests that dynamic Expect-CT state is serialized and deserialized correctly // when there is also STS data present. -TEST_F(TransportSecurityPersisterTest, ExpectCTWithSTSDataPresent) { +TEST_P(TransportSecurityPersisterTest, ExpectCTWithSTSDataPresent) { base::test::ScopedFeatureList feature_list; feature_list.InitAndEnableFeature( TransportSecurityState::kDynamicExpectCTFeature); @@ -257,36 +396,38 @@ TEST_F(TransportSecurityPersisterTest, ExpectCTWithSTSDataPresent) { TransportSecurityState::ExpectCTState expect_ct_state; static const char kTestDomain[] = "example.test"; - EXPECT_FALSE(state_.GetDynamicExpectCTState(kTestDomain, &expect_ct_state)); + EXPECT_FALSE(state_->GetDynamicExpectCTState( + kTestDomain, NetworkIsolationKey(), &expect_ct_state)); const base::Time current_time(base::Time::Now()); const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000); - state_.AddHSTS(kTestDomain, expiry, false /* include subdomains */); - state_.AddExpectCT(kTestDomain, expiry, true /* enforce */, GURL()); + state_->AddHSTS(kTestDomain, expiry, false /* include subdomains */); + state_->AddExpectCT(kTestDomain, expiry, true /* enforce */, GURL(), + NetworkIsolationKey()); std::string serialized; EXPECT_TRUE(persister_->SerializeData(&serialized)); - bool dirty; + bool data_in_old_format; // LoadEntries() clears existing dynamic data before loading entries from // |serialized|. - EXPECT_TRUE(persister_->LoadEntries(serialized, &dirty)); + EXPECT_TRUE(persister_->LoadEntries(serialized, &data_in_old_format)); TransportSecurityState::ExpectCTState new_expect_ct_state; - EXPECT_TRUE( - state_.GetDynamicExpectCTState(kTestDomain, &new_expect_ct_state)); + EXPECT_TRUE(state_->GetDynamicExpectCTState( + kTestDomain, NetworkIsolationKey(), &new_expect_ct_state)); EXPECT_TRUE(new_expect_ct_state.enforce); EXPECT_TRUE(new_expect_ct_state.report_uri.is_empty()); EXPECT_EQ(expiry, new_expect_ct_state.expiry); // Check that STS state is loaded properly as well. TransportSecurityState::STSState sts_state; - EXPECT_TRUE(state_.GetDynamicSTSState(kTestDomain, &sts_state, nullptr)); + EXPECT_TRUE(state_->GetDynamicSTSState(kTestDomain, &sts_state)); EXPECT_EQ(sts_state.upgrade_mode, TransportSecurityState::STSState::MODE_FORCE_HTTPS); } // Tests that Expect-CT state is not serialized and persisted when the feature // is disabled. -TEST_F(TransportSecurityPersisterTest, ExpectCTDisabled) { +TEST_P(TransportSecurityPersisterTest, ExpectCTDisabled) { base::test::ScopedFeatureList feature_list; feature_list.InitAndDisableFeature( TransportSecurityState::kDynamicExpectCTFeature); @@ -294,19 +435,184 @@ TEST_F(TransportSecurityPersisterTest, ExpectCTDisabled) { TransportSecurityState::ExpectCTState expect_ct_state; static const char kTestDomain[] = "example.test"; - EXPECT_FALSE(state_.GetDynamicExpectCTState(kTestDomain, &expect_ct_state)); + EXPECT_FALSE(state_->GetDynamicExpectCTState( + kTestDomain, NetworkIsolationKey(), &expect_ct_state)); const base::Time current_time(base::Time::Now()); const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000); - state_.AddExpectCT(kTestDomain, expiry, true /* enforce */, GURL()); + state_->AddExpectCT(kTestDomain, expiry, true /* enforce */, GURL(), + NetworkIsolationKey()); std::string serialized; EXPECT_TRUE(persister_->SerializeData(&serialized)); - bool dirty; - EXPECT_TRUE(persister_->LoadEntries(serialized, &dirty)); + bool data_in_old_format; + EXPECT_TRUE(persister_->LoadEntries(serialized, &data_in_old_format)); TransportSecurityState::ExpectCTState new_expect_ct_state; - EXPECT_FALSE( - state_.GetDynamicExpectCTState(kTestDomain, &new_expect_ct_state)); + EXPECT_FALSE(state_->GetDynamicExpectCTState( + kTestDomain, NetworkIsolationKey(), &new_expect_ct_state)); +} + +// Save data with several NetworkIsolationKeys with +// kPartitionExpectCTStateByNetworkIsolationKey enabled, and then load it with +// the feature enabled or disabled, based on partition_expect_ct_state(). +TEST_P(TransportSecurityPersisterTest, ExpectCTWithNetworkIsolationKey) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature( + TransportSecurityState::kDynamicExpectCTFeature); + + const GURL report_uri(kReportUri); + static const char kTestDomain[] = "example.test"; + const url::Origin kOrigin = + url::Origin::Create(GURL("https://somewhere.else.test")); + const NetworkIsolationKey empty_network_isolation_key; + const NetworkIsolationKey network_isolation_key(kOrigin /* top_frame_origin*/, + kOrigin /* frame_origin*/); + const NetworkIsolationKey transient_network_isolation_key = + NetworkIsolationKey::CreateTransient(); + + const base::Time current_time(base::Time::Now()); + const base::Time expiry1 = current_time + base::TimeDelta::FromSeconds(1000); + const base::Time expiry2 = current_time + base::TimeDelta::FromSeconds(2000); + const base::Time expiry3 = current_time + base::TimeDelta::FromSeconds(3000); + + // Serialize data with kPartitionExpectCTStateByNetworkIsolationKey enabled, + // and then revert the feature to its previous value. + std::string serialized; + { + base::test::ScopedFeatureList feature_list2; + feature_list2.InitAndEnableFeature( + features::kPartitionExpectCTStateByNetworkIsolationKey); + TransportSecurityState state2; + TransportSecurityPersister persister2( + &state2, temp_dir_.GetPath(), + std::move(base::ThreadPool::CreateSequencedTaskRunner( + {base::MayBlock(), base::TaskPriority::BEST_EFFORT, + base::TaskShutdownBehavior::BLOCK_SHUTDOWN}))); + TransportSecurityState::ExpectCTState expect_ct_state; + state2.AddExpectCT(kTestDomain, expiry1, true /* enforce */, GURL(), + empty_network_isolation_key); + state2.AddExpectCT(kTestDomain, expiry2, true /* enforce */, GURL(), + network_isolation_key); + state2.AddExpectCT(kTestDomain, expiry3, true /* enforce */, GURL(), + transient_network_isolation_key); + EXPECT_TRUE(persister2.SerializeData(&serialized)); + + EXPECT_TRUE(state2.GetDynamicExpectCTState( + kTestDomain, empty_network_isolation_key, &expect_ct_state)); + EXPECT_TRUE(state2.GetDynamicExpectCTState( + kTestDomain, network_isolation_key, &expect_ct_state)); + EXPECT_TRUE(state2.GetDynamicExpectCTState( + kTestDomain, transient_network_isolation_key, &expect_ct_state)); + } + + bool data_in_old_format; + // Load entries into the other persister. + EXPECT_TRUE(persister_->LoadEntries(serialized, &data_in_old_format)); + EXPECT_FALSE(data_in_old_format); + + if (partition_expect_ct_state()) { + TransportSecurityState::ExpectCTState new_expect_ct_state; + EXPECT_TRUE(state_->GetDynamicExpectCTState( + kTestDomain, empty_network_isolation_key, &new_expect_ct_state)); + EXPECT_TRUE(new_expect_ct_state.enforce); + EXPECT_TRUE(new_expect_ct_state.report_uri.is_empty()); + EXPECT_EQ(expiry1, new_expect_ct_state.expiry); + + EXPECT_TRUE(state_->GetDynamicExpectCTState( + kTestDomain, network_isolation_key, &new_expect_ct_state)); + EXPECT_TRUE(new_expect_ct_state.enforce); + EXPECT_TRUE(new_expect_ct_state.report_uri.is_empty()); + EXPECT_EQ(expiry2, new_expect_ct_state.expiry); + + // The data associated with the transient NetworkIsolationKey should not + // have been saved. + EXPECT_FALSE(state_->GetDynamicExpectCTState( + kTestDomain, transient_network_isolation_key, &new_expect_ct_state)); + } else { + std::set<std::string> expect_ct_saved; + TransportSecurityState::ExpectCTStateIterator expect_ct_iter(*state_); + ASSERT_TRUE(expect_ct_iter.HasNext()); + EXPECT_EQ(empty_network_isolation_key, + expect_ct_iter.network_isolation_key()); + EXPECT_TRUE(expect_ct_iter.domain_state().enforce); + EXPECT_TRUE(expect_ct_iter.domain_state().report_uri.is_empty()); + expect_ct_iter.Advance(); + EXPECT_FALSE(expect_ct_iter.HasNext()); + } +} + +// Test the case when deserializing a NetworkIsolationKey fails. This happens +// when data is persisted with kAppendFrameOriginToNetworkIsolationKey, but +// loaded without it, or vice-versa. +TEST_P(TransportSecurityPersisterTest, + ExpectCTNetworkIsolationKeyDeserializationFails) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature( + TransportSecurityState::kDynamicExpectCTFeature); + + const GURL report_uri(kReportUri); + static const char kTestDomain[] = "example.test"; + const url::Origin kOrigin = + url::Origin::Create(GURL("https://somewhere.else.test")); + const NetworkIsolationKey empty_network_isolation_key; + const NetworkIsolationKey network_isolation_key(kOrigin /* top_frame_origin*/, + kOrigin /* frame_origin*/); + const base::Time current_time(base::Time::Now()); + const base::Time expiry1 = current_time + base::TimeDelta::FromSeconds(1000); + const base::Time expiry2 = current_time + base::TimeDelta::FromSeconds(2000); + + // Serialize data with kPartitionExpectCTStateByNetworkIsolationKey and + // kAppendFrameOriginToNetworkIsolationKey enabled, and then revert the + // features to their previous values. + std::string serialized; + { + base::test::ScopedFeatureList feature_list2; + feature_list2.InitWithFeatures( + // enabled_features + {features::kPartitionExpectCTStateByNetworkIsolationKey, + features::kAppendFrameOriginToNetworkIsolationKey}, + // disabled_features + {}); + TransportSecurityState state2; + TransportSecurityPersister persister2( + &state2, temp_dir_.GetPath(), + std::move(base::ThreadPool::CreateSequencedTaskRunner( + {base::MayBlock(), base::TaskPriority::BEST_EFFORT, + base::TaskShutdownBehavior::BLOCK_SHUTDOWN}))); + TransportSecurityState::ExpectCTState expect_ct_state; + state2.AddExpectCT(kTestDomain, expiry1, true /* enforce */, GURL(), + empty_network_isolation_key); + state2.AddExpectCT(kTestDomain, expiry2, true /* enforce */, GURL(), + network_isolation_key); + EXPECT_TRUE(persister2.SerializeData(&serialized)); + + EXPECT_TRUE(state2.GetDynamicExpectCTState( + kTestDomain, empty_network_isolation_key, &expect_ct_state)); + EXPECT_TRUE(state2.GetDynamicExpectCTState( + kTestDomain, network_isolation_key, &expect_ct_state)); + } + + base::test::ScopedFeatureList feature_list3; + feature_list3.InitAndDisableFeature( + features::kAppendFrameOriginToNetworkIsolationKey); + + bool data_in_old_format; + // Load entries into the other persister. + EXPECT_TRUE(persister_->LoadEntries(serialized, &data_in_old_format)); + EXPECT_FALSE(data_in_old_format); + + // Regardless of whether kPartitionExpectCTStateByNetworkIsolationKey is + // enabled or not, the different kAppendFrameOriginToNetworkIsolationKey state + // will cause the entry with a non-empty NetworkIsolationKey to be dropped. + std::set<std::string> expect_ct_saved; + TransportSecurityState::ExpectCTStateIterator expect_ct_iter(*state_); + ASSERT_TRUE(expect_ct_iter.HasNext()); + EXPECT_EQ(empty_network_isolation_key, + expect_ct_iter.network_isolation_key()); + EXPECT_TRUE(expect_ct_iter.domain_state().enforce); + EXPECT_TRUE(expect_ct_iter.domain_state().report_uri.is_empty()); + expect_ct_iter.Advance(); + EXPECT_FALSE(expect_ct_iter.HasNext()); } } // namespace diff --git a/chromium/net/http/transport_security_state.cc b/chromium/net/http/transport_security_state.cc index 29ee1e2ffa0..f7b7de2f277 100644 --- a/chromium/net/http/transport_security_state.cc +++ b/chromium/net/http/transport_security_state.cc @@ -4,7 +4,9 @@ #include "net/http/transport_security_state.h" +#include <algorithm> #include <memory> +#include <tuple> #include <utility> #include <vector> @@ -12,6 +14,7 @@ #include "base/bind.h" #include "base/build_time.h" #include "base/containers/span.h" +#include "base/feature_list.h" #include "base/json/json_writer.h" #include "base/logging.h" #include "base/metrics/field_trial.h" @@ -28,6 +31,7 @@ #include "build/branding_buildflags.h" #include "build/build_config.h" #include "crypto/sha2.h" +#include "net/base/features.h" #include "net/base/hash_value.h" #include "net/base/host_port_pair.h" #include "net/cert/ct_policy_status.h" @@ -207,7 +211,7 @@ std::string HashesToBase64String(const HashValueVector& hashes) { return str; } -std::string HashHost(const std::string& canonicalized_host) { +std::string HashHost(base::StringPiece canonicalized_host) { char hashed[crypto::kSHA256Length]; crypto::SHA256HashString(canonicalized_host, hashed, sizeof(hashed)); return std::string(hashed, sizeof(hashed)); @@ -392,29 +396,6 @@ bool DecodeHSTSPreload(const std::string& search_hostname, PreloadResult* out) { return found; } -// Records a histogram for details on the HSTS status of a host. |enabled| is -// true if the host had HSTS enabled when considering both the preload list and -// the current dynamic implementation and false otherwise. |should_be_dynamic| -// is true if the current dynamic implementation reported host did not have HSTS -// enabled, but a spec-compliant implementation would have reported it enabled. -// Note both parameters may be true, in which case the spec non-compliance was -// masked by the HSTS preload list. -// -// See https://crbug.com/821811. -void RecordHstsInfo(bool enabled, bool should_be_dynamic) { - HstsInfo info; - if (enabled) { - info = should_be_dynamic - ? HstsInfo::kDynamicIncorrectlyMaskedButMatchedStatic - : HstsInfo::kEnabled; - } else { - info = should_be_dynamic ? HstsInfo::kDynamicIncorrectlyMasked - : HstsInfo::kDisabled; - } - - UMA_HISTOGRAM_ENUMERATION("Net.HstsInfo", info); -} - } // namespace // static @@ -435,7 +416,9 @@ TransportSecurityState::TransportSecurityState( enable_static_expect_ct_(true), enable_pkp_bypass_for_local_trust_anchors_(true), sent_hpkp_reports_cache_(kMaxReportCacheEntries), - sent_expect_ct_reports_cache_(kMaxReportCacheEntries) { + sent_expect_ct_reports_cache_(kMaxReportCacheEntries), + key_expect_ct_by_nik_(base::FeatureList::IsEnabled( + features::kPartitionExpectCTStateByNetworkIsolationKey)) { // Static pinning is only enabled for official builds to make sure that // others don't end up with pins that cannot be easily updated. #if !BUILDFLAG(GOOGLE_CHROME_BRANDING) || defined(OS_ANDROID) || defined(OS_IOS) @@ -455,13 +438,9 @@ TransportSecurityState::TransportSecurityState( bool TransportSecurityState::ShouldSSLErrorsBeFatal(const std::string& host) { STSState unused_sts; PKPState unused_pkp; - // Query GetDynamicSTSState() first to set |sts_should_be_dynamic|. - bool sts_should_be_dynamic = false; - bool ret = GetDynamicSTSState(host, &unused_sts, &sts_should_be_dynamic) || - GetDynamicPKPState(host, &unused_pkp) || - GetStaticDomainState(host, &unused_sts, &unused_pkp); - RecordHstsInfo(ret, sts_should_be_dynamic); - return ret; + return GetDynamicSTSState(host, &unused_sts) || + GetDynamicPKPState(host, &unused_pkp) || + GetStaticDomainState(host, &unused_sts, &unused_pkp); } bool TransportSecurityState::ShouldUpgradeToSSL(const std::string& host) { @@ -512,7 +491,8 @@ TransportSecurityState::CheckCTRequirements( const SignedCertificateTimestampAndStatusList& signed_certificate_timestamps, const ExpectCTReportStatus report_status, - ct::CTPolicyCompliance policy_compliance) { + ct::CTPolicyCompliance policy_compliance, + const NetworkIsolationKey& network_isolation_key) { using CTRequirementLevel = RequireCTDelegate::CTRequirementLevel; std::string hostname = host_port_pair.host(); @@ -535,16 +515,17 @@ TransportSecurityState::CheckCTRequirements( // Expect-CT reports from being sent. bool required_via_expect_ct = false; ExpectCTState state; - if (IsDynamicExpectCTEnabled() && GetDynamicExpectCTState(hostname, &state)) { + if (IsDynamicExpectCTEnabled() && + GetDynamicExpectCTState(hostname, network_isolation_key, &state)) { UMA_HISTOGRAM_ENUMERATION( "Net.ExpectCTHeader.PolicyComplianceOnConnectionSetup", policy_compliance, ct::CTPolicyCompliance::CT_POLICY_COUNT); if (!complies && expect_ct_reporter_ && !state.report_uri.is_empty() && report_status == ENABLE_EXPECT_CT_REPORTS) { - MaybeNotifyExpectCTFailed(host_port_pair, state.report_uri, state.expiry, - validated_certificate_chain, - served_certificate_chain, - signed_certificate_timestamps); + MaybeNotifyExpectCTFailed( + host_port_pair, state.report_uri, state.expiry, + validated_certificate_chain, served_certificate_chain, + signed_certificate_timestamps, network_isolation_key); } required_via_expect_ct = state.enforce; } @@ -658,14 +639,28 @@ void TransportSecurityState::AddHSTSInternal( const base::Time& expiry, bool include_subdomains) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + const std::string canonicalized_host = CanonicalizeHost(host); + if (canonicalized_host.empty()) + return; STSState sts_state; + // No need to store |sts_state.domain| since it is redundant. + // (|canonicalized_host| is the map key.) sts_state.last_observed = base::Time::Now(); sts_state.include_subdomains = include_subdomains; sts_state.expiry = expiry; sts_state.upgrade_mode = upgrade_mode; - EnableSTSHost(host, sts_state); + // Only store new state when HSTS is explicitly enabled. If it is + // disabled, remove the state from the enabled hosts. + if (sts_state.ShouldUpgradeToSSL()) { + enabled_sts_hosts_[HashHost(canonicalized_host)] = sts_state; + } else { + const std::string hashed_host = HashHost(canonicalized_host); + enabled_sts_hosts_.erase(hashed_host); + } + + DirtyNotify(); } void TransportSecurityState::AddHPKPInternal(const std::string& host, @@ -675,80 +670,22 @@ void TransportSecurityState::AddHPKPInternal(const std::string& host, const HashValueVector& hashes, const GURL& report_uri) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + const std::string canonicalized_host = CanonicalizeHost(host); + if (canonicalized_host.empty()) + return; PKPState pkp_state; + // No need to store |pkp_state.domain| since it is redundant. + // (|canonicalized_host| is the map key.) pkp_state.last_observed = last_observed; pkp_state.expiry = expiry; pkp_state.include_subdomains = include_subdomains; pkp_state.spki_hashes = hashes; pkp_state.report_uri = report_uri; - EnablePKPHost(host, pkp_state); -} - -void TransportSecurityState::AddExpectCTInternal( - const std::string& host, - const base::Time& last_observed, - const base::Time& expiry, - bool enforce, - const GURL& report_uri) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - ExpectCTState expect_ct_state; - expect_ct_state.last_observed = last_observed; - expect_ct_state.expiry = expiry; - expect_ct_state.enforce = enforce; - expect_ct_state.report_uri = report_uri; - - EnableExpectCTHost(host, expect_ct_state); -} - -void TransportSecurityState:: - SetEnablePublicKeyPinningBypassForLocalTrustAnchors(bool value) { - enable_pkp_bypass_for_local_trust_anchors_ = value; -} - -void TransportSecurityState::EnableSTSHost(const std::string& host, - const STSState& state) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - const std::string canonicalized_host = CanonicalizeHost(host); - if (canonicalized_host.empty()) - return; - - // Only store new state when HSTS is explicitly enabled. If it is - // disabled, remove the state from the enabled hosts. - if (state.ShouldUpgradeToSSL()) { - STSState sts_state(state); - // No need to store this value since it is redundant. (|canonicalized_host| - // is the map key.) - sts_state.domain.clear(); - - enabled_sts_hosts_[HashHost(canonicalized_host)] = sts_state; - } else { - const std::string hashed_host = HashHost(canonicalized_host); - enabled_sts_hosts_.erase(hashed_host); - } - - DirtyNotify(); -} - -void TransportSecurityState::EnablePKPHost(const std::string& host, - const PKPState& state) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - const std::string canonicalized_host = CanonicalizeHost(host); - if (canonicalized_host.empty()) - return; - // Only store new state when HPKP is explicitly enabled. If it is // disabled, remove the state from the enabled hosts. - if (state.HasPublicKeyPins()) { - PKPState pkp_state(state); - // No need to store this value since it is redundant. (|canonicalized_host| - // is the map key.) - pkp_state.domain.clear(); - + if (pkp_state.HasPublicKeyPins()) { enabled_pkp_hosts_[HashHost(canonicalized_host)] = pkp_state; } else { const std::string hashed_host = HashHost(canonicalized_host); @@ -758,8 +695,13 @@ void TransportSecurityState::EnablePKPHost(const std::string& host, DirtyNotify(); } -void TransportSecurityState::EnableExpectCTHost(const std::string& host, - const ExpectCTState& state) { +void TransportSecurityState::AddExpectCTInternal( + const std::string& host, + const base::Time& last_observed, + const base::Time& expiry, + bool enforce, + const GURL& report_uri, + const NetworkIsolationKey& network_isolation_key) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); if (!IsDynamicExpectCTEnabled()) return; @@ -768,23 +710,33 @@ void TransportSecurityState::EnableExpectCTHost(const std::string& host, if (canonicalized_host.empty()) return; + ExpectCTState expect_ct_state; + // No need to store |expect_ct_state.domain| since it is redundant. + // (|canonicalized_host| is the map key.) + expect_ct_state.last_observed = last_observed; + expect_ct_state.expiry = expiry; + expect_ct_state.enforce = enforce; + expect_ct_state.report_uri = report_uri; + // Only store new state when Expect-CT is explicitly enabled. If it is // disabled, remove the state from the enabled hosts. - if (state.enforce || !state.report_uri.is_empty()) { - ExpectCTState expect_ct_state(state); - // No need to store this value since it is redundant. (|canonicalized_host| - // is the map key.) - expect_ct_state.domain.clear(); - - enabled_expect_ct_hosts_[HashHost(canonicalized_host)] = expect_ct_state; + ExpectCTStateIndex index = CreateExpectCTStateIndex( + HashHost(canonicalized_host), network_isolation_key); + if (expect_ct_state.enforce || !expect_ct_state.report_uri.is_empty()) { + enabled_expect_ct_hosts_[index] = expect_ct_state; + MaybePruneExpectCTState(); } else { - const std::string hashed_host = HashHost(canonicalized_host); - enabled_expect_ct_hosts_.erase(hashed_host); + enabled_expect_ct_hosts_.erase(index); } DirtyNotify(); } +void TransportSecurityState:: + SetEnablePublicKeyPinningBypassForLocalTrustAnchors(bool value) { + enable_pkp_bypass_for_local_trust_anchors_ = value; +} + TransportSecurityState::PKPStatus TransportSecurityState::CheckPinsAndMaybeSendReport( const HostPortPair& host_port_pair, @@ -855,7 +807,6 @@ bool TransportSecurityState::GetStaticExpectCTState( if (!enable_static_expect_ct_ || !result.expect_ct) return false; - expect_ct_state->domain = host.substr(result.hostname_offset); expect_ct_state->report_uri = GURL( g_hsts_source->expect_ct_report_uris[result.expect_ct_report_uri_id]); return true; @@ -868,7 +819,8 @@ void TransportSecurityState::MaybeNotifyExpectCTFailed( const X509Certificate* validated_certificate_chain, const X509Certificate* served_certificate_chain, const SignedCertificateTimestampAndStatusList& - signed_certificate_timestamps) { + signed_certificate_timestamps, + const NetworkIsolationKey& network_isolation_key) { // Do not send repeated reports to the same host/port pair within // |kTimeToRememberReportsMins|. Theoretically, there could be scenarios in // which the same host/port generates different reports and it would be useful @@ -886,7 +838,8 @@ void TransportSecurityState::MaybeNotifyExpectCTFailed( expect_ct_reporter_->OnExpectCTFailed( host_port_pair, report_uri, expiration, validated_certificate_chain, - served_certificate_chain, signed_certificate_timestamps); + served_certificate_chain, signed_certificate_timestamps, + network_isolation_key); } bool TransportSecurityState::DeleteDynamicDataForHost(const std::string& host) { @@ -910,9 +863,16 @@ bool TransportSecurityState::DeleteDynamicDataForHost(const std::string& host) { deleted = true; } - auto expect_ct_iterator = enabled_expect_ct_hosts_.find(hashed_host); - if (expect_ct_iterator != enabled_expect_ct_hosts_.end()) { - enabled_expect_ct_hosts_.erase(expect_ct_iterator); + // Delete matching entries for all NetworkIsolationKeys. Performance isn't + // important here, since this is only called when directly initiated by the + // user, so a linear search is fine. + for (auto it = enabled_expect_ct_hosts_.begin(); + it != enabled_expect_ct_hosts_.end();) { + auto current = it; + ++it; + if (current->first.hashed_host != hashed_host) + continue; + enabled_expect_ct_hosts_.erase(current); deleted = true; } @@ -1024,18 +984,22 @@ void TransportSecurityState::AddHPKP(const std::string& host, report_uri); } -void TransportSecurityState::AddExpectCT(const std::string& host, - const base::Time& expiry, - bool enforce, - const GURL& report_uri) { +void TransportSecurityState::AddExpectCT( + const std::string& host, + const base::Time& expiry, + bool enforce, + const GURL& report_uri, + const NetworkIsolationKey& network_isolation_key) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - AddExpectCTInternal(host, base::Time::Now(), expiry, enforce, report_uri); + AddExpectCTInternal(host, base::Time::Now(), expiry, enforce, report_uri, + network_isolation_key); } void TransportSecurityState::ProcessExpectCTHeader( const std::string& value, const HostPortPair& host_port_pair, - const SSLInfo& ssl_info) { + const SSLInfo& ssl_info, + const NetworkIsolationKey& network_isolation_key) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); // If a site sends `Expect-CT: preload` and appears on the preload list, they @@ -1057,10 +1021,10 @@ void TransportSecurityState::ProcessExpectCTHeader( } ExpectCTState state; if (GetStaticExpectCTState(host_port_pair.host(), &state)) { - MaybeNotifyExpectCTFailed(host_port_pair, state.report_uri, base::Time(), - ssl_info.cert.get(), - ssl_info.unverified_cert.get(), - ssl_info.signed_certificate_timestamps); + MaybeNotifyExpectCTFailed( + host_port_pair, state.report_uri, base::Time(), ssl_info.cert.get(), + ssl_info.unverified_cert.get(), + ssl_info.signed_certificate_timestamps, network_isolation_key); } return; } @@ -1104,16 +1068,17 @@ void TransportSecurityState::ProcessExpectCTHeader( } ExpectCTState state; if (expect_ct_reporter_ && !report_uri.is_empty() && - !GetDynamicExpectCTState(host_port_pair.host(), &state)) { - MaybeNotifyExpectCTFailed(host_port_pair, report_uri, base::Time(), - ssl_info.cert.get(), - ssl_info.unverified_cert.get(), - ssl_info.signed_certificate_timestamps); + !GetDynamicExpectCTState(host_port_pair.host(), network_isolation_key, + &state)) { + MaybeNotifyExpectCTFailed( + host_port_pair, report_uri, base::Time(), ssl_info.cert.get(), + ssl_info.unverified_cert.get(), + ssl_info.signed_certificate_timestamps, network_isolation_key); } return; } AddExpectCTInternal(host_port_pair.host(), now, now + max_age, enforce, - report_uri); + report_uri, network_isolation_key); } // static @@ -1126,6 +1091,10 @@ void TransportSecurityState::ClearReportCachesForTesting() { sent_expect_ct_reports_cache_.Clear(); } +size_t TransportSecurityState::num_expect_ct_entries() const { + return enabled_expect_ct_hosts_.size(); +} + // static bool TransportSecurityState::IsBuildTimely() { const base::Time build_time = base::GetBuildTime(); @@ -1209,11 +1178,8 @@ bool TransportSecurityState::GetStaticDomainState(const std::string& host, bool TransportSecurityState::GetSTSState(const std::string& host, STSState* result) { PKPState unused; - bool should_be_dynamic = false; - bool ret = GetDynamicSTSState(host, result, &should_be_dynamic) || - GetStaticDomainState(host, result, &unused); - RecordHstsInfo(ret, should_be_dynamic); - return ret; + return GetDynamicSTSState(host, result) || + GetStaticDomainState(host, result, &unused); } bool TransportSecurityState::GetPKPState(const std::string& host, @@ -1224,22 +1190,18 @@ bool TransportSecurityState::GetPKPState(const std::string& host, } bool TransportSecurityState::GetDynamicSTSState(const std::string& host, - STSState* result, - bool* should_be_dynamic) { + STSState* result) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - if (should_be_dynamic) - *should_be_dynamic = false; const std::string canonicalized_host = CanonicalizeHost(host); if (canonicalized_host.empty()) return false; base::Time current_time(base::Time::Now()); - bool first_match = true; for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) { - std::string host_sub_chunk(&canonicalized_host[i], - canonicalized_host.size() - i); + base::StringPiece host_sub_chunk = + base::StringPiece(canonicalized_host).substr(i); auto j = enabled_sts_hosts_.find(HashHost(host_sub_chunk)); if (j == enabled_sts_hosts_.end()) continue; @@ -1251,27 +1213,13 @@ bool TransportSecurityState::GetDynamicSTSState(const std::string& host, continue; } - // If this is the most specific STS match, add it to the result. Note: a STS - // entry at a more specific domain overrides a less specific domain whether - // or not |include_subdomains| is set. + // An entry matches if it is either an exact match, or if it is a prefix + // match and the includeSubDomains directive was included. if (i == 0 || j->second.include_subdomains) { - // TransportSecurityState considers a more specific non-includeSubDomains - // entry to override a less specific includeSubDomain entry. This does not - // match the specification and results in confusing behavior, so evaluate - // both versions for histogramming purposes. - if (!first_match) { - if (should_be_dynamic) - *should_be_dynamic = true; - // No need to continue iterating. - break; - } - *result = j->second; result->domain = DNSDomainToString(host_sub_chunk); return true; } - - first_match = false; } return false; @@ -1288,8 +1236,8 @@ bool TransportSecurityState::GetDynamicPKPState(const std::string& host, base::Time current_time(base::Time::Now()); for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) { - std::string host_sub_chunk(&canonicalized_host[i], - canonicalized_host.size() - i); + base::StringPiece host_sub_chunk = + base::StringPiece(canonicalized_host).substr(i); auto j = enabled_pkp_hosts_.find(HashHost(host_sub_chunk)); if (j == enabled_pkp_hosts_.end()) continue; @@ -1304,6 +1252,10 @@ bool TransportSecurityState::GetDynamicPKPState(const std::string& host, // If this is the most specific PKP match, add it to the result. Note: a PKP // entry at a more specific domain overrides a less specific domain whether // or not |include_subdomains| is set. + // + // TODO(davidben): This does not match the HSTS behavior. We no longer + // implement HPKP, so this logic is only used via AddHPKP(), reachable from + // Cronet. if (i == 0 || j->second.include_subdomains) { *result = j->second; result->domain = DNSDomainToString(host_sub_chunk); @@ -1316,8 +1268,10 @@ bool TransportSecurityState::GetDynamicPKPState(const std::string& host, return false; } -bool TransportSecurityState::GetDynamicExpectCTState(const std::string& host, - ExpectCTState* result) { +bool TransportSecurityState::GetDynamicExpectCTState( + const std::string& host, + const NetworkIsolationKey& network_isolation_key, + ExpectCTState* result) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); const std::string canonicalized_host = CanonicalizeHost(host); @@ -1325,7 +1279,8 @@ bool TransportSecurityState::GetDynamicExpectCTState(const std::string& host, return false; base::Time current_time(base::Time::Now()); - auto j = enabled_expect_ct_hosts_.find(HashHost(canonicalized_host)); + auto j = enabled_expect_ct_hosts_.find(CreateExpectCTStateIndex( + HashHost(canonicalized_host), network_isolation_key)); if (j == enabled_expect_ct_hosts_.end()) return false; // If the entry is invalid, drop it. @@ -1349,10 +1304,12 @@ void TransportSecurityState::AddOrUpdateEnabledSTSHosts( void TransportSecurityState::AddOrUpdateEnabledExpectCTHosts( const std::string& hashed_host, + const NetworkIsolationKey& network_isolation_key, const ExpectCTState& state) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK(state.enforce || !state.report_uri.is_empty()); - enabled_expect_ct_hosts_[hashed_host] = state; + enabled_expect_ct_hosts_[CreateExpectCTStateIndex( + hashed_host, network_isolation_key)] = state; } TransportSecurityState::STSState::STSState() @@ -1384,6 +1341,15 @@ TransportSecurityState::ExpectCTState::ExpectCTState() : enforce(false) {} TransportSecurityState::ExpectCTState::~ExpectCTState() = default; +TransportSecurityState::ExpectCTStateIndex::ExpectCTStateIndex( + const std::string& hashed_host, + const NetworkIsolationKey& network_isolation_key, + bool respect_network_isolation_keyn_key) + : hashed_host(hashed_host), + network_isolation_key(respect_network_isolation_keyn_key + ? network_isolation_key + : NetworkIsolationKey()) {} + TransportSecurityState::ExpectCTStateIterator::ExpectCTStateIterator( const TransportSecurityState& state) : iterator_(state.enabled_expect_ct_hosts_.begin()), @@ -1433,4 +1399,140 @@ bool TransportSecurityState::PKPState::HasPublicKeyPins() const { return spki_hashes.size() > 0 || bad_spki_hashes.size() > 0; } +TransportSecurityState::ExpectCTStateIndex +TransportSecurityState::CreateExpectCTStateIndex( + const std::string& hashed_host, + const NetworkIsolationKey& network_isolation_key) { + return ExpectCTStateIndex(hashed_host, network_isolation_key, + key_expect_ct_by_nik_); +} + +void TransportSecurityState::MaybePruneExpectCTState() { + if (!base::FeatureList::IsEnabled(features::kExpectCTPruning) || + enabled_expect_ct_hosts_.size() < + static_cast<size_t>(features::kExpectCTPruneMax.Get())) { + return; + } + + base::Time now = base::Time::Now(); + if (now < earliest_next_prune_expect_ct_time_) + return; + + earliest_next_prune_expect_ct_time_ = + now + + base::TimeDelta::FromSeconds(features::kExpectCTPruneDelaySecs.Get()); + + base::Time last_prunable_observation_time = + now - + base::TimeDelta::FromDays(features::kExpectCTSafeFromPruneDays.Get()); + + // Cache this locally, so don't have to repeatedly query the value. + size_t expect_ct_prune_min = features::kExpectCTPruneMin.Get(); + + // Entries that are eligible to be pruned based on the global (not per-NIK) + // entry limit. + std::vector<ExpectCTStateMap::iterator> prunable_expect_ct_entries; + + // Clear expired entries first. If that's enough, maybe no valid entries have + // to be removed. Also populate |prunable_expect_ct_entries|. + for (auto expect_ct_iterator = enabled_expect_ct_hosts_.begin(); + expect_ct_iterator != enabled_expect_ct_hosts_.end();) { + if (expect_ct_iterator->second.expiry < now) { + enabled_expect_ct_hosts_.erase(expect_ct_iterator++); + continue; + } + + // If there are fewer than |expect_ct_prune_min| entries remaining, no need + // to delete anything else. + if (enabled_expect_ct_hosts_.size() <= expect_ct_prune_min) + return; + + // Entries that are older than the prunable time window, are report-only, or + // have a transient NetworkIsolationKey, are considered prunable. + // + // If |key_expect_ct_by_nik_| is false, all entries have an empty NIK. + // IsTransient() returns true for the empty NIK, despite entries being saved + // to disk, so don't want to delete entries with empty NIKs. + if (expect_ct_iterator->second.last_observed < + last_prunable_observation_time || + !expect_ct_iterator->second.enforce || + (key_expect_ct_by_nik_ && + expect_ct_iterator->first.network_isolation_key.IsTransient())) { + prunable_expect_ct_entries.push_back(expect_ct_iterator); + } + ++expect_ct_iterator; + } + + // Number of entries that need to be removed to reach |expect_ct_prune_min|. + size_t num_entries_to_prune = + enabled_expect_ct_hosts_.size() - expect_ct_prune_min; + if (num_entries_to_prune < prunable_expect_ct_entries.size()) { + // There are more than enough prunable entries to reach kExpectCTPruneMin. + // Find the |num_entries_to_prune| most prunable entries, according to + // ExpectCTPruningSorter. + auto expect_ct_prune_end = + prunable_expect_ct_entries.begin() + num_entries_to_prune; + std::partial_sort(prunable_expect_ct_entries.begin(), expect_ct_prune_end, + prunable_expect_ct_entries.end(), ExpectCTPruningSorter); + } else { + // Otherwise, delete all prunable entries. + num_entries_to_prune = prunable_expect_ct_entries.size(); + } + DCHECK_LE(num_entries_to_prune, prunable_expect_ct_entries.size()); + + for (size_t i = 0; i < num_entries_to_prune; ++i) { + enabled_expect_ct_hosts_.erase(prunable_expect_ct_entries[i]); + } + + // If there are fewer than |kExpectCTPruneMin| entries remaining, or entries + // are not being keyed by NetworkIsolationKey, nothing left to do. + if (enabled_expect_ct_hosts_.size() <= expect_ct_prune_min || + !key_expect_ct_by_nik_) { + return; + } + + // Otherwise, cap the number of entries per NetworkIsolationKey to + // |kMaxEntriesPerNik|. + + // Create a vector of all the ExpectCT entries for each NIK. + std::map<net::NetworkIsolationKey, std::vector<ExpectCTStateMap::iterator>> + nik_map; + for (auto expect_ct_iterator = enabled_expect_ct_hosts_.begin(); + expect_ct_iterator != enabled_expect_ct_hosts_.end(); + ++expect_ct_iterator) { + nik_map[expect_ct_iterator->first.network_isolation_key].push_back( + expect_ct_iterator); + } + + // For each NIK with more than the maximum number of entries, remove the most + // prunable entries until it has exactly |kExpectCTMaxEntriesPerNik| entries. + size_t max_entries_per_nik = features::kExpectCTMaxEntriesPerNik.Get(); + for (auto& nik_entries : nik_map) { + if (nik_entries.second.size() < max_entries_per_nik) + continue; + auto top_frame_origin_prune_end = nik_entries.second.begin() + + nik_entries.second.size() - + max_entries_per_nik; + std::partial_sort(nik_entries.second.begin(), top_frame_origin_prune_end, + nik_entries.second.end(), ExpectCTPruningSorter); + for (auto entry_to_prune = nik_entries.second.begin(); + entry_to_prune != top_frame_origin_prune_end; ++entry_to_prune) { + enabled_expect_ct_hosts_.erase(*entry_to_prune); + } + } +} + +bool TransportSecurityState::ExpectCTPruningSorter( + const ExpectCTStateMap::iterator& it1, + const ExpectCTStateMap::iterator& it2) { + // std::tie requires r-values, so have to put these on the stack to use + // std::tie. + bool is_not_transient1 = !it1->first.network_isolation_key.IsTransient(); + bool is_not_transient2 = !it2->first.network_isolation_key.IsTransient(); + return std::tie(is_not_transient1, it1->second.enforce, + it1->second.last_observed) < + std::tie(is_not_transient2, it2->second.enforce, + it2->second.last_observed); +} + } // namespace net diff --git a/chromium/net/http/transport_security_state.h b/chromium/net/http/transport_security_state.h index b54581d4a2e..ba863bd6bae 100644 --- a/chromium/net/http/transport_security_state.h +++ b/chromium/net/http/transport_security_state.h @@ -20,6 +20,7 @@ #include "net/base/expiring_cache.h" #include "net/base/hash_value.h" #include "net/base/net_export.h" +#include "net/base/network_isolation_key.h" #include "net/cert/signed_certificate_timestamp_and_status.h" #include "net/http/transport_security_state_source.h" #include "url/gurl.h" @@ -31,6 +32,7 @@ enum class CTPolicyCompliance; } class HostPortPair; +class NetworkIsolationKey; class SSLInfo; class X509Certificate; @@ -232,8 +234,6 @@ class NET_EXPORT TransportSecurityState { ExpectCTState(); ~ExpectCTState(); - // The domain which matched during a search for this DomainState entry. - std::string domain; // The URI to which reports should be sent if valid CT info is not // provided. GURL report_uri; @@ -247,6 +247,30 @@ class NET_EXPORT TransportSecurityState { base::Time expiry; }; + // Unlike other data, Expect-CT information is indexed by NetworkIsolationKey + // in addition to domain hash, to prevent leaking user IDs across different + // first party contexts. Public only because ExpectCTStateIterator is public + // and depends on it. + struct ExpectCTStateIndex { + // Creates an ExpectCTStateIndex. Uses an empty NetworkIsolationKey instead + // of the passed in one, depending on |respect_network_isolation_key|. + // The value of features::kPartitionExpectCTStateByNetworkIsolationKey is + // cached on creation of the TransportSecurityState, and then passed in to + // this method whenever an ExpectCTStateIndex() is created, to avoid + // constantly querying the field trial. + ExpectCTStateIndex(const std::string& hashed_host, + const NetworkIsolationKey& network_isolation_key, + bool respect_network_isolation_key); + + bool operator<(const ExpectCTStateIndex& other) const { + return std::tie(hashed_host, network_isolation_key) < + std::tie(other.hashed_host, other.network_isolation_key); + } + + std::string hashed_host; + NetworkIsolationKey network_isolation_key; + }; + class NET_EXPORT ExpectCTStateIterator { public: explicit ExpectCTStateIterator(const TransportSecurityState& state); @@ -254,12 +278,15 @@ class NET_EXPORT TransportSecurityState { bool HasNext() const { return iterator_ != end_; } void Advance() { ++iterator_; } - const std::string& hostname() const { return iterator_->first; } + const std::string& hostname() const { return iterator_->first.hashed_host; } + const NetworkIsolationKey& network_isolation_key() const { + return iterator_->first.network_isolation_key; + } const ExpectCTState& domain_state() const { return iterator_->second; } private: - std::map<std::string, ExpectCTState>::const_iterator iterator_; - std::map<std::string, ExpectCTState>::const_iterator end_; + std::map<ExpectCTStateIndex, ExpectCTState>::const_iterator iterator_; + std::map<ExpectCTStateIndex, ExpectCTState>::const_iterator end_; }; // An interface for asynchronously sending HPKP violation reports. @@ -301,7 +328,8 @@ class NET_EXPORT TransportSecurityState { const X509Certificate* validated_certificate_chain, const X509Certificate* served_certificate_chain, const SignedCertificateTimestampAndStatusList& - signed_certificate_timestamps) = 0; + signed_certificate_timestamps, + const NetworkIsolationKey& network_isolation_key) = 0; protected: virtual ~ExpectCTReporter() {} @@ -383,7 +411,8 @@ class NET_EXPORT TransportSecurityState { const SignedCertificateTimestampAndStatusList& signed_certificate_timestamps, const ExpectCTReportStatus report_status, - ct::CTPolicyCompliance policy_compliance); + ct::CTPolicyCompliance policy_compliance, + const NetworkIsolationKey& network_isolation_key); // Assign a |Delegate| for persisting the transport security state. If // |NULL|, state will not be persisted. The caller retains @@ -425,8 +454,10 @@ class NET_EXPORT TransportSecurityState { // |hashed_host|. |hashed_host| is already in the internal representation. // Note: This is only used for serializing/deserializing the // TransportSecurityState. - void AddOrUpdateEnabledExpectCTHosts(const std::string& hashed_host, - const ExpectCTState& state); + void AddOrUpdateEnabledExpectCTHosts( + const std::string& hashed_host, + const NetworkIsolationKey& network_isolation_key, + const ExpectCTState& state); // Deletes all dynamic data (e.g. HSTS or HPKP data) created since a given // time. @@ -465,19 +496,15 @@ class NET_EXPORT TransportSecurityState { // Returns true and updates |*result| iff |host| has dynamic // HSTS/HPKP/Expect-CT (respectively) state. If multiple entries match |host|, - // the most specific match determines the return value. |*should_be_dynamic| - // is set to true if |host| has no dynamic HSTS state based on the current - // implementation but would have it based on a spec-compliant implementation. - // See https://crbug.com/821811. |should_be_dynamic| may be nullptr to ignore - // the output. + // the most specific match determines the return value. // // Note that these methods are not const because they opportunistically remove // entries that have expired. - bool GetDynamicSTSState(const std::string& host, - STSState* result, - bool* should_be_dynamic); + bool GetDynamicSTSState(const std::string& host, STSState* result); bool GetDynamicPKPState(const std::string& host, PKPState* result); - bool GetDynamicExpectCTState(const std::string& host, ExpectCTState* result); + bool GetDynamicExpectCTState(const std::string& host, + const NetworkIsolationKey& network_isolation_key, + ExpectCTState* result); // Processes an HSTS header value from the host, adding entries to // dynamic state if necessary. @@ -505,7 +532,8 @@ class NET_EXPORT TransportSecurityState { void AddExpectCT(const std::string& host, const base::Time& expiry, bool enforce, - const GURL& report_uri); + const GURL& report_uri, + const NetworkIsolationKey& network_isolation_key); // Enables or disables public key pinning bypass for local trust anchors. // Disabling the bypass for local trust anchors is highly discouraged. @@ -527,7 +555,8 @@ class NET_EXPORT TransportSecurityState { // connection is not CT-compliant, then a report will be sent. void ProcessExpectCTHeader(const std::string& value, const HostPortPair& host_port_pair, - const SSLInfo& ssl_info); + const SSLInfo& ssl_info, + const NetworkIsolationKey& network_isolation_key); void AssertCalledOnValidThread() const { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); @@ -545,6 +574,9 @@ class NET_EXPORT TransportSecurityState { void EnableStaticPinsForTesting() { enable_static_pins_ = true; } bool has_dynamic_pkp_state() const { return !enabled_pkp_hosts_.empty(); } + // The number of cached ExpectCTState entries. + size_t num_expect_ct_entries() const; + private: friend class TransportSecurityStateTest; friend class TransportSecurityStateStaticFuzzer; @@ -553,7 +585,7 @@ class NET_EXPORT TransportSecurityState { typedef std::map<std::string, STSState> STSStateMap; typedef std::map<std::string, PKPState> PKPStateMap; - typedef std::map<std::string, ExpectCTState> ExpectCTStateMap; + typedef std::map<ExpectCTStateIndex, ExpectCTState> ExpectCTStateMap; typedef ExpiringCache<std::string, bool, base::TimeTicks, @@ -579,34 +611,26 @@ class NET_EXPORT TransportSecurityState { // changed. void DirtyNotify(); - // Adds HSTS state to |host|. + // Adds HSTS, HPKP, and Expect-CT state for |host|. The new state supercedes + // any previous state for the |host|, including static entries. + // + // The new state for |host| is persisted using the Delegate (if any). void AddHSTSInternal(const std::string& host, STSState::UpgradeMode upgrade_mode, const base::Time& expiry, bool include_subdomains); - - // Adds HPKP state to |host|. void AddHPKPInternal(const std::string& host, const base::Time& last_observed, const base::Time& expiry, bool include_subdomains, const HashValueVector& hashes, const GURL& report_uri); - - // Adds Expect-CT state to |host|. void AddExpectCTInternal(const std::string& host, const base::Time& last_observed, const base::Time& expiry, bool enforce, - const GURL& report_uri); - - // Enable TransportSecurity for |host|. |state| supercedes any previous - // state for the |host|, including static entries. - // - // The new state for |host| is persisted using the Delegate (if any). - void EnableSTSHost(const std::string& host, const STSState& state); - void EnablePKPHost(const std::string& host, const PKPState& state); - void EnableExpectCTHost(const std::string& host, const ExpectCTState& state); + const GURL& report_uri, + const NetworkIsolationKey& network_isolation_key); // Returns true if a request to |host_port_pair| with the given // SubjectPublicKeyInfo |hashes| satisfies the pins in |pkp_state|, @@ -637,7 +661,24 @@ class NET_EXPORT TransportSecurityState { const X509Certificate* validated_certificate_chain, const X509Certificate* served_certificate_chain, const SignedCertificateTimestampAndStatusList& - signed_certificate_timestamps); + signed_certificate_timestamps, + const NetworkIsolationKey& network_isolation_key); + + // Convenience method to create ExpectCTStateIndex, taking into account + // |key_expect_ct_by_nik_|. + ExpectCTStateIndex CreateExpectCTStateIndex( + const std::string& hashed_host, + const NetworkIsolationKey& network_isolation_key); + + // Checks if Expect-CT entries should be pruned, based on number of them and + // when entries were last pruned, and then performs pruning if necessary. + void MaybePruneExpectCTState(); + + // Sort ExpectCTState based on retention priority, with earlier entries to be + // removed first. Transient entries put in the front, then report-only + // entries, then entries are sorted by age, oldest first. + static bool ExpectCTPruningSorter(const ExpectCTStateMap::iterator& it1, + const ExpectCTStateMap::iterator& it2); // The sets of hosts that have enabled TransportSecurity. |domain| will always // be empty for a STSState, PKPState, or ExpectCTState in these maps; the @@ -670,6 +711,16 @@ class NET_EXPORT TransportSecurityState { ReportCache sent_hpkp_reports_cache_; ReportCache sent_expect_ct_reports_cache_; + // Whether Expect-CT data should keyed by a NetworkIsolationKey. When false, + // ExpectCTStateIndex is always created with an empty NetworkIsolationKey. + // Populated based on features::kPartitionExpectCTStateByNetworkIsolationKey + // on construction of the TransportSecurityStateObject to avoid repeatedly + // querying the feature. + bool key_expect_ct_by_nik_; + + // The earliest possible time for the next pruning of Expect-CT state. + base::Time earliest_next_prune_expect_ct_time_; + std::set<std::string> hsts_host_bypass_list_; THREAD_CHECKER(thread_checker_); diff --git a/chromium/net/http/transport_security_state_static.json b/chromium/net/http/transport_security_state_static.json index 6f54b439db4..8f4ba4124c4 100644 --- a/chromium/net/http/transport_security_state_static.json +++ b/chromium/net/http/transport_security_state_static.json @@ -31,8 +31,11 @@ // - bulk-legacy: bulk entries preloaded before Chrome 50. // - bulk-18-weeks: bulk entries with max-age >= 18 weeks (Chrome 50-63). // - bulk-1-year: bulk entries with max-age >= 1 year (after Chrome 63). -// - public-suffix-requested: public suffixes preloaded at the owners -// request (manual). +// - public-suffix: public suffixes (e.g. TLDs or other public suffix +// list entries) preloaded at the owner's request. +// - public-suffix-requested: domains under a public suffix that have +// been preloaded at the request of the the public suffix owner (e.g. +// the registry for the TLD). // include_subdomains: (optional boolean) For backwards compatibility, this // means: // - If mode == "force-https", then apply force-https to subdomains. @@ -263,6 +266,7 @@ { "name": "bmoattachments.org", "policy": "public-suffix", "mode": "force-https", "include_subdomains": true }, { "name": "now.sh", "policy": "public-suffix", "mode": "force-https", "include_subdomains": true }, { "name": "cnpy.gdn", "policy": "public-suffix", "mode": "force-https", "include_subdomains": true }, + { "name": "gentapps.com", "policy": "public-suffix", "mode": "force-https", "include_subdomains": true }, // Google domains using Expect-CT. { @@ -1237,7 +1241,6 @@ { "name": "datenkeks.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "derhil.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "energy-drink-magazin.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "ferienhaus-polchow-ruegen.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "freeshell.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "greensolid.biz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "hasilocke.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -1573,7 +1576,6 @@ { "name": "onedot.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "powerplannerapp.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "ru-sprachstudio.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "slattery.co", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "slidebatch.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "smartship.co.jp", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "southside-crew.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -1582,7 +1584,6 @@ { "name": "fleximus.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "animurecs.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "arendburgers.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "big-andy.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "bitgo.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "buttercoin.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "chainmonitor.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -1647,7 +1648,6 @@ { "name": "ethack.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "fabianfischer.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "fastcomcorp.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "gizzo.sk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "itshost.ru", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "jmedved.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "keepclean.me", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -1800,7 +1800,6 @@ { "name": "atlassian.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "atte.fi", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "bizon.sk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "broeselei.at", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "cordial-restaurant.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "curiosity-driven.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "egfl.org.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -2061,7 +2060,6 @@ { "name": "mailmag.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "mevs.cz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "miconcinemas.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "mister.hosting", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "mtau.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "myprintcard.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "nationalpriorities.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -2141,7 +2139,6 @@ { "name": "imgg.es", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "ipmimagazine.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "isogram.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "j0s.at", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "jbn.mx", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "jeremyness.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "jkb.pics", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -2196,7 +2193,6 @@ { "name": "securedrop.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "sigterm.sh", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "sleio.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "souki.cz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "speedcounter.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "stesti.cz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "stevegrav.es", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -2242,7 +2238,6 @@ { "name": "fa-works.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "getmango.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "gokmenguresci.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "goodwin43.ru", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "gotspot.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "gra2.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "hledejpravnika.cz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -2302,7 +2297,6 @@ { "name": "ge3k.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "hboeck.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "indovinabank.com.vn", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "ipsec.pl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "jamesdoylephoto.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "jpbike.cz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "kaneo-gmbh.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -2768,7 +2762,6 @@ { "name": "sarahlicity.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "schreibnacht.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "screenlight.tv", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "search-one.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "shanewadleigh.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "shasso.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "shoprose.ru", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -3337,7 +3330,6 @@ { "name": "iqboxy.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "ivk.website", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "jacekowski.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "kermadec.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "latrine.cz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "lmddgtfy.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "lmsptfy.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -3715,7 +3707,6 @@ { "name": "billninja.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "bionicspirit.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "blackburn.link", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "blazor.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "blechschmidt.saarland", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "bugginslab.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "bwcscorecard.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -3917,7 +3908,6 @@ { "name": "elimdengelen.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "entersynapse.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "epay.bg", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "escalate.eu", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "espci.fr", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "ev-zertifikate.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "evdenevenakliyatankara.pw", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -3980,7 +3970,6 @@ { "name": "nikolasbradshaw.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "nomial.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "npmcdn.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "nutritionculture.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "oasis.mobi", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "opsbears.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "otchecker.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -4021,7 +4010,6 @@ { "name": "teampaddymurphy.ie", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "teampoint.cz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "therewill.be", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "thomspooren.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "threelions.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "tm-solutions.eu", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "tomasjacik.cz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -4051,7 +4039,6 @@ { "name": "binaryevolved.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "bitcoinhk.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "blackdragoninc.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "c16t.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "cabarave.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "cannyfoxx.me", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "clmde.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -4356,7 +4343,6 @@ { "name": "kleppe.co", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "konijntjes.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "kraft.im", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "kredietpaspoort.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "kurtmclester.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "labs.directory", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "lambda-complex.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -4431,7 +4417,6 @@ { "name": "profundr.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "proxybay.al", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "purplemoon.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "qiliang.wang", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "quotehex.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "redshield.co", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "responsibledisclosure.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -4458,7 +4443,6 @@ { "name": "sslpoint.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "stalkerhispano.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "star-citizen.wiki", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "staticisnoise.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "statuscode.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "storycollective.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "stricted.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -4494,7 +4478,6 @@ { "name": "unitel2000.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "unixadm.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "unoccupyabq.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "unterschicht.tv", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "unwiredbrain.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "uvarov.pw", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "valentin-sundermann.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -4503,8 +4486,6 @@ { "name": "vissanum.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "vsund.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "walkeryoung.ca", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "wangqiliang.cn", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "wangqiliang.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "wartorngalaxy.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "wealthprojector.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "wealthprojector.com.au", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -5089,7 +5070,6 @@ { "name": "alexvetter.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "alkami.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "alkamitech.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "andrewbroekman.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "angristan.fr", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "annabellaw.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "approlys.fr", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -5272,7 +5252,6 @@ { "name": "eligible.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "englishclub.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "esclear.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "fearsomegaming.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "firevap.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "gintenreiter-photography.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "graphire.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -5312,7 +5291,6 @@ { "name": "netsystems.pro", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "neuralgic.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "nolberg.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "onefour.co", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "openxmpp.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "optenhoefel.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "oversight.garden", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -5361,7 +5339,6 @@ { "name": "adams.dk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "anderslind.dk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "chiru.no", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "consul.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "dealpass.no", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "driving-lessons.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "elbetech.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -5387,7 +5364,6 @@ { "name": "lyx.dk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "martinp.no", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "minpingvin.dk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "mt.me.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "omniti.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "open-bs.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "perfect.in.th", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -5407,7 +5383,6 @@ { "name": "tresorsecurity.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "urphp.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "v0tti.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "vagrantup.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "wegner.no", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "wilddog.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "wlzhiyin.cn", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -5456,7 +5431,6 @@ { "name": "alexn.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "allbenjoy.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "am3.se", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "amavis.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "ambiente.one", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "ancientkarma.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "andreaboero.it", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -5724,7 +5698,6 @@ { "name": "fiksel.info", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "fikt.space", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "finfev.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "firebird.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "fischers.cc", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "flamingkeys.com.au", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "flocktofedora.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -5772,7 +5745,6 @@ { "name": "gravitechthai.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "greedbutt.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "greenpeace.berlin", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "gresak.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "griesser2.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "grog.pw", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "gropp.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -5838,7 +5810,6 @@ { "name": "infosenior.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "inios.fr", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "insane.zone", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "interference.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "internetcasinos.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "inton.biz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "investorforms.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -5898,7 +5869,6 @@ { "name": "ke7tlf.us", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "keaysmillwork.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "kekku.li", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "kermadec.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "ketosecology.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "kevinapease.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "kevinbusse.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -5951,7 +5921,6 @@ { "name": "logicsale.it", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "loginseite.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "loli.bz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "lonal.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "loopstart.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "lpm-uk.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "lubot.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -6081,7 +6050,6 @@ { "name": "ozvolvo.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "p1984.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "p1c.pw", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "pagerate.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "paginapolitica.ro", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "pakke.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "paneu.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -6127,7 +6095,6 @@ { "name": "qingpei.me", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "qinxi1992.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "qop.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "qorm.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "qtl.me", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "quantoras.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "quranserver.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -6156,7 +6123,6 @@ { "name": "richardhering.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "ringingliberty.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "rix.ninja", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "rkmantpur.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "robertkrueger.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "rodehutskors.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "rodney.id.au", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -6223,7 +6189,6 @@ { "name": "someshit.xyz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "soph.us", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "sortaweird.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "sourcelair.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "sown.dyndns.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "spacedust.xyz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "sparsa.army", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -6762,7 +6727,6 @@ { "name": "newportpropertygroup.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "ninchat.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "nobly.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "nocit.dk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "nodelia.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "noop.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "noxlogic.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -6794,7 +6758,6 @@ { "name": "palatin.at", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "pamplona.tv", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "panaceallc.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "panmetro.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "panni.me", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "paradoxdesigns.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "parithy.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -6840,7 +6803,6 @@ { "name": "reprolife.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "richsiciliano.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "ring0.xyz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "rop.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "rossen.be", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "rous.se", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "rozalisbengal.ro", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -6965,7 +6927,6 @@ { "name": "viciousviscosity.xyz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "videomuz.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "visiontree-beta.eu", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "visiontree.eu", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "vmem.jp", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "vogt.tech", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "vonedelmann.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -7256,7 +7217,6 @@ { "name": "glasschmuck-millefiori.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "goge.site", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "graavaapi.elasticbeanstalk.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "gyz.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "gz-architekten.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "httpsecurityreport.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "ibron.co", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -7421,7 +7381,6 @@ { "name": "datacalle.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "datacandy.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "datortipsen.se", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "deer.team", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "detutorial.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "developmentaid.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "digminecraft.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -8126,7 +8085,6 @@ { "name": "appreciationkards.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "appsdash.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "aprovpn.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "aquapoint.kiev.ua", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "aramido.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "aran.me.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "arlen.se", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -8185,7 +8143,6 @@ { "name": "bcbsmagentprofile.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "bcmlu.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "bcweightlifting.ca", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "beavers.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "bebef.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "beeznest.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "befundonline.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -8249,7 +8206,6 @@ { "name": "bluepoint.foundation", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "bluepoint.institute", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "blusmurf.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "bngsecure.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "boensou.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "boernecancerfonden.dk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "bonfi.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -8372,7 +8328,6 @@ { "name": "cmahy.be", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "cni-certing.it", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "coachingconsultancy.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "coam.co", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "cocolovesdaddy.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "codeferm.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "coderhangout.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -8631,7 +8586,6 @@ { "name": "evi.be", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "evin.ml", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "evites.me", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "evowl.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "exchangeworks.co", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "exemples-de-stands.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "exoscale.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -8993,7 +8947,6 @@ { "name": "janosh.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "japan4you.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "japlex.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "jaredeberle.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "jaredfernandez.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "jartza.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "javelinsms.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -9344,7 +9297,6 @@ { "name": "nako.no", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "nalifornia.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "nargileh.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "natalia.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "natalt.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "natanaelys.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "natenom.name", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -9538,7 +9490,6 @@ { "name": "pieq.eu.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "pieterjangeeroms.me", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "piliszek.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "pinnaclelife.co.nz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "pinnaclelife.nz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "pirateproxy.tv", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "pisupp.ly", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -9798,7 +9749,6 @@ { "name": "simonsreich.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "simplepractice.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "simplixos.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "simplymozzo.se", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "singleuse.link", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "singlu10.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "sinosky.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -9961,7 +9911,6 @@ { "name": "tempcraft.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "tenenz.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "tennisadmin.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "teos.online", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "teoskanta.fi", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "tepid.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "terracloud.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -9979,7 +9928,6 @@ { "name": "theendofzion.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "thefarbeyond.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "thefootballanalyst.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "thefox.co", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "thegcccoin.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "thegvoffice.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "thehiddenbay.eu", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -10065,7 +10013,6 @@ { "name": "tsgbit.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "tsrstore.gq", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "tubepro.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "tunai.id", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "turnik-67.ru", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "turtle.ai", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "turtlementors.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -10389,7 +10336,6 @@ { "name": "azino777.ru", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "badoo.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "ballmerpeak.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "bandb.xyz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "bangzafran.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "barrett.ag", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "baffinlee.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -10474,7 +10420,6 @@ { "name": "cheapestgamecards.se", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "cheapestgamecards.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "cjcaron.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "chloeallison.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "cheapgoa.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "christina-quast.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "classicsandexotics.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -10569,7 +10514,6 @@ { "name": "droomhuis-in-friesland-kopen.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "dredgepress.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "duernberg.at", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "dustri.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "e-lifetechnology.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "eames-clayton.us", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "dvotx.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -10660,7 +10604,6 @@ { "name": "geneau.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "gameparade.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "getflorence.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "gilgaz.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "gasnews.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "giant-powerfit.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "ginzadelunch.jp", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -10687,7 +10630,6 @@ { "name": "grozip.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "hallelujahsoftware.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "hakugin.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "happygastro.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "gold24.in", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "hdrboundless.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "hatcherlawgroupnm.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -10998,7 +10940,6 @@ { "name": "oxynux.xyz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "papa-webzeit.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "pastenib.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "penguinclientsystem.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "percolate.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "pdevio.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "oyste.in", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -11007,7 +10948,6 @@ { "name": "phantasie.cc", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "perroud.pro", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "perthdevicelab.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "peterfolta.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "pfolta.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "performancesantafe.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "pirateproxy.pe", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -11085,7 +11025,6 @@ { "name": "riscascape.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "rithm.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "rhapsodhy.hu", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "rochman.id", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "rointe.online", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "royalhop.co", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "rokort.dk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -11102,7 +11041,6 @@ { "name": "ruh-veit.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "saleslift.pl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "saba-piserver.info", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "sangwon.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "saml-gateway.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "sbirecruitment.co.in", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "sansemea.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -11275,7 +11213,6 @@ { "name": "trondelan.no", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "ueu.me", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "twelve.today", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "tuxflow.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "tumelum.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "tyrelius.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "unblocked.win", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -11344,7 +11281,6 @@ { "name": "web-hotel.gr", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "webdev.mobi", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "webmedpharmacy.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "weme.eu", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "werktor.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "wheeler.kiwi.nz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "whiterabbitcakery.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -11702,7 +11638,6 @@ { "name": "justinho.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "justupdate.me", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "jxm.in", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "kaizenreporting.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "karmaflux.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "kayon.cf", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "keepcoalintheground.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -11710,7 +11645,6 @@ { "name": "kialo.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "kiapps.ovh", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "kielderweather.org.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "kilometertje.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "kinomoto.me", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "kircp.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "kitk.at", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -12109,7 +12043,6 @@ { "name": "4vf.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "540.co", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "7thcircledesigns.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "88.to", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "8mpay.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "922.be", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "9906753.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -12260,7 +12193,6 @@ { "name": "bownty.it", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "bownty.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "bownty.pt", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "brandspray.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "brashear.me", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "brasilmorar.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "bratislava-airport-taxi.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -12656,7 +12588,6 @@ { "name": "hartmancpa.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "hasdf.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "hatethe.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "haxoff.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "hcs-company.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "hdrtranscon.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "healthjoy.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -12816,7 +12747,6 @@ { "name": "kadmec.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "kanar.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "kartec.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "kasadara.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "kashmirobserver.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "kateduggan.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "kati-raumplaner.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -12938,7 +12868,6 @@ { "name": "manageall.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "manageforall.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "manageforall.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "manesht.ir", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "maniadeprazer.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "mansion-note.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "marble.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -12983,7 +12912,6 @@ { "name": "mind.sh", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "minux.info", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "mipla.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "miragrow.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "missoy.me", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "mivcon.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "mixtape.moe", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -13121,7 +13049,6 @@ { "name": "petrasestakova.cz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "pexieapp.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "pgnetwork.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "phcnetworks.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "phenomeno-porto.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "phenomeno.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "phenomenoporto.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -14602,7 +14529,6 @@ { "name": "mazda-mps.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "marc-schlagenhauf.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "mechmk1.me", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "marketio.co", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "microlog.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "mobio.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "map4erfurt.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -15114,7 +15040,6 @@ { "name": "sw-servers.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "stair.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "tcby45.xyz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "suksit.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "testadron.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "supersonnig-festival.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "sweep-me.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -15122,7 +15047,6 @@ { "name": "studybay.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "tetrarch.co", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "studio-panic.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "teamtrack.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "solariiknight.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "suckmyan.us", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "talun.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -15159,7 +15083,6 @@ { "name": "timnash.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "thues.eu", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "ti-pla.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "timdebruijn.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "tolboe.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "tomandshirley.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "tinyssh.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -15183,7 +15106,6 @@ { "name": "tracetracker.no", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "todoescine.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "topaxi.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "tradinews.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "trafficquality.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "thomasvochten.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "thedarkartsandcrafts.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -15253,7 +15175,6 @@ { "name": "vocab.guru", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "vinner.com.au", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "v4veedu.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "webstellung.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "uberwald.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "w7k.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "wawak.pl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -15270,7 +15191,6 @@ { "name": "wowjs.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "webthings.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "wait.moe", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "wemakemenus.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "waits.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "whoownsmyavailability.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "wachtwoordencheck.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -15615,7 +15535,6 @@ { "name": "curveprotect.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "devafterdark.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "customfilmworks.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "cyberpeace.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "cytadel.fr", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "crossborderreturns.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "cybersins.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -15731,7 +15650,6 @@ { "name": "esample.info", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "europapier.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "europapier.sk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "fastograph.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "etheria-software.tk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "fastconfirm.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "exactlyinfinite.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -16114,7 +16032,6 @@ { "name": "momentumdash.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "minitruckin.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "meincloudspeicher.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "migrator.co", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "mimemo.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "medialab.nrw", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "miguelmoura.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -16473,7 +16390,6 @@ { "name": "theflowerbasketonline.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "team-pancake.eu", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "stilmobil.se", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "teambeoplay.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "thesaturdaypaper.com.au", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "telling.xyz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "telefoonabonnement.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -16504,7 +16420,6 @@ { "name": "syt3.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "timewasters.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "studentrightsadvocate.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "tomharris.tech", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "triadwars.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "uhm.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "thewebsitemarketingagency.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -16514,7 +16429,6 @@ { "name": "trynowrinkleseyeserum.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "tragmi.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "thijsvanderveen.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "tradinews.fr", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "transcricentro.pt", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "tobi-mayer.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "theschool.jp", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -16635,7 +16549,6 @@ { "name": "xat.re", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "yotilabs.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "wundtherapie-schulung.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "zupago.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "yuki.xyz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "yukiminami.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "xn--mentaltraining-fr-musiker-uwc.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -16977,7 +16890,6 @@ { "name": "aoku3d.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "biospeak.solutions", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "camperlist.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "cctld.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "bundespolizei-forum.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "carbon12.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "cesipagano.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -17240,7 +17152,6 @@ { "name": "ecomlane.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "duncanwinfrey.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "droni.cz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "eddyn.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "egbert.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "droomhuis-in-de-friese-meren-kopen.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "droomhuisophetplattelandverkopen.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -17294,7 +17205,6 @@ { "name": "et180.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "especificosba.com.mx", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "eengezinswoningverkopen.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "eastmanbusinessinstitute.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "enginepit.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "buildingclouds.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "erick.blog", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -17614,7 +17524,6 @@ { "name": "inima.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "indusap.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "infinity-freedom.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "hydra.zone", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "ihrhost.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "inme.ga", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "interhosts.co.za", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -17906,7 +17815,6 @@ { "name": "matthias-muenzner.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "lorenadumitrascu.ro", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "lovelyblogacademy.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "mentalhealth.gov", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "laurelblack.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "melhorproduto.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "metsasta.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -18102,7 +18010,6 @@ { "name": "nordwaldzendo.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "neofelhz.space", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "nurses.dating", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "oktoberfeststore.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "osburn.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "olswangtrainees.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "new.travel.pl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -18231,7 +18138,6 @@ { "name": "r-rickroll-u.pw", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "rally-base.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "novurania.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "qqj.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "rasagiline.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "questsocial.it", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "rathorian.fr", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -18338,7 +18244,6 @@ { "name": "selegiline.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "semianalog.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "safelist.eu", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "sensebridge.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "schauer.so", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "sendthisfile.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "safeex.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -18672,7 +18577,6 @@ { "name": "unblocked.works", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "upmchealthsecurity.us", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "tumagiri.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "usability.gov", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "uctarna.online", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "utilitarianism.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "twee-onder-een-kap-woning-in-leeuwarden-kopen.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -19061,7 +18965,6 @@ { "name": "ballbusting-cbt.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "b422edu.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "avdagic.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "automotivemechanic.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "auerbach-verlag.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "axem.co.jp", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "ave.zone", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -19332,7 +19235,6 @@ { "name": "co-yutaka.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "coding.lv", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "channellife.asia", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "clovissantos.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "codelitmus.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "craigwfox.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "cnbs.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -19492,7 +19394,6 @@ { "name": "dohanews.co", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "dorfbaeck.at", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "dreamaholic.club", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "domaine-aigoual-cevennes.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "dopravni-modely.cz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "drabbin.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "duckbase.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -19708,7 +19609,6 @@ { "name": "garageenginuity.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "ftang.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "fuchsy.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "fx24.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "freelo.cz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "fegans.org.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "gayforgenji.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -19809,7 +19709,6 @@ { "name": "hackbubble.me", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "hawk-la.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "grieg.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "heavyequipments.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "hearttruth.gov", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "heisenberg.co", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "friendship-quotes.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -20225,7 +20124,6 @@ { "name": "main-street-seo.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "macht-elektro.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "matlss.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "maquinariaspesadas.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "manitasicily.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "marcelmarnitz.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "masty.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -20245,7 +20143,6 @@ { "name": "matthew-carson.info", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "matillat.ovh", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "kinderopvangengeltjes.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "mecanicoautomotriz.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "mi80.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "mediumraw.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "maurus-automation.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -20324,7 +20221,6 @@ { "name": "muwatenraqamy.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "morpheusxaut.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "morpheusx.at", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "mannford.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "mrd.ninja", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "mygrotto.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "mode-marine.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -20510,7 +20406,6 @@ { "name": "payfazz.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "panama-gbs.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "open-sauce-recipes.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "padovani.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "pbytes.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "olightstore.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "otellio.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -20637,7 +20532,6 @@ { "name": "radiomodem.dk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "progressivecfo.co.nz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "pianetaottica.eu", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "prepaid-voip.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "readingandmath.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "ravengergaming.ga", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "rbti.me", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -20704,7 +20598,6 @@ { "name": "rehabthailand.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "rockpesado.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "robertattfield.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "reussirsavie.info", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "ripa.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "rough.nu", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "rockbankland.com.au", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -20724,7 +20617,6 @@ { "name": "reto.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "reality.news", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "rolroer.co.za", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "rulu.co", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "saferedirect.link", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "rpasafrica.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "portaluniversalista.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -20805,7 +20697,6 @@ { "name": "sebastianhampl.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "shanekoster.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "shareoffice.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "schroettle.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "sergeyreznikov.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "seriousclimbing.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "shareeri.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -21030,7 +20921,6 @@ { "name": "theyear199x.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "throttlerz.in", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "thejobauction.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "startuppeople.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "techday.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "thairehabassociation.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "sportchirp-internal.azurewebsites.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -21052,7 +20942,6 @@ { "name": "tomiler.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "tobiassachs.cf", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "teulon.eu", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "theobromos.fr", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "tolud.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "tlcdn.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "thesignalco.com.au", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -21193,7 +21082,6 @@ { "name": "vsestiralnie.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "vasileruscior.ro", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "vitaminler.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "westtulsa.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "webpublica.pt", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "web404.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "whereiszakir.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -21284,7 +21172,6 @@ { "name": "xn--90accgba6bldkcbb7a.xn--p1acf", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "xninja.xyz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "youdungoofd.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "xn--d1acj9c.xn--90ais", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "yukonrefugees.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "zeds-official.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "wildcard.hu", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -21707,7 +21594,6 @@ { "name": "gelb-computer.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "gfk-kunststoff-luebben.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "ghislainphu.fr", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "gianlucapartengo.photography", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "giduv.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "giochi-online.ws", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "girlan.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -22202,7 +22088,6 @@ { "name": "theavenuegallery.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "thecodeninja.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "thehoopsarchive.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "thelefthand.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "thelinuxtree.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "themoneyconverter.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "thepcweb.tk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -22443,7 +22328,6 @@ { "name": "abasky.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "abi-fvs.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "abigisp.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "aboderenovation.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "abolicionistas.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "abolition.co", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "abolition.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -22482,7 +22366,6 @@ { "name": "active-escape.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "addicional.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "adlerweb.info", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "administratorserwera.pl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "admongo.gov", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "adrafinil.wiki", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "adriancohea.ninja", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -22640,7 +22523,6 @@ { "name": "astenretail.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "astronomie-fulda.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "at-one.ca", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "at1.co", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "athena-bartholdi.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "atkdesign.pt", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "atlantareroof.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -22788,7 +22670,6 @@ { "name": "bltc.org.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "bluefrag.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "blues-and-pictures.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "bluteklab.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "bnty.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "bobep.ru", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "boboates.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -23116,7 +22997,6 @@ { "name": "cvninja.pl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "cwrcoding.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "cyber-computer.club", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "cyber.cafe", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "cybercecurity.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "cyberwars.dk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "cyoda.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -23284,7 +23164,6 @@ { "name": "dzomo.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "e-migration.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "e-newshub.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "e-pokupki.eu", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "e-tune-mt.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "e-vau.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "e-wishlist.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -23419,7 +23298,6 @@ { "name": "falkus.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "fame-agency.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "familyreal.ru", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "fanflow.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "fantasticgardenersmelbourne.com.au", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "fantastichandymanmelbourne.com.au", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "fantasticpestcontrolmelbourne.com.au", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -24062,8 +23940,6 @@ { "name": "kirainmoe.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "kisallatorvos.hu", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "kisstube.tv", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "kitchen-profi.com.ua", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "kitchen-profi.kz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "kittyhacker101.tk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "kjg-bachrain.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "kjoglum.me", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -24410,7 +24286,6 @@ { "name": "mister-cooks.fr", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "mk-dizajn.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "mkaciuba.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "mkakh.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "mkakh.xyz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "mlcambiental.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "mlpchan.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -24526,7 +24401,6 @@ { "name": "neeerd.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "neemzy.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "neet-investor.biz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "nemcd.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "nemez.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "neobits.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "neokobe.city", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -24608,7 +24482,6 @@ { "name": "obyvateleceska.cz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "ocelot.help", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "ocsigroup.fr", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "odzyskaniedomeny.pl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "ofcss.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "off-the-clock.us", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "offroadeq.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -24799,7 +24672,6 @@ { "name": "popmagz.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "poppetsphere.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "population-ethics.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "poquvi.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "porg.es", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "pork.org.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "porn77.info", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -25001,7 +24873,6 @@ { "name": "robin.co.kr", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "robu.in", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "rocketnet.ml", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "rockfax.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "rodichi.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "rodomonte.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "rogagym.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -25580,7 +25451,6 @@ { "name": "uex.im", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "ufo.moe", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "ufplanets.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "ukclimbing.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "ukhillwalking.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "ukkeyholdingcompany.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "ukrnet.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -25668,7 +25538,6 @@ { "name": "vorlicek.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "vpc-display.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "vpsboard.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "vsc-don-stocksport.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "vsesrazu-raiffeisen.ru", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "vstehn.ru", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "vuakhuyenmai.vn", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -26197,7 +26066,6 @@ { "name": "beckerantiques.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "belfastlocks.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "benburwell.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "benfairclough.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "aurora-multimedia.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "balidesignshop.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "around-the-blog.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -26332,7 +26200,6 @@ { "name": "c2o-library.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "burckardtnet.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "bronetb2b.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "bm-i.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "by1898.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "boyan.in", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "buttercupstraining.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -26387,7 +26254,6 @@ { "name": "celigo.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "ccv-deutschland.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "cc-brantomois.fr", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "catburton.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "chaurocks.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "charmingsaul.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "chatbots.email", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -26479,7 +26345,6 @@ { "name": "coolbutbroken.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "collard.tk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "cloud2go.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "capachitos.cl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "continuation.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "comyuno.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "cloud.bugatti", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -26515,7 +26380,6 @@ { "name": "crossfunctional.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "curiouscat.me", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "cosmiatria.pe", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "conkret.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "conkret.eu", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "colarelli.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "conformist.jp", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -26589,7 +26453,6 @@ { "name": "ddocu.me", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "deflumeri.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "davie3.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "dai.top", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "delahrzolder.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "cutelariafiveladeouro.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "dcw.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -26754,7 +26617,6 @@ { "name": "eidolons.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "egeozcan.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "encouragemarketing.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "ecirtam.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "electragirl.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "elosrah.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "dtx.sk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -26775,7 +26637,6 @@ { "name": "elliff.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "dovenzorgmalawi.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "efa-football.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "emil.click", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "elektro-roth.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "eolme.ml", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "drlazarina.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -26929,7 +26790,6 @@ { "name": "flagshop.jp", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "fonseguin.ca", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "fidelis-it.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "flanga.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "fidelis-it.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "fiodental.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "frankyan.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -27033,7 +26893,6 @@ { "name": "gnosticjade.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "gidea.nu", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "gevaulug.fr", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "ghaglund.se", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "geld-im-blick.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "glahcks.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "goemail.me", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -27114,7 +26973,6 @@ { "name": "gugert.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "harveyauzorst.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "hammer-schnaps.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "hanfox.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "handyglas.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "gynaecology.co", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "haruue.moe", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -27576,7 +27434,6 @@ { "name": "linearaudio.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "lipex.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "local360.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "lotuscloud.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "lolibrary.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "livingforreal.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "llvm.us", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -27650,7 +27507,6 @@ { "name": "madbin.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "mastichor.info", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "markus-ullmann.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "mainston.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "maroc-bivouac.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "markllego.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "marqueswines.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -27840,7 +27696,6 @@ { "name": "netki.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "napcae.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "myrig.ru", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "nebul.at", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "nakanishi-paint.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "nedwave.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "newbownerton.xyz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -27859,7 +27714,6 @@ { "name": "neostralis.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "nella.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "nickcraver.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "nbur.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "newaccess.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "nicolasiung.me", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "night2stay.cn", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -28340,7 +28194,6 @@ { "name": "rumoterra.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "s4tips.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "rummel-platz.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "savingbytes.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "salonestella.it", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "sbobetfun.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "sanatrans.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -29050,7 +28903,6 @@ { "name": "woomu.me", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "vysko.cz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "wvw698.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "xiaoniaoyou.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "wangkezun.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "xn--w22a.jp", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "xn--tigreray-i1a.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -29318,7 +29170,6 @@ { "name": "alroniks.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "anttitenhunen.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "aevpn.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "b8a.me", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "aqua-fitness-nacht.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "asmdz.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "ammoulianiapartments.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -29644,7 +29495,6 @@ { "name": "downtimerobot.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "downtimerobot.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "dualascent.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "dev-bluep.pantheonsite.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "drogoz.moe", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "dosomeworks.biz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "droidgyan.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -29871,7 +29721,6 @@ { "name": "gogleapis.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "ghkim.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "glencarbide.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "gamebrott.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "givesunlight.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "gtopala.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "giveme.online", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -29933,7 +29782,6 @@ { "name": "hostworkz.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "fire-wolf.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "hiteco.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "gencmedya.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "heverhagen.rocks", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "horkel.cf", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "hfu.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -30098,7 +29946,6 @@ { "name": "kremalicious.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "kabashop.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "keycenter.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "kitchen-profi.by", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "kobofarm.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "kostecki.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "kevinroebert.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -30111,9 +29958,7 @@ { "name": "koryfi.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "jacobsenarquitetura.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "kitatec.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "konoe.studio", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "lannainnovation.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "knep.me", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "lazulu.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "leadgenie.me", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "laraveldirectory.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -30163,7 +30008,6 @@ { "name": "littlefairy.no", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "lockyourcomputer.pw", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "linux-vme.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "lavolte.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "linkage.ph", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "logimagine.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "kswcosmetics.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -30359,7 +30203,6 @@ { "name": "nba2k.co", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "nba2k.live", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "nba2k.download", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "myliveupdates.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "microbiote-insectes-vecteurs.group", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "nba2k.tw", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "nba.vg", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -30390,7 +30233,6 @@ { "name": "nbaspot.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "nbalivex.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "nbask.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "mundoadulto.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "mvnet.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "mundtec.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "multibomasm.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -30434,7 +30276,6 @@ { "name": "notablog.xyz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "nyphox.ovh", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "numwave.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "mrksk.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "neurocny.cloud", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "netscaler.expert", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "opposer.me", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -30790,7 +30631,6 @@ { "name": "snovey.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "softrobot.se", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "slo-net.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "sorinmuntean.ro", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "speedracer.ca", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "snakafya.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "snowraven.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -30926,7 +30766,6 @@ { "name": "tomticket.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "timbishopartist.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "thuisverpleging-meerdael.be", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "the.ie", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "transcriptionwave.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "tomwassenberg.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "toptec.net.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -31400,7 +31239,6 @@ { "name": "jungleculture.co.za", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "www-8522.am", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "savecrypto.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "rickmartensen.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "vigoxatelier.tech", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "sproing.ca", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "webveloper.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -31471,7 +31309,6 @@ { "name": "corporatecomputingsolutions.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "cosmeticosdelivery.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "creativeapple.ltd", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "d.nf", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "d.nr", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "dbq.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "deliver.moe", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -31871,7 +31708,6 @@ { "name": "enamae.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "enlazaresbueno.cl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "entaurus.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "eoitek.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "equinox.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "esb111.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "espacio-cultural.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -32327,7 +32163,6 @@ { "name": "complexsystems.fail", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "cranforddental.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "crea.bg", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "cusfit.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "cyberlightapp.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "dado.fr", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "dado.me", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -32601,7 +32436,6 @@ { "name": "bewerbungsfoto-deinfoto.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "bewertet.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "bezemkast.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "bhost.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "biaoqingfuhao.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "biaoqingfuhao.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "bidorbuy.co.ke", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -32900,7 +32734,6 @@ { "name": "failover.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "failover.eu", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "fakerli.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "fakti.bg", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "familie-leu.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "familletouret.fr", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "fantasyescortsbirmingham.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -32934,7 +32767,6 @@ { "name": "firstq.xyz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "fiuxy.bz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "fl0222.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "flehm.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "flets-ms.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "fliacuello.com.ar", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "flightzero.cf", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -33069,7 +32901,6 @@ { "name": "holidaysportugal.eu", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "homatism.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "homeodynamics.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "homeownersinsurancenevada.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "homeownersinsurancenv.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "hoplongtech.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "horrendous-servers.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -33135,7 +32966,6 @@ { "name": "itzap.com.au", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "ivanbenito.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "iwell.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "j-elliott.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "janssen.fm", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "japaneseemoticons.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "japanesenames.biz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -33333,7 +33163,6 @@ { "name": "melakaltenegger.at", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "melaniebernhardt.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "melbourneapartments.website", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "melikoff.es", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "melina-schefczyk.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "memetrash.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "memorygame.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -33398,7 +33227,6 @@ { "name": "myaggic.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "mybloggedlife.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "myclinicalstudybuddy.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "mydmdi.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "myforfaitmobile.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "mygaysitges.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "mygoldennetwork.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -33813,7 +33641,6 @@ { "name": "tijo.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "tik.edu.ee", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "tik.help", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "timeatlas.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "timer.fit", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "tkn.me", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "tlca.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -33840,7 +33667,6 @@ { "name": "tridimage.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "trymegadrol.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "tsuki.moe", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "ttbonline.gov", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "ttdsevaonline.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "turigum.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "tutanota.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -34047,7 +33873,6 @@ { "name": "unblocked.pro", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "upd.jp", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "uscp8.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "vida.es", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "viepixel.at", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "wochennummern.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "wplatin.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -34170,8 +33995,6 @@ { "name": "dellipaoli.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "depotsquarekerrville.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "depthe.gr", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "di2pra.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "di2pra.fr", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "diamondyze.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "dice.tokyo", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "digilicious.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -34275,7 +34098,6 @@ { "name": "helpantiaging.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "hevertonfreitas.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "hfcbank.com.gh", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "hh-medic.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "hiddenmalta.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "hiltonarubabeachservices.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "himens.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -34292,7 +34114,6 @@ { "name": "hotelsinformer.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "house-of-japan.co.jp", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "hp42.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "hrjfeedstock.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "hustlehope.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "hyakumachi.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "i-hakul.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -34843,7 +34664,6 @@ { "name": "bolivarfm.com.ve", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "boogiebouncecastles.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "boosinflatablegames.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "bopp.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "born2bounce.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bounce-a-mania.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bounce-a-roo.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -35755,7 +35575,6 @@ { "name": "primalinea.pro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "pristineevents.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "projectcastle.tech", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "promarketer.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "provokator.co.il", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "psc.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ptmarquees.ie", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -35914,7 +35733,6 @@ { "name": "supercastlessouthsydney.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "supercastlessunshinecoast.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "supercastlessydney.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "supersole.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "supersteosbouncycastles.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "sushi.roma.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "suttonbouncycastles.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -35973,7 +35791,6 @@ { "name": "tokobungadilampung.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tokobungadipadangflorist.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tokyo-onkyo.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "topbounce.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "topbouncycastles.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "topclassfun.ie", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "topdogsinflatables.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -36002,7 +35819,6 @@ { "name": "tuppenceworth.ie", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "turtles.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tuthowto.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "tuvangoicuoc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tverdohleb.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tvs-virtual.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "twizzkidzinflatables.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -36174,7 +35990,6 @@ { "name": "rogerdat.ovh", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "roomongo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "securi-tay.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "simontaite.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "skks.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "stackunderflow.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "stedb.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -36256,7 +36071,6 @@ { "name": "bikehistory.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bizstarter.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "blackmonday.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "blarg.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "blogexpert.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bloodyexcellent.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bluesecure.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -36284,7 +36098,6 @@ { "name": "carolynjoyce.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "carteirasedistintivos.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cartelcircuit.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "cartertonscouts.org.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "catveteran.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "centrolavoro.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "centurionunderground.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -37082,11 +36895,9 @@ { "name": "iczc.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "iea-annex61.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "illsley.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "imageination.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ims-sargans.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "inixal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "inkvisual.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "isfriday.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "isotope.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "isz.no", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "it-jobbank.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -37134,7 +36945,6 @@ { "name": "larondinedisinfestazione.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lasuzefc.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "laviedalex.ovh", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "lbc.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "legumefederation.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "legumeinfo.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lemni.top", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -37194,7 +37004,6 @@ { "name": "ntx360grad-fallakte.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "numarasorgulama.tel", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "o-loska.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "oaksbloom.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ocenovani-inspekce.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "okib.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "omegahosting.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -37202,7 +37011,6 @@ { "name": "onepopstore.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "opencircuit.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "optimal-e.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "optimisedlabs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "pabloarteaga.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "pabloarteaga.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "pabloarteaga.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -37339,7 +37147,6 @@ { "name": "waltellis.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "waterleeftinbeek.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "waterschaplimburg.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "wdodelta.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "wearedisneyland.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "webartex.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "websiterent.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -37779,7 +37586,6 @@ { "name": "robotattack.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "rockthebabybump.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "rubenkruisselbrink.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "rybox.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "safeinfra.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "safesecret.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "sana-store.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -37933,7 +37739,6 @@ { "name": "abstractbarista.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "aceanswering.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "acroso.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "actom.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "adhd-inattentive.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "admin-forms.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "adminwerk.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -37962,7 +37767,6 @@ { "name": "alpinechaletrental.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "altaplana.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "alwaysonssl.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "amaderelectronics.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "amalficoastchauffeur.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "amalfitabula.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "amauf.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -38072,7 +37876,6 @@ { "name": "baptistedeleris.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "barabrume.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "barryswebdesign.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "bayz.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bbnbb.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bbswin9.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bcdonadio.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -38315,7 +38118,6 @@ { "name": "deltaonlineguards.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "deparis.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "depedtayo.ph", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "desuperheroes.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "devagency.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dewaard.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dicio.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -38449,7 +38251,6 @@ { "name": "euvo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "eva-select.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "evailoil.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "evamira.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "event64.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "everydaywp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "evilsite.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -38744,7 +38545,6 @@ { "name": "klseet.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kocherev.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kochereva.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "kochhar.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kogcoder.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "koka-shop.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "koninkrijk.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -38961,7 +38761,6 @@ { "name": "neoeliteconsulting.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "neonataleducationalresources.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "neonatalgoldenhours.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "nepageeks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "nepremicninar.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "nepremicnine.click", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "nepremicnine.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -39256,7 +39055,6 @@ { "name": "sorenam.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "soruly.moe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "spaconnection.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "spaldingwall.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "spanyolul.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "sparendirekt.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "sparprofi.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -39690,7 +39488,6 @@ { "name": "campamentos.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cangelloplasticsurgery.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cardboard.cx", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "casinobonuscodes.online", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "catchers.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "catfooddispensersreviews.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "catherinesarasin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -39828,7 +39625,6 @@ { "name": "euro-servers.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "eurofrank.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "europeanpreppers.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "evamachkova.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "evenementenhoekvanholland.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "examsmate.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "expoort.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -39949,7 +39745,6 @@ { "name": "ip-tanz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "isakssons.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "itaiferber.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "jak-na-les.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jalogisch.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jamberry.com.mx", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jazzfeet.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -40135,7 +39930,6 @@ { "name": "pirateproxy.sh", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "planetromeo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "planformation.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "plotbubble.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "plural.cafe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "pm.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "pn.id.lv", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -40293,13 +40087,11 @@ { "name": "suisui.stream", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "suitesapp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "supernaut.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "sxistolithos.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "symfora-meander.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "syncflare.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "syslogic.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tabarnak.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tabitatsu.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "talenthub.co.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tamersunion.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tangerine.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tanyanama.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -40307,7 +40099,6 @@ { "name": "technicalbrothers.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "techwithcromulent.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tecnicoelettrodomestici.roma.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "tecnogazzetta.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "temnacepel.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ten-cafe.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "terabyte.services", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -40351,7 +40142,6 @@ { "name": "tycom.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ugx-mods.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "uiberlay.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "unapolegetic.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "unblocked.sh", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "underfloorheating-uk.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "unitedkingdoms-guild.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -40761,7 +40551,6 @@ { "name": "imyz.tw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "indiraactive.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "infosec-handbook.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "injapan.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "inlabo.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "insureon.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "inup.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -40987,7 +40776,6 @@ { "name": "programlama.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "projektarbeit-projektplanung.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "proprietairesmaisons.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "pxio.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "pycrc.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "quantolytic.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "quizl.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -41361,7 +41149,6 @@ { "name": "cldfile.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "clicandfioul.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cliniquecomplementaire.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "cloaked.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cloudfiles.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cmftech.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cna-aiic.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -42328,7 +42115,6 @@ { "name": "aisi316l.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "albanboye.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "alco-united.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "aldred.cloud", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "allontanamentovolatili.milano.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "allstakesupply.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "alphaetomega3d.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -42415,8 +42201,6 @@ { "name": "elnoorandelmohanad.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "emaging-productions.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "escort-fashion.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "ethantskinner.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "etskinner.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "eurotravelstar.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "evidentiasoftware.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "evodia-spirits.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -42636,7 +42420,6 @@ { "name": "touhouwiki.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "transbike.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "transfers.mx", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "tsukeawase.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tulenceria.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "uclip.club", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "uktw.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -42655,7 +42438,6 @@ { "name": "voidcore.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "votesandymurman.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "wealthformyhealth.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "webstijlen.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "welovecatsandkittens.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "wentu.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "wesoco.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -42820,7 +42602,6 @@ { "name": "buildmorebuslanes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "c12discountonline.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "c3.pm", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "calluna.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "camshowhub.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "captainsinn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cartouche-deal.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -43014,7 +42795,6 @@ { "name": "inquant.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "intasky.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "intasky.sk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "invitacionesytarjetas.gratis", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ionote.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "iphonekaitori.tokyo", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ipo-times.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -43070,7 +42850,6 @@ { "name": "learning-id.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "leastsignificantbit.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "legaillart.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "lelambiental.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lemondenumerique.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lequerceagriturismo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "linext.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -43615,7 +43394,6 @@ { "name": "ewaipiotr.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ewtl.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "exceptionalbits.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "exocen.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "extintormadrid.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "faraonplay7.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "faraonplay8.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -44080,7 +43858,6 @@ { "name": "webwinkelexploitatie.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "weekendinitaly.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "weitergedacht.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "wepay.vn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "westcoastaggregate.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "wft-portfolio.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "whateveraspidercan.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -44197,7 +43974,6 @@ { "name": "dinocarrozzeria.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "disinfestazioni.treviso.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "disinfestazionivespe.milano.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "dolt.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dsuinnovation.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ecobergerie.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ecos.srl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -44518,7 +44294,6 @@ { "name": "kobejet.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kooliveeb.ee", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kovehitus.ee", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "ladraiglaan.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lalajj.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lederer-it.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "libricks.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -44715,7 +44490,6 @@ { "name": "barpodsosnami.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "basementfinishingohio.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "batch.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "betterweb.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bezr.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "biehlsoft.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bifrost.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -44870,7 +44644,6 @@ { "name": "falling.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ferienhausprovence.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ferm-rotterdam.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "ffh.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "fileon.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "filmesonline.online", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "fiskestang.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -46229,7 +46002,6 @@ { "name": "boattrader.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bonami.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bordadoenpedreria.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "brand-foo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "brand-foo.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "brand-foo.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bsee.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -46612,7 +46384,6 @@ { "name": "mekesh.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mekesh.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mekesh.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "melissameuwszen.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "messagevortex.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "messagevortex.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "meta-word.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -46820,7 +46591,6 @@ { "name": "safaritenten.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "samhuri.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "samwrigley.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "sandrocorapi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "satoshinumbers.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "scaarus.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "scalacollege.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -46895,7 +46665,6 @@ { "name": "thalia.nu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "thebonerking.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "theimagefile.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "thetree.ro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "thewaxhouse.shop", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "thuybich.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tiantangbt.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -46961,7 +46730,6 @@ { "name": "wijzijnwolf.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "winddan.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "windowslatest.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "winepress.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "wingify.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "wire.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "wonderfuleducation.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -47635,7 +47403,6 @@ { "name": "retronet.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "returnpath.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "reussir-ma-fete.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "revirt.global", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "rmm-i.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "root.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "royalasianescorts.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -47714,7 +47481,6 @@ { "name": "tdpblog.site", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "technicalsystemsprocessing.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "techsys.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "teknolit.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "terranova-nutrition.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "testdomain.ovh", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "texasparkinglotstriping.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -48006,7 +47772,6 @@ { "name": "kockanakocko.si", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "la-kaz-a-velo.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lacaserita.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "lacoquette.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lamikvah.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "landchecker.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lanforalla.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -48064,7 +47829,6 @@ { "name": "nshipster.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "numerologist.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "nuwaterglobal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "oanalista.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ocdadmin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "oirealtor.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "onepointsafeband.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -48305,7 +48069,6 @@ { "name": "bitfence.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "blackhat.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "blending.kr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "blockchainwhiz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bobaly.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bowdens.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "brettw.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -48331,7 +48094,6 @@ { "name": "casadellecose.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cbd.casa", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cbdmarket.space", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "centralmarket.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cherry-green.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "childrens-room.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "christec.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -48363,13 +48125,11 @@ { "name": "csu.st", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ctl.email", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "customfitbymj.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "cutimbo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cwinfo.fi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cyberpubonline.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "danielpeukert.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "danmassarano.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "darinjohnson.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "davidundetiwan.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dccommunity.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ddholdingservices.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "debarrasantony.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -48492,7 +48252,6 @@ { "name": "grozter.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "gruppoipl.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "hackettrecipes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "hackzogtum-coburg.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "harekaze.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "harry-baker.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "havenstrategies.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -48595,7 +48354,6 @@ { "name": "l33te.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lachlan-harris.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lancashirecca.org.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "latiendauno.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "laufers.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lauraenvoyage.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lawyerkf.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -48670,7 +48428,6 @@ { "name": "mobiproj.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "moderncoinmart.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "modosaude.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "momjoyas.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "monlabs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mono.cafe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "morgner.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -48711,9 +48468,7 @@ { "name": "nansa.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "narardetval.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "nature-shots.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "natureword.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ncdc.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "neocoding.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "nerdbox.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "net-share.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "netfuture.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -48933,7 +48688,6 @@ { "name": "uniojeda.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "upsettunnel.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "usadba.net.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "user-re.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "vagrantbits.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "valiant.finance", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "valleyautoloan.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -49094,7 +48848,6 @@ { "name": "cyberexplained.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "damghaem.ir", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "danielgorr.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "danielt.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "danslan.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "degosoft.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "digital1world.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -49991,8 +49744,6 @@ { "name": "loigiai.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "loihay.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "loli.tube", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "loyaltyondemand.club", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "loyaltyondemand.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lsmpx.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lucasbergen.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "luke6887.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -50091,7 +49842,6 @@ { "name": "nechiactua.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "neffat.si", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "neos.co.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "neotist.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "netsec.cloud", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "network-midlands.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "network-midlands.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -50428,7 +50178,6 @@ { "name": "theworldexchange.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "thisisgrey.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "thisisthefinalact.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "thomasduerlund.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "thomasmerritt.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "thoroughbreddiesel.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "threit.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -50613,7 +50362,6 @@ { "name": "amati.solutions", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "amend-friseur-schwabing.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "americandetour.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "amitabhsirkiclasses.org.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "amiu.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "animeinsights.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "antiekboerderijgraafland.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -50641,7 +50389,6 @@ { "name": "bcs.adv.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "beacham.online", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "beeming.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "beerly.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bemindly.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ben-jarvis.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "benedikt-tuchen.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -50801,7 +50548,6 @@ { "name": "huonit.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "hyperstack.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "iaf.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "iam.lc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ibodyiq.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "idealimplant.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "idratherbequilting.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -50820,7 +50566,6 @@ { "name": "integratedintegrations.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "iposm.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "irandp.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "isitpatchtuesday.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "it-seems-to.work", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "itruth.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "iuyos.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -50854,7 +50599,6 @@ { "name": "krazyboi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "krey.is", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "krishnenduayur.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "kuro.link", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kvantel.no", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kwiknews.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lappari.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -51086,7 +50830,6 @@ { "name": "stromzivota.sk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "studiobergaminloja.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "suited21.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "sunset.im", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "sunsong.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "surasak.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "surefit-oms.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -51317,7 +51060,6 @@ { "name": "dota2huds.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dowell.media", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dreamersgiftshopec.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "dressify.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dressify.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "drgdrp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "druckerei-huesgen.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -51860,7 +51602,6 @@ { "name": "evilbunnyfufu.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "exitooutdoor.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "expertviolinteacher.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "facepainting.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "faelix.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "fahnen-fanwelt.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "fameus.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -51938,7 +51679,6 @@ { "name": "hirakatakoyou.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "hirevo.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "hisgifts.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "hlin.cloud", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "home-insurance-quotes.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "hotelpostaorvieto.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "howtoteachviolin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -51960,7 +51700,6 @@ { "name": "ihakkitekin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ilookz.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "industriafranchini.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "infinitomaisum.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "infomir.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "infuzeit.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "inglebycakes.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -52428,7 +52167,6 @@ { "name": "tannerwilliamson.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tar-mag.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tccmb.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "techamigo.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tellyourtale.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "teriyakisecret.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "terminsrakning.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -52466,7 +52204,6 @@ { "name": "trendus.no", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "trilliumvacationrentals.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "trouble-free-employees.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "trueproxy.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tsgkc1.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tuasaude.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "turf-experts.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -52823,7 +52560,6 @@ { "name": "dorpshuis-dwarsgracht.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dr-it.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "drump-truck.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "drwang.group", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dschwarzachtaler.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dsgnet.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dubious-website.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -53054,7 +52790,6 @@ { "name": "lng-17.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lohl1kohl.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "looseleafsecurity.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "lord.sh", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "louisemisellinteriors.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "loveamber.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lovevape.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -53168,7 +52903,6 @@ { "name": "openroademail.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "oriondynamic.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "orocojuco.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "otmo7.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "otoblok.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "otokiralama.name.tr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "out-of-scope.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -53282,8 +53016,6 @@ { "name": "savingsoftheyear.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "schgroup.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "schoeller.click", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "scholar.group", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "scholar.site", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "scholledev.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "seachef.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "secpoc.online", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -53573,7 +53305,6 @@ { "name": "cpe-colleg.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cplala.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "craftsmany.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "createcos.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "creditta.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cstrong.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cxadd.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -53897,7 +53628,6 @@ { "name": "thevenueofhollywood.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "thrillernyc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tiekoetter.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "tilman.ninja", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "toontown.team", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "topdroneusa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "topgshop.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -53930,7 +53660,6 @@ { "name": "vlakem.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "vos-systems.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "vtuber.art", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "webutils.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "weems.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "whirlpool.net.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "whiskygentle.men", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -54484,7 +54213,6 @@ { "name": "annunciationbvmchurch.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "anoncrypto.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "apkmod.id", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "appelaprojets.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "aranchhomes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "architectureandgovernance.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "arizonahomeownerinsurance.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -54510,7 +54238,6 @@ { "name": "awningcanopyus.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "baazee.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ball-bizarr.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "bangridho.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "banjostringiz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "barbarabowersrealty.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "barbiere.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -54570,7 +54297,6 @@ { "name": "calenfil.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "canal-onanismo.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "candguchocolat.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "candidaturedunprix.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "capitalfps.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "capsulesubs.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "carburetorcycleoi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -54603,7 +54329,6 @@ { "name": "cl0ud.space", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "clayprints.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cleanfiles.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "click4web.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "clippings.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cloudchart.site", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cmgacheatcontrol.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -54799,7 +54524,6 @@ { "name": "form3w.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "formsbyair.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "fossforward.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "francescopandolfibalbi.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "francoisbelangerboisclair.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "frasesconemocion.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "freemanlogistics.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -54980,7 +54704,6 @@ { "name": "libre.cr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lifeenrichmentnc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lifelenz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "lifereset.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "linchpin-it.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lincolnpedsgroup.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lindaolsson.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -55126,7 +54849,6 @@ { "name": "phpower.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "pierrickdeniel.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "pinetopazrealestate.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "plateformecandidature.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "playcollect.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "poc88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "pogetback.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -55135,7 +54857,6 @@ { "name": "pooltools.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "poorclarepa.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "pornovk.xxx", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "poterepersonale.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "precisionventures.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "presentationmedia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "preserveourhillcountry.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -55368,7 +55089,6 @@ { "name": "thestandingroomrestaurant.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "thetinylife.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "thevalueofarchitecture.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "think-pink.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "this-server-will-be-the-death-of-me.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "thomas-schmittner.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "timewk.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -55506,7 +55226,6 @@ { "name": "zydronium.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "10414.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "1527web.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "159cp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "1cswd.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "1way.faith", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "222001.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -55650,7 +55369,6 @@ { "name": "avtomarket.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "awarify.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "awarify.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "axon-toumpa.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "axre.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "azane.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "azarus.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -56024,8 +55742,6 @@ { "name": "findyourtrainer.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "fionafuchs.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "fisinfomanagerdr.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "fj.je", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "fjdekermadec.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "fjzone.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "fleesty.dynv6.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "floify.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -56264,7 +55980,6 @@ { "name": "kermadec.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kevin-ta.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kgv-schlauroth.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "kiisu.club", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kinderpneumologie.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kinerd.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kinesiomed-cryosauna.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -56764,7 +56479,6 @@ { "name": "section77.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "securist.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "secvault.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "sedomicilier.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "seedcoworking.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "segnidisegni.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "sekikawa.biz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -57016,7 +56730,6 @@ { "name": "videojuegos.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "videosparatodos.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "vikaviktoria.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "viktorbarzin.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "vim.cx", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "vinigas.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "vitalium-therme.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -57318,7 +57031,6 @@ { "name": "mrhookupsd.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mteleport.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mullerimoveisrj.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "musikholics.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "myduffyfamily.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "nakladki.su", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "natureclaim.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -57667,7 +57379,6 @@ { "name": "ctr.id", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cyberlegal.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dailyroverr.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "danieln.tech", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "danielparker.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "darkestproductions.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "datahive360.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -57698,7 +57409,6 @@ { "name": "dodomu.ddns.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "donnajeanbooks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "doorswest.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "dophys.top", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dox-box.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dragon.nu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "draintechnorthwest.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -57764,7 +57474,6 @@ { "name": "gekosoft.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "georgiatransport.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "gettodoing.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "giftya.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "glamouria.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "goldenmonrepos.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "gomel.chat", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -57873,7 +57582,6 @@ { "name": "klemkow.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "klemkow.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "klinik-fuer-aesthetische-zahnheilkunde.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "knowyourday.ai", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kongsecuritydata.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kos4all.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kosherjava.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -57890,7 +57598,6 @@ { "name": "lancelhoff.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lancemanion.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "latinmusicrecords.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "leaf-consulting.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lehmitz-weinstuben.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "leibniz-gymnasium-altdorf.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lequest.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -58015,7 +57722,6 @@ { "name": "preme.name", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "pretor.com.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "pretor.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "pretor.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "pretorcup.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "primananda.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "proformer.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -58402,7 +58108,6 @@ { "name": "adtelligent.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "advaithbot.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "advenacs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "aegis.moe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "aenterprise.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "aeonct.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "aff.moe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -58508,7 +58213,6 @@ { "name": "bootsschule-weiss.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "boreo.si", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "boysontech.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "bps.vc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "breakwall.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "brightside.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "britanniacateringyeovil.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -58765,7 +58469,6 @@ { "name": "flibusta.appspot.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "fmstr.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "followmystaff.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "fono.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "forbidden-mods.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ford.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ford.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -58801,7 +58504,6 @@ { "name": "gehrke.cloud", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "general-plast.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "geniofinanciero.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "gesnex.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "gfedating.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ghost-legion.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "givingtools.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -58817,7 +58519,6 @@ { "name": "gostargazing.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "goufaan.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "graandco.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "grenlandkiropraktor.no", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "grupodatco.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "gtn-pravda.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "gyakori.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -59095,13 +58796,11 @@ { "name": "meuble-house.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mexicodental.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mgiljum.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "mi92.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mibh.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "micelius.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "michaell.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "michaell.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "michaelloveys.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "micromookie.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "micsell.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mihgroup.eu.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mihgroup.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -59175,7 +58874,6 @@ { "name": "nosuch.blog", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "nosuch.site", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "nosuch.website", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "noteshare.online", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "nourishandnestle.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "nowitzki.network", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "npbeta.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -59361,7 +59059,6 @@ { "name": "selectionengine.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "send4x.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "seomik.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "seotools.asia", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "seowebexpert.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "seriousaboutsecurity.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "servicerequesthub.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -59516,7 +59213,6 @@ { "name": "ufo-blogger.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ultramookie.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "umzuege-berlin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "umzug-berlin24.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "unik.bg", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "united-german-commander.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "uoone.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -59802,7 +59498,6 @@ { "name": "inoxmavang.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "isaropiping.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jabba.homelinux.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "joeseago.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jonas.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jxkangyifu.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jz585.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -59863,7 +59558,6 @@ { "name": "nyoliveoil.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "oaktonhouseandgardens.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "omenprinting.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "orangesquash.org.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ordekho.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "organicskincare.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "oximo.lviv.ua", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -59901,7 +59595,6 @@ { "name": "scottmay.id.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "secure-computing.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "securefiletransfer.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "securemy.website", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "securityrussia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "seminariruumid.ee", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "server92.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -60115,7 +59808,6 @@ { "name": "hyyen.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ifreetion.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ingridbai.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "injurylawyer.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "inspiredlife.fun", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "instant-clearance-sale.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "interessengemeinschaft-pregelstrasse.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -60134,7 +59826,6 @@ { "name": "kinkyhookup.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kirkwoodfence.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kooxdiving.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "kopplin.family", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kosinc.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kozawa.tokyo", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kscarlett.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -60421,7 +60112,6 @@ { "name": "dickord.cloud", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dictionarypro.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "directoriostelefonicos.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "donetsk24.su", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dotesports.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dpsg-hohenlinden.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "drros.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -60606,7 +60296,6 @@ { "name": "rvsuitlaatdelen.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "sabbottlabs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "safungerar.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "scevity.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "searchpartners.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "securevideo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "seemomclick.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -60818,7 +60507,6 @@ { "name": "ekpj.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "elitepaintingsa.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "elon-musk.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "emergeandsee.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "energysolutionstech.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "esu.wiki", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "etnoria.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -61092,7 +60780,6 @@ { "name": "achat-volets-roulants.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "addistribution.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "agenciamseo.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "ak47-miyamoto.spdns.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "alabordage.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "alfredapp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "altijdleroy.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -61101,7 +60788,6 @@ { "name": "anarajaoui.ma", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "aoe9.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "aptumseguros.mx", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "arabhardware.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "arcobalabs.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "artacadia.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "asemanhotel.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -61243,7 +60929,6 @@ { "name": "ibericarcuzcomini.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ijinus.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "imaginationpathway.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "impossible.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "impossible.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "impossiblefitness.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "impossiblehq.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -61422,7 +61107,6 @@ { "name": "traha.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tulsaworkshop.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tupass.pw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "tw-hosting.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tyroremotes.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "uberactivist.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ultimatepaleoguide.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -61977,7 +61661,6 @@ { "name": "euroroad17.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "expertpanel.gc.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "exvs.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "eythorsson.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "facesdr.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "faggut.gg", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "fanzhencha.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -62300,7 +61983,6 @@ { "name": "africankitchen.gallery", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "akrep.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "albareport.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "alexlambertz.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "algebra-quiz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "allesovertech.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "alloutsec.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -62424,7 +62106,6 @@ { "name": "gunz.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "gyoza.beer", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "haju.fi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "hamikala.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "hatcher.cloud", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "hikawa.top", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "hillier-swift.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -62466,7 +62147,6 @@ { "name": "kulinaristi.fi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kysil.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "l0v0l.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "lambertz.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lapatio.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "laurineprice.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lawabidingcactus.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -62557,7 +62237,6 @@ { "name": "realgear.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "rebelko.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "redgravity.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "rentaways.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "residentialmortgageholdings.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ribtours.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "rizonrice.club", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -62776,7 +62455,6 @@ { "name": "iondrey.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "itpanda.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ix.mk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "jackflet.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jackfletcher.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jerseyplantsdirect.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jesusvazquez.online", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -62804,7 +62482,6 @@ { "name": "llandudnochristmasfayre.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "locksmith--sanantoniotx.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lohmeyer-it.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "losmedicamentos.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lowcost.to", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lrumeq.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lsh1688.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -62939,7 +62616,6 @@ { "name": "videoseriesbiblicas.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "vikramkulkarni.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "vqcymsa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "vuldb.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "vvild.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "wasteman.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "whitevpn.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -63032,7 +62708,6 @@ { "name": "clite.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "clubmarina.store", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "codemahrt.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "colantonio.homelinux.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "colectivos.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "commercia.srl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "communitychurchafrica.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -63057,7 +62732,6 @@ { "name": "determapp.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dhelixnet.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "die-pleners.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "direct.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "directscripts.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "distraction.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dmoj.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -63528,7 +63202,6 @@ { "name": "hq77.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "huoyankan.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ibb.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "ieji.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "img.com.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "impactplumbingdrainage.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "indiapur.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -63637,7 +63310,6 @@ { "name": "powerwashingproslosangeles.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "premsarswat.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "privc.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "quieroserdoula.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "quieroserdoula.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "quranliveonline.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ramsdensforcash.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -64256,7 +63928,6 @@ { "name": "ip-address.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ireviewi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "irvingramo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "is-rocket.science", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "isaaccomputerscience.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "isovideo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "israel-in-color.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -64396,7 +64067,6 @@ { "name": "mimavision.ddns.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "minandolacorrupcion.mx", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mio-ip.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "miroctum.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mmprojects.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mobizma.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "moduloseltaladro.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -64480,7 +64150,6 @@ { "name": "orgyporngroup.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "osteendiner.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ota365.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "otomobilforumu.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "outfunnel.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "outinjersey.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ouxiang.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -65090,7 +64759,6 @@ { "name": "icetravellers.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "iglosujemy.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ihearmedical.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "ihempz.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "impresa-di-pulizie.milano.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "infohub.com.ua", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "infrafile.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -65170,7 +64838,6 @@ { "name": "nivelul2.ro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "noiglosujemy.com.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "noiglosujemy.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "novema.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "noxx.solutions", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "olitham.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "oneearthapp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -66287,7 +65954,6 @@ { "name": "aromachat.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "arttel-media.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "as8423.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "asfaleianet.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "attendanceondemand.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "auvidos.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "awesomenamegenerator.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -66342,7 +66008,6 @@ { "name": "d9397.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "d9721.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "d9728.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "datelah.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dd5197.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dd9297.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dd9397.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -66463,7 +66128,6 @@ { "name": "ibavaro.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ibi.mt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "icloud.st", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "igarage.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ii5197.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ii9297.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ii9397.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -66544,7 +66208,6 @@ { "name": "mazepa.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "medcorfu.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "medicinasaludvida.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "meeplegamers.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mehmetdursun.av.tr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "meinewolke.pw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "memmertusa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -66873,7 +66536,6 @@ { "name": "z9397.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "z9721.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "z9728.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "zacco.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "zebranolemagicien.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "zhaotongjun.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "zz5197.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -67167,7 +66829,6 @@ { "name": "linkk9.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lndrive.space", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "londonindustry.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "lorenzocompeticion.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lsiq.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "luckystorevn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "madsstorm.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -68318,7 +67979,6 @@ { "name": "n6957.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "n6957.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "n8ta.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "nattiam.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "netexpat.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "networg.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "networg.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -68449,7 +68109,6 @@ { "name": "tda602-secure-login.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tentech.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "termoidraulica.roma.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "thealchemistatelier.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "theantarticx.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "theaviationagency.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "thecr3ative.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -68457,7 +68116,6 @@ { "name": "thedailyshirts.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "themenmedia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "thetipo01.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "thewoosh.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tielecingenieria.com.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tipo01.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tldtattoo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -68503,7 +68161,6 @@ { "name": "werkenbijsherpa.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "wervingenselectieamsterdam.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "wikibuy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "workingon.tech", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "wowin58.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "wowin88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ww6729.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -68605,7 +68262,6 @@ { "name": "918sa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "a1post.bg", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "a6729.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "adamlee.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ag-2.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ag-3.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ag-55.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -68731,7 +68387,6 @@ { "name": "eons.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "eqassociates.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "erfolgsmaschine.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "eshterry.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "especialistagoogleadwords.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "espyder.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "euc.world", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -69009,7 +68664,6 @@ { "name": "2222k8.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "222k8.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "2264707.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "2isk.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "3333k8.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "36594.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "518k8.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -69074,9 +68728,7 @@ { "name": "brettpostin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "broadyexpress.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bsimyanmar.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "btt269g.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "butterflycare.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "bytheglass.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "campaignlake.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "canine-mobility.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "carefulcolor.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -69312,7 +68964,6 @@ { "name": "lysbed.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "magnumwallet.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mailbro.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "maximind.sg", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "md19lc8.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "md21lc8.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "md24lc8.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -69327,7 +68978,6 @@ { "name": "mklenterprises.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mklenterprisesacademy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mklenterprisescoaching.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "mmpaymentsystem.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "momobako.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "moosmaus.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "motorzone.od.ua", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -69441,7 +69091,6 @@ { "name": "we9988.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "webcaptive.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "webhostingspace.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "werd.pw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "win365.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "xboxachievements.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "xn--90adahrqfmec.xn--p1ai", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -69743,7 +69392,6 @@ { "name": "osterlensyd.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "pandiora.pw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "pcr24.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "pixelabs.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "planet.live", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "popitsnack.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "proctorauth.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -69864,7 +69512,6 @@ { "name": "aktca.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "alchemy.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "allcarespecialty.pharmacy", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "allied.sh", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "alpharail.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "amsfoodhk.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "anora.ai", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -69901,7 +69548,6 @@ { "name": "byraje.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "caetanoflotas.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cafedelahalle.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "carbonating.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "casino-cash-flow.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "casino-cash-flow.com.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "casino-cash-flow.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -69910,7 +69556,6 @@ { "name": "casinocashflow.pro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "casinocashflow.su", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "casinocashflow.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "cdireland.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "centumail.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "chataberan.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "chaturbate.com.tw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -70027,7 +69672,6 @@ { "name": "kk575757.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "konfekcjonowanie.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "koreanrandom.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "kusadasiforum.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "labworks.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lelux.fi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "leminhduong.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -70042,7 +69686,6 @@ { "name": "londontaxipr.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "luctam.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lueersen.homedns.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "luu.moe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lxx77.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "m23cal.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "magestionfinanciere.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -70111,8 +69754,6 @@ { "name": "photolessya.by", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "pirateproxy.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "piucellulare.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "planetofwoman.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "planetofwomen.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "plu-pro.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "plusmobile.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "pointclickcare.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -70184,7 +69825,6 @@ { "name": "toolshero.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "top2servers.tv", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "topreit.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "trianglebruins.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "trutopoffer.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "twin-tails.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tytod.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -70438,11 +70078,9 @@ { "name": "kennethandersen.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "khohangmadeinvietnam.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kiomara.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "kirklandtriallawyer.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kleinhelena.dynv6.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kmnsk.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kotonozaka.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "ks0816.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "labavn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "labibikids.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "landassessmentservices.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -70522,11 +70160,9 @@ { "name": "ocnjapartment.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "okasurfbali.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "oliverah.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "orebolt.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "orged.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ostechnix.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "otoma.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "oxygenit.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "pactandoconlamoda.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "panoramichq.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "patriciaandpaul.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -70587,7 +70223,6 @@ { "name": "sagenesykkel.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "sainikbiswas.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "salesblackbelt.coach", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "saluddecalidad.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "sam-cousins.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "sampleappservice.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "sduconnect.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -70641,7 +70276,6 @@ { "name": "testmx.email", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "testmx.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "testmx.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "tetr.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "textonly.email", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "thailandlongtime.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "thaqfni.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -70842,7 +70476,6 @@ { "name": "588e.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "58w66.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "62222.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "8102d88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "88btt.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "91milk.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "a2os.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -70900,8 +70533,6 @@ { "name": "cadastroloteamento.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "calendriergn.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "careerdirectionsltd.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "cheapsharedhost.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "cheapsharedhost.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "chicourologist.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "childrensfurniture.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "chrisseoguy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -71193,7 +70824,6 @@ { "name": "tytocare.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "uboratz.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "uix.biz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "ultrasdesign.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "un-instantpoursoi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "unicorndesign.ninja", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "universal-village.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -71212,12 +70842,10 @@ { "name": "vinmmo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "voevm.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "volvoconnect.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "w4040w.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "wallisch.pro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "wearefrantic.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "websiteboost.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "websitesmiths.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "webx5.pro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "weecarepreschool.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "weightlossoutcome.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "wormhol.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -71350,7 +70978,6 @@ { "name": "9k686.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "9k689.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "9k692.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "9k698.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "9k823.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "9k826.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "9k833.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -71425,7 +71052,6 @@ { "name": "ccriderlosangeles.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "centrederessourcement.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "chifumi.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "clubapk.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "coachapp-ipass.herokuapp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "coachsystem.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "combigo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -72395,11 +72021,6 @@ { "name": "906vv.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "90920.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "90n13.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "918aav.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "918aff.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "918bip.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "918bis.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "918bit.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "918nn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "91d91.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "940365.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -72756,15 +72377,6 @@ { "name": "brusselsexpoloft.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "brusselsexpostudio.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bryanarmijomd.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "btt0101.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "btt0505.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "btt0606.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "btt11.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "btt583g.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "btt7878.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "btt829.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "btt830g.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "btt889g.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "btta16.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "buddy-acceptance-authentication-api.azurewebsites.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "buddy-acceptance-profiles-api.azurewebsites.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -72952,7 +72564,6 @@ { "name": "deionized.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "delcan.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "delcan.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "dellacasapizzasemassas.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dementieva-pennetta.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "demicrofonos.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "demirdokum.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -73378,9 +72989,7 @@ { "name": "jose-latino.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "joseenriquegonzalez.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "josefernandomorilloardila.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "journeyfitness.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jovenescontraelaburrimiento.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "jqk918.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jsidefox.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "julia-clarete.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jungyonghwa.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -73438,8 +73047,6 @@ { "name": "kresimir-blazevic.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kryptologie.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ks023.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "ks0566.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "ks0668.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ks257.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ks318.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ks641.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -73728,7 +73335,6 @@ { "name": "olivejs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ollo.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "omretreats.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "one-news.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "onlineautodealered.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ooo-santal.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "operanavigation.ro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -74050,7 +73656,6 @@ { "name": "skante.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "skateswagger.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "skirts.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "sky-live.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "slipknot-site.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "smartcover.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "smartleads.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -74182,7 +73787,6 @@ { "name": "thaihotmodels.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "thaiportal.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "the51news.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "theandroidsoul.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "thebacteriafight.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "thebestlaos.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "thecarpenters.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -74577,7 +74181,6 @@ { "name": "1lc22.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "1lc55.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "1vpns.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "2000meter.no", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "2018j95.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "2019j95.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "2020j95.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -75199,7 +74802,6 @@ { "name": "justquoteme.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jvlfinance.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jwimps.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "jysk-kornteknik.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kadvi.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kalamos.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kaliboairport.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -76709,7 +76311,6 @@ { "name": "maneql.co.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "maneql.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "marcus.pw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "martin-renze.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "masarn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mbadika.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mdihi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -76857,7 +76458,6 @@ { "name": "undeadpirates.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "unitedmatrix.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "universal-tutorial.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "unlocktechs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "unternehmensbewertung.pro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "upgradedpoints.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "v800d.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -77087,7 +76687,6 @@ { "name": "instawierszyki.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "internetloansdirect.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "iqskinclinics.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "irgendeine.cloud", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "issaias.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "it-journal.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "j81818.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -77141,7 +76740,6 @@ { "name": "mitratech.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mjniessen.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mkpdeepclean.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "mlxysf.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mokhan.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "monkatos.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "monodejuegos.shop", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -77268,7 +76866,6 @@ { "name": "t5880.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "t81818.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "temperandtantrum.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "termbackti.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "terra-24.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "thealonas.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "thealonas.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -77335,7 +76932,6 @@ { "name": "yourpocketbook.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "yspa.tv", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "zeilenwind.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "zenideen.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "zeta.hk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "zgndh.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "zhendre.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -77629,7 +77225,6 @@ { "name": "sam88.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "sanketsu.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "scapdoors.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "scheinerhaus.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "seaborn.top", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "securelogin.nu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "seminariosvip.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -77679,7 +77274,6 @@ { "name": "tube8.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "twobitbusker.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tyc001.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "unifestal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "uppercap.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "vaisselle-nature.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "vandijkmaatwerk.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -77907,7 +77501,6 @@ { "name": "lonelypawn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "loverngifts.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lz898.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "m6pub.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "machinerysafety101.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "magicnethosting.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "magicvps.md", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -78013,7 +77606,6 @@ { "name": "spectrum-markets.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "srfloki.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "srkb.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "stainhaufen.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "summusglobal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "suniru.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "sunnistan.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -78074,7 +77666,6 @@ { "name": "wirkungs-forschung.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "wjg.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "wordops.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "woxter.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "wsv-pfeffingen.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ww8989.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "wwin818.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -78087,7 +77678,6 @@ { "name": "xn--nidar-tib.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "xn--prfontaine-c7a.name", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "xuehao.net.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "yaseminuzumcu.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "yesh.lk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "yesildiyetisyen.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "yuleyule88game.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -78104,7 +77694,6 @@ { "name": "1lc44.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "220control.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "33weishang.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "369018.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "50milli.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "5eki.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "690938.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -78233,7 +77822,6 @@ { "name": "goodfor.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "granli.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "gregmarziomedia-dev.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "griswoldwellwaterct.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "gujun-sky.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "haitou.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "harley-davidson-live.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -78249,8 +77837,6 @@ { "name": "highclasseducation.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "holacannx.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "holacbdoils.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "holenergies.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "holenergies.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "hongbomiao.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "howmanypeoplearethereinthe.world", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "howmanypeoplearethereintheworld.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -78380,7 +77966,6 @@ { "name": "s2i.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "salvameuba.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "salvandoalocombia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "sanix.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "secureenduserconnection.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "sevipro.mx", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "shakthifacility.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -78793,7 +78378,6 @@ { "name": "z6.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "znn.co.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "0x15.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "131ks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "162229.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "22i.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "27is.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -78804,7 +78388,6 @@ { "name": "52062n.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "52062o.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "52062s.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "8869ks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "88djl.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "9118inc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "aanwp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -78813,8 +78396,6 @@ { "name": "acneintelligence.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "acunetix.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "agencyalacarte.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "agks89.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "agks998.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "airconrandburg.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "aljaspod.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "alpharoofga.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -78848,7 +78429,6 @@ { "name": "brojagraphics.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bumble.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "campo-salado.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "carbonvision.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "caycehouse.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cbnainital.org.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ccli.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -78923,7 +78503,6 @@ { "name": "honeymaze.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ictindia.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "incomeproshoutr.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "irequi.re", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "itsallaboutplumbing.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "itschromeos.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jakse.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -78942,9 +78521,6 @@ { "name": "knowledgebuilds.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kroyclothing.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "krupacars.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "ks0558.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "ks0660.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "ks597.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ks89.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kstr.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lacochinacounselor.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -79072,7 +78648,6 @@ { "name": "unblocked.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "unitedfitness.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "upliving.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "urb-budex.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "vangore.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ventadecolchones.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "veryswing.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -79082,7 +78657,6 @@ { "name": "vuelacaruru.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "walkingandcycling.org.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "warthog.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "wegiel24.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "wellandslim.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "weloveliving.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "wemajin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -79104,7 +78678,6 @@ { "name": "ywyz.tech", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "zd739.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "zone-de-confiance.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "zorgenvoorandrea.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "zoubaa.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "0cd.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "123666365.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -79185,7 +78758,6 @@ { "name": "callmewhatever.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cameramark.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "canhas.report", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "cardozovargas.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cardozovargas.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "casashmodel.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ceramiche.roma.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -79211,7 +78783,6 @@ { "name": "cubesugar.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cuckoo.ee", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cursosgratuitos.pe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "cybertrash.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "d1qvlbepn0kduz.cloudfront.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dal.net.sa", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dating.wedding", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -79303,7 +78874,6 @@ { "name": "johannfritsche.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jyk.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "karawanken-tunnel.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "karolak.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "katapult.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "keestalkstech.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kingfast.eu.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -79584,7 +79154,6 @@ { "name": "beeksnetwork.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "beeremovalspretoria.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "beestation13.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "berndklaus.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bestcivilattorneys.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bestroofbox.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "betmobilenigeria.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -79671,7 +79240,6 @@ { "name": "flightright.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "flightright.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "flightright.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "foair.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "fojing.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "fraufries.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "freedomtoolkit.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -79707,7 +79275,6 @@ { "name": "harrisonm.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "hendranicholas.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "hl8id.vip", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "hl8th.vip", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "hosteons.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "hotelmonal.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "hvenetworks.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -79842,7 +79409,6 @@ { "name": "odesenvolvedor.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ohmy.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ohoreviews.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "ojojz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "on9.link", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ondeapostar.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "one6688.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -80298,7 +79864,6 @@ { "name": "b67803.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "b67804.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "b67805.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "b70881.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "b70883.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "b70884.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "b70885.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -80410,7 +79975,6 @@ { "name": "creaintel.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "crownsterling.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "curanderosantiago.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "cvdc.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "danskefilm.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dartydiscount.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dc-acupuncture.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -80550,7 +80114,6 @@ { "name": "linuxhilux.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "livelondon.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "livingspace.co.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "liz-fry.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lohr.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lowestpriceremovals.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lsmarketing.ie", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -80578,7 +80141,6 @@ { "name": "mountbatten.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "msoll.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "msoll.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "msopopop.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "murmu.re", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "myinjuryattorney.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mythoughtmachine.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -81119,7 +80681,6 @@ { "name": "latinoramarecords.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "le-fumoir.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lesptitstutos.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "lg2.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "liborburda.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lightyear.no", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "liypoi.top", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -81443,7 +81004,6 @@ { "name": "background-checks.mobi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "backgroundchecks.online", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bairuo.top", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "bandolino-bewind.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bandolino.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "baypromoteam.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "beautyandfashionadvice.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -81495,7 +81055,6 @@ { "name": "dandan101.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "datacommissioner.gov.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "defendtheweb.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "dekel.co.il", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "delhitalkie.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "deltafinanceiro.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "deltaloja.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -81581,7 +81140,6 @@ { "name": "illange.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "inspiresurgery.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "intrixgroup.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "intrixlifestyle.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "inyr.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ipinfo.tw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "irenkuhn.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -81858,7 +81416,6 @@ { "name": "22lc8.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "234lc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "3002712.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "365yuwen.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "3dnovedades.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "4233070.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "455328.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -82076,7 +81633,6 @@ { "name": "fonamperu.org.pe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "forfeiture.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "forthewin.rocks", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "forumstandaardisatie.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "foselectro.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "fozzie.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "frankieistanbul.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -82159,10 +81715,7 @@ { "name": "k852.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "k860.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "k865.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "k865.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "k86690.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "k867.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "k867.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "k869.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "k87071.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "k87072.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -82238,7 +81791,6 @@ { "name": "kimkyzcrs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kingstake.network", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kneli.co.il", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "koladeogunleye.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kritikahotels.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "larsson-ornmark.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lc0188.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -82255,18 +81807,14 @@ { "name": "lc3746.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lc3747.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lc3748.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "lc3757.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lc3759.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lc3760.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "lc3772.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lc3774.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "lc3776.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lc3778.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lc3779.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lc3780.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lc3781.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lc3782.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "lc3783.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lc3793.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lc3794.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lc3795.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -82353,7 +81901,6 @@ { "name": "lc8md77.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lc90000.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lc9108.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "lc9256.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lc9862.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lc9899.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lc9900.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -82399,7 +81946,6 @@ { "name": "mochilerostailandia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mojizuri.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "moninformaticien.ovh", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "moninformaticien.shop", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "movahoteis.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "myebony.cam", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "myintimtoys.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -82514,7 +82060,6 @@ { "name": "tiendadolca.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "timeforcoffe.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tishopsv.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "toldositajuba.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "travelassist.us.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "trechosemilhas.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "trezor.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -82894,7 +82439,6 @@ { "name": "openbayes.blog", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "osano.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "paardenpro.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "pacificintegration.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "packetoverflow.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "panthi.lk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "parfum-selbermachen.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -83153,7 +82697,6 @@ { "name": "boundaryvets.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bracknellvets.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "brainboxai.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "breakingtech.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "brindice.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "broadwayvets.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bszoft.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -83338,8 +82881,6 @@ { "name": "josealonsodds.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "josephquinaucho.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jourdain.pro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "k88398.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "k88399.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "k88601.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "k88602.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "k88603.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -83421,7 +82962,6 @@ { "name": "myqservices.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "nachovni.pp.ua", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "naiaokami.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "nategreen.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ndx.ee", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "netferie.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "netferie.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -83466,7 +83006,6 @@ { "name": "nic.youtube", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "nic.zip", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "nihaarpstars.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "ningrui.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "nocommentsallowed.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "nordvestkysten.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "nordvestkysten.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -83486,7 +83025,6 @@ { "name": "opp.moe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ordevanoranjenassau.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ortopedistamarcelocosta.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "osteolaclusaz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "otocenterfelix.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "oxidemusic.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "p-damda.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -83553,7 +83091,6 @@ { "name": "seedboite.ovh", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "selltous.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "senshot.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "seriesdatv.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "servermaster.sk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "setuplog.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "sevilinux.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -83585,7 +83122,6 @@ { "name": "spellic.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "sportchirp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "spotworld.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "ssfbank.no", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ssmut.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "stage-recuperation-points-bordeaux.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "stage-recuperation-points-lille.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -83790,7 +83326,6 @@ { "name": "brendansbits.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "brookes.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "brutecloud.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "burotec-sarl.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "buster.me.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "buycurious.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bxegypt.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -84064,7 +83599,6 @@ { "name": "on-targettrainingcourses.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "on-this.link", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "onlineltctraining.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "op3y.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "openstakes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "opstory.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ornsyn.no", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -84339,7 +83873,6 @@ { "name": "aarwer.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "aarwer.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "abacross.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "abelrubio.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "abona24.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "aboutasia-trade.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "aboutasia.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -84368,7 +83901,6 @@ { "name": "am8028.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "am8866m.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "am8895.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "amalficoastransfers.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "amazighlove.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "amb8.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "amjinc.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -84385,7 +83917,6 @@ { "name": "arhitekti.hr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "artikel9.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "artisan-emmanuel.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "artsacademics.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "aseth.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "askexpert.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "asmrbuluo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -84762,7 +84293,6 @@ { "name": "gainins.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "gantt-chart.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "garagedoorrepaircedarhilltx.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "gentapps.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "gentlemens-life.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "gentlentapis.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "germfr.ee", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -84874,7 +84404,6 @@ { "name": "kyivstar-internet.com.ua", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "labs.ro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ladeboks.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "lambda.dance", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lamchannang.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lamnhom.com.vn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "laprensadelasagradafamilia.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -85087,7 +84616,6 @@ { "name": "tapasnandi.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tarba-schluesseldienst-duesseldorf.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tateishi-ip.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "tathanhson.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tauerperfumes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tche.digital", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "techfishnews.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -85653,7 +85181,6 @@ { "name": "metrolaut.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "miacordeonstereo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mightybit.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "mijam.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mijnkantoor.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mikedhoore.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "minibaggerverleih-aulendorf.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -86389,7 +85916,6 @@ { "name": "maxiglobal.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "meekhak.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "meldpuntemma.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "melento.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "metadedi.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "microcyber.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mijnkwadraad.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -86466,7 +85992,6 @@ { "name": "q81365.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "q82365.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "qpaypro.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "qualiacomputers.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "r81365.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "r82365.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "rainbowswingers.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -86573,7 +86098,6 @@ { "name": "valutienda.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "vectordtg.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "vegner.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "verymetal.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "vibgyorhigh.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "viceversa2013.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "videograb.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -86681,7 +86205,6 @@ { "name": "ahlstrom-filters.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "alibamu.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "alphabet-z.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "alvaiazere.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "amanduscommunication.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ambra.net.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ameeventos.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -86693,7 +86216,6 @@ { "name": "apexfacades.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "apsscientific.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "arablovepet.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "arcismant.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "arktalentsolutions.com.mx", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "arooshi.website", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "asiaflash.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -86803,14 +86325,12 @@ { "name": "dubyou.tw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "durastill-distiller.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dustpla.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "dwword.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ebooklib.club", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "echoesfromantiquity.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "edisongroup.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "edisonprint.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "edisontent.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "eikerposten.no", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "eladvardi.co.il", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "elgenero.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "eliezermarcano.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "elmarchive.ir", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -86859,8 +86379,6 @@ { "name": "gevme.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "giancarlomarino.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "go-indochine.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "go6.si", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "go6lab.si", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "goftava.ir", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "golvlyftarna.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "goolnk.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -86890,7 +86408,6 @@ { "name": "ian678.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ian678.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ibadboy.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "ibexrepair.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "imagevillage.ir", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "imaxinaria.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "imgbu.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -87112,7 +86629,6 @@ { "name": "shtaketnik-metall.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "sindlerova.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "sindlerova.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "sinog.si", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "sloanestreetdeli.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "sologoc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "sotaytienganh.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -87132,7 +86648,6 @@ { "name": "techday.asia", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "techday.network", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "techvrse.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "techzhou.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tehranlittmann.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "telegram-sms.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "teleportweb.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -87177,7 +86692,6 @@ { "name": "vl-grafikdesign.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "vrgamecritic.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "vrgametrailers.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "vveactiefbeheer.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "wa7sh-seo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "waaifu.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "wbcasaverde.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -87474,7 +86988,6 @@ { "name": "chinesemedicine.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "christianbsl.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "christianhamacher.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "cimala5bta.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "circlepluscircle.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "circumstances.ir", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ckenel.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -87652,7 +87165,6 @@ { "name": "globalizationpedia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "glpepper.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "goddard.id.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "godknowsclothing.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "gokhana.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "gordon-reid.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "gorlani.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -87691,7 +87203,6 @@ { "name": "hoorig.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "hostwinds.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "hotdates18.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "hotrowordpress.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "houselovin.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "hsimrall.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "hyundaisrilanka.lk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -87723,7 +87234,6 @@ { "name": "integrityoklahoma.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "interallied.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "interconlarp.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "internettradie.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "intracdf.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "introverted.ninja", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ionutnechita.ro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -87744,7 +87254,6 @@ { "name": "jchn.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jed.site", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jedcg.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "jellypepper.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jeremywinn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jeremywinn.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jeretec.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -87808,7 +87317,6 @@ { "name": "legion.ge", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lerefugedujambon.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lesacredescouleurs.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "leventmebel.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "levidromelist.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "libertytereconoce.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "libertywines.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -87865,7 +87373,6 @@ { "name": "minhng99.cloud", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "minimalmx.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mipasevip.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "mitsubishi-club.ge", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mix-recruit.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mkgraves.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mlstav.sk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -88003,7 +87510,6 @@ { "name": "promax.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "promocjedladzieci.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "promotech.pro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "propertysold.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "prosperfit.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "prostoporno.life", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ptk-svarka.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -88023,7 +87529,6 @@ { "name": "rama.ovh", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "rassadacvetov.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "rasset.ie", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "ratul.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "rayfalling.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "recordmeeting.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "recreatieftotaal.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -88064,7 +87569,6 @@ { "name": "sanctum.geek.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "sandra-perlbach.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "saorsat.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "sarahjanecreates.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "saronikos.guide", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "scatterscasino.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "schafzwitschern.blog", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -88716,7 +88220,6 @@ { "name": "zolotoy-standart.com.ua", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "01.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "038899.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "0verl0rd.ir", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "1248.ink", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "1eanda.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "2fr3.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -88830,8 +88333,6 @@ { "name": "dfc52.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "diamondyacca.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "diesicheremail.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "digipolis.gent", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "dominionedge.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "douzer.earth", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dreamingwolf.sk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "drtis.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -88965,7 +88466,6 @@ { "name": "nutritionalsupplement.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "obliviate.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "officevibe.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "onlinecasinolisboa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "opendoorcounselingpa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "opnaarsalto.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "opticasocialvision.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -89031,7 +88531,6 @@ { "name": "sardinianvillas.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "sardinianvillas.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "saxis.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "scarabcoder.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "schiau.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "schoolofequineshiatsu.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "servermacher.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -89083,7 +88582,6 @@ { "name": "vlqnc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "vnetboard.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "voedselbankmoerwijk.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "vontainment.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "vvtv.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "warmsquirrel.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "warupu.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -89117,37 +88615,12 @@ { "name": "x59788.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "x59888.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "x59988.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "x98d.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "x98e.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "x98f.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "x98g.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "x98h.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "x98i.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "x98k.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "x98l.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "x98m.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "x98n.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "x98o.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "x98p.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "x98q.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "x98r.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "x98s.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "x98w.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "x98y.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "x98z.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "x993.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "xamax.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "xemcloud.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "xiaoneijun.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "xiaoneimao.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "xn--lti-3qa.lv", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "xpj000444.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "xpj000555.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "xpj000666.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "xpj678678.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "xpj909.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "xpjbeting.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "xpjcs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "yellsy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "yourbusinesscommunity.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "yourpalmbeachcountyrealtor.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -89218,7 +88691,6 @@ { "name": "asm.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "asps.biz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "audioblackmagic.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "audiovoodoo.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "b89bb.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "b89cc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "b89dd.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -89269,7 +88741,6 @@ { "name": "bet7234.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "betza.online", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bicicletassym.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "bidadari.my", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "biotecommunity.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bizeasesupport.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "blixtv.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -89362,7 +88833,6 @@ { "name": "elijahzawesome.casa", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "emergencycommand.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "empreinte.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "energy.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "eoy.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "epsi.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "espacioprofundo.com.ar", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -89379,7 +88849,6 @@ { "name": "fauxcams.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "fenriragic.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "fetishblend.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "fieldelite.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "finprison.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "fish-n-chips.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "fitrecepty.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -89389,7 +88858,6 @@ { "name": "foxycredit.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "fracturedperspective.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "free-sex-sites.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "freecodezilla.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "freedomdujour.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "freetext.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "fsd.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -90169,7 +89637,6 @@ { "name": "palessit.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "pcf-frankfurt.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "pipscprd.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "poirierlavoie.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "pojdnafp.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "pomdoc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "poquiloco.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -90407,7 +89874,6 @@ { "name": "autopeople.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "averste.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "aviannahelise.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "aviationweather.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "awinninghabit.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "axearrow.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "azl-app.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -90420,7 +89886,6 @@ { "name": "b67883.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "b67884.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "b67885.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "b9l8tt.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bachomp.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "backspace.dev", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "backspace.rocks", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -90477,12 +89942,6 @@ { "name": "brisbaneflamenco.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "brooklyntheborough.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "brunoamaral.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "btt1313.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "btt1515.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "btt185.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "btt494g.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "btt949g.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "btt9595.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "buffalowdown.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "burdine-andersoninc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "businessgram.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -90520,10 +89979,8 @@ { "name": "chanderson.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "chaoscommunication.camp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "chaturbate.global", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "chaussmomes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "checkmedia.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "christoph-gadow.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "cimaflash.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cleankey.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "clearlakechildrenscenter.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "clientesal100.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -90583,12 +90040,6 @@ { "name": "cybersecurity.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cyprus-company-for.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "d-vision-create.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "d868.app", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "d881.app", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "d882.app", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "d885.app", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "d889.app", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "d898.app", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dailyblocks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dailyngn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "daltcore.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -90782,7 +90233,6 @@ { "name": "gobiernousa.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "gocdn.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "godofredo.ninja", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "gomelagromashplus.by", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "gometa.link", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "gomods.link", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "goontu.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -90856,7 +90306,6 @@ { "name": "iemsamex.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ifashionable.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "iganesh.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "ikhwanto.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ilawgix.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ilovehoney.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "imoasis.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -91022,13 +90471,9 @@ { "name": "mcsteve.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "medibasket.co.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "megamov.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "megamov.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "megamov.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "megamov.pro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "megazine3.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "meinforum.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "meldwekker.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "mentorbuk.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "menurutparaahli.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mettin.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "meziblog.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -91038,9 +90483,7 @@ { "name": "milanvit.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "milehighmaniac.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mileyweasel.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "millim.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "minicampingshalom.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "minilov.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mississippigenealogy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mitchkalf.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mmxx-distribution.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -91048,7 +90491,6 @@ { "name": "mobileinternetbanking.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mobilmobil.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mobincube.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "mobinstore.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "modelbase.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mohamedhamuda.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "montsearias.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -91073,7 +90515,6 @@ { "name": "myersking.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "myforum.community", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mygate.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "mymartinbeckeropenhab.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mypharmjar.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "nachovni.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "nasehyar.ir", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -91203,7 +90644,6 @@ { "name": "pornokran.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "postman.com.ng", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "pouchdog.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "poupee.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "powertoolsrater.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ppissis.com.cy", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "preciodolarhoymexico.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -91459,7 +90899,6 @@ { "name": "tloschinski.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tobdesignfirm.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "toepferwerk.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "tommyphotographie.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "toolsense.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "toperadigital.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "totalwebboost.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -91500,7 +90939,6 @@ { "name": "unpause.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "upgradeguru.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "uponsel.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "uptime.fm", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "uptownbabe.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "uropenn.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "usa.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -91571,7 +91009,6 @@ { "name": "xtom.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "xtom.gg", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "xtom.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "xuexi.icu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "xxxuno.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "yahav.co.il", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "yasic.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -91593,14 +91030,9 @@ { "name": "00228vip5.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "00228vip6.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "00228vip8.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "00228vv.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "00228w.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "00228ww.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "00228x.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "00228xx.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "00228y.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "00228yy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "00228z.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "00228zz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "01zemi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "0cdn.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -91615,7 +91047,6 @@ { "name": "22884.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "22884a.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "22884b.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "22884c.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "22884d.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "22884e.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "22884f.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -91673,7 +91104,6 @@ { "name": "9968love.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "9968xpj.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "a00228.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "a77018.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "aa00228.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "aarsunwoods.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "abelordbalagtas.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -91730,7 +91160,6 @@ { "name": "archim.org.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "arest.web.id", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "arganwinkel.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "artchic.vn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "aryankhera.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "asgardiamc.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "assessortrainingonline.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -91752,7 +91181,6 @@ { "name": "avionschool.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "axisins.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "azadcyber.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "b00228.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "b77018.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "baixarvideosgratis.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bajarvideosinstagram.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -91785,7 +91213,6 @@ { "name": "beus.ink", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bihaberkalma.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bijou.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "billchen.win", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "billiebone.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bim0s.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "binarypuzzle.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -91887,14 +91314,12 @@ { "name": "cr1coffee.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "creati.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "crossconnected.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "crowdfundingwaterresearch.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cs-kurnik.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cube-filing.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cumulus.photo", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "curl.tw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "customerfocus.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "d00228.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "d88.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dada.is", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "daimonikos.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dalvik.sh", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -92085,7 +91510,6 @@ { "name": "gressnet.id", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "gridky.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "gryphonnetworks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "gsaadvantage.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "gugcstudentguild.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "guochang.fun", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "guyuy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -92607,7 +92031,6 @@ { "name": "stopsscam.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "strategic9.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "strategiczni.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "strenght.biz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "stress-mess-punkte.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "stuccorepaircontractors.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "subafoto.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -92619,12 +92042,10 @@ { "name": "symbolic.software", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "synergenxhealth.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "synth.style", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "t00228.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "t4gh.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tadzkitchen.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tamboa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tanahtinggi.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "tandoanh.vn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tapple.world", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "taxi-meridian.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tcspartner.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -92667,7 +92088,6 @@ { "name": "tomiubezpiecz.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "topbdnews.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "topdomainsandhosting.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "tophatpuffin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "topofmind.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "torisamaahirusama.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "totalmdplan.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -92785,7 +92205,6 @@ { "name": "www00228d.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "www00228e.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "wwwn888.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "x00228.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "xavio-design.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "xbblog.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "xbots.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -92810,11 +92229,9 @@ { "name": "yannyann.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "yellowtrace.net.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "yj4p.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "yjav.tv", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "yjav11.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "yjav8.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "yjav9.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "yjsp.tv", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "yjsp07.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "yjsp17.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "yjsp333.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -93892,7 +93309,6 @@ { "name": "63wq.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "663365i.vip", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "663365j.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "663365j.vip", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "663365k.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "663365k.vip", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "663365l.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -94306,9 +93722,7 @@ { "name": "b131000.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "b2222.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "b789.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "b979555.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "b979666.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "b979999.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "badnjar.rs", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "banajanitorialservices.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bassment.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -94401,7 +93815,6 @@ { "name": "elsenzhafen.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "employmentlawworldview.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "empregopraontem.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "eproceedings.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "equinenow.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "equityelevate.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "eremnews.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -94431,7 +93844,6 @@ { "name": "flowdise.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "fnckfashion.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "foochia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "fortressis.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "francoise-angelini.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "frederickbourget.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "funtransport.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -94498,7 +93910,6 @@ { "name": "itabi.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "itajvi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "itsapps.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "j51365.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jackwarren.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jakartacloudhosting.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jamiehansonyoga.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -94585,7 +93996,6 @@ { "name": "neosys.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "netrilo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "newgle.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "nextsociety.la", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "nexustraducoes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ngawa-avocat-paris.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "niemandmussirgendwas.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -94605,21 +94015,6 @@ { "name": "outrider.ai", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "owmobility.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "p7jl.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "p88813.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "p88814.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "p88816.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "p88817.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "p88823.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "p88825.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "p88827.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "p88829.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "p88835.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "p88836.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "p88845.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "p88848.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "p88856.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "p88867.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "p888a.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "pablosaraiva.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "panelesyperfiles.com.mx", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "papascave.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -94790,7 +94185,6 @@ { "name": "vichama.pe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "victorique.moe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "visse-if.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "vns6654.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "vosges-tourisme.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "w123.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "warmteshop.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -94818,7 +94212,6 @@ { "name": "zamor.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "zeglujemy.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "zhoujianghan.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "zieler.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "zivver.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "0x12.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "0x22.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -94881,7 +94274,6 @@ { "name": "brisbanecashforcars.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "buyiptv.tv", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "calibreapp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "camwoodbats.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "carbuzz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cardiaccane.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cartale.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -95176,7 +94568,6 @@ { "name": "urbanon.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "v.ps", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "v8abc.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "vaioswolke.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "vetapp.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "viaura.biz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "victoria-legis.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -95229,7 +94620,6 @@ { "name": "bugfender.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "burgerbites.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "candytip.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "cerecup.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ceyhanmolla.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cheapfarestouk.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "chowchowugo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -95403,7 +94793,6 @@ { "name": "pechibani.by", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "penisenlargementpro.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "pixelshape.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "placenet.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "platform.ltd.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "pragatiparasguesthouse.co.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "prod-simplesend-api.azurewebsites.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -95421,7 +94810,6 @@ { "name": "sharingiscaring.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "shaunallen.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "shiulungkungfu.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "signal34.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "simplesend.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "skidzun.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "sorocabacopos.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -95511,7 +94899,6 @@ { "name": "xz0.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ymy.zone", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "you-livetv.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "yuweetek.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "zakbk.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "0km.top", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "0x2a.ninja", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -96179,7 +95566,6 @@ { "name": "gutterguardcharlotte.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "guttershutter.biz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "habibitravels.com.ng", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "hae.sh", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "haizrulamrie.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "hby.cx", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "heckmann.photos", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -96233,7 +95619,6 @@ { "name": "jettenbommelaer.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jettenjachtbouw.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "joico.by", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "jonaskruckenberg.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "josephrichard.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jrfortune.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "julianporras.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -96309,7 +95694,6 @@ { "name": "luxplay.com.tw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lvee.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lvfc.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "machkovi.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "madeincana.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "magazineflex.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mailsupport.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -99015,7 +98399,6 @@ { "name": "e-umbrellas.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "e-zine.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "earth-quake.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "eas.ee", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "eastdream.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "eastendonline.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "eastheaven.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -99790,7 +99173,6 @@ { "name": "getinfoleads.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "getme.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "getreadyforever.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "getrealutah.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "gettwo.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "getvalidate.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "getyoureuro.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -99931,7 +99313,6 @@ { "name": "gpl25.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "gppro.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "graberbooks.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "grabtech.vn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "gracia-club.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "graciasmarvin.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "graduados.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -100368,7 +99749,6 @@ { "name": "imeria.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "imgo.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "imgo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "imiku.fun", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "immoraldoctors.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "immortal-it.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "immune.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -100702,26 +100082,6 @@ { "name": "justpdf.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "justrighthsc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jwompa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "k8866088.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "k8866089.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "k8866090.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "k8866091.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "k8866092.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "k8866093.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "k8866094.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "k8866095.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "k8866096.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "k8866097.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "k8866098.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "k8866099.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "k8866100.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "k8866101.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "k8866102.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "k8866103.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "k8866104.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "k8866105.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "k8866106.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "k8866107.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "k9lady.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "k9life.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ka4ka-ru.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -101130,7 +100490,6 @@ { "name": "lean-consulting.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "leandromarcolino.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "learn-this.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "learolstore.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "leatherstreet.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lebensinselparaguay.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lechenietravami.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -102066,7 +101425,6 @@ { "name": "mywebserver.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "myweightlosstips.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "myzarabot.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "n-mail.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "n3rd0rama.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "nabeer.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "nabiev.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -102280,7 +101638,6 @@ { "name": "no-terrorism.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "no-war-on-iraq.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "noart.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "nocoffeetech.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "nocturnos.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "nodde.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "nonemail.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -102573,7 +101930,6 @@ { "name": "overtunes.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ovez.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ovodakadarkut.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "owall.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "oxaliz.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "oxbridge.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "oxigenoinformatica.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -104204,8 +103560,6 @@ { "name": "start-knighki.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "startbetter.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "startgeophysical.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "startnowmakingmoneyonline.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "startpa.ge", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "startplats.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "startupyourmind.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "statcenter.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -104591,7 +103945,6 @@ { "name": "textcounter.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "textil-kyoto.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "textsite.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "tfrei.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "thailandpropertylisting.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "thailandvariety.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "thais.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -106127,7 +105480,6 @@ { "name": "claudia-halfter.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "claudiahalfter.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "clean.my", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "clouditme.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cm-valenca.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "codefive.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "colah.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -106166,7 +105518,6 @@ { "name": "ebooksa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "eccologic.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ecn.ir", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "elartedelaweb.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "electricianboksburg24-7.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "elona-wvw.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "emarketingprince.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -106176,7 +105527,6 @@ { "name": "epicsoft.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "escobpb.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "esea.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "esj.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "esperanto.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "eudireto.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "evga.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -106347,7 +105697,6 @@ { "name": "kitagawa-internal-medicine-clinic.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "klankenkast.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "klausbijou.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "kngkng.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "knowledze.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kod13.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "koehn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -106355,13 +105704,11 @@ { "name": "konzepttreu.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kood13.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "koood13.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "kouroshnet.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "krishnakalisaha.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kurenivka.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kurniasihmandiri.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lakewylietax.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lapulgaflamenco.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "lazyw.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ledcross.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "legion.hosting", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lendingmate.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -106386,7 +105733,6 @@ { "name": "macc.org.my", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "madebythijmen.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "magicorama.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "maleylabapplications.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mansys.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "maratondeclics.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "matjarkom.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -106488,7 +105834,6 @@ { "name": "roethelheim.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "romatours.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "rosaserra.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "rot256.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "running.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "rx-safety.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "sabrinajoiasvarejo.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -106512,8 +105857,6 @@ { "name": "seditious.games", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "segdomedia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "seniorhomexchange.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "seocompany1.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "seowebstat.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "sertaobom.eco.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "serverfix.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "sextop1.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -106537,7 +105880,6 @@ { "name": "stove-server.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "sultangroup.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "supedium.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "swj.red", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tandemwise.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tannextcloud.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tarahancenter.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -106546,11 +105888,9 @@ { "name": "tcmk-tomsk.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "techsna.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "theatrepremol.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "thequalitycleaning.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "thesemperfibeard.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tomasdrtina.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tomphenix.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "top10antivirus.review", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "torohandyman.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tsaama2.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tsproesasac.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -106577,7 +105917,6 @@ { "name": "vulnerabilityscans.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "wars.cat", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "waseetalnokhba.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "wealthsuccess.edu.vn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "webparallevar.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "weddingwire.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "wedooper.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -106595,7 +105934,6 @@ { "name": "wuifan.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "wuifan.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "wuifan.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "xialingshi.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "xkeyc.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "xn----7sbbhzfbdo6dnf.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "xn--xwqa8512b.eu.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -106619,7 +105957,6 @@ { "name": "557bbb.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "722sss.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "795sss.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "840.gg", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "991ccc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "aaflalo.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "abeshultz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -106676,7 +106013,6 @@ { "name": "boundless-designs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "brazilhealth.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "breteuilcommerceartisanat.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "brexitmart.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bride.vn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "butlerdisposal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "camshowhive.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -106934,7 +106270,6 @@ { "name": "mdsconcept.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "medicano.site", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "medicoway.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "meer-der-ideen.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mendrala.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mendrala.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mendrala.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -106966,7 +106301,6 @@ { "name": "nbsgames.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "nectere.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "nejrecept.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "networkprosecurity.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "newikis.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "newshour.media", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ngservers.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -107007,7 +106341,6 @@ { "name": "philippehannes.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "philpatch.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "piezus.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "pjdigitalmarketing.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "platform-med.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "playorigin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "playstationplus.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -107020,7 +106353,6 @@ { "name": "pro-dog.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "proficiodigital.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "proficiodigital.sk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "proitsecurity.cl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "protection-plexi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "protection-plexi.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "psicologomogidascruzes.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -107035,7 +106367,6 @@ { "name": "rabec.com.sa", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "refansta.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "renedekoeijer.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "reseau-protestant.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ricor.cl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "riley.love", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "rinton.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -107149,7 +106480,6 @@ { "name": "zook.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "016910804.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "123start.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "2002000.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "2makeu.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "4driver.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "4hypo.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -107187,7 +106517,6 @@ { "name": "apuraytravel.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "arabwomen.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "archaeology.lk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "aromaimportado.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "artlinestix.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "artofclouds.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "asdf.one", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -107232,7 +106561,6 @@ { "name": "campus-competences.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "candalgic.com.tr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "canopy.garden", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "captainkids.vn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cardoneshop.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "careify.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cateromarket.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -107274,7 +106602,6 @@ { "name": "covidmodel.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cpad.org.pk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "crea.codes", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "creatapeak.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "credee.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cricoff.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "crohnszone.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -107297,7 +106624,6 @@ { "name": "digino.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "digino.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "digino.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "digitalmarketerconsultant.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dioxido.com.ar", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dnddobbelstenen.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dossierweb.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -107412,31 +106738,10 @@ { "name": "korkortonline.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "krome.sg", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "krpaforum.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "ks178.vip", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "ks187.vip", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "ks500.vip", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "ks700.vip", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "ks800.vip", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "l2l.vn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lablic-beta.work", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "langages-programmation.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "latronicenergy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "lc80803.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "lc80804.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "lc80805.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "lc80806.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "lc80807.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "lc80808.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "lc80809.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "lc80810.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "lc80811.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "lc80812.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "lc80813.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "lc80815.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "lc80817.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "lc80818.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "lc80819.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "lc80820.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lejade.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "letterzaken.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "leyendaluzrenacer.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -107572,7 +106877,6 @@ { "name": "ragnarokhpg.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "rallyekrumlov.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "rapidxray.biz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "ravihotel.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ravijuhend.ee", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "rcsscontractors.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "rebelsewerservices.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -107742,7 +107046,6 @@ { "name": "yanwo.com.tw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "yg-crew.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "yobda.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "yojanahub.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "youbehero.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ywyz.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "zagainov.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -107836,7 +107139,6 @@ { "name": "cafminiapp.ac.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "callumgroeger.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "camslagz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "capradip.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "car-clean-nord.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "carcleannord.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "carinaklijn.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -107971,10 +107273,8 @@ { "name": "georgewilsonvsgatsbyjs.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "gestalte-deinen-balkon.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "getsmartlife.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "gilar2.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "goenea.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "goldenworldec.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "goover.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "grapheneengine.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "graphicapps.online", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "graphicwallet.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -108036,7 +107336,6 @@ { "name": "kibazen.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kinklist.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kinkyheretics.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "kitajagakawasan.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kmzs123.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kocovi.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "kokily.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -108048,10 +107347,6 @@ { "name": "layers.media", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lazoscollection.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lc3755.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "lc80801.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "lc80802.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "lc80814.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "lc80816.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "learnpine.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lebozec.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lidl.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -108200,7 +107495,6 @@ { "name": "sharonsplace.biz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "shouohkai-dental.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "sipln.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "skrealtyplus.co.th", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "smaden.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "smikom.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "snitch.rocks", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -108221,7 +107515,6 @@ { "name": "survivalfitnessplan.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "svatba.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "sylencegsm.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "synology.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "systemplust.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "taguiginfo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "takeshi.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -108386,7 +107679,6 @@ { "name": "casalor.ro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cccp-o.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ccnexus.global", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "cdxmaster.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cecilgreens.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ceifx.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "certified-cpr.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -108422,7 +107714,6 @@ { "name": "daniel-san.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "danielives.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "darkovepredmety.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "datashenas.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "davusito.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dayman.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dccomputerrepair.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -108454,7 +107745,6 @@ { "name": "ecomoov.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "eggzr.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "eklavyacs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "elbassira.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "eleonoramazzola.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "emeraldshield.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "empty.host", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -108607,7 +107897,6 @@ { "name": "mandospersonalizados.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "marketingseo.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "marklehane.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "marshallpeak.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "marta.uz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mask4all.shop", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mastercareplus-demo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -108780,7 +108069,6 @@ { "name": "storebusy.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "storeinstallieren.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "strafe-muss-sein.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "supercima.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "suritylabs.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "sylvain.codes", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "synapseretailing.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -108904,7 +108192,6 @@ { "name": "aprenderjuntos.cl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "aptekaref.pro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "arcanehardware.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "area51-project.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "argon2.online", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "armilex.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "arobaz-informatique.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -108914,7 +108201,6 @@ { "name": "artesaniaselmagodeoz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "artisansofsleep.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "artizlibranza.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "artworksthatlookgood.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "asabharwal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "asalearn.ir", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "assignmentshelp.co.ke", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -109161,7 +108447,6 @@ { "name": "htsm.top", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "hunhee.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "hushbabysleep.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "hutuishangmeng.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "hypertensionexplained.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "hypno-thera.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "hysupchile.cl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -109344,7 +108629,6 @@ { "name": "pueblanmilksnake.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "purepowercycle.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "pygmyleafchameleon.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "qnixon.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "quietapple.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "quoteee.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ratsmicedormice.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -109425,14 +108709,10 @@ { "name": "theartofe.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "thebookiejoint.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "thefireflygrill.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "thepainapple.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "thrivebymitchelle.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "timecaptis.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "tirion.network", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "tirion.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tirion.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "todocruces.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "topnotchsociety.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "topvision.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tra-tra.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tradesrenovations.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -109461,7 +108741,6 @@ { "name": "virus.cafe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "vlaser.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "volreinsistemas.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "vondenstein.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "voxengo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "waf.hk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "wallamigos.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -109469,7 +108748,6 @@ { "name": "warszawa-pranie-dywanow.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "webslate.co.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "wheyteck.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "why7.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "willobyhomes.realestate", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "wineforhelp.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "wmbey.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -109524,7 +108802,6 @@ { "name": "airtrolinc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "alfransiacademy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "allitschool.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "alnavedic.co.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "altecgmbh.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "altrasoluzione.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ambulanceplus.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -109532,7 +108809,6 @@ { "name": "amroofingelpaso.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "andrewsandford.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "androtiyas.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "anitahebe.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "anthonywesbrook.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "antivirus.directory", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "anzahcraft.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -109612,7 +108888,6 @@ { "name": "computingaustralia.group", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "coniectoinvestments.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "continuumm-tech.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "coopemep.live", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cooperativaminka.cl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cravecraftonline.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cuscocontable.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -109650,7 +108925,6 @@ { "name": "dy.express", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dynamicsdays.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "e30019.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "easynotes4u.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ecozona.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "eda.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "edok.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -109781,7 +109055,6 @@ { "name": "laptopnewbie.eu.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "laudlab.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "laudworks.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "lc9915.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "leales.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lecoquelicot.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "legterm.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -109794,7 +109067,6 @@ { "name": "localcryptos.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lojasmary.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "longoconsulting.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "los-hoppers.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lost-illusions.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lostserial.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "lourencolar.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -109865,7 +109137,6 @@ { "name": "oblitsov.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ofasoft.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ofcac.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "ohitsviral.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "olegchursin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "olimpikfit.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "olimpikfit.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -109929,7 +109200,6 @@ { "name": "pornogo.sex", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "portfreezone.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "portusidades.com.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "postfree.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "pp30019.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ppapogey.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ppapogey.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -110064,7 +109334,6 @@ { "name": "taskseller.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "teacuppersiancats.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "teacupyorkiespets.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "tecnikan.ar", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tendoryu-aikido.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tfok.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "thaserv.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -110115,7 +109384,6 @@ { "name": "velorail01.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "very-stylish.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "vestakassa-online.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "veterinariaelcrack.com.ar", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "vihotar.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "vinaygarg.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "visionmedicale.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -110153,7 +109421,6 @@ { "name": "yewtu.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "yuina.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "yukinarita.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "yvcr.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "yvonne-stingel.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "yy30019.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "z30019.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -110162,6 +109429,3268 @@ { "name": "zorox.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "zporno.porn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "zz30019.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "flynnhub.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "0x5f3759df.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "112q.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "123hpcom.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "1337ersprime.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "205920.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "3niu10.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "573sss.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "797sss.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "7qlm.vip", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "941618.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aaex.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "abram-lab.ir", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "absurdopedia.wiki", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aciclinical.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "adaiacorporation.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "admin-gator.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "admin-gator.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "admingator.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "admingator.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aechelon.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "afive.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "africanchildrenschoir.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aiken.golf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aim.org.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aion-beritra.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "akoya.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aktarma.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alexgsites.co.il", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alghadpowersolutions.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alinol.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alpineitltd.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "amatya.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ameri.capital", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "americanhoneyproducers.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "anblife.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "antidopamine.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "anuncioacompanhantes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "arc.run", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "argovpn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "askingmonkey.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "asocedune.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aspenrealestate.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aspire-irb.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "astellaria.ee", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "atheatac.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aube.kr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "autumn.today", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "avgeeksunited.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "awtogid.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "babaganousha.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bahai-rdc.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bahiastudios.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "baixtaxi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "balosport.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bazhan.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "beijing30019.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bellezademujeres.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "berichandcreamy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "berjou.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "big4mas.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "blueparrotpainting.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bookworld.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "borsodsakk.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bothive.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bricmon.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "britishcountrymusicfestival.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "buerliag.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "builtinsf.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "buycompanyname.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "buynowbol.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "c19explorer.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "c4safety.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cachacagaboardi.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cangku.one", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "capitalism.rip", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cariadcymru.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "carolinelanthier.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "casaruralcincoleyendas.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "casasincreibles.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "catpic.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cccanna.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "celebrate-creativity.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "celebritypictures.blog", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cerberusecurity.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cgirb.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cgplumbing.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ch-y.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "charitocracy.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "charlie-liveshow.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chatx.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chkserv.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chongqing30019.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ciplerli.st", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "classificar.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "clintraxglobal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "clixa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cloudlfront.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cloudsys.dnsalias.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "coinsconnect.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "conceptground.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "concern.co.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "confortiaperu.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "consultahn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "core.md", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cortho.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "covidfreeathome.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "covidlive.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "covidpppstore.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "creacode.tech", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cri-cloud.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "crm911.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cryptocentral.africa", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cryptotaxonline.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "csgostash.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cyptechost.co.ke", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dagyirivera.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dailyw88.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "damebe.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dan124.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "danielnaaman.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dawlya-19089.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "daxrunbase.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "denoroulette.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "devandy.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "devincave.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "devopt.win", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dexign.ro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "diabhalstaff.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "diaspordc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dickp.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "didakeanimaciones.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dietaparaadelgazar1.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "digit2go.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "digitalgeekspro.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "diplomatcruises.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "django-lessons.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dnspropagation.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dodolle.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dokutech.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "domainsetup.email", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "douglasrumbaugh.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dripindustries.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "drjungspine.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dunangel.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "e5xbps.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ebcfx.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ebuyon.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ecohousejapan.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ecologiahoy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eg7.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eladalfassa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "elimidrol.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "elphnt.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "emarch.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "enstructo.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "epharmasolutions.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esale.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esprit.tn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "etbtoursegypt.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eteachbd.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "europeanbizhealthcare.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "exbasi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "extrasauber.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "extrasauber.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "extrasauber.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "f88vip1.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "f88vip101.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "f88vip113.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "facileway.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fazz.id", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "felixgerschau.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fenyks.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fidemlenceria.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "finalgambit.band", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "firstbaptistchurchofchrist.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fitmybike.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fl0w.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "flowbuk.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "flowcrypt.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fluenciamodas.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fogonrustico.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "forers.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fors.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fortcommunity.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "freecam-sex.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "freedailygifts.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "freehdporn.tv", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "freehqporno.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "freshmusicsheets.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "frog.industries", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "frown.town", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fujian30019.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fynbo.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "g2price.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gaboardi.net.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gansu30019.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gaonadigital.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "garage.click", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gatehub.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gbhem.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "geekcreations.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gergoladi.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ghostruler.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "giannifoti.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "girassolacessorios.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "glaccessonline.icu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "glserviciosweb.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gold-iptv.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gregbonner.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "grsstore.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gsoluzioniweb.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "guadaluperoses.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "guangdong30019.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gudbrand.no", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "guiadev.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "guizhou30019.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "guruminode.kr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gzhzg.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "h5q.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hack-bang.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hainan30019.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hakiminvestment.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "handsaccounting.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hebei30019.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "heilongjiang30019.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "heixiongwl.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hejazultra.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "henan30019.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hidraulic.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hitpt.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hostingdiario.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "houlang.ac.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "houseepropiedadraiz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hqmovies.blog", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hqmovies.club", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hrlab.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hu2ty.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hubei30019.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hunan30019.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "iflipy.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ihct.sch.id", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "imaginativo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "imanageproducts.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "imf-online.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "imfacademy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "implantologiadentalgt.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "impressionusa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "incnjp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "interchangeillawarra.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "internetstones.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "invicti.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "inweb.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "iprash.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "irwinvalera.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "isinolsun.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "islide-powerpoint.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "iszy.wtf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "iszy.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "itaro.bot", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "iurisnovagestion.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jamereviews.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jiangsu30019.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jiangxi30019.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jilin30019.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jonathan.us.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jpdineroasi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jpmultimedia.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "js-webcoding.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "js889.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jswc.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "juraganilmu.web.id", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kamery.top", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kanker.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kap-kirche.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "karwish.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kcpromi.sk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kescher.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kihi.news", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kingsol.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kizuki1749.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "klinikum-oldenburg.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "klofteam.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kloftowel.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kloftowel.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "knowledge-base.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "koko.news", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kor.ovh", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kosturanov.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kpop.events", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kuestensiegel.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kutalek.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kuzmik.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kuzmik.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kuzmiks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lagrotta.pizza", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lanthanum.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lawncorner.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ld-duesseldorf.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "learnblue.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lepallec.tv", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lgerman.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "liaoning30019.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lidservicessac.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "limportemps.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "linux.monster", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lkotlarenko.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "localdmcs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "loxdonmarkets.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lundlist.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mackungfu.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "macupdate.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "madadmin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mail.ac", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "makocontrols.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mamapatrzy.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "marinelife.store", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "markocloud.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "marturet.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mascarillas.blog", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "matega.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mclanedirect.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mclanexpress.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "meetsummer.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "merkleforest.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mgmpic.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "microbird.club", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "microsolenergy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mikkel.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "minapan.ro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "miraclesformya.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "misterd.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "misterorion.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mlada-moda.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mlirb.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mlpvcdn.top", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "moblkar.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "modacruz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mods.fm", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "monveilleuretmoi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "morwynna.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mrsourabh.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "msoida.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mueblescuerolorca.cl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mui.today", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mujeresfemeninas.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "muskokadanceconnection.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mutsumikai8989.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "myerscreekcascades.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mypdns.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mypdns.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mysites.guru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nanomap.ddns.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "natuwa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "naxoprojects.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "neimenggu30019.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "neirb.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nestorgaleanomegamariachi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "netweaver.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "newyorkhipknee.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ningxia30019.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ninpang.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nixcp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "noawildschut.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nodi.cloud", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "notaryassistant.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "novaway.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nycstyleboutique.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "oecdpisaforschools.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "offtherayles.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ohiowebtech.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "orbitgoods.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "osdnc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "otrainfans.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "overlandirelandtours.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "p-vegas.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "packservice.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pagbitcoin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pagexl.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pakarrumah.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pakcha.com.ar", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "paleblue.cloud", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "paranoid.network", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "parkviewcity.com.pk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "paysensei.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "paysitesreviews.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "perfumerh.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "phygitalentrepreneur.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "planisware.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "planisware.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "planiswareusa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pley.today", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pocketcraft.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "policymakr.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "popotomodem.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "porkbun.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "portaledelira.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "portalpower.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "press-presse.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "procode.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "proconspain.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "procore.space", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "progressivepurchasing.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "proiceresurfacer.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "projectalias.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "propertea.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "puntacanavapor.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "qinghai30019.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "qrlab.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "quellenwiese.ski", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "quesecelebra.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "radiosimba.ug", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "raycon.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "reaff.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "realwinner.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rebajasoferta.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rebeccakirk.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "reck.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "redecloud.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "reducealcoholism.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "reiff-schlauchkonfigurator.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "remediohalkiparaladiabetes.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "renaudmuller.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "restaurantbetriebe.schwarz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "riseofthewildwoman.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "roge.pw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "routerchart.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "safiosolutions.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sairus.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "salkield.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "saludparatodos.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "santehnik-home.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "saudiglasses.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "scanmy.email", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "schleifenbaum.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "screenzy.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "secureover.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "segmentify.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "seincojavea.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "seo-en-barcelona.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "seoargentina.com.ar", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "seospecialist.ma", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "servi-tek.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ses-egy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shandong30019.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shanghai30019.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shanxi30019.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sharingcolombia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shipbuddies.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shutterstreetblog.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sichuang30019.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "skilift-quellenwiese.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "smartriotour.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sme-gmbh.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "snatertlc.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "socialabstracto.website", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "soroush-barber.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "starborne.space", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stoneoakgs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stoom-stichting.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "subastasnacionales.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "suger.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "t90official.games", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "taibachicken.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "taibafarms.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "taskman.london", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "taxisantandreudelabarca.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tch-forum.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tecnologia.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tecnomagazine.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "teknologiia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tempoprimo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "teplo-russia.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "termodej.ir", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tescomobile.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "teslasuit.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tevi.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "theboltway.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thefoxtalk.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thehomemademasks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "theocoffee.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thepalateportfolio.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "therra.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thevirtualdetective.games", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tianjin30019.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "timqueen.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tobacco-shop.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "today.ng", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tokoword.id", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tomacino.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "totkamassage.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tourfunnels.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "traintowin.tv", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "travelwithlocalspecialists.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "trespedia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "trifence.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "troyjanda.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "trypt.am", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "turismogdl.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tvtorcedor.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "uffserver.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ukvoipforums.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ultifreehosting.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "urge55.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "utaowan.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vader.news", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "valvulasvaneo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "variadoresindustriales.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vdlegal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vennprime.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "verdi.is", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "verzi.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "villu.stream", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "virtool.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vivo.cam", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "voltajedigital.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wallabywallaroo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "waranistudios.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "washingmachinesguide.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wasithard.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "webcontentserver.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "websitedown.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "weimaranerdogcare.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "weirdware.tech", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "westlab.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wicca-witchcraft.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wjtje.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wolrdwidessl.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wordwidessl.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "worldwidessl.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wpboys.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wxw.moe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xanzhu.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xgys.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xinjiang30019.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xizang30019.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xoxo.news", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xyz.ng", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yaay.today", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yasikish.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yingshu.hopto.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yorkiepooexpert.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yorkshireterrieraspets.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yunnan30019.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zbuilderz-lb.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zeitgitter.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zhejiang30019.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ziron.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zombie-apocalypse-survival.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "123-d.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "138.hk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "1pieces.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "3ecpa.com.hk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "3ecpa.com.my", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "3ecpa.com.sg", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "4245pay.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "42usd.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "4huawei.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "4meizu.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "4nokia.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "4xiaomi.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "889vip1.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aaablindfactory.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "addedesign.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "adventistai.lt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "africanbushcamps.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "agroturismoenpanama.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aihub.codes", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "airit.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alamanceconstruction.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alastalonmailla.fi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "albourne.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "allpvrtours.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "altrei.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "amanandalens.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "americapitalfunding.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "amlakzibakenar.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "andradealbuquerque.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "angelesverdes.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "anhui30019.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "annuitycommunity.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "anzalikala.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "apfm.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "arc-relight.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "arcsar.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "armourroofinc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "arnamur.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "asteq.com.ar", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "athorcis.ovh", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "avalontechsv.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "avtorlab.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aykonet.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "azimech.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b88vip1.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "babyshopsupport.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "babystudio.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bags-ua.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "balkanturist.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "barbaleonecuador.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "barriotoboardroom.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bbqs-algarve.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "beecreative.company", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "behtarin10.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bereelcorporation.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "besox.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bigone.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bigpresentes.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bitcoinsv.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "blackhealthwealth.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "blightnight.games", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "blightnight.live", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "blightnight.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bocciatitanium.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bollymarket.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "brasilmedia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "brianleemarketing.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bridge-to-knowledge.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "brigantinebeachguide.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bringfido.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "brndtfy.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "brskt.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bss-systems.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bss.com.ph", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bss.net.ph", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bss.systems", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "btcshower.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bubsngrubs.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "burz.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "buurtkeukens.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "buyer.pro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "buzzkuri.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bv-driver.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "byll.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "californiahempin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "calzaturesira.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "canakkalebasin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cannamaca.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "casamentos.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cbvoucher.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "celulares.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "centralex.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "centrosocialferrel.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chambermeansbusiness.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "charles-brian.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cherokee.net.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "christinaaguilera.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "christophergowerjohnson.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chufftex.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chuongle.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cindydudley.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cirasync.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "citacitaku.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "clevyr.work", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cmnc.ddns.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "codectron.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "coloradoseodesign.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "completecareair.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "configwizard.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "corpomotriztokio.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "coviddrawings.org.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "createcode.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cubex.ltd", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "curseus.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cushytushiediapers.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cyberallegiance.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "danielleskosky.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dbradley771.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dekasseguiempregos.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "delta11.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "demaison.pro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "demapachesweb.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "denisalmeida.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "denizuydur.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "denverilluminations.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "devin.bg", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dicoeste.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dievozodis.lt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "digitale-oekonomie.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "disenoyarquitectura.com.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "displayrd.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "djmcadam.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "djmoremusic.ng", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dogwoodceramics.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dominicself.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dominicself.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "doranobi-fansub.id", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "draughts64.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "draughts64.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "e-facture.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "earthpoints.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eightyfour.pictures", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ejcabinets.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "elbiaadmin.sk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "elielsanchez.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "enerity.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "enginytech.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "epsamsg.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "erkankavas.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "etics.com.mx", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "extrafrei.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fahadbook.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "familychiropracticcolumbus.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "famouschilirecipes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fapality.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fastrack.co.mz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fdm.ddns.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "felipesuri.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "filmphotograph.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fipackaging.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "flanderslaw.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "flog.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "flytrap.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "foguest.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "forex-opinie.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "forexplay.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "forwardemail.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fotohunter.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fourseasonsgrower.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "free8.cloud", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "freehotline.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "freepornomovies.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "freesexvidz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "freeths.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "frilima.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fromsalttopepper.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fsinsight.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "furzone.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fussy.ee", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "galodasa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gayryder.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gbusercontent.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "georgiaparks.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "getfithtx.biz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "getthegoat.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "getveer.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gfmomcertified.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ghanabusiness.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gitesprestige.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "glk.academy", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gobytedesign.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "goingawesomeplaces.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "goudsbloemonline.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gplah.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gradedblue.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "grafik.org.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gravitydrawn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "grupoenelcolombia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gvaa.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "h10s.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "habboz.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hackathontwjr.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hamiltonsalestraining.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hangmychanhhieu.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hard.email", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hardmc.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hawa-adam.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "henrybrown0.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "heritagemachining.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hesanlang.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hireteen.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hqteas.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hrxkauppa.fi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "htxnet.biz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hx-sun.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hyllie.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "i-3c.co.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "i2i.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ibliss.digital", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ibtba.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "idehvector.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "iexpats.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "illumepgh.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "imperialism.rip", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "infantry.org.ua", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "infomalin.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "inmucrom.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "inmucrom.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "insideevs.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "insightfully.co.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "institutosparroquiales.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "instrumentodepaz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "internalfb.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "international-genealogy-services.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "intruder.ws", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "iosme.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "iowxy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ipadshowroom.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "iphonesoft.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "islaminbremen.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "itapuapotynoticias.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "itraincalisthenic.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "itrezzo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ivan1874.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jasper.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jasperpatterson.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jasperpatterson.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jesuschrist.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jian.spb.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jmbelloteau.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jobkeus.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jobs.schwarz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jobsjets.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "johncunningham.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "julioteixeira.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "justforsunn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jwala.diamonds", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kadeshfoundation.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kaijo-physics-club.work", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kalafard.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kccargo.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kenoschwalb.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kevinbauer.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "khazarvila.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kickassblogger.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kievantico.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kinderevents-sehnde.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kingdomcoffee.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kiplelive.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kmrgroup.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kojiishikawa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "koredia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kosterenpartners.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "krilotek.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kswork.life", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "labelledigital.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lagaleria-ag.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lanasomething.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "landofoz.dynu.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "laparoscopic-urology.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "latestmata.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "layar.my.id", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "learnspace.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lecafedugeek.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lefarsankids.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "legadosindumentaria.com.ar", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lellek.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "leonardoneiva.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lespepinspunk.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lidl.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lifeismmo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lineaesse5.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "linulex.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lizteacher.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "locoxlasmascotas.com.ar", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lojaonlineshop.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "loopcore.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lost-in-place.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "maianhtravel.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "maiotik.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "maison-coutin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "maksimyugai.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "malaysiabrands.com.my", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "malenachzahlen.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "maracarlinicourses.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "marcyacademiademusica.com.ar", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "markellos-olive.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "marthus.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mastercheat.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "masterpizzaiolo.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mathieuescos.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mayesoley.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mazayaashop.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mcplat.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mediabrandgroup.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mediacritik.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "megacity.com.ng", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "meine-stirnlampe.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mes-courriers.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mikeborowskigroup.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mips.co.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "missinicial.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mjgroup.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mmaker.pw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mnemonicninja.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "moddedphones.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "modsrigs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mojezegarki.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "morgan.solutions", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "moviles.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mrpanipiales.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mrunang.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mvwr.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mydaxio.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mydigicard.biz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mydigicard.host", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mynaturalhairstyles.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mywoodbridgedentist.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nanosealcreto.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "naplestotalgarage.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "neniu.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "neophotonics.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nesheims.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "netmarvic.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nfmovies.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nibbler.ai", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nick-black.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nikhilnimiya.love", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nikz.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nodegalaxy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "noggalito.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nordcheckout.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nordesttrasporti.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nordpass.asia", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "notcurses.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nrmc.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "o5.vc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ob-salon.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "oceane.training", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "odabilocal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "odensc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ok.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "onsitemower.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "orlandooutdoor.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "orquestaataulfoargenta.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "osborneprice.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "oscaroverton.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ouderamstelbridge.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ozcreatives.tech", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "padena.shop", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pancakesfromscratch.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pblandscapesolutions.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pcverge.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pdpa.ai", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pfeifferszilard.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "phoenix-cms.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "photographymof.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "piekblog.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "plahtan.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "playblightnight.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "plcclosets.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "politicaprivacidade.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "preferidaseguros.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "prefolio.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "proitsecurity.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "promotionnissanauto.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "protech.ge", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ptcdogpark.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "punjabitube.blog", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pureindoorair.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "qclean.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "qr0.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "radechefonne.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "radio-valois-multien.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rburz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "redcross.com.ph", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "redtrig.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "redtrig.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "revisionvillage.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ritoner.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rockymountaininsurancecenter.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rvmfm.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ryzen.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "saadat.in.ua", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "saltyproshop.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sanisafepro.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sardoche.lol", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sarkarinaukriworld.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sb-webdev.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "scan.computer", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "schwb.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "scif.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "scphotography.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "seestersmexicancantina.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "semillainfinita.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "semiotical.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "serverportugal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "seve7.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sgsmart.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shodanian.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shopexo.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "siika.solutions", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "singaporebrand.com.sg", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sisbensantarosa.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sjlegacy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "skf-arts.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "smallsites.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "smart-ket.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "smtchahal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "snapsh.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "softsite.cl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "soji.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "soon.lk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "soulplay.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "spfl.org.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sprayontv.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ssshh.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "starseersprophecy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "statefundca.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "statefunddirect.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stealth.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stg-0-con.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stiltnerelectric.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stuudium.link", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sukker-oaxaca.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "supercursosonline.store", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "supershrooms.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "superstone.diamonds", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sveikas.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "swoop-qa.cloud", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "syncgal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tagaytayhighlands.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "taksa-club.org.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tarahi-seo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tavoseimai.lt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tavsiyeforumu.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tcckonsult.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "teawithmum.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "technetutrecht.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tema.wiki", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "temporaris.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tenshokudo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tenshokufair.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "teogramm.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "terminalserver.com.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "teronia.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "terraneesens.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "testadministrators.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "theangelgivingtree.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "theangelgivingtree.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "theangelgivingtree.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "theatheistbook.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thebookietrials.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thedoc.eu.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thefitcareerist.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "themodernalchemist.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "therenderingmachine.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "theselfcarenook.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thesimarchitect.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "threadtrails.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tiendashuacho.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "time4writing.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "toledotrainday.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tookiweb.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "topbrunchspots.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "toph.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "training-eca.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tricountyheatingcooling.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "trypenspinning.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tsacareer.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tsakalian.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tuherbalife.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "turnosinscripcionchascomus.site", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tutima.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "twocatsinacaravan.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ucabinet.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ultimatepatrol.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "universdejeff.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "unleashyouridentity.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "updoze.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "uu939.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vagabond.film", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vanessailustracoes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "veracruzti.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "viatvperu.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "victoria.associates", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vincexpertconsulting.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vipenvia.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "visionwow.ai", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vokzalkursk.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vokzalperm.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vuohijarvisoi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vuoto.fi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vzzjoias.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wapplerbrewing.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "webmediaclick.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "webusage.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "weddingwire.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wideweb.host", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wirbsinglereview.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wisehome.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wokfilms.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "worldspirituality.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wwads.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xbros.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xcafe.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xerbisworks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xiaobai.pro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xn----7sbq4auch5b4b.xn--p1ai", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xn--6n2ao17b.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xn--c1aapkosapc.xn--80asehdb", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xn--dy-via.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xpertsunlimited.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xps-auto.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xps3dp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xpsauto.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xpsautomation.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xvaldezendocrino.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xyz.blue", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yamanami.tokyo", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yerbamatero.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yourcrypto.tax", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zamtech.co.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zenspace.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zoopix.ir", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "1001reasonstolearnspanish.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "11traders.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "186526.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "3degreedesign.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "3niu668.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "3niu99.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "4hw.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "8bitsafe.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "92ganb.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "99casinos.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "9ss6.cloud", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "a05webapp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "abatex.cl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "abellanillos.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aceofdiamondspainting.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "acephalafashion.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "adhyayanclasses.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aepx.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "agilecyber.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ainouno.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "airdropkings.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aksuplast.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alexandbonnie.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alexkushner.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alojamientos-cuba.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ambicorpenergy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "animestreamingfr.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "anthonys-landscaping.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aprizalputra.my.id", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "articole.casa", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "artworks.gd", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "as41405.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "atk-huolto.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aunto.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "autohit.ro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "autotras.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "auxessenceselfiques.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "awoau.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bakerbasements.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bamheroes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bcome.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "beauty92.com.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "beautyest.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "beestitching.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "benmedia.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bentcreekvineyards.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bestvpnservice.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "betrimus.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bgjargon.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bicicletassym.com.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bigeasygrille.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bithugo.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bka.li", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "blc.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "block-planet.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "blossomsflowerboutique.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bluerabbit.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bobbleheads.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "boizeau.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "borza.blog", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bowlidex.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "breffa.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "brickland.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bricksandmotor.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bryantluk.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "buchangroupinc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bunnyworld.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "burmeister-gmbh.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bylivetrp.no", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "c01webapp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "c01webappv.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cailoli.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "caiqueparrot.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "camarguinho.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "camarguinhokids.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "camilafloresrp.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "carcare.net.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "casa-familia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cbtl-see.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cdseditora.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chamonixcamera.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ciel.coffee", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ciph.one", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "civilcorner.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "clinicadentalayomunoz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "clinicortinascali.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cod-ggw.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cody.sh", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "coffeeciel.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "coffeeciel.com.tr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "compare-energie.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "compustore.pe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "computerscience.guide", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "condormobile.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "construademadeira.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "coomer.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "corectim.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "coronavirus-19.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "correoscorporativos.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "couchidiomas.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "covid-games.herokuapp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cryptsus.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "csgo.wiki", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "curtispope.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "curts-showcars.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "custombobbleheads.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cybeautiful.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cyklistika24.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "d-solutions.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "d-va.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "damacosmeticos.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dancesafe.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dannys.space", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "davidskinnerantiques.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dealershipdrop.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "delta-wings.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "deltaworkssecurity.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "deltaworkssecurity.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dennis-aumiller.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "detailingsp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "diamondanzali.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "digitalitglobal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "digitalsearchlab.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "docket.systems", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "documentnode.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dodotek.digital", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dominobreaker.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dookhtaniha.ir", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "downloadbestapps.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "drinkvhemp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eazydokan.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ebino.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "economyroofingco.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "edgelogs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "edibleforest.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "egh.ir", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ehmkala.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ejit.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "elhacedordemarcas.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "empleosdorita.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "enactusteesside.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "envirotecstructures.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "erogen.su", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esgfoundation.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "everythingcovid-19.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "evolucionhoy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "evonet.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "evoprint.com.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "famlefeber.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fantasiasaitian.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "farb-tabelle.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fasmaritime.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fgeiger.dnshome.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fggpay.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fixedpricemovers.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "flashcardsmobile.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "flsbanners.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "flucover.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "flurecover.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "flystar.immo", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "followboost.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fourfivecbd.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fourmaq.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "freelyplaygames.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "freerun.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ftx.digital", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gabnotes.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gamesics.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "geblitzt.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "geenoo.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gefeuert.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "genesisgrade.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gentlent.group", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gentlent.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "github.blog", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "good-time-to-be.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gopress.web.id", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gpereira.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "graffitinetwerk.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "grappes.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gregbonner.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "grimms-schuhe.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gruaskmsa.cl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "grupo-zoom.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gsa-online.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gsaauctions.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "habana.ai", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hdevent.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hearted.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hekoro.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "heliumbrno.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "herbamedicine.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hertzhz.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hesaplat.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "heyitgirl.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hibiscuscoastfinancialservices.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hockeycircles.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hostingtipps.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hx36.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ian-barker.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "iblog.pk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "iceberg.ddns.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "iclg.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ideagen-ops-sandbox.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "igry-onlayn.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "iitala.fi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "imiku.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "imransarwar.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "infcloud.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ingeniotic.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "innovatech.pe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "inshared.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "instantsystems.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "intedot.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ioanamateas.ro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "iskariot.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "it-xperts.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "itguru7.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "itreboot.co.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "itsoft.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "iuspenal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jamieb.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jasalokal.id", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jav.st", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jhtrades.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "joomlaclub.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "joshua.mn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kabuki-inc.co.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kaffeepflanze-pflege.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kanivatonga.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kardjali.bg", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kedero.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kevinperrow.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "keyserve.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kochcommunity.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kopieid.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kreidl.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kristall.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kushfest.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kushfest.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kwieben.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "laguiadelpapa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lansilesia.tf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lazzzy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ldtborovina.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lefcoaching.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "leilaelu.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lemkinlaw.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "leontic.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "letschat.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lhuilerie.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "liisauusitaloarola.fi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lirelesgens.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lojadosirmaos.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lokjagruktafoundation.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lopezmanzano.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lsv-tech.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lucacastelnuovo.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "luxembourgapartment.lu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lwis.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lynamhomeloans.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "magenta-health.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "main1.host", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "makesenseofdata.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mantalak.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "markentier.tech", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "marketingdigitalefisiente.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "maskmondelez.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "maslife365.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "maxiutov.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mbrjun.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "megawhat.energy", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "menufree.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mercadopago.cl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mercadopago.com.ar", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mercadopago.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mercadopago.com.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mercadopago.com.mx", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mercadopago.com.pe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mercadopago.com.uy", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mercadopago.com.ve", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mibeneficio.cl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "misbalances.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mksport.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ml-academy.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mnml.blog", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mobidesigns.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "moderntrailers.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "montagetravel.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "morz.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mostfamousbirthdays.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mouracloset.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mrmn.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "muellerurology.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "muntajati-om.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "myfxbook.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nadacnifondacr.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nakazato-shika.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nalipapelaria.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "namiejscu.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nangluongxanhbinhphuoc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ncksrv.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ncksrv.email", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ncksrv.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ncksrv.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ncksrv.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ncksrv.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ndev.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "necd.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nemplex.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "neo1.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "netdisk.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "netzwerk-sozialliberal.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "neurosurgeryinmexico.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nfluence.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "niinaratsula.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nikitacartes.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nillarayeshi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nksmart.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nlivestream.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nostoautomaatti.fi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "notizienelmondooggi.altervista.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nslacandelaria.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nunoprospero.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "odsylvie.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "officecode.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ofo.moe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "onedollar.fund", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "onemac.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "openid.net.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "opil.no", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "optimumcoffeesv.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "orenohatake.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ormanetrading.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ottoduarte.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "oursiteupdates.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "outerface.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ozudogru.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pachinstyle.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pasclassic.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pazzmodernist.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pensan.ge", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "peoplesrights.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "perroon.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "phony.host", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "phv-bw.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pincodehome.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "piszmak.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pixelmonworld.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "plan.in.ua", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "planeta-tierra.cl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pravlife.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "presgrp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "presgrp.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "private-relay.email", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "privatepilot.lu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "prospect1838.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "putchiconsultorias.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rahulgupta.co.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ranters.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rdmc.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "readlight.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "readydedis.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "realtechreviews.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "recipekensaku.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "recursoscristianosleinad.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "regionaalenergieloket.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "relations-business.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "remotish.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "repairtly.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rexeroofing.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rezni.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rhymesofreason.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rivals.space", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rko.guru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rogue.pw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "roguecoder.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "romantica90.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "royal939.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rsrv.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rszm.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rueckert-gymnasium-blog.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "s-mall.com.sg", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "samskaar.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sapporo-asaichi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "satoshibattles.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sauve-tes-euros.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "savonsuuntaporaus.fi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "says.lol", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "scoutbee.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "secretzone.bg", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "semtinde.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "serviciosparaconsorcio.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "servimecabrasil.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "share2act-dev.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "share2act-test.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sheepymeh.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shenming.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shevelev.design", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shirro.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shopcceputnam.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "silverfalcon.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "skyarch.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "skywalkersa.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "slowhttp.herokuapp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "smartit.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "smileback.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "smkn5smg.sch.id", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "snacdata.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "snohomishdragons.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sodermans.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "some.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "somosdefensores.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sosou.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "specificenergy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "staging-covid-games.herokuapp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stampingoriginal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stars24.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stategov.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "staygold.blog", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stlpoolattendants.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "strappazzon.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "strobel.cl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "suceveanca.ro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sugarondemand.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sugaropencloud.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sugaropencloud.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "suicide.top", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "super11.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "talenthubmpi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "teleyal.blog", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "temporalmotivation.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "terryburton.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "the-burtons.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thenova.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "theunleashedpet.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thevitpro.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thierrymazue.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thinxtream.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tianbo1088.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tianbo1998.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tiktokoff.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tiny777.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tinychen.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tommycarrauto.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "topspani.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "trackingencomendas.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "transportcomparator.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "triballi.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "triploqal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tsekhovik-agro.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ttr-home.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "uhuc.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "umlt.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "universiteplatformu.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vapezone.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vapocial.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vcz.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vendaonlinebr.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "venomxsecurity.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "verzekerdbijhema.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "viilup.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "villekautto.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vinicius.sl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "visiondigitalpe.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "visionseal.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vital-pack.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vkr2020.herokuapp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vooxia.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vros.co.id", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wakuwakustudyworld.co.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "war-requiem.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wcloud.pro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "weboperater.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "weboperater.rs", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wegivetlc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "whattheactual.nyc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wikalin.ski", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wobblyibiza.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xn--s1r71tg0o30bxm52odlvspdop4b.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yangmaopubu.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yuanandyuan.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zehka.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zhouzhi.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zuhausejobs.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zzcc.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "00000000-0000-0000-0000-000000000000.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "0x3a.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "0x6470.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "2.ag", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "22.ag", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "2makeu.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "3654.vip", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "3pif.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "533sss.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "761.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "abellagranitecountertops.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "abogadamediadora.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "abrightsolution.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "acidoascorbico.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "acuvate.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "adeloveshipping.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "adenopatia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "adesachatbottecnicowab01.azurewebsites.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "afoch.cl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aguilarsoluciones.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aimanance.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aimmail.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aksot.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alanbleiweiss.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alanina.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alexandraschmidt.coach", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alianet.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alng.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "altokep.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "amdrumors.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aminovega.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "andreamonicahug.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "angelzapien.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "antihistaminico.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "antikeo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "antoni.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aptctg.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "asana.biz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "asana.plus", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "asesoramientosolay.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ashevillemenshealth.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "asian-rugby-exchange-fest.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "asitanc.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "asm802.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "asm802.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "asoziales-netzwerk.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "astrolab.mx", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "asylinfo.no", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "atrakcjenaeventy.com.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "babylurve.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "backlotgaming.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bajarjuegos.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bandaumnikov.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "belzlongroup.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "benjaminleupold.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "besiconstruct.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bestsiteporn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "betalgroup.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "betterbusiness.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bfkkutu.kr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bharatology.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "biologo.club", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bitbroker.exchange", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "biuromowcow.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bjecard.buzz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "blackhat.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "blardiblah.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "blogtechnologiczny.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bnb.direct", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bodas.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "boehm.sh", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "booked.md", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bremermaschinenbau.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "brewit.online", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "brighterimagelab.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bsmsl.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bsmsoluciones.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bss.solutions", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bsurfcr.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "budofjoy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bugfuzz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "buscalotodo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "buzzword24.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "c2athletics.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "c3stream.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cancersintomas.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "carlingforddental.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "carnetdeconducir.club", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "catartofsweden.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "centrmrt.spb.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "checkrz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chesstempo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chnroute.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "christianyleny.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ciclodekrebs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ciclodelcarbono.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ciclohidrologico.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cinematictouch.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "clarkhowell.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cloudomation.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cloudplan.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cmrconstructions.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cms-world.co.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cnpkg.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "coderslight.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "coenzima.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "coindica.com.ve", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "collegium-musicum-bocholt.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "comprar.club", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "comviodemo.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "condictor.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "conphungtourist.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "conpulpademanzana.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "consolebros.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "consumercouncil.je", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "contralegem.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "correo.club", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cosmic-relations.co.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cottage.direct", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "covid19.govt.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cozzack.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cpucheu.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "crashbolsa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "criscond.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "csaerotherm.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cuties.chat", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cv-developpeur-web.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cyberskyline.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "d-taube.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "daoplatthanhhoa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "daycubrem.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dealbeathn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "deathcult.fun", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "debattinnlegg.no", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dela.com.ar", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "deltav.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dendi-staging.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dendisoftware.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "depedtambayan.blog", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "depedtambayan.net.ph", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "deportes.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dienmattroichonthanh.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "directmailctr.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "discordextremelist.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "docedic.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "docedic.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "docsrev-aws.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "doterrashop.ec", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "drawjar.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dreamytheatre.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dupuis.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dutchpentathlon.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dyregrave.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "earthsocialism.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eisei-iinkai.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eldiariodemof.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "elektroruoff.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "emvitals.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eod-dissemination-uat.azurewebsites.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eod-dissemination.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eosinofilos.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "est-tatsujin.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "etf2l.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eurocom.bg", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "execupharm.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "exentio.sexy", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "expand.technology", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "exyusubs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ezhub.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ezone57.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "feastofplants.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "federaljob.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "femiwiki.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ferad.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fernandezvilar.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fibune.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "findcheap.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fleeb.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "flowlytics.host", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fn-0.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "foundationrepairpro.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fprinnovaciones.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "freefinancialhelp.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "freegaypornhd.online", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "futbito.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "futbolcba.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "garrow.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "geekynutritionist.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "georgiebailey.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "getscif.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gillettechampions.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "golovabol.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "goodseed.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gordonbeeming.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gosiberia.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gpsmith.tech", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "grahamsmith.tech", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "growthlab.com.my", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gruveo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gryphzia.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "guythomasevans.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gzfc.com.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "harumi-cl.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "headfullofdynamite.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "heavymetalonline.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "heimdall-home.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hellopowerserg.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hestegrovvaren.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "higleyarts.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hiranosayuri-piano.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "histhist.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hobbslanddevelopment.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "home-page.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hourai.gg", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "huesers.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ideagenpentana.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "idowp.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "illuminaterecovery.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "immijobs.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "immobilier-swiss.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "immoe.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "inoreader.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "instaart.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "invisitone.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "iox.is", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "itaro.ee", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "itaro.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jandj.yachts", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jefcorlabs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jloh.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jmeno.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "johnmac.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "joomladeveloper.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jrulka.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "justpractice.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jwala.eu.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kadooonline.ir", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "katerinastudio.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kathrin-maren-enders.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kgky.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kidan.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kimino-school.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kinetikos.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kiseki.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kitaplus.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kreuzbergflieger.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kstasinos.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "labels.co.ke", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "laby.one", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lacarna.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lagloriadehuampani.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lajas.com.ve", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "laoudit.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "larenas.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ldbeauty.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "legowerewolf.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "leo.co.ke", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "letriolet-tignes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lightquantum.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "link.sb", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "listazakupow.com.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "littlefingersindia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "livetv.tube", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "llredac.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lolifamily.js.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lovesquirting.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lukaskollmer.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lumien.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "luxeblades.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "m-a-i-l.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "macabacus.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "machinerysource.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "magetsi.co.zw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mahmalci.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "marcillacetfils.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mariages.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "marinasmad.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "marleenjacobi.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "martinschulze.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "massdesigners.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mathiasheise.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "matrimonio.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mattmorrissound.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mayacoa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "medsanuk.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "medstatix-dev.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "megatorrenthd.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mf58.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mhcouncil.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "middle.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "midl.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "millennium-thisiswhoweare.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "millersprolandscape.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "miriamgamburd.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "missbitcoin.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mitchkiah.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mlsvallarta.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "modax.ua", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "monmiel.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "moonbyte.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "motolinesupply.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "movihut.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "msngr.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mtran.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "multimediosmonti.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "museodefutbol.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "musicwind.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "muydelgada.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "my.urown.cloud", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mybokx.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "myheartlaundry.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "myload.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mysouschef.herokuapp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mytransmissionexperts.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "myzoograd.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "natuurlijkmooi-meppel.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nekochan.blog", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "neoseo.com.ua", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "netzabfragen.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ngo-online.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nistorvictor.software", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nmcep.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nobitex.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "noktaradyo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "notteit.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "novi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nuclea.id", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nya.one", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "oboivam.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "obs.plus", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ocastrowork.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "office.urown.cloud", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "offsetservices.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "onpaws.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "open-fixture-library.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "operationtulip.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "oralb-prestazioni-odontoiatriche.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "oralbregalaoralb.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "organicseo4u.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "osaka-hero-project.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "osteopathe-voisine.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "outervision.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "oversightboard.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pachamamaproduct.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "paketverfolgung.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "paviformas.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "peelawayyourpain.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "perved.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "petitsfreresdespauvres.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "petya.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pfarrhaus-mon.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "phw.org.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "picomedia.ir", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pnp.ac.id", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pockets.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "polaxtor.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pornfreesites.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pornmad.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "porthos.com.ar", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "powerscif.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "powerserg.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "powersergfeds.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "powersergisrc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "powersergsecure.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pozitone.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "poziworld.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pradmin.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "prestatyn-scala.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "prestatynflowershow.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "prijmeni.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "printwasteminimizer.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "problemysholkama.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "producciondealimentos.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "productive-garden.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "project-scarlett.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "projectarmy.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "promospg.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "proservices-informatique.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "protrainerbrasil.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "psc.gov.ws", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pujasharma.associates", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pv-golf.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pvao.gov.ph", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "qigehl.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "quentindestombes.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "raderamig.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "radiation-oncologist.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "raniwan.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rasc.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rbn.is", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "readyscif.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "readysetscif.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "regalador.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "reinheft.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "remigius-michael.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "reviewpipe.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "richfieldsean.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "road-safety.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rodnik-pansionat.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "roishopper.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rosewebdesignstudio.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "roveridx.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rpcinmobiliaria.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rpj.life", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "russell-tech.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "s2.coach", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "safefreepornsites.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "safescif.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "safetydrivessuccess.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "samuelcoles.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sanitix.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "santandertrade.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sarahjaneredmond.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "saxobroko.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "schoffelcountry.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "scifplus.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "scifsafe.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "scorb.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "scroll-to-top-button.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sentralshop.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shakalaka.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shincastella.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shoppingjin.pk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sieliakus.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "simplylocalhosting.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sincromyl.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sitinjau.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "slabstage.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "slavblog.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "smithandellis.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "smltour.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sns.med.sa", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "snsdomain.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "solaxfaq.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "solviq.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "soykaf.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "spicystove.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sportify-design.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sportspassbremen.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "squarepocketdesign.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "starthubs.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stilus-patent.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stla.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stomwhite.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "storage-base.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stuartparsons.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stuudium.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sugarsalted.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "svse.global", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "svseglobal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "swiffertirimborsa.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sypreformas.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tangochoang.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "taroe.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "team957.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "techgarage.blog", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tenken1010.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thekokuin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thelaurelchiropractor.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "themenucard.online", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "themusicalsafari.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thewaytoyourself.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thoplam.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tiendamaquillajes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tilcra.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tinmarin.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tradeshift.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "trains.sexy", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "transdev.blog", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "transdev.club", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tridnice.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "trpl.host", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tryfrontline.cloud", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "twilo-host.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "txyz.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "typesofdogs.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ubsolutions.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "unblockedgames.live", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "up.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "uradvd.best", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "urby.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "url.kg", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "useworkshop.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "valsorey.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vapourtown.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "verso.money", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vibetribe.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "videoclases.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vietnamhairs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vinyl-digital.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "visabuddy.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vision-painting.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vpnstreamer.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vrallart.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "walla.store", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wallatienda.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "warrenhousevets.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wass.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "watchtolearn.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wdesk.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "weitweg.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "whiskey.com.my", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "whiskey.money", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "whiskey.my", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "whisky.com.my", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "whisky.money", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "whiskymy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "whiskyshop.com.my", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "whiskyshop.my", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "whmcs.xn--9dbq2a", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "winkli.ddns.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "winnersaffiliate.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wis.moe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wivcfinancialservices.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wivenhoeforum.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wngs-creative.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "womywomwoo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "woodwicker.cl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "worldfinancenews.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wpspeedking.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xn--avocai-timioara-kmf1a.ro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xn--hsers-kva.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xunmengdu.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yarowork.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yellowsource.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yescool.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yozakura.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yuth.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zegarkidlakazdego.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zotan.email", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zotan.network", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zotan.pw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "17avolemsaberlaveritat.cat", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "2q.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "2vp-an.online", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "360kuvia.fi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "360prokuvat.fi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "9to5linux.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "a3sys.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aanlynskool.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "abhijitvalluri.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "academy.city", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "acaseta.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "action1st.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "addendum.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "adkup.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "agviet88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ajvco.com.hk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alemorbel.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alexandrepedrosa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aliamex.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alltape.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alphabytes.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "amicusmed.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "amordetelas.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "anabolic.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "anasibrahim.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "andigraf.cl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "andsecure.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "anitalk.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "anthro.icu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "anthro.ltd", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aothuntees.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "apiora.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "armodobrasil.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "as41073.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "asa.moe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "asamoe.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "astrology.stream", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "atakac.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "atm.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "audiomedica.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "autoverhuur-tilburg.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "awe130.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "awedience.tv", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bait55.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bangim.co.il", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "banyaktutorial.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bargest.su", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "barronmartins.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bdsmcontrol.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "belic.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bellaireroofinginc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "benepla.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bestbudget.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "betterboards.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bhemcasa.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bighorn.co.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bigmama.travel", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bilicdn.pw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bintube.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "biocbdolio.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "blogsnote.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "brainstorm.social", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "brnrx.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bruniano.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "buckanddoe.farm", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "buckdoeand.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bydik.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "c7n.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cabazon-tu.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cajaica.pe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "californiakingsnakepet.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "camaraslima.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "camposcasares.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "canekeiros.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "canonisti.fi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "carbonholic.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cardsbymaria.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cardschat.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "carevo.id", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "carsonkoziol.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "caumont-normandie.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cbcf.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cbd-oil.ro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ccaguavivadonaciones.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cctf-m.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chacoonline.com.py", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chacraexperimental.com.py", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "charlyclearsky.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "christiangaro.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chronikdanceclub.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chshuju.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cities.mx", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "clapbacks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "clarity-online.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cleangreen.tech", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cleverdarts.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "clevyrhub.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cloudeffects.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "code.golf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "colchesterglobal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "conexionok.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "connecto.group", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "connecto.marketing", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cons.one", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "consejociudadanomx.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "consens.us.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cooltrades.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "coop.com.py", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "coronasafe.network", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cosmetology.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "creatapeak.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "crrapi.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ctendoscopy.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cuhawaii.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cyberwritersink.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "daniweb.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "datadorf.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "david-osipov.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dbnext.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "deemasfashion.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "deiamodas.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "delicatewonders.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "depedcommons.blog", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "depedcommons.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "depedcommons.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "depedcommons.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "deremedioss.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "derguns.town", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dethoi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "detroitlocksmiths.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "devenv.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "devxify.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "diennobi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "diff-speed.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "digiaika.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "digiaika.fi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "digichurch.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "digikerk.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "discrete-passion.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dlagoss.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "donewhen.email", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "donewhen.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "donewhen.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "donewhen.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "donewhen.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "donwhen.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "donwhen.email", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "donwhen.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "donwhen.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "donwhen.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "donwhen.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dosimabag.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dropsite.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "duysondang.name.vn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "echoteam.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ecostarcleaning.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ectpro.co.th", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "elad.wtf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "elahuehuete.art", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "electricbeast.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "elimperiolatino.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "elisabeth-raendel.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "emptyarcade.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "emxvn.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "encontro.online", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "entropyofdelicatewonders.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "epitafija.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "erpollo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "erysonhandel.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eslove.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "evadi.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "everydaypower.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "exarcheia.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eye-move.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fairwaynow.mortgage", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fannietremblay.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "feehla.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fernheim.com.py", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ferozes.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fightsupplies.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "findeth.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "finestinfo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "flashlightchart.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fleischkaes.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "flinny.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fnpodinajpur.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "foreverbreak.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "forevertoday.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fortsecure.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "freegovernmentcellphoneguide.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "freenome.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "frigochaco.com.py", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fundaekhaya.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fwg.sk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fwt99.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fwt999.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fwtapp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fwtewm.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fwtpic.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gaming-lenkrad-experten.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gba.ge", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "geekymansion.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "genghan.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gentlent.blog", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gentlent.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gentlent.help", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gentlent.tech", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gentlent.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gentlent.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gentlentgroup.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ggld.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gharbala.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ghyvelde.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gloryhere.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "glpreparation.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gms-records.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "goldsteingloves.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gomezhvac.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "govorenefekt.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gralhaazulcondominio.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gti.cx", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "happytestings.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hashi.la", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hassmelden.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hbomaxaustralia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hemopet.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hemp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hemsfoods.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hifiaudio.sk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hindigalaxy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hiracar.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hope21.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hopkinsmediation.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hotelfloridachaco.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "howarh.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "howtohomeschool.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hypertesto.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hypr.ee", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "i-can.center", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "iamattila.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ifederalland.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "igloopreview.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "igloosandbox.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "imhotx.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "index-of.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "infohas.ma", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "inmadesarrollos.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "inoder.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "inscribeusercontent.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "inszu.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "itexpress.cloud", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ivelop.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ivixor.space", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jaiyen.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "javocean.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jcelectronics.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jel-tech.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jobsoid.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jocata.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jsg.hk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jsjfact.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jtg-inc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "junshinkai.ed.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kadimperium.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kadmirra.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kaleylocks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kalpavriksh.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "karting-normandie.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kennedy.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kennedy.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kinderosteopathie-osteopathie.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kindredcode.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kindredcode.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kjs73.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kkc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kojima-life.co.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "konflikte-als-chance.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "konflikthaus.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "korofilms.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kosto.store", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kotaartsklan.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kra2laiz.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kratom-k.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kryptoforce.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kuraga.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "la-vraie-histoire.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "laby.link", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lacatta.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lamaturitadidaniele.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lambda-calculus.church", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "leidegoncalves.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lesultandalep.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lgam.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lit.foundation", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "liveteachers.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "logopaedie-sandkrug.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "looop.rocks", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "loukkos.ma", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lovegpl.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lovemoon.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lowcarbspark.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lpasteur.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lucidea.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lumi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "machin.email", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "maciej.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "madurasfollando.online", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "magaliff.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "magikbyte.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "maisonmere.group", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "maksatmoda.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "malcathatochen.co.il", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "maniadicane.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "manulife.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mapuut.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "marblenexus.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "margherita.cl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "marijuanamed420.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "marketfeed.news", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "martelus.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "maschine.email", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "maschinen.email", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "masconil.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mastercareplus.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "matrichelp.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "matriekhulp.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "maxwellcody.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mchollet.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mediamonitors.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "megafide.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "memola.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mentorbuk.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "metropole.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "michaelmckenney.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "michaelstoffer.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mikaknuutila.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mikaknuutila.fi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mikaknuutila.photography", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "milenkojovanov.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mineralnibani.bg", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "minetrack.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "modulkuhni.by", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mon-dolibarr.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "monidenum.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "moustream.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "muellercustombuild.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "museodefutbol.online", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "museumofautism.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "musicbow.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "musttest.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "musttest.email", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "musttest.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "musttest.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "musttest.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mylever.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mymartinbeckeropenhab.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mysteriousbeans.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mzyxsl.club", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "n-a-railways.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "n-metz.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nachbar.chat", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nalits.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nanamovies.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nanxin.live", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "natalia-shablo.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "natwest.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nautile.space", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ndaal.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nei.st", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "netpreneur.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "newburymobility.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nextcloud-server.spdns.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nieuwebroek.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nieuwebroek.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nihon-mozartaikoukai.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nocoffeetech.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nonuplebroken.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "notrero13.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "npc-ts.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "offgridbound.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "office-dolmetscher-scharnagl.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "okmaybe.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "olajcbd.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "oofishing.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "oops.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "opcod3.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "organic-cbdoil.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "oromolido.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "oroygrana.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ortanatech.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pamiers-citoyenne.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pasnyburiat.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "payalts.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pekcazip.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pentruprieteni.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "peterlajos.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pioneersenior.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "plexverzoek.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "plum.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "poezja.art", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "positivefocus.ie", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "postex.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pqd.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "principalstest.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "problempaws.ie", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "processout.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "profitimages.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "propertyupdate.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "prospa.digital", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "prostoporno.fun", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pwgenerator.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pygb.cl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "qnixon.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "quantatec.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "qwrk.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "railsideworks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rainbowbrains.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "recycledinorsett.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "recycledinorsett.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "release.monster", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "remoteroom.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "repairgeniuses.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "reviewsonlineguide.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "riku.pro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "riosoil.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "riosoil.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "riosoils.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "riosoils.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rivalsa.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rncc.mx", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "roodfruit.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "roodfruit.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rubdiavila.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "russiancms.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "s-4.host", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sabinespielberg.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "saghekin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "saigonland24h.vn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sakakun.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sarv.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sawiday.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sawiday.work", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sccoaching.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "schambereich.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "scholarships.link", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "scott.st", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "scouting-westenenk.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "security-systems.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "seeker.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "seoz.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shahidfakih.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shanteo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shopazmoon.ir", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shopforeverproducts.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shore.co.il", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shotgunstudio.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shouldtest.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shouldtest.email", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shouldtest.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shouldtest.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shouldtest.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "simpelkoken.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "simpelkoken.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "simpelkoken.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "skartecedu.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "skyblond.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "skylightipv.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sl41.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "slab.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sodelicious.recipes", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "soeasy.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sogo.com.my", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "solostocks.cl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "solostocks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "solostocks.com.ar", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "solostocks.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "solostocks.com.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "solostocks.com.mx", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "solostocks.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "solostocks.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "solostocks.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "solostocks.ma", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "solostocks.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "solostocks.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "solostocks.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "solutionmotsfleches.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "soml.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "somosti.cl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sopenguin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "spjaet.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sportllux.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "squarewave.cloud", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "standoffdrop.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "steinmetz.cloud", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "strandypink.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "suerteloteria.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "surgerylifeenhancement.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tagat.top", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "taki.sk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "taki.to", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "taqeemi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "taytaytiangge.ph", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "telemedi.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "teodw.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "teodw.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "terranovadesignbuild.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "terryoconnor.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tf2pickup.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tfsound.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thecolourcloset.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thecubepsych.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "theentropyofdelicatewonders.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thefarleys.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "theparklane-sukhumvitbearing.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thetransformingchurch.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thevoltageteam.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tifile.ir", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tisec.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "topb.vn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "totalintegratedtherapy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "toyotasp.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "transformatutrading.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tribeoftomorrow.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "triedandtruebytrista.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "trussgenius.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tryin.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ts3.ink", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tschang.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ubetoo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "unblockit.pw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "understandmaths.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "unfoldbeauty.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "uniteforrecovery.govt.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "unitefortherecovery.govt.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "untamedprints.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "us-igloopreview.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "valkyriecloud.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vanillacoder.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "venbraca.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "verstaanwiskunde.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "verygoodwebsite.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vidaxp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vincentwolsink.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vincie.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vipturismo-europa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "virtualx.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "visionacademy.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vivi.fyi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vkgpakketkorting.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vojtechpetrasek.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vokabl.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wallinvogue.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wangyp.eu.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wbookcompany.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wbsogids.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "webdesign-kall.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "webdesignzarin.ir", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "websiteproxy.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "whattyre.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "whiskersandtails.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "whiteglovemoving.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "willenberg.family", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wisemen.digital", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wisersp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "withgentlent.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wordpress-szakerto.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "work-shift.work", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "worldstyling.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wpg-verwaltungen.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "writtenandrecorded.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wuchoamoveis.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "www-fwt.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xiaodingyi.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yangrq.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yinyang.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yjdevtech.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "youran.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yukino.space", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zaimitut.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ziad87.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zlatograd.bg", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zubr.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zzops.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zzops.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zzops.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zzops.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "3sixtydutyfree.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "604windswell.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "70mpg.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "8800.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "8885asknick.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "99laptops.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aboutyou.si", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "achat-de-lead.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "adaptationplatform.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "addresstobe.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "adilgraphics.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "adutoras.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aflam4you.tv", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "afrique.buzz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "agence-initiale.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "agrecosolutions.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ahstrem.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ai.mr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aklagare.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aldyputra.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alex-weigle.shop", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alterlinks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alterlinks.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alterlinks.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alterlinks.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "altinopoliscervejaria.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alvastonauto.fi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "americanpop.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "amoraparavoce.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ancroma.ro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "apartema.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "apartema.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "apfhaiti.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "apkmody.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "apsb.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "arabakiralama.name.tr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "argo.moe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "arina.is", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "arlenitas.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "artchic.vn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "artigoagency.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "artsautomotive.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ats-autohandel.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "attcleaning.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "avclub.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "avogel-company.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "avogel.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "avogel.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "avogel.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "avogel.ie", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "avogel.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "avogel.si", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "avogelusa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "awesomeness.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bacahorror.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "balp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "banhphongtomquangtran.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "banmapvn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bartholf.nu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bb-ek.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bb-moisel.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bent-nails.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "besate.ec", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bgm.bg", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bieville-beuville.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bigcountry.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "biocbdolej.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "biocbdolja.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bitcoinlatestnewstoday.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bitcoinnewsupdates.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bjarno.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "blockexplorer.online", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "blockfi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "boostplm.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bouville.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "brownwrapper.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "buggiano.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bunbun.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bunniesoflasvegas.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "buyupstorepremium.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ca-saintdie.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cadeirasparaescritorio.ind.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cafefacil.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "camisetas4fun.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "camisetasbichopreguica.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "caribeeficiente.com.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "casanovafishtacos.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "casavlas.ro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cattsgym.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cbd181.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cbd2050.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cbdeighty.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cbdnews.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cbdtelegram.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ccnadesdecero.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cheekboss.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chick-goo-ewe-farm.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "christiamguerra.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chronocarpe.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cjr.is", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cjw.design", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "clearcomm.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cmtportal.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cntraveller.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cobbm.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cocomelody.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cocomelody.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cocomelody.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cocomelody.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "collateral360.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "colorfulcloud.eu.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "columbiaproemergencymovers.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "comerciaonline.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "conoceme.bio", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "conservationfreedivers.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "contractstore.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cosmosmkt.com.mx", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cougar-bordeaux.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "couplesapp.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cpgiiaragon.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "craftyproducts.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cresserons.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cristaleslitios.com.mx", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cronjob.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cryptoeighty.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cryptohinge.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cryptoleed.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cryptowhile.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "csis.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "csisgroup.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ctyrisinkneri.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cultrixdigital.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "currentbitcoin.news", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "currentcryptocurrency.news", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "currentcryptocurrencynews.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cursointeractivo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dallaswebsite.design", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dangeredwolf.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "danielaeichberger.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dannys.cloud", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "date-hijri.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "deadspin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dealsfromheaven.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "decorarei.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "deemasfashion.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "deemasfashion.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "deemasfashion.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dentystabirmingham.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "desanctispro.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dharma-clinic.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dice-strategy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "digimoncard.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "digivet.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "direcore.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dispemec.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dnratthee.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "donacarlota.net.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "draft.cards", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "drivehub.win", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "drrenointerior.sg", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dymovskiy.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ecocleanpower.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eggbay.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eldiedesign.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "elecpromo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "elfatih-markting.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "elmnt.store", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "emporiopurochile.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "emprendimientoweb.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "enequilibreflocoach.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "epirk.lt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "erotycznehistorie.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "espaceroseauteinturiers.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "espectrocrom.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "essentialoils.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "estampascriativas.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "etaldelune.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "etdonline.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "evolucionestudios.com.bo", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ezinternet.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "f3b.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fabfrugals.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "facebook-program.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "factsvision.sr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "faktury.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fapobyte.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fatvalley.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fbthirdpartypixel.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fbwat.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "feecreativity.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "feedthefuture.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "feitam.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fetish-x.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "filokiralama.name.tr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "finanzasydinero.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "finapi.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fivetecnologia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fixverkaufen.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "floline.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "flooddoctorva.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "flow-serv.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "foodling.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "forecastapp.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "forexnews.world", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "forexnewslive.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "forklift.name.tr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "forthenrycustomknives.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "freehomerisk.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "frikandellenmoord.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "frikandelmoord.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fxaltas.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fxperk.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fxpunch.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fxwrite.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gabe.watch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ganaderosdeceres.com.ar", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gaytubec.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "genlack.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gentlent.biz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ghgkhalsaschool.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "giddyhub.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gil.re", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gizmodo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "glamourmagazine.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gncsuplementos.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gopass-dev.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gopass.health", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gougeul.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gq-magazine.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "grabtech.vn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gradecube.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "grasengroenkunstgras.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gumbointro.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gutterbus.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "h2cclipboard.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hacktivitycon.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "half-dead.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hardies.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hathai.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "havebetterconversations.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hazardhub.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "healthbrochures.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hementaze.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "herbarex.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "herreriamauricio.com.ar", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hesabcenter.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hexapk.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "highaltitudearchery.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hob.bi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hobbypow.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hometechmtl.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "homeysnack.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hookahshop.lt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hostelxaxid.si", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hotsoft.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hrsa.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hydroxide.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hyy.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hyychat.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hyyperchat.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "icid.com.mx", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "idlemon.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "igloocommunities.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "igloodigitalworkplace.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "igloodigitalworkplace.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "igloodigitalworkplaces.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "igloopartnerportal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "illumis.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ilusionphoto.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "imageessentialsweightloss.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "imawasn-consulting.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "imexmed.com.gt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "impresadipulizia.milano.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "infernal.rs", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "infotectsecurity.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "insidetheigloo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "internet.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "intiveo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "investors.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ireta.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "iritual.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "irmo.hr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ironbarnyc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "isharryworking.today", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "istramaster.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "istramoda.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "istratehnik.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "itvia.email", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "itvia.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "itvia.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "itvia.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "iuup.menu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "izdaher.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ja-tay.sr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jalopnik.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "japaneseacupuncture.london", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "japatacado.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jarno.rocks", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "javanie.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jaylee.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jcbfshr.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jeevanpaul.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jellebuitenhuis.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jeneratorkiralama.name.tr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jezebel.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jichi.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jkuu.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jobinbennykutty.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "johngreatwood.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "joshmoulin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "joshu.am", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "juguetron.com.ec", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kabataanpartylist.com.ph", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kahane.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kazumi-clinic.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "keithwillcock.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "keramikaopava.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "keyspanish.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kientrucnamcuong.vn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kinja.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kissmateszabolcs.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kit.watch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kleincliche.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "knovator.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "koe.kr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kostenlosepornos.online", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kotaku.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "la-meute.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ladrilleraeldiamante.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lagalaxiagrafica.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lampiaoluz.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "larsi.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "las.so", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "latestbitcoinnews.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "latestbitcoinnews.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "laughingloon.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "laveriebyk.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lawyersofmissouri.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lawzava.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "leclicbazar.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lemans.com.gt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "letrissimas.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "letssolarize.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "levico.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lifehacker.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "listing-here.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "littlesk.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lloydrogerspencer.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "logay.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lojacorbuccieats.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lojamultplick.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lucasuwadi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lysel.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "macawos.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mag-led.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "magneticarrow.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "magneticarrowdev.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "malek3d.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "manchestertechservices.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "marthus.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "masterminer.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "materasocial.live", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mattdrew.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "maynails.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mchughisle.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "meatfoods.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "metrourgentcarestl.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mindspace.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "miscursosdebelleza.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "misterboddy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mit.gg", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mkws.sh", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mngfam.ddns.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mns.llc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "moderndeck.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "moneytamer.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "moscow-xiaomi.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mrtprioritet.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mrtskidkispb.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mumbairoleplay.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mundialpresentes.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "musicradar.co.il", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mustardwallet.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "myjosephine.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mypinasale.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "n8solutions.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "naif.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nakliye.name.tr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nathanphoenix.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "natsar.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "near.sh", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nemberone.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nerdnet.goip.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nesez.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "newlight.net.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nextalefieldrecording.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nicklazarov.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nihon-rosoku.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nilpointer.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nobasico.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nukleovisual.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nullbox.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nvlifeinsurance.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nyangasm.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nyangasm.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nyangasm.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ocdhub.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "onechronos.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "oomuj.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "optimale.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "oraclecode.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "oriya-hrs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "padena.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "parroquiaelcarmen.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "partsbox.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "partsbox.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "payrollhr.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "peerpressurecreative.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pijamasbichopreguica.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pirateproxy.voto", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "planned-cities.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "polifisio.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "poppylala.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pornbot.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "precisionstocks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "privatefiles.host", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "proxybay.id", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "qinh.ren", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "qlulife.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rad2share.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rase.rocks", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ravron.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rc21x.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "readable.pw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "realcanada.com.gt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "realestatesales.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "redraven.studio", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rentacar.name.tr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "replyua.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "resolvo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rgl.support", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rhysre.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rioinbox.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "riverdale.net.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rurian-gyohen.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "saint-aubin-sur-scie.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "saint-leonard.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sakiborislam.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "samanexports.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sechssiwwe.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "security.golf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "seexw.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "segurancaresidencialbh.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "semiweb.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "senditvia.email", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "senior2senior.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sentitvia.email", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shinice.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shoarq.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shoppingdascapinhas.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sintraunipricol.com.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "siongseafood.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sitestudio.com.ua", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "skedo.tech", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "skovbosburgerblog.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "slimmarkets.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "smokkelenken.no", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "smyleo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "so-buff.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "so-commerce.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "song.ski", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sound-recording.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sozialistische-gruppe.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "spb-xiaomi.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "speedsvip.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stabilization-in.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stamurai.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "starlabs.bio", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "starsub.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "staydryohio.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stemgirls.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "surgerylifeenhancement.cloud", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "switchinitiatives.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "switchinitiatives.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "switchinitiatives.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "syazli7.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "taiwan-kitchen.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "taleintwo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tasintrip.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tcdn.tech", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "teammojo.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "technopost.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thapduoc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thebusinessmasterminds.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "theinventory.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "themurrayfamily.me.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "theonion.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "theroot.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thetakeout.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thetipo01.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thinkconsultores.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "toolip.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "touchandpark.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "trabajarytrabajar.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tractor-pulling.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tradedigital.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "trakid.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "transferwise.jobs", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "trappeer.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "trollbox.fun", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "trophyshopinc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tscomputers.net.pe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tukaraokeonline.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ubereatsprinters.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ultravendas.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ulyamuhendislik.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "uniforcele.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "unitedsapiens.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "usecamisetas.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ut-jobs.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vaclavkocum.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vedshastradata.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "velocitycu.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "venturebum.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "veules-les-roses.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vfxstudy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "viera.pe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "viewpointsfromfacebook.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "villers-ecalles.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vinc.name.tr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "voetbalquizkopen.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vogue.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "voyancedanslenord.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vpsce.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vrimcas.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vuldb.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wabbel.sa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wbbauth.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wcfauth.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "webdevoo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "webforce.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "webformula.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "webpressbuilder.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "websiteurl.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wemediate.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wexfly.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "whaleapp.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "whaller.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wigwam.design", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "willmage.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "windrich-werkzeugmaschinen.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "winebrasil.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wired.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "woltauth.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wptrigone.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wscauth.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wurzelkanal.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wykop.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xn--d1acalaltdk2d.xn--p1ai", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xosh.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ysoft.cloud", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zappy.wtf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zero-skill.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zigao.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, // END OF 1-YEAR BULK HSTS ENTRIES // Only eTLD+1 domains can be submitted automatically to hstspreload.org, diff --git a/chromium/net/http/transport_security_state_unittest.cc b/chromium/net/http/transport_security_state_unittest.cc index f68e798ccf2..8131e687c03 100644 --- a/chromium/net/http/transport_security_state_unittest.cc +++ b/chromium/net/http/transport_security_state_unittest.cc @@ -17,6 +17,7 @@ #include "base/metrics/field_trial_param_associator.h" #include "base/rand_util.h" #include "base/strings/string_piece.h" +#include "base/strings/stringprintf.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/mock_entropy_provider.h" #include "base/test/scoped_feature_list.h" @@ -24,8 +25,10 @@ #include "build/build_config.h" #include "crypto/openssl_util.h" #include "crypto/sha2.h" +#include "net/base/features.h" #include "net/base/host_port_pair.h" #include "net/base/net_errors.h" +#include "net/base/network_isolation_key.h" #include "net/base/test_completion_callback.h" #include "net/cert/asn1_util.h" #include "net/cert/cert_verifier.h" @@ -35,13 +38,13 @@ #include "net/cert/x509_cert_types.h" #include "net/cert/x509_certificate.h" #include "net/extras/preload_data/decoder.h" -#include "net/http/hsts_info.h" #include "net/http/http_status_code.h" #include "net/http/http_util.h" #include "net/net_buildflags.h" #include "net/ssl/ssl_info.h" #include "net/test/cert_test_util.h" #include "net/test/test_data_directory.h" +#include "net/test/test_with_task_environment.h" #include "net/tools/huffman_trie/bit_writer.h" #include "net/tools/huffman_trie/trie/trie_bit_buffer.h" #include "testing/gmock/include/gmock/gmock.h" @@ -171,13 +174,15 @@ class MockExpectCTReporter : public TransportSecurityState::ExpectCTReporter { MockExpectCTReporter() : num_failures_(0) {} ~MockExpectCTReporter() override = default; - void OnExpectCTFailed(const HostPortPair& host_port_pair, - const GURL& report_uri, - base::Time expiration, - const X509Certificate* validated_certificate_chain, - const X509Certificate* served_certificate_chain, - const SignedCertificateTimestampAndStatusList& - signed_certificate_timestamps) override { + void OnExpectCTFailed( + const HostPortPair& host_port_pair, + const GURL& report_uri, + base::Time expiration, + const X509Certificate* validated_certificate_chain, + const X509Certificate* served_certificate_chain, + const SignedCertificateTimestampAndStatusList& + signed_certificate_timestamps, + const NetworkIsolationKey& network_isolation_key) override { num_failures_++; host_port_pair_ = host_port_pair; report_uri_ = report_uri; @@ -185,22 +190,26 @@ class MockExpectCTReporter : public TransportSecurityState::ExpectCTReporter { served_certificate_chain_ = served_certificate_chain; validated_certificate_chain_ = validated_certificate_chain; signed_certificate_timestamps_ = signed_certificate_timestamps; + network_isolation_key_ = network_isolation_key; } - const HostPortPair& host_port_pair() { return host_port_pair_; } - const GURL& report_uri() { return report_uri_; } - const base::Time& expiration() { return expiration_; } - uint32_t num_failures() { return num_failures_; } - const X509Certificate* served_certificate_chain() { + const HostPortPair& host_port_pair() const { return host_port_pair_; } + const GURL& report_uri() const { return report_uri_; } + const base::Time& expiration() const { return expiration_; } + uint32_t num_failures() const { return num_failures_; } + const X509Certificate* served_certificate_chain() const { return served_certificate_chain_; } - const X509Certificate* validated_certificate_chain() { + const X509Certificate* validated_certificate_chain() const { return validated_certificate_chain_; } - const SignedCertificateTimestampAndStatusList& - signed_certificate_timestamps() { + const SignedCertificateTimestampAndStatusList& signed_certificate_timestamps() + const { return signed_certificate_timestamps_; } + const NetworkIsolationKey& network_isolation_key() const { + return network_isolation_key_; + } private: HostPortPair host_port_pair_; @@ -210,6 +219,7 @@ class MockExpectCTReporter : public TransportSecurityState::ExpectCTReporter { const X509Certificate* served_certificate_chain_; const X509Certificate* validated_certificate_chain_; SignedCertificateTimestampAndStatusList signed_certificate_timestamps_; + NetworkIsolationKey network_isolation_key_; }; class MockRequireCTDelegate : public TransportSecurityState::RequireCTDelegate { @@ -307,12 +317,38 @@ bool operator==(const TransportSecurityState::PKPState& lhs, lhs.domain == rhs.domain && lhs.report_uri == rhs.report_uri; } +// Creates a unique new host name every time it's called. Tests should not +// depend on the exact domain names, as they may vary depending on what other +// tests have been run by the same process. Intended for Expect-CT pruning +// tests, which add a lot of domains. +std::string CreateUniqueHostName() { + static int count = 0; + return base::StringPrintf("%i.test", ++count); +} + +// As with CreateUniqueHostName(), returns a unique NetworkIsolationKey for use +// with Expect-CT prunung tests. +NetworkIsolationKey CreateUniqueNetworkIsolationKey(bool is_transient) { + if (is_transient) + return NetworkIsolationKey::CreateTransient(); + url::Origin origin = url::Origin::CreateFromNormalizedTuple( + "https", CreateUniqueHostName(), 443); + return NetworkIsolationKey(origin /* top_frame_origin */, + origin /* frame_origin */); +} + } // namespace -class TransportSecurityStateTest : public testing::Test { +class TransportSecurityStateTest : public ::testing::Test, + public WithTaskEnvironment { public: - TransportSecurityStateTest() { + TransportSecurityStateTest() + : WithTaskEnvironment( + base::test::TaskEnvironment::TimeSource::MOCK_TIME) { SetTransportSecurityStateSourceForTesting(&test_default::kHSTSSource); + // Need mocked out time for pruning tests. Don't start with a + // time of 0, as code doesn't generally expect it. + FastForwardBy(base::TimeDelta::FromDays(1)); } ~TransportSecurityStateTest() override { @@ -480,51 +516,65 @@ TEST_F(TransportSecurityStateTest, SubdomainMatches) { EXPECT_FALSE(state.ShouldUpgradeToSSL("notexample.test")); } -// Tests that a more-specific HSTS or HPKP rule overrides a less-specific rule -// with it, regardless of the includeSubDomains bit. This is a regression test -// for https://crbug.com/469957. Note this behavior does not match the spec. -// See https://crbug.com/821811. -TEST_F(TransportSecurityStateTest, SubdomainCarveout) { +// Tests that a more-specific HSTS rule without the includeSubDomains bit does +// not override a less-specific rule with includeSubDomains. Applicability is +// checked before specificity. See https://crbug.com/821811. +TEST_F(TransportSecurityStateTest, STSSubdomainNoOverride) { const GURL report_uri(kReportUri); TransportSecurityState state; const base::Time current_time(base::Time::Now()); const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000); const base::Time older = current_time - base::TimeDelta::FromSeconds(1000); - state.AddHSTS("example1.test", expiry, true); - state.AddHSTS("foo.example1.test", expiry, false); + state.AddHSTS("example.test", expiry, true); + state.AddHSTS("foo.example.test", expiry, false); - state.AddHPKP("example2.test", expiry, true, GetSampleSPKIHashes(), - report_uri); - state.AddHPKP("foo.example2.test", expiry, false, GetSampleSPKIHashes(), - report_uri); + // The example.test rule applies to the entire domain, including subdomains of + // foo.example.test. + EXPECT_TRUE(state.ShouldUpgradeToSSL("example.test")); + EXPECT_TRUE(state.ShouldUpgradeToSSL("foo.example.test")); + EXPECT_TRUE(state.ShouldUpgradeToSSL("bar.foo.example.test")); + EXPECT_TRUE(state.ShouldSSLErrorsBeFatal("bar.foo.example.test")); - EXPECT_TRUE(state.ShouldUpgradeToSSL("example1.test")); - EXPECT_TRUE(state.ShouldUpgradeToSSL("foo.example1.test")); + // Expire the foo.example.test rule. + state.AddHSTS("foo.example.test", older, false); + + // The example.test rule still applies. + EXPECT_TRUE(state.ShouldUpgradeToSSL("example.test")); + EXPECT_TRUE(state.ShouldUpgradeToSSL("foo.example.test")); + EXPECT_TRUE(state.ShouldUpgradeToSSL("bar.foo.example.test")); + EXPECT_TRUE(state.ShouldSSLErrorsBeFatal("bar.foo.example.test")); +} - // The foo.example1.test rule overrides the example1.test rule, so - // bar.foo.example1.test has no HSTS state. - EXPECT_FALSE(state.ShouldUpgradeToSSL("bar.foo.example1.test")); - EXPECT_FALSE(state.ShouldSSLErrorsBeFatal("bar.foo.example1.test")); +// Tests that a more-specific HPKP rule overrides a less-specific rule +// with it, regardless of the includeSubDomains bit. Note this behavior does not +// match HSTS. See https://crbug.com/821811. +TEST_F(TransportSecurityStateTest, PKPSubdomainCarveout) { + const GURL report_uri(kReportUri); + TransportSecurityState state; + const base::Time current_time(base::Time::Now()); + const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000); + const base::Time older = current_time - base::TimeDelta::FromSeconds(1000); - EXPECT_TRUE(state.HasPublicKeyPins("example2.test")); - EXPECT_TRUE(state.HasPublicKeyPins("foo.example2.test")); + state.AddHPKP("example.test", expiry, true, GetSampleSPKIHashes(), + report_uri); + state.AddHPKP("foo.example.test", expiry, false, GetSampleSPKIHashes(), + report_uri); + EXPECT_TRUE(state.HasPublicKeyPins("example.test")); + EXPECT_TRUE(state.HasPublicKeyPins("foo.example.test")); - // The foo.example2.test rule overrides the example1.test rule, so - // bar.foo.example2.test has no HPKP state. - EXPECT_FALSE(state.HasPublicKeyPins("bar.foo.example2.test")); - EXPECT_FALSE(state.ShouldSSLErrorsBeFatal("bar.foo.example2.test")); + // The foo.example.test rule overrides the example1.test rule, so + // bar.foo.example.test has no HPKP state. + EXPECT_FALSE(state.HasPublicKeyPins("bar.foo.example.test")); + EXPECT_FALSE(state.ShouldSSLErrorsBeFatal("bar.foo.example.test")); - // Expire the foo.example*.test rules. - state.AddHSTS("foo.example1.test", older, false); - state.AddHPKP("foo.example2.test", older, false, GetSampleSPKIHashes(), + // Expire the foo.example.test rule. + state.AddHPKP("foo.example.test", older, false, GetSampleSPKIHashes(), report_uri); - // Now the base example*.test rules apply to bar.foo.example*.test. - EXPECT_TRUE(state.ShouldUpgradeToSSL("bar.foo.example1.test")); - EXPECT_TRUE(state.ShouldSSLErrorsBeFatal("bar.foo.example1.test")); - EXPECT_TRUE(state.HasPublicKeyPins("bar.foo.example2.test")); - EXPECT_TRUE(state.ShouldSSLErrorsBeFatal("bar.foo.example2.test")); + // Now the base example.test rule applies to bar.foo.example.test. + EXPECT_TRUE(state.HasPublicKeyPins("bar.foo.example.test")); + EXPECT_TRUE(state.ShouldSSLErrorsBeFatal("bar.foo.example.test")); } TEST_F(TransportSecurityStateTest, FatalSSLErrors) { @@ -667,7 +717,7 @@ TEST_F(TransportSecurityStateTest, DynamicDomainState) { TransportSecurityState::STSState sts_state; TransportSecurityState::PKPState pkp_state; - ASSERT_TRUE(state.GetDynamicSTSState("foo.example.com", &sts_state, nullptr)); + ASSERT_TRUE(state.GetDynamicSTSState("foo.example.com", &sts_state)); ASSERT_TRUE(state.GetDynamicPKPState("foo.example.com", &pkp_state)); EXPECT_TRUE(sts_state.ShouldUpgradeToSSL()); EXPECT_TRUE(pkp_state.HasPublicKeyPins()); @@ -729,21 +779,24 @@ TEST_F(TransportSecurityStateTest, DeleteAllDynamicDataSince) { EXPECT_FALSE(state.ShouldUpgradeToSSL("example.com")); EXPECT_FALSE(state.HasPublicKeyPins("example.com")); - EXPECT_FALSE(state.GetDynamicExpectCTState("example.com", &expect_ct_state)); + EXPECT_FALSE(state.GetDynamicExpectCTState( + "example.com", NetworkIsolationKey(), &expect_ct_state)); bool include_subdomains = false; state.AddHSTS("example.com", expiry, include_subdomains); state.AddHPKP("example.com", expiry, include_subdomains, GetSampleSPKIHashes(), GURL()); - state.AddExpectCT("example.com", expiry, true, GURL()); + state.AddExpectCT("example.com", expiry, true, GURL(), NetworkIsolationKey()); state.DeleteAllDynamicDataSince(expiry, base::DoNothing()); EXPECT_TRUE(state.ShouldUpgradeToSSL("example.com")); EXPECT_TRUE(state.HasPublicKeyPins("example.com")); - EXPECT_TRUE(state.GetDynamicExpectCTState("example.com", &expect_ct_state)); + EXPECT_TRUE(state.GetDynamicExpectCTState( + "example.com", NetworkIsolationKey(), &expect_ct_state)); state.DeleteAllDynamicDataSince(older, base::DoNothing()); EXPECT_FALSE(state.ShouldUpgradeToSSL("example.com")); EXPECT_FALSE(state.HasPublicKeyPins("example.com")); - EXPECT_FALSE(state.GetDynamicExpectCTState("example.com", &expect_ct_state)); + EXPECT_FALSE(state.GetDynamicExpectCTState( + "example.com", NetworkIsolationKey(), &expect_ct_state)); // Dynamic data in |state| should be empty now. EXPECT_FALSE(TransportSecurityState::STSStateIterator(state).HasNext()); @@ -753,32 +806,48 @@ TEST_F(TransportSecurityStateTest, DeleteAllDynamicDataSince) { TEST_F(TransportSecurityStateTest, DeleteDynamicDataForHost) { base::test::ScopedFeatureList feature_list; - feature_list.InitAndEnableFeature( - TransportSecurityState::kDynamicExpectCTFeature); + feature_list.InitWithFeatures( + /* enabled_features */ + {TransportSecurityState::kDynamicExpectCTFeature, + features::kPartitionExpectCTStateByNetworkIsolationKey}, + /* disabled_features */ + {}); TransportSecurityState state; const base::Time current_time(base::Time::Now()); const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000); bool include_subdomains = false; + NetworkIsolationKey network_isolation_key = + NetworkIsolationKey::CreateTransient(); state.AddHSTS("example1.test", expiry, include_subdomains); state.AddHPKP("example1.test", expiry, include_subdomains, GetSampleSPKIHashes(), GURL()); - state.AddExpectCT("example1.test", expiry, true, GURL()); + state.AddExpectCT("example1.test", expiry, true, GURL(), + NetworkIsolationKey()); EXPECT_TRUE(state.ShouldUpgradeToSSL("example1.test")); EXPECT_FALSE(state.ShouldUpgradeToSSL("example2.test")); EXPECT_TRUE(state.HasPublicKeyPins("example1.test")); EXPECT_FALSE(state.HasPublicKeyPins("example2.test")); TransportSecurityState::ExpectCTState expect_ct_state; - EXPECT_TRUE(state.GetDynamicExpectCTState("example1.test", &expect_ct_state)); - EXPECT_FALSE( - state.GetDynamicExpectCTState("example2.test", &expect_ct_state)); + EXPECT_TRUE(state.GetDynamicExpectCTState( + "example1.test", NetworkIsolationKey(), &expect_ct_state)); + EXPECT_FALSE(state.GetDynamicExpectCTState( + "example2.test", NetworkIsolationKey(), &expect_ct_state)); + EXPECT_FALSE(state.GetDynamicExpectCTState( + "example1.test", network_isolation_key, &expect_ct_state)); + state.AddExpectCT("example1.test", expiry, true, GURL(), + network_isolation_key); + EXPECT_TRUE(state.GetDynamicExpectCTState( + "example1.test", network_isolation_key, &expect_ct_state)); EXPECT_TRUE(state.DeleteDynamicDataForHost("example1.test")); EXPECT_FALSE(state.ShouldUpgradeToSSL("example1.test")); EXPECT_FALSE(state.HasPublicKeyPins("example1.test")); - EXPECT_FALSE( - state.GetDynamicExpectCTState("example1.test", &expect_ct_state)); + EXPECT_FALSE(state.GetDynamicExpectCTState( + "example1.test", NetworkIsolationKey(), &expect_ct_state)); + EXPECT_FALSE(state.GetDynamicExpectCTState( + "example1.test", network_isolation_key, &expect_ct_state)); } TEST_F(TransportSecurityStateTest, LongNames) { @@ -790,7 +859,7 @@ TEST_F(TransportSecurityStateTest, LongNames) { TransportSecurityState::PKPState pkp_state; // Just checks that we don't hit a NOTREACHED. EXPECT_FALSE(state.GetStaticDomainState(kLongName, &sts_state, &pkp_state)); - EXPECT_FALSE(state.GetDynamicSTSState(kLongName, &sts_state, nullptr)); + EXPECT_FALSE(state.GetDynamicSTSState(kLongName, &sts_state)); EXPECT_FALSE(state.GetDynamicPKPState(kLongName, &pkp_state)); } @@ -940,7 +1009,6 @@ TEST_F(TransportSecurityStateTest, PreloadedExpectCT) { TransportSecurityState::ExpectCTState expect_ct_state; EXPECT_TRUE( GetExpectCTState(&state, kExpectCTStaticHostname, &expect_ct_state)); - EXPECT_EQ(kExpectCTStaticHostname, expect_ct_state.domain); EXPECT_EQ(GURL(kExpectCTStaticReportURI), expect_ct_state.report_uri); EXPECT_FALSE( GetExpectCTState(&state, "hsts-preloaded.test", &expect_ct_state)); @@ -967,13 +1035,15 @@ TEST_F(TransportSecurityStateTest, InvalidExpectCTHeader) { TransportSecurityStateTest::EnableStaticExpectCT(&state); MockExpectCTReporter reporter; state.SetExpectCTReporter(&reporter); - state.ProcessExpectCTHeader("", host_port, ssl_info); + state.ProcessExpectCTHeader("", host_port, ssl_info, NetworkIsolationKey()); EXPECT_EQ(0u, reporter.num_failures()); - state.ProcessExpectCTHeader("blah blah", host_port, ssl_info); + state.ProcessExpectCTHeader("blah blah", host_port, ssl_info, + NetworkIsolationKey()); EXPECT_EQ(0u, reporter.num_failures()); - state.ProcessExpectCTHeader("preload", host_port, ssl_info); + state.ProcessExpectCTHeader("preload", host_port, ssl_info, + NetworkIsolationKey()); EXPECT_EQ(1u, reporter.num_failures()); } @@ -998,11 +1068,13 @@ TEST_F(TransportSecurityStateTest, ExpectCTNonPublicRoot) { TransportSecurityStateTest::EnableStaticExpectCT(&state); MockExpectCTReporter reporter; state.SetExpectCTReporter(&reporter); - state.ProcessExpectCTHeader("preload", host_port, ssl_info); + state.ProcessExpectCTHeader("preload", host_port, ssl_info, + NetworkIsolationKey()); EXPECT_EQ(0u, reporter.num_failures()); ssl_info.is_issued_by_known_root = true; - state.ProcessExpectCTHeader("preload", host_port, ssl_info); + state.ProcessExpectCTHeader("preload", host_port, ssl_info, + NetworkIsolationKey()); EXPECT_EQ(1u, reporter.num_failures()); } @@ -1027,12 +1099,14 @@ TEST_F(TransportSecurityStateTest, ExpectCTComplianceNotAvailable) { TransportSecurityStateTest::EnableStaticExpectCT(&state); MockExpectCTReporter reporter; state.SetExpectCTReporter(&reporter); - state.ProcessExpectCTHeader("preload", host_port, ssl_info); + state.ProcessExpectCTHeader("preload", host_port, ssl_info, + NetworkIsolationKey()); EXPECT_EQ(0u, reporter.num_failures()); ssl_info.ct_policy_compliance = ct::CTPolicyCompliance::CT_POLICY_NOT_DIVERSE_SCTS; - state.ProcessExpectCTHeader("preload", host_port, ssl_info); + state.ProcessExpectCTHeader("preload", host_port, ssl_info, + NetworkIsolationKey()); EXPECT_EQ(1u, reporter.num_failures()); } @@ -1057,12 +1131,14 @@ TEST_F(TransportSecurityStateTest, ExpectCTCompliantCert) { TransportSecurityStateTest::EnableStaticExpectCT(&state); MockExpectCTReporter reporter; state.SetExpectCTReporter(&reporter); - state.ProcessExpectCTHeader("preload", host_port, ssl_info); + state.ProcessExpectCTHeader("preload", host_port, ssl_info, + NetworkIsolationKey()); EXPECT_EQ(0u, reporter.num_failures()); ssl_info.ct_policy_compliance = ct::CTPolicyCompliance::CT_POLICY_NOT_DIVERSE_SCTS; - state.ProcessExpectCTHeader("preload", host_port, ssl_info); + state.ProcessExpectCTHeader("preload", host_port, ssl_info, + NetworkIsolationKey()); EXPECT_EQ(1u, reporter.num_failures()); } @@ -1087,14 +1163,16 @@ TEST_F(TransportSecurityStateTest, PreloadedExpectCTBuildNotTimely) { TransportSecurityStateTest::EnableStaticExpectCT(&state); MockExpectCTReporter reporter; state.SetExpectCTReporter(&reporter); - state.ProcessExpectCTHeader("preload", host_port, ssl_info); + state.ProcessExpectCTHeader("preload", host_port, ssl_info, + NetworkIsolationKey()); EXPECT_EQ(0u, reporter.num_failures()); // Sanity-check that the reporter is notified if the build is timely and the // connection is not compliant. ssl_info.ct_policy_compliance = ct::CTPolicyCompliance::CT_POLICY_NOT_DIVERSE_SCTS; - state.ProcessExpectCTHeader("preload", host_port, ssl_info); + state.ProcessExpectCTHeader("preload", host_port, ssl_info, + NetworkIsolationKey()); EXPECT_EQ(1u, reporter.num_failures()); } @@ -1119,18 +1197,21 @@ TEST_F(TransportSecurityStateTest, DynamicExpectCTBuildNotTimely) { MockExpectCTReporter reporter; state.SetExpectCTReporter(&reporter); const char kHeader[] = "max-age=10, report-uri=http://report.test"; - state.ProcessExpectCTHeader(kHeader, host_port, ssl_info); + state.ProcessExpectCTHeader(kHeader, host_port, ssl_info, + NetworkIsolationKey()); // No report should have been sent and the state should not have been saved. EXPECT_EQ(0u, reporter.num_failures()); TransportSecurityState::ExpectCTState expect_ct_state; - EXPECT_FALSE(state.GetDynamicExpectCTState("example.test", &expect_ct_state)); + EXPECT_FALSE(state.GetDynamicExpectCTState( + "example.test", NetworkIsolationKey(), &expect_ct_state)); // Sanity-check that the reporter is notified if the build is timely and the // connection is not compliant. ssl_info.ct_policy_compliance = ct::CTPolicyCompliance::CT_POLICY_NOT_DIVERSE_SCTS; - state.ProcessExpectCTHeader(kHeader, host_port, ssl_info); + state.ProcessExpectCTHeader(kHeader, host_port, ssl_info, + NetworkIsolationKey()); EXPECT_EQ(1u, reporter.num_failures()); } @@ -1155,11 +1236,13 @@ TEST_F(TransportSecurityStateTest, ExpectCTNotPreloaded) { TransportSecurityStateTest::EnableStaticExpectCT(&state); MockExpectCTReporter reporter; state.SetExpectCTReporter(&reporter); - state.ProcessExpectCTHeader("preload", host_port, ssl_info); + state.ProcessExpectCTHeader("preload", host_port, ssl_info, + NetworkIsolationKey()); EXPECT_EQ(0u, reporter.num_failures()); host_port.set_host(kExpectCTStaticHostname); - state.ProcessExpectCTHeader("preload", host_port, ssl_info); + state.ProcessExpectCTHeader("preload", host_port, ssl_info, + NetworkIsolationKey()); EXPECT_EQ(1u, reporter.num_failures()); } @@ -1183,12 +1266,15 @@ TEST_F(TransportSecurityStateTest, ExpectCTReporter) { std::string(), std::string(), base::Time::Now(), ct::SCT_STATUS_INVALID_SIGNATURE, &ssl_info.signed_certificate_timestamps); + NetworkIsolationKey network_isolation_key = + NetworkIsolationKey::CreateTransient(); TransportSecurityState state; TransportSecurityStateTest::EnableStaticExpectCT(&state); MockExpectCTReporter reporter; state.SetExpectCTReporter(&reporter); - state.ProcessExpectCTHeader("preload", host_port, ssl_info); + state.ProcessExpectCTHeader("preload", host_port, ssl_info, + network_isolation_key); EXPECT_EQ(1u, reporter.num_failures()); EXPECT_EQ(host_port.host(), reporter.host_port_pair().host()); EXPECT_EQ(host_port.port(), reporter.host_port_pair().port()); @@ -1202,6 +1288,7 @@ TEST_F(TransportSecurityStateTest, ExpectCTReporter) { reporter.signed_certificate_timestamps()[0].status); EXPECT_EQ(ssl_info.signed_certificate_timestamps[0].sct, reporter.signed_certificate_timestamps()[0].sct); + EXPECT_EQ(network_isolation_key, reporter.network_isolation_key()); } // Tests that the Expect CT reporter is not notified for repeated noncompliant @@ -1229,11 +1316,13 @@ TEST_F(TransportSecurityStateTest, RepeatedExpectCTReportsForStaticExpectCT) { TransportSecurityStateTest::EnableStaticExpectCT(&state); MockExpectCTReporter reporter; state.SetExpectCTReporter(&reporter); - state.ProcessExpectCTHeader("preload", host_port, ssl_info); + state.ProcessExpectCTHeader("preload", host_port, ssl_info, + NetworkIsolationKey()); EXPECT_EQ(1u, reporter.num_failures()); // After processing a second header, the report should not be sent again. - state.ProcessExpectCTHeader("preload", host_port, ssl_info); + state.ProcessExpectCTHeader("preload", host_port, ssl_info, + NetworkIsolationKey()); EXPECT_EQ(1u, reporter.num_failures()); } @@ -1467,7 +1556,7 @@ TEST_F(TransportSecurityStateTest, RequireCTConsultsDelegate) { using CTRequirementLevel = TransportSecurityState::RequireCTDelegate::CTRequirementLevel; - // Dummy cert to use as the validate chain. The contents do not matter. + // Dummy cert to use as the validation chain. The contents do not matter. scoped_refptr<X509Certificate> cert = ImportCertFromFile(GetTestCertsDirectory(), "expired_cert.pem"); ASSERT_TRUE(cert); @@ -1486,7 +1575,8 @@ TEST_F(TransportSecurityStateTest, RequireCTConsultsDelegate) { HostPortPair("www.example.com", 443), true, hashes, cert.get(), cert.get(), SignedCertificateTimestampAndStatusList(), TransportSecurityState::ENABLE_EXPECT_CT_REPORTS, - ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS); + ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS, + NetworkIsolationKey()); MockRequireCTDelegate always_require_delegate; EXPECT_CALL(always_require_delegate, IsCTRequiredForHost(_, _, _)) @@ -1498,28 +1588,32 @@ TEST_F(TransportSecurityStateTest, RequireCTConsultsDelegate) { HostPortPair("www.example.com", 443), true, hashes, cert.get(), cert.get(), SignedCertificateTimestampAndStatusList(), TransportSecurityState::ENABLE_EXPECT_CT_REPORTS, - ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS)); + ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS, + NetworkIsolationKey())); EXPECT_EQ( TransportSecurityState::CT_REQUIREMENTS_NOT_MET, state.CheckCTRequirements( HostPortPair("www.example.com", 443), true, hashes, cert.get(), cert.get(), SignedCertificateTimestampAndStatusList(), TransportSecurityState::ENABLE_EXPECT_CT_REPORTS, - ct::CTPolicyCompliance::CT_POLICY_NOT_DIVERSE_SCTS)); + ct::CTPolicyCompliance::CT_POLICY_NOT_DIVERSE_SCTS, + NetworkIsolationKey())); EXPECT_EQ( TransportSecurityState::CT_REQUIREMENTS_MET, state.CheckCTRequirements( HostPortPair("www.example.com", 443), true, hashes, cert.get(), cert.get(), SignedCertificateTimestampAndStatusList(), TransportSecurityState::ENABLE_EXPECT_CT_REPORTS, - ct::CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS)); + ct::CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS, + NetworkIsolationKey())); EXPECT_EQ( TransportSecurityState::CT_REQUIREMENTS_MET, state.CheckCTRequirements( HostPortPair("www.example.com", 443), true, hashes, cert.get(), cert.get(), SignedCertificateTimestampAndStatusList(), TransportSecurityState::ENABLE_EXPECT_CT_REPORTS, - ct::CTPolicyCompliance::CT_POLICY_BUILD_NOT_TIMELY)); + ct::CTPolicyCompliance::CT_POLICY_BUILD_NOT_TIMELY, + NetworkIsolationKey())); state.SetRequireCTDelegate(nullptr); EXPECT_EQ( @@ -1528,7 +1622,8 @@ TEST_F(TransportSecurityStateTest, RequireCTConsultsDelegate) { HostPortPair("www.example.com", 443), true, hashes, cert.get(), cert.get(), SignedCertificateTimestampAndStatusList(), TransportSecurityState::ENABLE_EXPECT_CT_REPORTS, - ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS)); + ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS, + NetworkIsolationKey())); } // If CT is not required, then regardless of the CT state for the host, @@ -1540,7 +1635,8 @@ TEST_F(TransportSecurityStateTest, RequireCTConsultsDelegate) { HostPortPair("www.example.com", 443), true, hashes, cert.get(), cert.get(), SignedCertificateTimestampAndStatusList(), TransportSecurityState::ENABLE_EXPECT_CT_REPORTS, - ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS); + ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS, + NetworkIsolationKey()); MockRequireCTDelegate never_require_delegate; EXPECT_CALL(never_require_delegate, IsCTRequiredForHost(_, _, _)) @@ -1552,14 +1648,16 @@ TEST_F(TransportSecurityStateTest, RequireCTConsultsDelegate) { HostPortPair("www.example.com", 443), true, hashes, cert.get(), cert.get(), SignedCertificateTimestampAndStatusList(), TransportSecurityState::ENABLE_EXPECT_CT_REPORTS, - ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS)); + ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS, + NetworkIsolationKey())); EXPECT_EQ( TransportSecurityState::CT_NOT_REQUIRED, state.CheckCTRequirements( HostPortPair("www.example.com", 443), true, hashes, cert.get(), cert.get(), SignedCertificateTimestampAndStatusList(), TransportSecurityState::ENABLE_EXPECT_CT_REPORTS, - ct::CTPolicyCompliance::CT_POLICY_NOT_DIVERSE_SCTS)); + ct::CTPolicyCompliance::CT_POLICY_NOT_DIVERSE_SCTS, + NetworkIsolationKey())); state.SetRequireCTDelegate(nullptr); EXPECT_EQ( @@ -1568,7 +1666,8 @@ TEST_F(TransportSecurityStateTest, RequireCTConsultsDelegate) { HostPortPair("www.example.com", 443), true, hashes, cert.get(), cert.get(), SignedCertificateTimestampAndStatusList(), TransportSecurityState::ENABLE_EXPECT_CT_REPORTS, - ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS)); + ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS, + NetworkIsolationKey())); } // If the Delegate is in the default state, then it should return the same @@ -1580,7 +1679,8 @@ TEST_F(TransportSecurityStateTest, RequireCTConsultsDelegate) { HostPortPair("www.example.com", 443), true, hashes, cert.get(), cert.get(), SignedCertificateTimestampAndStatusList(), TransportSecurityState::ENABLE_EXPECT_CT_REPORTS, - ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS); + ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS, + NetworkIsolationKey()); MockRequireCTDelegate default_require_ct_delegate; EXPECT_CALL(default_require_ct_delegate, IsCTRequiredForHost(_, _, _)) @@ -1592,7 +1692,8 @@ TEST_F(TransportSecurityStateTest, RequireCTConsultsDelegate) { HostPortPair("www.example.com", 443), true, hashes, cert.get(), cert.get(), SignedCertificateTimestampAndStatusList(), TransportSecurityState::ENABLE_EXPECT_CT_REPORTS, - ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS)); + ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS, + NetworkIsolationKey())); state.SetRequireCTDelegate(nullptr); EXPECT_EQ( @@ -1601,7 +1702,8 @@ TEST_F(TransportSecurityStateTest, RequireCTConsultsDelegate) { HostPortPair("www.example.com", 443), true, hashes, cert.get(), cert.get(), SignedCertificateTimestampAndStatusList(), TransportSecurityState::ENABLE_EXPECT_CT_REPORTS, - ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS)); + ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS, + NetworkIsolationKey())); } } @@ -1639,7 +1741,8 @@ TEST_F(TransportSecurityStateTest, RequireCTForSymantec) { HostPortPair("www.example.com", 443), true, hashes, before_cert.get(), before_cert.get(), SignedCertificateTimestampAndStatusList(), TransportSecurityState::ENABLE_EXPECT_CT_REPORTS, - ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS)); + ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS, + NetworkIsolationKey())); // ... but certificates issued after 1 June 2016 are required to be... EXPECT_EQ( @@ -1648,28 +1751,32 @@ TEST_F(TransportSecurityStateTest, RequireCTForSymantec) { HostPortPair("www.example.com", 443), true, hashes, after_cert.get(), after_cert.get(), SignedCertificateTimestampAndStatusList(), TransportSecurityState::ENABLE_EXPECT_CT_REPORTS, - ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS)); + ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS, + NetworkIsolationKey())); EXPECT_EQ( TransportSecurityState::CT_REQUIREMENTS_NOT_MET, state.CheckCTRequirements( HostPortPair("www.example.com", 443), true, hashes, after_cert.get(), after_cert.get(), SignedCertificateTimestampAndStatusList(), TransportSecurityState::ENABLE_EXPECT_CT_REPORTS, - ct::CTPolicyCompliance::CT_POLICY_NOT_DIVERSE_SCTS)); + ct::CTPolicyCompliance::CT_POLICY_NOT_DIVERSE_SCTS, + NetworkIsolationKey())); EXPECT_EQ( TransportSecurityState::CT_REQUIREMENTS_MET, state.CheckCTRequirements( HostPortPair("www.example.com", 443), true, hashes, after_cert.get(), after_cert.get(), SignedCertificateTimestampAndStatusList(), TransportSecurityState::ENABLE_EXPECT_CT_REPORTS, - ct::CTPolicyCompliance::CT_POLICY_BUILD_NOT_TIMELY)); + ct::CTPolicyCompliance::CT_POLICY_BUILD_NOT_TIMELY, + NetworkIsolationKey())); EXPECT_EQ( TransportSecurityState::CT_REQUIREMENTS_MET, state.CheckCTRequirements( HostPortPair("www.example.com", 443), true, hashes, after_cert.get(), after_cert.get(), SignedCertificateTimestampAndStatusList(), TransportSecurityState::ENABLE_EXPECT_CT_REPORTS, - ct::CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS)); + ct::CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS, + NetworkIsolationKey())); // ... unless they were issued by an excluded intermediate. hashes.push_back(HashValue(google_hash_value)); @@ -1679,14 +1786,16 @@ TEST_F(TransportSecurityStateTest, RequireCTForSymantec) { HostPortPair("www.example.com", 443), true, hashes, before_cert.get(), before_cert.get(), SignedCertificateTimestampAndStatusList(), TransportSecurityState::ENABLE_EXPECT_CT_REPORTS, - ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS)); + ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS, + NetworkIsolationKey())); EXPECT_EQ( TransportSecurityState::CT_NOT_REQUIRED, state.CheckCTRequirements( HostPortPair("www.example.com", 443), true, hashes, after_cert.get(), after_cert.get(), SignedCertificateTimestampAndStatusList(), TransportSecurityState::ENABLE_EXPECT_CT_REPORTS, - ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS)); + ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS, + NetworkIsolationKey())); // And other certificates should remain unaffected. SHA256HashValue unrelated_hash_value = {{0x01, 0x02}}; @@ -1699,14 +1808,16 @@ TEST_F(TransportSecurityStateTest, RequireCTForSymantec) { before_cert.get(), before_cert.get(), SignedCertificateTimestampAndStatusList(), TransportSecurityState::ENABLE_EXPECT_CT_REPORTS, - ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS)); + ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS, + NetworkIsolationKey())); EXPECT_EQ(TransportSecurityState::CT_NOT_REQUIRED, state.CheckCTRequirements( HostPortPair("www.example.com", 443), true, unrelated_hashes, after_cert.get(), after_cert.get(), SignedCertificateTimestampAndStatusList(), TransportSecurityState::ENABLE_EXPECT_CT_REPORTS, - ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS)); + ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS, + NetworkIsolationKey())); } // Tests that CAs can enable CT for testing their issuance practices, prior @@ -1733,7 +1844,8 @@ TEST_F(TransportSecurityStateTest, RequireCTViaFieldTrial) { HostPortPair("www.example.com", 443), true, hashes, cert.get(), cert.get(), SignedCertificateTimestampAndStatusList(), TransportSecurityState::DISABLE_EXPECT_CT_REPORTS, - ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS)); + ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS, + NetworkIsolationKey())); // However, simulating a Field Trial in which CT is required for certificates // after 2017-12-01 should cause CT to be required for this certificate, as @@ -1753,7 +1865,8 @@ TEST_F(TransportSecurityStateTest, RequireCTViaFieldTrial) { HostPortPair("www.example.com", 443), true, hashes, cert.get(), cert.get(), SignedCertificateTimestampAndStatusList(), TransportSecurityState::DISABLE_EXPECT_CT_REPORTS, - ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS)); + ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS, + NetworkIsolationKey())); // It should succeed if it does comply with policy. EXPECT_EQ(TransportSecurityState::CT_REQUIREMENTS_MET, @@ -1761,7 +1874,8 @@ TEST_F(TransportSecurityStateTest, RequireCTViaFieldTrial) { HostPortPair("www.example.com", 443), true, hashes, cert.get(), cert.get(), SignedCertificateTimestampAndStatusList(), TransportSecurityState::DISABLE_EXPECT_CT_REPORTS, - ct::CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS)); + ct::CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS, + NetworkIsolationKey())); // It should succeed if the build is outdated. EXPECT_EQ(TransportSecurityState::CT_REQUIREMENTS_MET, @@ -1769,7 +1883,8 @@ TEST_F(TransportSecurityStateTest, RequireCTViaFieldTrial) { HostPortPair("www.example.com", 443), true, hashes, cert.get(), cert.get(), SignedCertificateTimestampAndStatusList(), TransportSecurityState::DISABLE_EXPECT_CT_REPORTS, - ct::CTPolicyCompliance::CT_POLICY_BUILD_NOT_TIMELY)); + ct::CTPolicyCompliance::CT_POLICY_BUILD_NOT_TIMELY, + NetworkIsolationKey())); // It should succeed if it was a locally-trusted CA. EXPECT_EQ(TransportSecurityState::CT_NOT_REQUIRED, @@ -1777,7 +1892,8 @@ TEST_F(TransportSecurityStateTest, RequireCTViaFieldTrial) { HostPortPair("www.example.com", 443), false, hashes, cert.get(), cert.get(), SignedCertificateTimestampAndStatusList(), TransportSecurityState::DISABLE_EXPECT_CT_REPORTS, - ct::CTPolicyCompliance::CT_POLICY_BUILD_NOT_TIMELY)); + ct::CTPolicyCompliance::CT_POLICY_BUILD_NOT_TIMELY, + NetworkIsolationKey())); } // Tests that Certificate Transparency is required for all of the Symantec @@ -1810,28 +1926,32 @@ TEST_F(TransportSecurityStateTest, RequireCTForSymantecManagedCAs) { HostPortPair("www.example.com", 443), true, hashes, before_cert.get(), before_cert.get(), SignedCertificateTimestampAndStatusList(), TransportSecurityState::ENABLE_EXPECT_CT_REPORTS, - ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS)); + ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS, + NetworkIsolationKey())); EXPECT_EQ( TransportSecurityState::CT_REQUIREMENTS_NOT_MET, state.CheckCTRequirements( HostPortPair("www.example.com", 443), true, hashes, before_cert.get(), before_cert.get(), SignedCertificateTimestampAndStatusList(), TransportSecurityState::ENABLE_EXPECT_CT_REPORTS, - ct::CTPolicyCompliance::CT_POLICY_NOT_DIVERSE_SCTS)); + ct::CTPolicyCompliance::CT_POLICY_NOT_DIVERSE_SCTS, + NetworkIsolationKey())); EXPECT_EQ( TransportSecurityState::CT_REQUIREMENTS_MET, state.CheckCTRequirements( HostPortPair("www.example.com", 443), true, hashes, before_cert.get(), before_cert.get(), SignedCertificateTimestampAndStatusList(), TransportSecurityState::ENABLE_EXPECT_CT_REPORTS, - ct::CTPolicyCompliance::CT_POLICY_BUILD_NOT_TIMELY)); + ct::CTPolicyCompliance::CT_POLICY_BUILD_NOT_TIMELY, + NetworkIsolationKey())); EXPECT_EQ( TransportSecurityState::CT_REQUIREMENTS_MET, state.CheckCTRequirements( HostPortPair("www.example.com", 443), true, hashes, before_cert.get(), before_cert.get(), SignedCertificateTimestampAndStatusList(), TransportSecurityState::ENABLE_EXPECT_CT_REPORTS, - ct::CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS)); + ct::CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS, + NetworkIsolationKey())); scoped_refptr<X509Certificate> after_cert = ImportCertFromFile(GetTestCertsDirectory(), "post_june_2016.pem"); @@ -1843,28 +1963,32 @@ TEST_F(TransportSecurityStateTest, RequireCTForSymantecManagedCAs) { HostPortPair("www.example.com", 443), true, hashes, after_cert.get(), after_cert.get(), SignedCertificateTimestampAndStatusList(), TransportSecurityState::ENABLE_EXPECT_CT_REPORTS, - ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS)); + ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS, + NetworkIsolationKey())); EXPECT_EQ( TransportSecurityState::CT_REQUIREMENTS_NOT_MET, state.CheckCTRequirements( HostPortPair("www.example.com", 443), true, hashes, after_cert.get(), after_cert.get(), SignedCertificateTimestampAndStatusList(), TransportSecurityState::ENABLE_EXPECT_CT_REPORTS, - ct::CTPolicyCompliance::CT_POLICY_NOT_DIVERSE_SCTS)); + ct::CTPolicyCompliance::CT_POLICY_NOT_DIVERSE_SCTS, + NetworkIsolationKey())); EXPECT_EQ( TransportSecurityState::CT_REQUIREMENTS_MET, state.CheckCTRequirements( HostPortPair("www.example.com", 443), true, hashes, after_cert.get(), after_cert.get(), SignedCertificateTimestampAndStatusList(), TransportSecurityState::ENABLE_EXPECT_CT_REPORTS, - ct::CTPolicyCompliance::CT_POLICY_BUILD_NOT_TIMELY)); + ct::CTPolicyCompliance::CT_POLICY_BUILD_NOT_TIMELY, + NetworkIsolationKey())); EXPECT_EQ( TransportSecurityState::CT_REQUIREMENTS_MET, state.CheckCTRequirements( HostPortPair("www.example.com", 443), true, hashes, after_cert.get(), after_cert.get(), SignedCertificateTimestampAndStatusList(), TransportSecurityState::ENABLE_EXPECT_CT_REPORTS, - ct::CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS)); + ct::CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS, + NetworkIsolationKey())); } // Tests that dynamic Expect-CT state is cleared from ClearDynamicData(). @@ -1878,14 +2002,16 @@ TEST_F(TransportSecurityStateTest, DynamicExpectCTStateCleared) { const base::Time current_time = base::Time::Now(); const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000); - state.AddExpectCT(host, expiry, true, GURL()); - EXPECT_TRUE(state.GetDynamicExpectCTState(host, &expect_ct_state)); + state.AddExpectCT(host, expiry, true, GURL(), NetworkIsolationKey()); + EXPECT_TRUE(state.GetDynamicExpectCTState(host, NetworkIsolationKey(), + &expect_ct_state)); EXPECT_TRUE(expect_ct_state.enforce); EXPECT_TRUE(expect_ct_state.report_uri.is_empty()); EXPECT_EQ(expiry, expect_ct_state.expiry); state.ClearDynamicData(); - EXPECT_FALSE(state.GetDynamicExpectCTState(host, &expect_ct_state)); + EXPECT_FALSE(state.GetDynamicExpectCTState(host, NetworkIsolationKey(), + &expect_ct_state)); } // Tests that dynamic Expect-CT state can be added and retrieved. @@ -1900,8 +2026,9 @@ TEST_F(TransportSecurityStateTest, DynamicExpectCTState) { const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000); // Test that Expect-CT state can be added and retrieved. - state.AddExpectCT(host, expiry, true, GURL()); - EXPECT_TRUE(state.GetDynamicExpectCTState(host, &expect_ct_state)); + state.AddExpectCT(host, expiry, true, GURL(), NetworkIsolationKey()); + EXPECT_TRUE(state.GetDynamicExpectCTState(host, NetworkIsolationKey(), + &expect_ct_state)); EXPECT_TRUE(expect_ct_state.enforce); EXPECT_TRUE(expect_ct_state.report_uri.is_empty()); EXPECT_EQ(expiry, expect_ct_state.expiry); @@ -1909,16 +2036,18 @@ TEST_F(TransportSecurityStateTest, DynamicExpectCTState) { // Test that Expect-CT can be updated (e.g. by changing |enforce| to false and // adding a report-uri). const GURL report_uri("https://example-report.test"); - state.AddExpectCT(host, expiry, false, report_uri); - EXPECT_TRUE(state.GetDynamicExpectCTState(host, &expect_ct_state)); + state.AddExpectCT(host, expiry, false, report_uri, NetworkIsolationKey()); + EXPECT_TRUE(state.GetDynamicExpectCTState(host, NetworkIsolationKey(), + &expect_ct_state)); EXPECT_FALSE(expect_ct_state.enforce); EXPECT_EQ(report_uri, expect_ct_state.report_uri); EXPECT_EQ(expiry, expect_ct_state.expiry); // Test that Expect-CT state is discarded when expired. state.AddExpectCT(host, current_time - base::TimeDelta::FromSeconds(1000), - true, report_uri); - EXPECT_FALSE(state.GetDynamicExpectCTState(host, &expect_ct_state)); + true, report_uri, NetworkIsolationKey()); + EXPECT_FALSE(state.GetDynamicExpectCTState(host, NetworkIsolationKey(), + &expect_ct_state)); } // Tests that the Expect-CT reporter is not notified for repeated dynamic @@ -1946,9 +2075,11 @@ TEST_F(TransportSecurityStateTest, DynamicExpectCTDeduping) { TransportSecurityState state; MockExpectCTReporter reporter; state.SetExpectCTReporter(&reporter); - state.ProcessExpectCTHeader(kHeader, HostPortPair("example.test", 443), ssl); + state.ProcessExpectCTHeader(kHeader, HostPortPair("example.test", 443), ssl, + NetworkIsolationKey()); TransportSecurityState::ExpectCTState expect_ct_state; - EXPECT_TRUE(state.GetDynamicExpectCTState("example.test", &expect_ct_state)); + EXPECT_TRUE(state.GetDynamicExpectCTState( + "example.test", NetworkIsolationKey(), &expect_ct_state)); EXPECT_EQ(GURL("http://foo.test"), expect_ct_state.report_uri); EXPECT_TRUE(expect_ct_state.enforce); EXPECT_LT(now, expect_ct_state.expiry); @@ -1963,7 +2094,8 @@ TEST_F(TransportSecurityStateTest, DynamicExpectCTDeduping) { HostPortPair("example.test", 443), true, HashValueVector(), cert1.get(), cert2.get(), sct_list, TransportSecurityState::ENABLE_EXPECT_CT_REPORTS, - ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS)); + ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS, + NetworkIsolationKey())); EXPECT_EQ(1u, reporter.num_failures()); // The second time it fails to meet CT requirements, a report should not be @@ -1973,7 +2105,8 @@ TEST_F(TransportSecurityStateTest, DynamicExpectCTDeduping) { HostPortPair("example.test", 443), true, HashValueVector(), cert1.get(), cert2.get(), sct_list, TransportSecurityState::ENABLE_EXPECT_CT_REPORTS, - ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS)); + ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS, + NetworkIsolationKey())); EXPECT_EQ(1u, reporter.num_failures()); } @@ -2002,7 +2135,8 @@ TEST_F(TransportSecurityStateTest, DynamicExpectCTCompliantConnection) { TransportSecurityState state; MockExpectCTReporter reporter; state.SetExpectCTReporter(&reporter); - state.ProcessExpectCTHeader(kHeader, HostPortPair("example.test", 443), ssl); + state.ProcessExpectCTHeader(kHeader, HostPortPair("example.test", 443), ssl, + NetworkIsolationKey()); // No report should be sent when the header was processed over a connection // that complied with CT policy. @@ -2011,7 +2145,8 @@ TEST_F(TransportSecurityStateTest, DynamicExpectCTCompliantConnection) { HostPortPair("example.test", 443), true, HashValueVector(), cert1.get(), cert2.get(), sct_list, TransportSecurityState::ENABLE_EXPECT_CT_REPORTS, - ct::CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS)); + ct::CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS, + NetworkIsolationKey())); EXPECT_EQ(0u, reporter.num_failures()); } @@ -2029,15 +2164,18 @@ TEST_F(TransportSecurityStateTest, DynamicExpectCTHeaderProcessingDeduping) { TransportSecurityState state; MockExpectCTReporter reporter; state.SetExpectCTReporter(&reporter); - state.ProcessExpectCTHeader(kHeader, HostPortPair("example.test", 443), ssl); + state.ProcessExpectCTHeader(kHeader, HostPortPair("example.test", 443), ssl, + NetworkIsolationKey()); TransportSecurityState::ExpectCTState expect_ct_state; - EXPECT_FALSE(state.GetDynamicExpectCTState("example.test", &expect_ct_state)); + EXPECT_FALSE(state.GetDynamicExpectCTState( + "example.test", NetworkIsolationKey(), &expect_ct_state)); // The first time the header was received over a connection that failed to // meet CT requirements, a report should be sent. EXPECT_EQ(1u, reporter.num_failures()); // The second time the header was received, no report should be sent. - state.ProcessExpectCTHeader(kHeader, HostPortPair("example.test", 443), ssl); + state.ProcessExpectCTHeader(kHeader, HostPortPair("example.test", 443), ssl, + NetworkIsolationKey()); EXPECT_EQ(1u, reporter.num_failures()); } @@ -2053,8 +2191,9 @@ TEST_F(TransportSecurityStateTest, DynamicExpectCTStateDisabled) { const base::Time current_time = base::Time::Now(); const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000); - state.AddExpectCT(host, expiry, true, GURL()); - EXPECT_FALSE(state.GetDynamicExpectCTState(host, &expect_ct_state)); + state.AddExpectCT(host, expiry, true, GURL(), NetworkIsolationKey()); + EXPECT_FALSE(state.GetDynamicExpectCTState(host, NetworkIsolationKey(), + &expect_ct_state)); } // Tests that dynamic Expect-CT opt-ins are processed correctly (when the @@ -2072,11 +2211,11 @@ TEST_F(TransportSecurityStateTest, DynamicExpectCT) { feature_list.InitAndDisableFeature( TransportSecurityState::kDynamicExpectCTFeature); TransportSecurityState state; - state.ProcessExpectCTHeader(kHeader, HostPortPair("example.test", 443), - ssl); + state.ProcessExpectCTHeader(kHeader, HostPortPair("example.test", 443), ssl, + NetworkIsolationKey()); TransportSecurityState::ExpectCTState expect_ct_state; - EXPECT_FALSE( - state.GetDynamicExpectCTState("example.test", &expect_ct_state)); + EXPECT_FALSE(state.GetDynamicExpectCTState( + "example.test", NetworkIsolationKey(), &expect_ct_state)); } // Now test that the header is processed when the feature is enabled. @@ -2088,11 +2227,11 @@ TEST_F(TransportSecurityStateTest, DynamicExpectCT) { TransportSecurityState state; MockExpectCTReporter reporter; state.SetExpectCTReporter(&reporter); - state.ProcessExpectCTHeader(kHeader, HostPortPair("example.test", 443), - ssl); + state.ProcessExpectCTHeader(kHeader, HostPortPair("example.test", 443), ssl, + NetworkIsolationKey()); TransportSecurityState::ExpectCTState expect_ct_state; - EXPECT_TRUE( - state.GetDynamicExpectCTState("example.test", &expect_ct_state)); + EXPECT_TRUE(state.GetDynamicExpectCTState( + "example.test", NetworkIsolationKey(), &expect_ct_state)); EXPECT_EQ(GURL("http://foo.test"), expect_ct_state.report_uri); EXPECT_TRUE(expect_ct_state.enforce); EXPECT_LT(now, expect_ct_state.expiry); @@ -2115,9 +2254,11 @@ TEST_F(TransportSecurityStateTest, DynamicExpectCTPrivateRoot) { TransportSecurityState state; MockExpectCTReporter reporter; state.SetExpectCTReporter(&reporter); - state.ProcessExpectCTHeader(kHeader, HostPortPair("example.test", 443), ssl); + state.ProcessExpectCTHeader(kHeader, HostPortPair("example.test", 443), ssl, + NetworkIsolationKey()); TransportSecurityState::ExpectCTState expect_ct_state; - EXPECT_FALSE(state.GetDynamicExpectCTState("example.test", &expect_ct_state)); + EXPECT_FALSE(state.GetDynamicExpectCTState( + "example.test", NetworkIsolationKey(), &expect_ct_state)); EXPECT_EQ(0u, reporter.num_failures()); } @@ -2145,9 +2286,11 @@ TEST_F(TransportSecurityStateTest, DynamicExpectCTNoComplianceDetails) { TransportSecurityState state; MockExpectCTReporter reporter; state.SetExpectCTReporter(&reporter); - state.ProcessExpectCTHeader(kHeader, HostPortPair("example.test", 443), ssl); + state.ProcessExpectCTHeader(kHeader, HostPortPair("example.test", 443), ssl, + NetworkIsolationKey()); TransportSecurityState::ExpectCTState expect_ct_state; - EXPECT_FALSE(state.GetDynamicExpectCTState("example.test", &expect_ct_state)); + EXPECT_FALSE(state.GetDynamicExpectCTState( + "example.test", NetworkIsolationKey(), &expect_ct_state)); EXPECT_EQ(0u, reporter.num_failures()); } @@ -2174,15 +2317,19 @@ TEST_F(TransportSecurityStateTest, ct::SCT_STATUS_INVALID_SIGNATURE, &ssl.signed_certificate_timestamps); + NetworkIsolationKey network_isolation_key = + NetworkIsolationKey::CreateTransient(); base::test::ScopedFeatureList feature_list; feature_list.InitAndEnableFeature( TransportSecurityState::kDynamicExpectCTFeature); TransportSecurityState state; MockExpectCTReporter reporter; state.SetExpectCTReporter(&reporter); - state.ProcessExpectCTHeader(kHeader, HostPortPair("example.test", 443), ssl); + state.ProcessExpectCTHeader(kHeader, HostPortPair("example.test", 443), ssl, + network_isolation_key); TransportSecurityState::ExpectCTState expect_ct_state; - EXPECT_FALSE(state.GetDynamicExpectCTState("example.test", &expect_ct_state)); + EXPECT_FALSE(state.GetDynamicExpectCTState( + "example.test", NetworkIsolationKey(), &expect_ct_state)); EXPECT_EQ(1u, reporter.num_failures()); EXPECT_EQ("example.test", reporter.host_port_pair().host()); EXPECT_TRUE(reporter.expiration().is_null()); @@ -2194,6 +2341,7 @@ TEST_F(TransportSecurityStateTest, reporter.signed_certificate_timestamps()[0].status); EXPECT_EQ(ssl.signed_certificate_timestamps[0].sct, reporter.signed_certificate_timestamps()[0].sct); + EXPECT_EQ(network_isolation_key, reporter.network_isolation_key()); } // Tests that CheckCTRequirements() returns the correct response if a connection @@ -2212,6 +2360,8 @@ TEST_F(TransportSecurityStateTest, CheckCTRequirementsWithExpectCT) { std::string(), std::string(), base::Time::Now(), ct::SCT_STATUS_INVALID_SIGNATURE, &sct_list); + NetworkIsolationKey network_isolation_key = + NetworkIsolationKey::CreateTransient(); base::test::ScopedFeatureList feature_list; feature_list.InitAndEnableFeature( TransportSecurityState::kDynamicExpectCTFeature); @@ -2220,11 +2370,11 @@ TEST_F(TransportSecurityStateTest, CheckCTRequirementsWithExpectCT) { MockExpectCTReporter reporter; state.SetExpectCTReporter(&reporter); state.AddExpectCT("example.test", expiry, true /* enforce */, - GURL("https://example-report.test")); + GURL("https://example-report.test"), network_isolation_key); state.AddExpectCT("example-report-only.test", expiry, false /* enforce */, - GURL("https://example-report.test")); + GURL("https://example-report.test"), network_isolation_key); state.AddExpectCT("example-enforce-only.test", expiry, true /* enforce */, - GURL()); + GURL(), network_isolation_key); // Test that a connection to an unrelated host is not affected. EXPECT_EQ(TransportSecurityState::CT_NOT_REQUIRED, @@ -2232,13 +2382,15 @@ TEST_F(TransportSecurityStateTest, CheckCTRequirementsWithExpectCT) { HostPortPair("example2.test", 443), true, HashValueVector(), cert1.get(), cert2.get(), sct_list, TransportSecurityState::ENABLE_EXPECT_CT_REPORTS, - ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS)); + ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS, + network_isolation_key)); EXPECT_EQ(TransportSecurityState::CT_NOT_REQUIRED, state.CheckCTRequirements( HostPortPair("example2.test", 443), true, HashValueVector(), cert1.get(), cert2.get(), sct_list, TransportSecurityState::ENABLE_EXPECT_CT_REPORTS, - ct::CTPolicyCompliance::CT_POLICY_NOT_DIVERSE_SCTS)); + ct::CTPolicyCompliance::CT_POLICY_NOT_DIVERSE_SCTS, + network_isolation_key)); EXPECT_EQ(0u, reporter.num_failures()); // A connection to an Expect-CT host should be closed and reported. @@ -2247,7 +2399,8 @@ TEST_F(TransportSecurityStateTest, CheckCTRequirementsWithExpectCT) { HostPortPair("example.test", 443), true, HashValueVector(), cert1.get(), cert2.get(), sct_list, TransportSecurityState::ENABLE_EXPECT_CT_REPORTS, - ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS)); + ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS, + network_isolation_key)); EXPECT_EQ(1u, reporter.num_failures()); EXPECT_EQ("example.test", reporter.host_port_pair().host()); EXPECT_EQ(443, reporter.host_port_pair().port()); @@ -2258,6 +2411,7 @@ TEST_F(TransportSecurityStateTest, CheckCTRequirementsWithExpectCT) { EXPECT_EQ(sct_list[0].status, reporter.signed_certificate_timestamps()[0].status); EXPECT_EQ(sct_list[0].sct, reporter.signed_certificate_timestamps()[0].sct); + EXPECT_EQ(network_isolation_key, reporter.network_isolation_key()); // A compliant connection to an Expect-CT host should not be closed or // reported. @@ -2266,14 +2420,16 @@ TEST_F(TransportSecurityStateTest, CheckCTRequirementsWithExpectCT) { HostPortPair("example.test", 443), true, HashValueVector(), cert1.get(), cert2.get(), sct_list, TransportSecurityState::ENABLE_EXPECT_CT_REPORTS, - ct::CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS)); + ct::CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS, + network_isolation_key)); EXPECT_EQ(1u, reporter.num_failures()); EXPECT_EQ(TransportSecurityState::CT_REQUIREMENTS_MET, state.CheckCTRequirements( HostPortPair("example.test", 443), true, HashValueVector(), cert1.get(), cert2.get(), sct_list, TransportSecurityState::ENABLE_EXPECT_CT_REPORTS, - ct::CTPolicyCompliance::CT_POLICY_BUILD_NOT_TIMELY)); + ct::CTPolicyCompliance::CT_POLICY_BUILD_NOT_TIMELY, + network_isolation_key)); EXPECT_EQ(1u, reporter.num_failures()); // A connection to a report-only host should be reported only. @@ -2282,7 +2438,8 @@ TEST_F(TransportSecurityStateTest, CheckCTRequirementsWithExpectCT) { HostPortPair("example-report-only.test", 443), true, HashValueVector(), cert1.get(), cert2.get(), sct_list, TransportSecurityState::ENABLE_EXPECT_CT_REPORTS, - ct::CTPolicyCompliance::CT_POLICY_NOT_DIVERSE_SCTS)); + ct::CTPolicyCompliance::CT_POLICY_NOT_DIVERSE_SCTS, + network_isolation_key)); EXPECT_EQ(2u, reporter.num_failures()); EXPECT_EQ("example-report-only.test", reporter.host_port_pair().host()); EXPECT_EQ(443, reporter.host_port_pair().port()); @@ -2292,6 +2449,7 @@ TEST_F(TransportSecurityStateTest, CheckCTRequirementsWithExpectCT) { EXPECT_EQ(sct_list[0].status, reporter.signed_certificate_timestamps()[0].status); EXPECT_EQ(sct_list[0].sct, reporter.signed_certificate_timestamps()[0].sct); + EXPECT_EQ(network_isolation_key, reporter.network_isolation_key()); // A connection to an enforce-only host should be closed but not reported. EXPECT_EQ(TransportSecurityState::CT_REQUIREMENTS_NOT_MET, @@ -2299,7 +2457,8 @@ TEST_F(TransportSecurityStateTest, CheckCTRequirementsWithExpectCT) { HostPortPair("example-enforce-only.test", 443), true, HashValueVector(), cert1.get(), cert2.get(), sct_list, TransportSecurityState::ENABLE_EXPECT_CT_REPORTS, - ct::CTPolicyCompliance::CT_POLICY_NOT_DIVERSE_SCTS)); + ct::CTPolicyCompliance::CT_POLICY_NOT_DIVERSE_SCTS, + network_isolation_key)); EXPECT_EQ(2u, reporter.num_failures()); // A connection with a private root should be neither enforced nor reported. @@ -2308,7 +2467,8 @@ TEST_F(TransportSecurityStateTest, CheckCTRequirementsWithExpectCT) { HostPortPair("example.test", 443), false, HashValueVector(), cert1.get(), cert2.get(), sct_list, TransportSecurityState::ENABLE_EXPECT_CT_REPORTS, - ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS)); + ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS, + network_isolation_key)); EXPECT_EQ(2u, reporter.num_failures()); // A connection with DISABLE_EXPECT_CT_REPORTS should not send a report. @@ -2317,7 +2477,8 @@ TEST_F(TransportSecurityStateTest, CheckCTRequirementsWithExpectCT) { HostPortPair("example.test", 443), true, HashValueVector(), cert1.get(), cert2.get(), sct_list, TransportSecurityState::DISABLE_EXPECT_CT_REPORTS, - ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS)); + ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS, + network_isolation_key)); EXPECT_EQ(2u, reporter.num_failures()); } @@ -2341,6 +2502,8 @@ TEST_F(TransportSecurityStateTest, CheckCTRequirementsWithExpectCTAndDelegate) { MakeTestSCTAndStatus(ct::SignedCertificateTimestamp::SCT_EMBEDDED, "test_log", std::string(), std::string(), base::Time::Now(), ct::SCT_STATUS_INVALID_SIGNATURE, &sct_list); + NetworkIsolationKey network_isolation_key = + NetworkIsolationKey::CreateTransient(); base::test::ScopedFeatureList feature_list; feature_list.InitAndEnableFeature( @@ -2350,7 +2513,7 @@ TEST_F(TransportSecurityStateTest, CheckCTRequirementsWithExpectCTAndDelegate) { MockExpectCTReporter reporter; state.SetExpectCTReporter(&reporter); state.AddExpectCT("example.test", expiry, false /* enforce */, - GURL("https://example-report.test")); + GURL("https://example-report.test"), network_isolation_key); // A connection to an Expect-CT host, which also requires CT by the delegate, // should be closed and reported. @@ -2363,7 +2526,8 @@ TEST_F(TransportSecurityStateTest, CheckCTRequirementsWithExpectCTAndDelegate) { HostPortPair("example.test", 443), true, HashValueVector(), cert1.get(), cert2.get(), sct_list, TransportSecurityState::ENABLE_EXPECT_CT_REPORTS, - ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS)); + ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS, + network_isolation_key)); EXPECT_EQ(1u, reporter.num_failures()); EXPECT_EQ("example.test", reporter.host_port_pair().host()); EXPECT_EQ(443, reporter.host_port_pair().port()); @@ -2374,6 +2538,7 @@ TEST_F(TransportSecurityStateTest, CheckCTRequirementsWithExpectCTAndDelegate) { EXPECT_EQ(sct_list[0].status, reporter.signed_certificate_timestamps()[0].status); EXPECT_EQ(sct_list[0].sct, reporter.signed_certificate_timestamps()[0].sct); + EXPECT_EQ(network_isolation_key, reporter.network_isolation_key()); } // Tests that for a host that explicitly disabled CT by delegate and is also @@ -2397,6 +2562,8 @@ TEST_F(TransportSecurityStateTest, MakeTestSCTAndStatus(ct::SignedCertificateTimestamp::SCT_EMBEDDED, "test_log", std::string(), std::string(), base::Time::Now(), ct::SCT_STATUS_INVALID_SIGNATURE, &sct_list); + NetworkIsolationKey network_isolation_key = + NetworkIsolationKey::CreateTransient(); base::test::ScopedFeatureList feature_list; feature_list.InitAndEnableFeature( @@ -2406,7 +2573,7 @@ TEST_F(TransportSecurityStateTest, MockExpectCTReporter reporter; state.SetExpectCTReporter(&reporter); state.AddExpectCT("example.test", expiry, false /* enforce */, - GURL("https://example-report.test")); + GURL("https://example-report.test"), network_isolation_key); // A connection to an Expect-CT host, which is exempted from the CT // requirements by the delegate, should be reported but not closed. @@ -2419,7 +2586,8 @@ TEST_F(TransportSecurityStateTest, HostPortPair("example.test", 443), true, HashValueVector(), cert1.get(), cert2.get(), sct_list, TransportSecurityState::ENABLE_EXPECT_CT_REPORTS, - ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS)); + ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS, + network_isolation_key)); EXPECT_EQ(1u, reporter.num_failures()); EXPECT_EQ("example.test", reporter.host_port_pair().host()); EXPECT_EQ(443, reporter.host_port_pair().port()); @@ -2430,6 +2598,7 @@ TEST_F(TransportSecurityStateTest, EXPECT_EQ(sct_list[0].status, reporter.signed_certificate_timestamps()[0].status); EXPECT_EQ(sct_list[0].sct, reporter.signed_certificate_timestamps()[0].sct); + EXPECT_EQ(network_isolation_key, reporter.network_isolation_key()); } // Tests that the dynamic Expect-CT UMA histogram is recorded correctly. @@ -2452,8 +2621,8 @@ TEST_F(TransportSecurityStateTest, DynamicExpectCTUMA) { TransportSecurityState state; MockExpectCTReporter reporter; state.SetExpectCTReporter(&reporter); - state.ProcessExpectCTHeader(kHeader, HostPortPair("example.test", 443), - ssl); + state.ProcessExpectCTHeader(kHeader, HostPortPair("example.test", 443), ssl, + NetworkIsolationKey()); histograms.ExpectTotalCount(kHistogramName, 1); histograms.ExpectBucketCount(kHistogramName, true, 1); } @@ -2466,67 +2635,13 @@ TEST_F(TransportSecurityStateTest, DynamicExpectCTUMA) { TransportSecurityState state; MockExpectCTReporter reporter; state.SetExpectCTReporter(&reporter); - state.ProcessExpectCTHeader(kHeader, HostPortPair("example.test", 443), - ssl); + state.ProcessExpectCTHeader(kHeader, HostPortPair("example.test", 443), ssl, + NetworkIsolationKey()); histograms.ExpectTotalCount(kHistogramName, 1); histograms.ExpectBucketCount(kHistogramName, false, 1); } } -// Tests the Net.HstsInfo histogram is recorded correctly. See -// https://crbug.com/821811. -TEST_F(TransportSecurityStateTest, HstsInfoHistogram) { - const base::Time current_time(base::Time::Now()); - const base::Time expiry = current_time + base::TimeDelta::FromDays(1000); - - TransportSecurityState state; - // a.test is not on the static list, so the dynamic set applies. - state.AddHSTS("a.test", expiry, /*include_subdomains=*/true); - state.AddHSTS("a.a.test", expiry, /*include_subdomains=*/false); - // Also test the interaction with the HSTS preload list. - state.AddHSTS("a.include-subdomains-hsts-preloaded.test", expiry, - /*include_subdomains=*/true); - state.AddHSTS("a.a.include-subdomains-hsts-preloaded.test", expiry, - /*include_subdomains=*/false); - - const struct { - const char* host; - HstsInfo expected; - } kTests[] = { - // HSTS was not enabled. - {"b.test", HstsInfo::kDisabled}, - // HSTS was enabled via the header. - {"a.test", HstsInfo::kEnabled}, - {"a.a.test", HstsInfo::kEnabled}, - // HSTS was enabled via the preload list. - {"b.include-subdomains-hsts-preloaded.test", HstsInfo::kEnabled}, - // HSTS should have been enabled but was not due to spec non-compliance. - {"a.a.a.test", HstsInfo::kDynamicIncorrectlyMasked}, - // Spec non-compliance was masked by the preload list. - {"a.a.a.include-subdomains-hsts-preloaded.test", - HstsInfo::kDynamicIncorrectlyMaskedButMatchedStatic}, - }; - - for (const auto& test : kTests) { - SCOPED_TRACE(test.host); - bool enabled = - test.expected == HstsInfo::kEnabled || - test.expected == HstsInfo::kDynamicIncorrectlyMaskedButMatchedStatic; - { - base::HistogramTester histograms; - EXPECT_EQ(enabled, state.ShouldUpgradeToSSL(test.host)); - histograms.ExpectTotalCount("Net.HstsInfo", 1); - histograms.ExpectBucketCount("Net.HstsInfo", test.expected, 1); - } - { - base::HistogramTester histograms; - EXPECT_EQ(enabled, state.ShouldSSLErrorsBeFatal(test.host)); - histograms.ExpectTotalCount("Net.HstsInfo", 1); - histograms.ExpectBucketCount("Net.HstsInfo", test.expected, 1); - } - } -} - #if BUILDFLAG(INCLUDE_TRANSPORT_SECURITY_STATE_PRELOAD_LIST) const char kSubdomain[] = "foo.example.test"; @@ -3274,4 +3389,506 @@ TEST_F(TransportSecurityStateTest, DecodeSizeFour) { #endif // BUILDFLAG(INCLUDE_TRANSPORT_SECURITY_STATE_PRELOAD_LIST) +TEST_F(TransportSecurityStateTest, + PartitionExpectCTStateByNetworkIsolationKey) { + const char kDomain[] = "example.test"; + HostPortPair host_port_pair(kDomain, 443); + + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature( + TransportSecurityState::kDynamicExpectCTFeature); + + const base::Time expiry = + base::Time::Now() + base::TimeDelta::FromSeconds(1000); + + // Dummy cert to use as the validation chain. The contents do not matter. + scoped_refptr<X509Certificate> cert = + ImportCertFromFile(GetTestCertsDirectory(), "expired_cert.pem"); + ASSERT_TRUE(cert); + HashValueVector hashes; + hashes.push_back( + HashValue(X509Certificate::CalculateFingerprint256(cert->cert_buffer()))); + + // An ExpectCT entry is set using network_isolation_key1, and then accessed + // using both keys. It should only be accessible using the other key when + // kPartitionExpectCTStateByNetworkIsolationKey is disabled. + NetworkIsolationKey network_isolation_key1 = + NetworkIsolationKey::CreateTransient(); + NetworkIsolationKey network_isolation_key2 = + NetworkIsolationKey::CreateTransient(); + + for (bool partition_expect_ct_state : {false, true}) { + base::test::ScopedFeatureList feature_list2; + if (partition_expect_ct_state) { + feature_list2.InitAndEnableFeature( + features::kPartitionExpectCTStateByNetworkIsolationKey); + } else { + feature_list2.InitAndDisableFeature( + features::kPartitionExpectCTStateByNetworkIsolationKey); + } + + // Add Expect-CT entry. + TransportSecurityState state; + state.AddExpectCT(kDomain, expiry, true, GURL(), network_isolation_key1); + TransportSecurityState::ExpectCTState expect_ct_state; + EXPECT_TRUE(state.GetDynamicExpectCTState(kDomain, network_isolation_key1, + &expect_ct_state)); + + // The Expect-CT entry should only be respected with + // |network_isolation_key2| when + // kPartitionExpectCTStateByNetworkIsolationKey is disabled. + EXPECT_EQ(!partition_expect_ct_state, + state.GetDynamicExpectCTState(kDomain, network_isolation_key2, + &expect_ct_state)); + EXPECT_EQ(TransportSecurityState::CT_REQUIREMENTS_NOT_MET, + state.CheckCTRequirements( + host_port_pair, true, hashes, cert.get(), cert.get(), + SignedCertificateTimestampAndStatusList(), + TransportSecurityState::ENABLE_EXPECT_CT_REPORTS, + ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS, + network_isolation_key1)); + EXPECT_EQ(!partition_expect_ct_state, + TransportSecurityState::CT_REQUIREMENTS_NOT_MET == + state.CheckCTRequirements( + host_port_pair, true, hashes, cert.get(), cert.get(), + SignedCertificateTimestampAndStatusList(), + TransportSecurityState::ENABLE_EXPECT_CT_REPORTS, + ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS, + network_isolation_key2)); + + // An Expect-CT header with |network_isolation_key2| should only overwrite + // the entry when |partition_expect_ct_state| is false. + SSLInfo ssl_info; + ssl_info.ct_policy_compliance = + ct::CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS; + ssl_info.is_issued_by_known_root = true; + MockExpectCTReporter reporter; + state.SetExpectCTReporter(&reporter); + const char kHeader[] = "max-age=0"; + state.ProcessExpectCTHeader(kHeader, host_port_pair, ssl_info, + network_isolation_key2); + EXPECT_EQ(partition_expect_ct_state, + state.GetDynamicExpectCTState(kDomain, network_isolation_key1, + &expect_ct_state)); + + // An Expect-CT header with |network_isolation_key1| should always overwrite + // the added entry. + state.ProcessExpectCTHeader(kHeader, host_port_pair, ssl_info, + network_isolation_key1); + EXPECT_FALSE(state.GetDynamicExpectCTState(kDomain, network_isolation_key1, + &expect_ct_state)); + } +} + +// Tests the eviction logic and priority of pruning resources, before applying +// the per-NetworkIsolationKey limit. +TEST_F(TransportSecurityStateTest, PruneExpectCTPriority) { + const GURL report_uri(kReportUri); + base::test::ScopedFeatureList feature_list; + feature_list.InitWithFeatures( + // enabled_features + {TransportSecurityState::kDynamicExpectCTFeature, + features::kPartitionExpectCTStateByNetworkIsolationKey}, + // disabled_features + {}); + + // Each iteration adds two groups of |kGroupSize| entries, with specified + // parameters, and then enough entries are added for a third group to trigger + // pruning. |kGroupSize| is chosen so that exactly all the entries in the + // first group or the second will typically be pruned. Note that group 1 is + // always added before group 2. + const size_t kGroupSize = + features::kExpectCTPruneMax.Get() - features::kExpectCTPruneMin.Get(); + // This test requires |2 * kGroupSize| to be less than |kExpectCTPruneMax|. + ASSERT_LT(2 * kGroupSize, + static_cast<size_t>(features::kExpectCTPruneMax.Get())); + const size_t kThirdGroupSize = + features::kExpectCTPruneMax.Get() - 2 * kGroupSize; + + // Specifies where the entries of no groups or of only the first group are old + // enough to be pruned. + enum class GroupsOldEnoughToBePruned { + kNone, + kFirstGroupOnly, + kFirstAndSecondGroups, + }; + + const struct TestCase { + bool first_group_has_transient_nik; + bool second_group_has_transient_nik; + bool first_group_has_enforce; + bool second_group_has_enforce; + bool first_group_is_expired; + bool second_group_is_expired; + GroupsOldEnoughToBePruned groups_old_enough_to_be_pruned; + bool expect_first_group_retained; + bool expect_second_group_retained; + } kTestCases[] = { + // No entries are prunable, so will exceed features::kExpectCTPruneMax. + { + false /* first_group_has_transient_nik */, + false /* second_group_has_transient_nik */, + true /* bool first_group_has_enforce */, + true /* bool second_group_has_enforce */, + false /* first_group_is_expired */, + false /* second_group_is_expired */, GroupsOldEnoughToBePruned::kNone, + true /* expect_first_group_retained */, + true /* expect_second_group_retained */ + }, + + // Only second group is prunable, so it should end up empty. + { + false /* first_group_has_transient_nik */, + false /* second_group_has_transient_nik */, + true /* bool first_group_has_enforce */, + false /* bool second_group_has_enforce */, + false /* first_group_is_expired */, + false /* second_group_is_expired */, GroupsOldEnoughToBePruned::kNone, + true /* expect_first_group_retained */, + false /* expect_second_group_retained */ + }, + { + false /* first_group_has_transient_nik */, + true /* second_group_has_transient_nik */, + true /* bool first_group_has_enforce */, + true /* bool second_group_has_enforce */, + false /* first_group_is_expired */, + false /* second_group_is_expired */, GroupsOldEnoughToBePruned::kNone, + true /* expect_first_group_retained */, + false /* expect_second_group_retained */ + }, + + // Only first group is prunable, so only it should be evicted. + { + false /* first_group_has_transient_nik */, + false /* second_group_has_transient_nik */, + false /* bool first_group_has_enforce */, + true /* bool second_group_has_enforce */, + false /* first_group_is_expired */, + false /* second_group_is_expired */, GroupsOldEnoughToBePruned::kNone, + false /* expect_first_group_retained */, + true /* expect_second_group_retained */ + }, + { + false /* first_group_has_transient_nik */, + false /* second_group_has_transient_nik */, + true /* bool first_group_has_enforce */, + true /* bool second_group_has_enforce */, + false /* first_group_is_expired */, + false /* second_group_is_expired */, + GroupsOldEnoughToBePruned::kFirstGroupOnly, + false /* expect_first_group_retained */, + true /* expect_second_group_retained */ + }, + + // Both groups are prunable for the same reason, but group 1 is older + // (since group 1 is added first). + { + true /* first_group_has_transient_nik */, + true /* second_group_has_transient_nik */, + true /* bool first_group_has_enforce */, + true /* bool second_group_has_enforce */, + false /* first_group_is_expired */, + false /* second_group_is_expired */, GroupsOldEnoughToBePruned::kNone, + false /* expect_first_group_retained */, + true /* expect_second_group_retained */ + }, + { + false /* first_group_has_transient_nik */, + false /* second_group_has_transient_nik */, + true /* bool first_group_has_enforce */, + true /* bool second_group_has_enforce */, + false /* first_group_is_expired */, + false /* second_group_is_expired */, + GroupsOldEnoughToBePruned::kFirstAndSecondGroups, + false /* expect_first_group_retained */, + true /* expect_second_group_retained */ + }, + + // First group has enforce not set, second uses a transient NIK. First + // should take priority. + { + false /* first_group_has_transient_nik */, + true /* second_group_has_transient_nik */, + false /* bool first_group_has_enforce */, + true /* bool second_group_has_enforce */, + false /* first_group_is_expired */, + false /* second_group_is_expired */, GroupsOldEnoughToBePruned::kNone, + true /* expect_first_group_retained */, + false /* expect_second_group_retained */ + }, + + // First group outside the non-prunable window, second has enforce set. + // not set. First should take priority. + { + false /* first_group_has_transient_nik */, + false /* second_group_has_transient_nik */, + true /* bool first_group_has_enforce */, + false /* bool second_group_has_enforce */, + false /* first_group_is_expired */, + false /* second_group_is_expired */, + GroupsOldEnoughToBePruned::kFirstGroupOnly, + true /* expect_first_group_retained */, + false /* expect_second_group_retained */ + }, + + // Second group is expired, so it is evicted, even though the first group + // would otherwise be prunable and the second would not. + { + true /* first_group_has_transient_nik */, + false /* second_group_has_transient_nik */, + false /* bool first_group_has_enforce */, + true /* bool second_group_has_enforce */, + false /* first_group_is_expired */, + true /* second_group_is_expired */, + GroupsOldEnoughToBePruned::kFirstGroupOnly, + true /* expect_first_group_retained */, + false /* expect_second_group_retained */ + }, + }; + + for (const auto& test_case : kTestCases) { + // Each test case simulates up to |features::kExpectCTSafeFromPruneDays + // + 1| days passing, so if an entry added for a test case should not expire + // over the course of running the test, its expiry date must be farther into + // the future than that. + base::Time unexpired_expiry_time = + base::Time::Now() + + base::TimeDelta::FromDays( + 2 * features::kExpectCTSafeFromPruneDays.Get() + 1); + + // Always add entries unexpired. + base::Time first_group_expiry = + test_case.first_group_is_expired + ? base::Time::Now() + base::TimeDelta::FromMilliseconds(1) + : unexpired_expiry_time; + + TransportSecurityState state; + base::Time first_group_observation_time = base::Time::Now(); + for (size_t i = 0; i < kGroupSize; ++i) { + // All entries use a unique NetworkIsolationKey, so + // NetworkIsolationKey-based pruning will do nothing. + state.AddExpectCT(CreateUniqueHostName(), first_group_expiry, + test_case.first_group_has_enforce, report_uri, + CreateUniqueNetworkIsolationKey( + test_case.first_group_has_transient_nik)); + } + + // Skip forward in time slightly, so the first group is always older than + // the first. + FastForwardBy(base::TimeDelta::FromSeconds(1)); + + // If only the first group should be old enough to be pruned, wait until + // enough time for the group to be prunable has passed. + if (test_case.groups_old_enough_to_be_pruned == + GroupsOldEnoughToBePruned::kFirstGroupOnly) { + FastForwardBy(base::TimeDelta::FromDays( + features::kExpectCTSafeFromPruneDays.Get() + 1)); + } + + // Always add entries unexpired. + base::Time second_group_expiry = + test_case.second_group_is_expired + ? base::Time::Now() + base::TimeDelta::FromMilliseconds(1) + : unexpired_expiry_time; + + base::Time second_group_observation_time = base::Time::Now(); + ASSERT_NE(first_group_observation_time, second_group_observation_time); + for (size_t i = 0; i < kGroupSize; ++i) { + state.AddExpectCT(CreateUniqueHostName(), second_group_expiry, + test_case.second_group_has_enforce, report_uri, + CreateUniqueNetworkIsolationKey( + test_case.second_group_has_transient_nik)); + } + + // Skip forward in time slightly, so the first group is always older than + // the first. This needs to be long enough so that if + // |second_group_is_expired| is true, the entry will expire. + FastForwardBy(base::TimeDelta::FromSeconds(1)); + + // If both the first and second groups should be old enough to be pruned, + // wait until enough time has passed for both groups to prunable. + if (test_case.groups_old_enough_to_be_pruned == + GroupsOldEnoughToBePruned::kFirstAndSecondGroups) { + FastForwardBy(base::TimeDelta::FromDays( + features::kExpectCTSafeFromPruneDays.Get() + 1)); + } + + for (size_t i = 0; i < kThirdGroupSize; ++i) { + state.AddExpectCT( + CreateUniqueHostName(), + base::Time::Now() + base::TimeDelta::FromSeconds(1), + true /* enforce */, report_uri, + CreateUniqueNetworkIsolationKey(false /* is_transient */)); + } + + size_t first_group_size = 0; + size_t second_group_size = 0; + size_t third_group_size = 0; + for (TransportSecurityState::ExpectCTStateIterator iterator(state); + iterator.HasNext(); iterator.Advance()) { + if (iterator.domain_state().last_observed == + first_group_observation_time) { + ++first_group_size; + } else if (iterator.domain_state().last_observed == + second_group_observation_time) { + ++second_group_size; + } else { + ++third_group_size; + } + } + + EXPECT_EQ(test_case.expect_first_group_retained ? kGroupSize : 0, + first_group_size); + EXPECT_EQ(test_case.expect_second_group_retained ? kGroupSize : 0, + second_group_size); + EXPECT_EQ(kThirdGroupSize, third_group_size); + + // Make sure that |unexpired_expiry_time| was set correctly - if this fails, + // it will need to be increased to avoid unexpected entry expirations. + ASSERT_LT(base::Time::Now(), unexpired_expiry_time); + } +} + +// Test the delay between pruning Expect-CT entries. +TEST_F(TransportSecurityStateTest, PruneExpectCTDelay) { + const GURL report_uri(kReportUri); + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature( + TransportSecurityState::kDynamicExpectCTFeature); + + TransportSecurityState state; + base::Time expiry = base::Time::Now() + base::TimeDelta::FromDays(10); + // Add prunable entries until pruning is triggered. + for (int i = 0; i < features::kExpectCTPruneMax.Get(); ++i) { + state.AddExpectCT(CreateUniqueHostName(), expiry, false /* enforce */, + report_uri, + CreateUniqueNetworkIsolationKey(true /* is_transient */)); + } + // Should have removed enough entries to get down to kExpectCTPruneMin + // entries. + EXPECT_EQ(features::kExpectCTPruneMin.Get(), + static_cast<int>(state.num_expect_ct_entries())); + + // Add more prunable entries, but pruning should not be triggered, due to the + // delay between subsequent pruning tasks. + for (int i = 0; i < features::kExpectCTPruneMax.Get(); ++i) { + state.AddExpectCT(CreateUniqueHostName(), expiry, false /* enforce */, + report_uri, + CreateUniqueNetworkIsolationKey(true /* is_transient */)); + } + EXPECT_EQ( + features::kExpectCTPruneMax.Get() + features::kExpectCTPruneMin.Get(), + static_cast<int>(state.num_expect_ct_entries())); + + // Time passes, which does not trigger pruning. + FastForwardBy( + base::TimeDelta::FromSeconds(features::kExpectCTPruneDelaySecs.Get())); + EXPECT_EQ( + features::kExpectCTPruneMax.Get() + features::kExpectCTPruneMin.Get(), + static_cast<int>(state.num_expect_ct_entries())); + + // Another entry is added, which triggers pruning, now that enough time has + // passed. + state.AddExpectCT(CreateUniqueHostName(), expiry, false /* enforce */, + report_uri, + CreateUniqueNetworkIsolationKey(true /* is_transient */)); + EXPECT_EQ(features::kExpectCTPruneMin.Get(), + static_cast<int>(state.num_expect_ct_entries())); + + // More time passes. + FastForwardBy(base::TimeDelta::FromSeconds( + 10 * features::kExpectCTPruneDelaySecs.Get())); + EXPECT_EQ(features::kExpectCTPruneMin.Get(), + static_cast<int>(state.num_expect_ct_entries())); + + // When enough entries are added to trigger pruning, it runs immediately, + // since enough time has passed. + for (int i = 0; i < features::kExpectCTPruneMax.Get() - + features::kExpectCTPruneMin.Get(); + ++i) { + state.AddExpectCT(CreateUniqueHostName(), expiry, false /* enforce */, + report_uri, + CreateUniqueNetworkIsolationKey(true /* is_transient */)); + } + EXPECT_EQ(features::kExpectCTPruneMin.Get(), + static_cast<int>(state.num_expect_ct_entries())); +} + +// Test that Expect-CT pruning respects kExpectCTMaxEntriesPerNik, which is only +// applied if there are more than kExpectCTPruneMin entries after global +// pruning. +TEST_F(TransportSecurityStateTest, PruneExpectCTNetworkIsolationKeyLimit) { + const GURL report_uri(kReportUri); + base::test::ScopedFeatureList feature_list; + feature_list.InitWithFeatures( + // enabled_features + {TransportSecurityState::kDynamicExpectCTFeature, + features::kPartitionExpectCTStateByNetworkIsolationKey}, + // disabled_features + {}); + + TransportSecurityState state; + + // Three different expiration times, which are used to distinguish entries + // added by each loop. No entries actually expire in this test. + base::Time expiry1 = base::Time::Now() + base::TimeDelta::FromDays(10); + base::Time expiry2 = expiry1 + base::TimeDelta::FromDays(10); + base::Time expiry3 = expiry2 + base::TimeDelta::FromDays(10); + + // Add non-prunable entries using different non-transient NIKs. They should + // not be pruned because they are recently-observed enforce entries. + for (int i = 0; i < features::kExpectCTPruneMax.Get(); ++i) { + state.AddExpectCT( + CreateUniqueHostName(), expiry1, true /* enforce */, report_uri, + CreateUniqueNetworkIsolationKey(false /* is_transient */)); + } + EXPECT_EQ(features::kExpectCTPruneMax.Get(), + static_cast<int>(state.num_expect_ct_entries())); + + // Add kExpectCTMaxEntriesPerNik non-prunable entries with a single NIK, + // allowing pruning to run each time. No entries should be deleted. + NetworkIsolationKey network_isolation_key = + CreateUniqueNetworkIsolationKey(false /* is_transient */); + for (int i = 0; i < features::kExpectCTMaxEntriesPerNik.Get(); ++i) { + FastForwardBy( + base::TimeDelta::FromSeconds(features::kExpectCTPruneDelaySecs.Get())); + state.AddExpectCT(CreateUniqueHostName(), expiry2, true /* enforce */, + report_uri, network_isolation_key); + EXPECT_EQ(features::kExpectCTPruneMax.Get() + i + 1, + static_cast<int>(state.num_expect_ct_entries())); + } + + // Add kExpectCTMaxEntriesPerNik non-prunable entries with the same NIK as + // before, allowing pruning to run each time. Each time, a single entry should + // be removed, resulting in the same total number of entries as before. + for (int i = 0; i < features::kExpectCTMaxEntriesPerNik.Get(); ++i) { + FastForwardBy( + base::TimeDelta::FromSeconds(features::kExpectCTPruneDelaySecs.Get())); + state.AddExpectCT(CreateUniqueHostName(), expiry3, true /* enforce */, + report_uri, network_isolation_key); + EXPECT_EQ(features::kExpectCTPruneMax.Get() + + features::kExpectCTMaxEntriesPerNik.Get(), + static_cast<int>(state.num_expect_ct_entries())); + + // Count entries with |expiry2| and |expiry3|. For each loop iteration, an + // entry with |expiry2| should be replaced by one with |expiry3|. + int num_expiry2_entries = 0; + int num_expiry3_entries = 0; + for (TransportSecurityState::ExpectCTStateIterator iterator(state); + iterator.HasNext(); iterator.Advance()) { + if (iterator.domain_state().expiry == expiry2) { + EXPECT_EQ(network_isolation_key, iterator.network_isolation_key()); + ++num_expiry2_entries; + } else if (iterator.domain_state().expiry == expiry3) { + EXPECT_EQ(network_isolation_key, iterator.network_isolation_key()); + ++num_expiry3_entries; + } + } + EXPECT_EQ(features::kExpectCTMaxEntriesPerNik.Get() - i - 1, + num_expiry2_entries); + EXPECT_EQ(i + 1, num_expiry3_entries); + } +} + } // namespace net diff --git a/chromium/net/http/url_security_manager_win.cc b/chromium/net/http/url_security_manager_win.cc index 33ab56efe09..4286ba72840 100644 --- a/chromium/net/http/url_security_manager_win.cc +++ b/chromium/net/http/url_security_manager_win.cc @@ -9,6 +9,7 @@ #include "base/logging.h" #include "base/macros.h" +#include "base/notreached.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "net/http/http_auth_filter.h" diff --git a/chromium/net/http2/platform/impl/http2_logging_impl.h b/chromium/net/http2/platform/impl/http2_logging_impl.h index 92f1a33b7df..804d6a7b3ca 100644 --- a/chromium/net/http2/platform/impl/http2_logging_impl.h +++ b/chromium/net/http2/platform/impl/http2_logging_impl.h @@ -5,7 +5,9 @@ #ifndef NET_HTTP2_PLATFORM_IMPL_HTTP2_LOGGING_IMPL_H_ #define NET_HTTP2_PLATFORM_IMPL_HTTP2_LOGGING_IMPL_H_ +#include "base/check_op.h" #include "base/logging.h" +#include "base/notreached.h" #include "build/build_config.h" #include "net/base/net_export.h" diff --git a/chromium/net/http2/platform/impl/http2_macros_impl.h b/chromium/net/http2/platform/impl/http2_macros_impl.h index 17628d338f3..c1029a26020 100644 --- a/chromium/net/http2/platform/impl/http2_macros_impl.h +++ b/chromium/net/http2/platform/impl/http2_macros_impl.h @@ -5,8 +5,8 @@ #ifndef NET_HTTP2_PLATFORM_IMPL_HTTP2_MACROS_IMPL_H_ #define NET_HTTP2_PLATFORM_IMPL_HTTP2_MACROS_IMPL_H_ +#include "base/check.h" #include "base/compiler_specific.h" -#include "base/logging.h" #define HTTP2_FALLTHROUGH_IMPL FALLTHROUGH #define HTTP2_UNREACHABLE_IMPL() DCHECK(false) diff --git a/chromium/net/log/file_net_log_observer.cc b/chromium/net/log/file_net_log_observer.cc index 722f95afaa2..1374fecc44c 100644 --- a/chromium/net/log/file_net_log_observer.cc +++ b/chromium/net/log/file_net_log_observer.cc @@ -481,7 +481,8 @@ FileNetLogObserver::FileNetLogObserver( write_queue_(std::move(write_queue)), file_writer_(std::move(file_writer)) { if (!constants) - constants = GetNetConstants(); + constants = base::DictionaryValue::From( + base::Value::ToUniquePtrValue(GetNetConstants())); file_task_runner_->PostTask( FROM_HERE, base::BindOnce(&FileNetLogObserver::FileWriter::Initialize, base::Unretained(file_writer_.get()), diff --git a/chromium/net/log/file_net_log_observer_unittest.cc b/chromium/net/log/file_net_log_observer_unittest.cc index 860a98defe9..7de5d885a55 100644 --- a/chromium/net/log/file_net_log_observer_unittest.cc +++ b/chromium/net/log/file_net_log_observer_unittest.cc @@ -123,12 +123,12 @@ struct ParsedNetLog { return ::testing::AssertionFailure() << "input is empty"; } - base::JSONReader reader; - base::Optional<base::Value> container_optional = reader.Read(input); - if (!container_optional) { - return ::testing::AssertionFailure() << reader.GetErrorMessage(); + base::JSONReader::ValueWithError parsed_json = + base::JSONReader::ReadAndReturnValueWithError(input); + if (!parsed_json.value) { + return ::testing::AssertionFailure() << parsed_json.error_message; } - container = std::move(*container_optional); + container = std::move(*parsed_json.value); if (!container.GetAsDictionary(&root)) { return ::testing::AssertionFailure() << "Not a dictionary"; diff --git a/chromium/net/log/net_log.cc b/chromium/net/log/net_log.cc index 6d10b0791c8..c648e76c2e5 100644 --- a/chromium/net/log/net_log.cc +++ b/chromium/net/log/net_log.cc @@ -198,11 +198,11 @@ const char* NetLog::EventTypeToString(NetLogEventType event) { // static base::Value NetLog::GetEventTypesAsValue() { - base::DictionaryValue dict; + base::Value dict(base::Value::Type::DICTIONARY); for (int i = 0; i < static_cast<int>(NetLogEventType::COUNT); ++i) { - dict.SetInteger(EventTypeToString(static_cast<NetLogEventType>(i)), i); + dict.SetIntKey(EventTypeToString(static_cast<NetLogEventType>(i)), i); } - return std::move(dict); + return dict; } // static @@ -221,11 +221,11 @@ const char* NetLog::SourceTypeToString(NetLogSourceType source) { // static base::Value NetLog::GetSourceTypesAsValue() { - base::DictionaryValue dict; + base::Value dict(base::Value::Type::DICTIONARY); for (int i = 0; i < static_cast<int>(NetLogSourceType::COUNT); ++i) { - dict.SetInteger(SourceTypeToString(static_cast<NetLogSourceType>(i)), i); + dict.SetIntKey(SourceTypeToString(static_cast<NetLogSourceType>(i)), i); } - return std::move(dict); + return dict; } // static diff --git a/chromium/net/log/net_log_entry.cc b/chromium/net/log/net_log_entry.cc index d889aed4140..40fe04da449 100644 --- a/chromium/net/log/net_log_entry.cc +++ b/chromium/net/log/net_log_entry.cc @@ -25,27 +25,27 @@ NetLogEntry::NetLogEntry(NetLogEntry&& entry) = default; NetLogEntry& NetLogEntry::operator=(NetLogEntry&& entry) = default; base::Value NetLogEntry::ToValue() const { - base::DictionaryValue entry_dict; + base::Value entry_dict(base::Value::Type::DICTIONARY); - entry_dict.SetString("time", NetLog::TickCountToString(time)); + entry_dict.SetStringKey("time", NetLog::TickCountToString(time)); // Set the entry source. - base::DictionaryValue source_dict; - source_dict.SetInteger("id", source.id); - source_dict.SetInteger("type", static_cast<int>(source.type)); - source_dict.SetString("start_time", - NetLog::TickCountToString(source.start_time)); + base::Value source_dict(base::Value::Type::DICTIONARY); + source_dict.SetIntKey("id", source.id); + source_dict.SetIntKey("type", static_cast<int>(source.type)); + source_dict.SetStringKey("start_time", + NetLog::TickCountToString(source.start_time)); entry_dict.SetKey("source", std::move(source_dict)); // Set the event info. - entry_dict.SetInteger("type", static_cast<int>(type)); - entry_dict.SetInteger("phase", static_cast<int>(phase)); + entry_dict.SetIntKey("type", static_cast<int>(type)); + entry_dict.SetIntKey("phase", static_cast<int>(phase)); // Set the event-specific parameters. if (!params.is_none()) entry_dict.SetKey("params", params.Clone()); - return std::move(entry_dict); + return entry_dict; } NetLogEntry NetLogEntry::Clone() const { diff --git a/chromium/net/log/net_log_event_type_list.h b/chromium/net/log/net_log_event_type_list.h index 12553338d45..36b24fb87a1 100644 --- a/chromium/net/log/net_log_event_type_list.h +++ b/chromium/net/log/net_log_event_type_list.h @@ -831,7 +831,7 @@ EVENT_TYPE(SOCKET_POOL_CLOSING_SOCKET) // "initiator": <Initiator origin of the request, if any, or else "not an // origin">, // "load_flags": <Numeric value of the combined load flags>, -// "privacy_mode": <True if privacy mode is enabled for the request>, +// "privacy_mode": <Privacy mode associated with the request>, // "network_isolation_key": <NIK associated with the request>, // "priority": <Numeric priority of the request>, // "site_for_cookies": <SiteForCookies associated with the request>, @@ -2004,6 +2004,20 @@ EVENT_TYPE(QUIC_SESSION_CRYPTO_HANDSHAKE_MESSAGE_RECEIVED) // } EVENT_TYPE(QUIC_SESSION_CRYPTO_HANDSHAKE_MESSAGE_SENT) +// A QUIC connection received transport parameters. +// { +// "quic_transport_parameters": <Human readable view of the transport +// parameters> +// } +EVENT_TYPE(QUIC_SESSION_TRANSPORT_PARAMETERS_RECEIVED) + +// A QUIC connection sent transport parameters. +// { +// "quic_transport_parameters": <Human readable view of the transport +// parameters> +// } +EVENT_TYPE(QUIC_SESSION_TRANSPORT_PARAMETERS_SENT) + // A QUIC connection received a PUSH_PROMISE frame. The following // parameters are attached: // { @@ -2284,6 +2298,13 @@ EVENT_TYPE(QUIC_CONNECTION_MIGRATION_TRIGGERED) // } EVENT_TYPE(QUIC_CONNECTION_MIGRATION_FAILURE) +// This event is emitted whenenver a platform notification is received that +// could possibly trigger connection migration. +// { +// "signal": <Type of the platform notification> +// } +EVENT_TYPE(QUIC_CONNECTION_MIGRATION_PLATFORM_NOTIFICATION) + // Records a successful QUIC connection migration attempt of the session // identified by connection_id. // { @@ -2357,6 +2378,15 @@ EVENT_TYPE(QUIC_CONNECTIVITY_PROBING_MANAGER_PROBE_SENT) // } EVENT_TYPE(QUIC_CONNECTIVITY_PROBING_MANAGER_PROBE_RECEIVED) +// Records that QUIC connectivity probing manager receives STATLESS_RESET on the +// following path: +// { +// "network": <ID of the network being probed> +// "self_address": <Self address on the probed path> +// "peer_address": <Peer address on the probed path> +// } +EVENT_TYPE(QUIC_CONNECTIVITY_PROBING_MANAGER_STATELESS_RESET_RECEIVED) + // ------------------------------------------------------------------------ // QuicPortMigration // ------------------------------------------------------------------------ @@ -2628,13 +2658,21 @@ EVENT_TYPE(AUTH_LIBRARY_ACQUIRE_CREDS) // This operation involves invoking an external library which may perform disk, // IPC, and network IO as a part of its work. // -// On Posix platforms, the END phase has the following parameters. +// On Windows, the BEGIN phase has the following parameters: +// { +// "spn": <Service Principle Name>, +// "context_flags": <Integer with bitfield value> +// } +// +// The END phase has the following parameters. +// +// On Posix platforms: // { // "context": <GSSAPI Context Description>, // "status" : <GSSAPI Status if the operation failed> // } // -// On Windows, the END phase has the following parameters. +// On Windows: // { // "context": <SSPI Context Description> // "status" : <SSPI SECURITY_STATUS> diff --git a/chromium/net/log/net_log_source.cc b/chromium/net/log/net_log_source.cc index 8386d63f338..a6c3eefdf0e 100644 --- a/chromium/net/log/net_log_source.cc +++ b/chromium/net/log/net_log_source.cc @@ -20,9 +20,9 @@ namespace { base::Value SourceEventParametersCallback(const NetLogSource source) { if (!source.IsValid()) return base::Value(); - base::DictionaryValue event_params; + base::Value event_params(base::Value::Type::DICTIONARY); source.AddToEventParameters(&event_params); - return std::move(event_params); + return event_params; } } // namespace diff --git a/chromium/net/log/net_log_source.h b/chromium/net/log/net_log_source.h index 01b091bd4b9..046f371c9f1 100644 --- a/chromium/net/log/net_log_source.h +++ b/chromium/net/log/net_log_source.h @@ -12,7 +12,6 @@ #include "net/log/net_log_source_type.h" namespace base { -class DictionaryValue; class Value; } @@ -29,7 +28,7 @@ struct NET_EXPORT NetLogSource { NetLogSource(NetLogSourceType type, uint32_t id, base::TimeTicks start_time); bool IsValid() const; - // Adds the source to a DictionaryValue containing event parameters, + // Adds the source to a dictionary containing event parameters, // using the name "source_dependency". void AddToEventParameters(base::Value* event_params) const; diff --git a/chromium/net/log/net_log_source_type_list.h b/chromium/net/log/net_log_source_type_list.h index ccde5695c03..15f1cdd6eb4 100644 --- a/chromium/net/log/net_log_source_type_list.h +++ b/chromium/net/log/net_log_source_type_list.h @@ -21,9 +21,8 @@ SOURCE_TYPE(TRANSPORT_CONNECT_JOB) SOURCE_TYPE(WEB_SOCKET_TRANSPORT_CONNECT_JOB) SOURCE_TYPE(SOCKET) SOURCE_TYPE(HTTP2_SESSION) -SOURCE_TYPE(QUIC_SESSION) SOURCE_TYPE(QUIC_CONNECTION_MIGRATION) -SOURCE_TYPE(QUIC_PORT_MIGRATION) +SOURCE_TYPE(QUIC_SESSION) SOURCE_TYPE(HOST_RESOLVER_IMPL_JOB) SOURCE_TYPE(DISK_CACHE_ENTRY) SOURCE_TYPE(MEMORY_CACHE_ENTRY) diff --git a/chromium/net/log/net_log_util.cc b/chromium/net/log/net_log_util.cc index b00221ea87d..91c57cc7da5 100644 --- a/chromium/net/log/net_log_util.cc +++ b/chromium/net/log/net_log_util.cc @@ -136,49 +136,48 @@ const char* NetInfoSourceToString(NetInfoSource source) { return "?"; } -std::unique_ptr<base::DictionaryValue> GetNetConstants() { - std::unique_ptr<base::DictionaryValue> constants_dict( - new base::DictionaryValue()); +base::Value GetNetConstants() { + base::Value constants_dict(base::Value::Type::DICTIONARY); // Version of the file format. - constants_dict->SetInteger("logFormatVersion", kLogFormatVersion); + constants_dict.SetIntKey("logFormatVersion", kLogFormatVersion); // Add a dictionary with information on the relationship between event type // enums and their symbolic names. - constants_dict->SetKey("logEventTypes", NetLog::GetEventTypesAsValue()); + constants_dict.SetKey("logEventTypes", NetLog::GetEventTypesAsValue()); // Add a dictionary with information about the relationship between CertStatus // flags and their symbolic names. { - std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); + base::Value dict(base::Value::Type::DICTIONARY); for (const auto& flag : kCertStatusFlags) - dict->SetInteger(flag.name, flag.constant); + dict.SetIntKey(flag.name, flag.constant); - constants_dict->Set("certStatusFlag", std::move(dict)); + constants_dict.SetKey("certStatusFlag", std::move(dict)); } // Add a dictionary with information about the relationship between // CertVerifier::VerifyFlags and their symbolic names. { - std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); + base::Value dict(base::Value::Type::DICTIONARY); - dict->SetInteger("VERIFY_DISABLE_NETWORK_FETCHES", - CertVerifier::VERIFY_DISABLE_NETWORK_FETCHES); + dict.SetIntKey("VERIFY_DISABLE_NETWORK_FETCHES", + CertVerifier::VERIFY_DISABLE_NETWORK_FETCHES); static_assert(CertVerifier::VERIFY_FLAGS_LAST == (1 << 0), "Update with new flags"); - constants_dict->Set("certVerifierFlags", std::move(dict)); + constants_dict.SetKey("certVerifierFlags", std::move(dict)); } { - std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); + base::Value dict(base::Value::Type::DICTIONARY); - dict->SetInteger( + dict.SetIntKey( "kStrong", static_cast<int>(SimplePathBuilderDelegate::DigestPolicy::kStrong)); - dict->SetInteger( + dict.SetIntKey( "kWeakAllowSha1", static_cast<int>( SimplePathBuilderDelegate::DigestPolicy::kWeakAllowSha1)); @@ -187,127 +186,126 @@ std::unique_ptr<base::DictionaryValue> GetNetConstants() { SimplePathBuilderDelegate::DigestPolicy::kWeakAllowSha1, "Update with new flags"); - constants_dict->Set("certPathBuilderDigestPolicy", std::move(dict)); + constants_dict.SetKey("certPathBuilderDigestPolicy", std::move(dict)); } { - std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); - - dict->SetInteger("DISTRUSTED", - static_cast<int>(CertificateTrustType::DISTRUSTED)); - dict->SetInteger("UNSPECIFIED", - static_cast<int>(CertificateTrustType::UNSPECIFIED)); - dict->SetInteger("TRUSTED_ANCHOR", - static_cast<int>(CertificateTrustType::TRUSTED_ANCHOR)); - dict->SetInteger( - "TRUSTED_ANCHOR_WITH_CONSTRAINTS", - static_cast<int>( - CertificateTrustType::TRUSTED_ANCHOR_WITH_CONSTRAINTS)); + base::Value dict(base::Value::Type::DICTIONARY); + + dict.SetIntKey("DISTRUSTED", + static_cast<int>(CertificateTrustType::DISTRUSTED)); + dict.SetIntKey("UNSPECIFIED", + static_cast<int>(CertificateTrustType::UNSPECIFIED)); + dict.SetIntKey("TRUSTED_ANCHOR", + static_cast<int>(CertificateTrustType::TRUSTED_ANCHOR)); + dict.SetIntKey("TRUSTED_ANCHOR_WITH_CONSTRAINTS", + static_cast<int>( + CertificateTrustType::TRUSTED_ANCHOR_WITH_CONSTRAINTS)); static_assert(CertificateTrustType::LAST == CertificateTrustType::TRUSTED_ANCHOR_WITH_CONSTRAINTS, "Update with new flags"); - constants_dict->Set("certificateTrustType", std::move(dict)); + constants_dict.SetKey("certificateTrustType", std::move(dict)); } // Add a dictionary with information about the relationship between load flag // enums and their symbolic names. { - std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); + base::Value dict(base::Value::Type::DICTIONARY); for (const auto& flag : kLoadFlags) - dict->SetInteger(flag.name, flag.constant); + dict.SetIntKey(flag.name, flag.constant); - constants_dict->Set("loadFlag", std::move(dict)); + constants_dict.SetKey("loadFlag", std::move(dict)); } // Add a dictionary with information about the relationship between load state // enums and their symbolic names. { - std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); + base::Value dict(base::Value::Type::DICTIONARY); for (const auto& state : kLoadStateTable) - dict->SetInteger(state.name, state.constant); + dict.SetIntKey(state.name, state.constant); - constants_dict->Set("loadState", std::move(dict)); + constants_dict.SetKey("loadState", std::move(dict)); } { - std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); + base::Value dict(base::Value::Type::DICTIONARY); #define NET_INFO_SOURCE(label, string, value) \ - dict->SetInteger(string, NET_INFO_##label); + dict.SetIntKey(string, NET_INFO_##label); #include "net/base/net_info_source_list.h" #undef NET_INFO_SOURCE - constants_dict->Set("netInfoSources", std::move(dict)); + constants_dict.SetKey("netInfoSources", std::move(dict)); } // Add information on the relationship between net error codes and their // symbolic names. { - std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); + base::Value dict(base::Value::Type::DICTIONARY); for (const auto& error : kNetErrors) - dict->SetInteger(ErrorToShortString(error), error); + dict.SetIntKey(ErrorToShortString(error), error); - constants_dict->Set("netError", std::move(dict)); + constants_dict.SetKey("netError", std::move(dict)); } // Add information on the relationship between QUIC error codes and their // symbolic names. { - std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); + base::Value dict(base::Value::Type::DICTIONARY); for (quic::QuicErrorCode error = quic::QUIC_NO_ERROR; error < quic::QUIC_LAST_ERROR; error = static_cast<quic::QuicErrorCode>(error + 1)) { - dict->SetInteger(QuicErrorCodeToString(error), static_cast<int>(error)); + dict.SetIntKey(QuicErrorCodeToString(error), static_cast<int>(error)); } - constants_dict->Set("quicError", std::move(dict)); + constants_dict.SetKey("quicError", std::move(dict)); } // Add information on the relationship between QUIC RST_STREAM error codes // and their symbolic names. { - std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); + base::Value dict(base::Value::Type::DICTIONARY); for (quic::QuicRstStreamErrorCode error = quic::QUIC_STREAM_NO_ERROR; error < quic::QUIC_STREAM_LAST_ERROR; error = static_cast<quic::QuicRstStreamErrorCode>(error + 1)) { - dict->SetInteger(QuicRstStreamErrorCodeToString(error), - static_cast<int>(error)); + dict.SetIntKey(QuicRstStreamErrorCodeToString(error), + static_cast<int>(error)); } - constants_dict->Set("quicRstStreamError", std::move(dict)); + constants_dict.SetKey("quicRstStreamError", std::move(dict)); } // Information about the relationship between event phase enums and their // symbolic names. { - std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); + base::Value dict(base::Value::Type::DICTIONARY); - dict->SetInteger("PHASE_BEGIN", static_cast<int>(NetLogEventPhase::BEGIN)); - dict->SetInteger("PHASE_END", static_cast<int>(NetLogEventPhase::END)); - dict->SetInteger("PHASE_NONE", static_cast<int>(NetLogEventPhase::NONE)); + dict.SetIntKey("PHASE_BEGIN", static_cast<int>(NetLogEventPhase::BEGIN)); + dict.SetIntKey("PHASE_END", static_cast<int>(NetLogEventPhase::END)); + dict.SetIntKey("PHASE_NONE", static_cast<int>(NetLogEventPhase::NONE)); - constants_dict->Set("logEventPhase", std::move(dict)); + constants_dict.SetKey("logEventPhase", std::move(dict)); } // Information about the relationship between source type enums and // their symbolic names. - constants_dict->SetKey("logSourceType", NetLog::GetSourceTypesAsValue()); + constants_dict.SetKey("logSourceType", NetLog::GetSourceTypesAsValue()); // Information about the relationship between address family enums and // their symbolic names. { - std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); + base::Value dict(base::Value::Type::DICTIONARY); - dict->SetInteger("ADDRESS_FAMILY_UNSPECIFIED", ADDRESS_FAMILY_UNSPECIFIED); - dict->SetInteger("ADDRESS_FAMILY_IPV4", ADDRESS_FAMILY_IPV4); - dict->SetInteger("ADDRESS_FAMILY_IPV6", ADDRESS_FAMILY_IPV6); + dict.SetIntKey("ADDRESS_FAMILY_UNSPECIFIED", ADDRESS_FAMILY_UNSPECIFIED); + dict.SetIntKey("ADDRESS_FAMILY_IPV4", ADDRESS_FAMILY_IPV4); + dict.SetIntKey("ADDRESS_FAMILY_IPV6", ADDRESS_FAMILY_IPV6); - constants_dict->Set("addressFamily", std::move(dict)); + constants_dict.SetKey("addressFamily", std::move(dict)); } // Information about how the "time ticks" values we have given it relate to @@ -327,14 +325,15 @@ std::unique_ptr<base::DictionaryValue> GetNetConstants() { base::TimeTicks::Now() - base::TimeTicks(); int64_t tick_to_unix_time_ms = (time_since_epoch - reference_time_ticks).InMilliseconds(); - constants_dict->SetKey("timeTickOffset", - NetLogNumberValue(tick_to_unix_time_ms)); + constants_dict.SetKey("timeTickOffset", + NetLogNumberValue(tick_to_unix_time_ms)); } // TODO(eroman): Is this needed? // "clientInfo" key is required for some log readers. Provide a default empty // value for compatibility. - constants_dict->Set("clientInfo", std::make_unique<base::DictionaryValue>()); + constants_dict.SetKey("clientInfo", + base::Value(base::Value::Type::DICTIONARY)); // Add a list of active field experiments. { @@ -346,8 +345,9 @@ std::unique_ptr<base::DictionaryValue> GetNetConstants() { it != active_groups.end(); ++it) { field_trial_groups->AppendString(it->trial_name + ":" + it->group_name); } - constants_dict->Set("activeFieldTrialGroups", - std::move(field_trial_groups)); + constants_dict.SetKey( + "activeFieldTrialGroups", + base::Value::FromUniquePtrValue(std::move(field_trial_groups))); } return constants_dict; diff --git a/chromium/net/log/net_log_util.h b/chromium/net/log/net_log_util.h index 62c3dd06b6d..b6391aae8fe 100644 --- a/chromium/net/log/net_log_util.h +++ b/chromium/net/log/net_log_util.h @@ -33,8 +33,8 @@ enum NetInfoSource { // Returns a friendly string to use for a given NetInfoSource in the net log. NET_EXPORT const char* NetInfoSourceToString(NetInfoSource source); -// Create a dictionary containing a legend for net/ constants. -NET_EXPORT std::unique_ptr<base::DictionaryValue> GetNetConstants(); +// Creates a dictionary containing a legend for net/ constants. +NET_EXPORT base::Value GetNetConstants(); // Retrieves a dictionary containing information about the current state of // |context|. |info_sources| is a set of NetInfoSources OR'd together, diff --git a/chromium/net/log/net_log_util_unittest.cc b/chromium/net/log/net_log_util_unittest.cc index 73ba2670b94..7da26248f9b 100644 --- a/chromium/net/log/net_log_util_unittest.cc +++ b/chromium/net/log/net_log_util_unittest.cc @@ -27,7 +27,7 @@ namespace { // Make sure GetNetConstants doesn't crash. TEST(NetLogUtil, GetNetConstants) { - std::unique_ptr<base::Value> constants(GetNetConstants()); + base::Value constants(GetNetConstants()); } // Make sure GetNetInfo doesn't crash when called on contexts with and without diff --git a/chromium/net/log/net_log_values.cc b/chromium/net/log/net_log_values.cc index d92d3fa2352..cc8bb8cdaa8 100644 --- a/chromium/net/log/net_log_values.cc +++ b/chromium/net/log/net_log_values.cc @@ -82,9 +82,9 @@ base::Value NetLogParamsWithInt(base::StringPiece name, int value) { } base::Value NetLogParamsWithInt64(base::StringPiece name, int64_t value) { - base::DictionaryValue event_params; - event_params.SetKey(name, NetLogNumberValue(value)); - return std::move(event_params); + base::Value params(base::Value::Type::DICTIONARY); + params.SetKey(name, NetLogNumberValue(value)); + return params; } base::Value NetLogParamsWithBool(base::StringPiece name, bool value) { diff --git a/chromium/net/log/net_log_with_source.cc b/chromium/net/log/net_log_with_source.cc index 5a6cbe10ea1..e1a44ff8b79 100644 --- a/chromium/net/log/net_log_with_source.cc +++ b/chromium/net/log/net_log_with_source.cc @@ -25,11 +25,11 @@ namespace { base::Value BytesTransferredParams(int byte_count, const char* bytes, NetLogCaptureMode capture_mode) { - base::DictionaryValue dict; - dict.SetInteger("byte_count", byte_count); + base::Value dict(base::Value::Type::DICTIONARY); + dict.SetIntKey("byte_count", byte_count); if (NetLogCaptureIncludesSocketBytes(capture_mode) && byte_count > 0) dict.SetKey("bytes", NetLogBinaryValue(bytes, byte_count)); - return std::move(dict); + return dict; } } // namespace diff --git a/chromium/net/network_error_logging/network_error_logging_service.cc b/chromium/net/network_error_logging/network_error_logging_service.cc index f8b47e3d030..c63d8e9a09c 100644 --- a/chromium/net/network_error_logging/network_error_logging_service.cc +++ b/chromium/net/network_error_logging/network_error_logging_service.cc @@ -143,12 +143,6 @@ bool IsHttpError(const NetworkErrorLoggingService::RequestDetails& request) { return request.status_code >= 400 && request.status_code < 600; } -void RecordHeaderOutcome(NetworkErrorLoggingService::HeaderOutcome outcome) { - UMA_HISTOGRAM_ENUMERATION(NetworkErrorLoggingService::kHeaderOutcomeHistogram, - outcome, - NetworkErrorLoggingService::HeaderOutcome::MAX); -} - void RecordSignedExchangeRequestOutcome( NetworkErrorLoggingService::RequestOutcome outcome) { UMA_HISTOGRAM_ENUMERATION( @@ -176,10 +170,8 @@ class NetworkErrorLoggingServiceImpl : public NetworkErrorLoggingService { const std::string& value) override { // NEL is only available to secure origins, so don't permit insecure origins // to set policies. - if (!origin.GetURL().SchemeIsCryptographic()) { - RecordHeaderOutcome(HeaderOutcome::DISCARDED_INSECURE_ORIGIN); + if (!origin.GetURL().SchemeIsCryptographic()) return; - } base::Time header_received_time = clock_->Now(); // base::Unretained is safe because the callback gets stored in @@ -366,19 +358,18 @@ class NetworkErrorLoggingServiceImpl : public NetworkErrorLoggingService { policy.origin = origin; policy.received_ip_address = received_ip_address; policy.last_used = header_received_time; - HeaderOutcome outcome = ParseHeader(value, clock_->Now(), &policy); + + if (!ParseHeader(value, clock_->Now(), &policy)) + return; + // Disallow eTLDs from setting include_subdomains policies. - if ((outcome == HeaderOutcome::SET || outcome == HeaderOutcome::REMOVED) && - policy.include_subdomains && + if (policy.include_subdomains && registry_controlled_domains::GetRegistryLength( policy.origin.GetURL(), registry_controlled_domains::INCLUDE_UNKNOWN_REGISTRIES, registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES) == 0) { - outcome = HeaderOutcome::DISCARDED_INCLUDE_SUBDOMAINS_NOT_ALLOWED; - } - RecordHeaderOutcome(outcome); - if (outcome != HeaderOutcome::SET && outcome != HeaderOutcome::REMOVED) return; + } // If a policy for |origin| already existed, remove the old policy. auto it = policies_.find(origin); @@ -551,37 +542,42 @@ class NetworkErrorLoggingServiceImpl : public NetworkErrorLoggingService { policies_.clear(); } - HeaderOutcome ParseHeader(const std::string& json_value, - base::Time now, - NelPolicy* policy_out) const { + // Returns whether the |json_value| was parsed as a valid header that either + // sets a NEL policy (max age > 0) or removes an existing one (max age == 0). + bool ParseHeader(const std::string& json_value, + base::Time now, + NelPolicy* policy_out) const { DCHECK(policy_out); + // JSON is malformed (too large, syntax error, not a dictionary). if (json_value.size() > kMaxJsonSize) - return HeaderOutcome::DISCARDED_JSON_TOO_BIG; + return false; std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated( json_value, base::JSON_PARSE_RFC, kMaxJsonDepth); if (!value) - return HeaderOutcome::DISCARDED_JSON_INVALID; + return false; const base::DictionaryValue* dict = nullptr; if (!value->GetAsDictionary(&dict)) - return HeaderOutcome::DISCARDED_NOT_DICTIONARY; + return false; + // Max-Age property is missing or malformed. if (!dict->HasKey(kMaxAgeKey)) - return HeaderOutcome::DISCARDED_TTL_MISSING; + return false; int max_age_sec; if (!dict->GetInteger(kMaxAgeKey, &max_age_sec)) - return HeaderOutcome::DISCARDED_TTL_NOT_INTEGER; + return false; if (max_age_sec < 0) - return HeaderOutcome::DISCARDED_TTL_NEGATIVE; + return false; + // Report-To property is missing or malformed. std::string report_to; if (max_age_sec > 0) { if (!dict->HasKey(kReportToKey)) - return HeaderOutcome::DISCARDED_REPORT_TO_MISSING; + return false; if (!dict->GetString(kReportToKey, &report_to)) - return HeaderOutcome::DISCARDED_REPORT_TO_NOT_STRING; + return false; } bool include_subdomains = false; @@ -605,13 +601,10 @@ class NetworkErrorLoggingServiceImpl : public NetworkErrorLoggingService { policy_out->include_subdomains = include_subdomains; policy_out->success_fraction = success_fraction; policy_out->failure_fraction = failure_fraction; - if (max_age_sec > 0) { - policy_out->expires = now + base::TimeDelta::FromSeconds(max_age_sec); - return HeaderOutcome::SET; - } else { - policy_out->expires = base::Time(); - return HeaderOutcome::REMOVED; - } + policy_out->expires = max_age_sec > 0 + ? now + base::TimeDelta::FromSeconds(max_age_sec) + : base::Time(); + return true; } const NelPolicy* FindPolicyForOrigin(const url::Origin& origin) const { @@ -885,9 +878,6 @@ const char NetworkErrorLoggingService::kHeaderName[] = "NEL"; const char NetworkErrorLoggingService::kReportType[] = "network-error"; -const char NetworkErrorLoggingService::kHeaderOutcomeHistogram[] = - "Net.NetworkErrorLogging.HeaderOutcome"; - const char NetworkErrorLoggingService::kSignedExchangeRequestOutcomeHistogram[] = "Net.NetworkErrorLogging.SignedExchangeRequestOutcome"; @@ -921,29 +911,6 @@ const char NetworkErrorLoggingService::kCertUrlKey[] = "cert_url"; const size_t NetworkErrorLoggingService::kMaxPolicies = 1000u; // static -void NetworkErrorLoggingService:: - RecordHeaderDiscardedForNoNetworkErrorLoggingService() { - RecordHeaderOutcome( - HeaderOutcome::DISCARDED_NO_NETWORK_ERROR_LOGGING_SERVICE); -} - -// static -void NetworkErrorLoggingService::RecordHeaderDiscardedForInvalidSSLInfo() { - RecordHeaderOutcome(HeaderOutcome::DISCARDED_INVALID_SSL_INFO); -} - -// static -void NetworkErrorLoggingService::RecordHeaderDiscardedForCertStatusError() { - RecordHeaderOutcome(HeaderOutcome::DISCARDED_CERT_STATUS_ERROR); -} - -// static -void NetworkErrorLoggingService:: - RecordHeaderDiscardedForMissingRemoteEndpoint() { - RecordHeaderOutcome(HeaderOutcome::DISCARDED_MISSING_REMOTE_ENDPOINT); -} - -// static std::unique_ptr<NetworkErrorLoggingService> NetworkErrorLoggingService::Create( PersistentNelStore* store) { return std::make_unique<NetworkErrorLoggingServiceImpl>(store); diff --git a/chromium/net/network_error_logging/network_error_logging_service.h b/chromium/net/network_error_logging/network_error_logging_service.h index 8f233bbe55a..514d61c5a64 100644 --- a/chromium/net/network_error_logging/network_error_logging_service.h +++ b/chromium/net/network_error_logging/network_error_logging_service.h @@ -142,37 +142,8 @@ class NET_EXPORT NetworkErrorLoggingService { // Maximum number of NEL policies to store before evicting. static const size_t kMaxPolicies; - // Histograms. These are mainly used in test cases to verify that interesting - // events occurred. - - static const char kHeaderOutcomeHistogram[]; static const char kSignedExchangeRequestOutcomeHistogram[]; - enum class HeaderOutcome { - DISCARDED_NO_NETWORK_ERROR_LOGGING_SERVICE = 0, - DISCARDED_INVALID_SSL_INFO = 1, - DISCARDED_CERT_STATUS_ERROR = 2, - - DISCARDED_INSECURE_ORIGIN = 3, - - DISCARDED_JSON_TOO_BIG = 4, - DISCARDED_JSON_INVALID = 5, - DISCARDED_NOT_DICTIONARY = 6, - DISCARDED_TTL_MISSING = 7, - DISCARDED_TTL_NOT_INTEGER = 8, - DISCARDED_TTL_NEGATIVE = 9, - DISCARDED_REPORT_TO_MISSING = 10, - DISCARDED_REPORT_TO_NOT_STRING = 11, - - REMOVED = 12, - SET = 13, - - DISCARDED_MISSING_REMOTE_ENDPOINT = 14, - DISCARDED_INCLUDE_SUBDOMAINS_NOT_ALLOWED = 15, - - MAX - }; - // Used for histogramming Signed Exchange request outcomes only. Previously, // the outcome of all requests would be histogrammed, but this was removed in // crbug.com/1007122 because the histogram was very large and not very useful. @@ -193,11 +164,6 @@ class NET_EXPORT NetworkErrorLoggingService { kMaxValue = kDiscardedIPAddressMismatch }; - static void RecordHeaderDiscardedForNoNetworkErrorLoggingService(); - static void RecordHeaderDiscardedForInvalidSSLInfo(); - static void RecordHeaderDiscardedForCertStatusError(); - static void RecordHeaderDiscardedForMissingRemoteEndpoint(); - // NEL policies are persisted to disk if |store| is not null. // The store, if given, should outlive |*this|. static std::unique_ptr<NetworkErrorLoggingService> Create( diff --git a/chromium/net/proxy_resolution/configured_proxy_resolution_service.cc b/chromium/net/proxy_resolution/configured_proxy_resolution_service.cc index c699df2bb33..68fc89b5455 100644 --- a/chromium/net/proxy_resolution/configured_proxy_resolution_service.cc +++ b/chromium/net/proxy_resolution/configured_proxy_resolution_service.cc @@ -391,34 +391,6 @@ GURL SanitizeUrl(const GURL& url) { return url.ReplaceComponents(replacements); } -// Do not change the enumerated value as it is relied on by histograms. -enum class PacUrlSchemeForHistogram { - kOther = 0, - - kHttp = 1, - kHttps = 2, - kFtp = 3, - kFile = 4, - kData = 5, - - kMaxValue = kData, -}; - -PacUrlSchemeForHistogram GetPacUrlScheme(const GURL& pac_url) { - if (pac_url.SchemeIs("http")) - return PacUrlSchemeForHistogram::kHttp; - if (pac_url.SchemeIs("https")) - return PacUrlSchemeForHistogram::kHttps; - if (pac_url.SchemeIs("data")) - return PacUrlSchemeForHistogram::kData; - if (pac_url.SchemeIs("ftp")) - return PacUrlSchemeForHistogram::kFtp; - if (pac_url.SchemeIs("file")) - return PacUrlSchemeForHistogram::kFile; - - return PacUrlSchemeForHistogram::kOther; -} - } // namespace // ConfiguredProxyResolutionService::InitProxyResolver @@ -1511,11 +1483,6 @@ void ConfiguredProxyResolutionService::OnProxyConfigChanged( }); } - if (config.value().has_pac_url()) { - UMA_HISTOGRAM_ENUMERATION("Net.ProxyResolutionService.PacUrlScheme", - GetPacUrlScheme(config.value().pac_url())); - } - // Set the new configuration as the most recently fetched one. fetched_config_ = effective_config; diff --git a/chromium/net/proxy_resolution/configured_proxy_resolution_service_unittest.cc b/chromium/net/proxy_resolution/configured_proxy_resolution_service_unittest.cc index 9b129ee2e81..c9a5fb01269 100644 --- a/chromium/net/proxy_resolution/configured_proxy_resolution_service_unittest.cc +++ b/chromium/net/proxy_resolution/configured_proxy_resolution_service_unittest.cc @@ -346,42 +346,6 @@ JobMap GetCancelledJobsForURLs(const MockAsyncProxyResolver& resolver, return GetJobsForURLs(map, urls); } -// Helper class to verify the bucket counts for PacUrlScheme histogram. -class PacUrlSchemeHistogramTester { - public: - void VerifyHistogram() const { - const char kPacUrlSchemeHistogram[] = - "Net.ProxyResolutionService.PacUrlScheme"; - - int total = GetTotal(); - - histograms_.ExpectTotalCount(kPacUrlSchemeHistogram, total); - - if (total > 0) { - histograms_.ExpectBucketCount(kPacUrlSchemeHistogram, 0, num_other); - histograms_.ExpectBucketCount(kPacUrlSchemeHistogram, 1, num_http); - histograms_.ExpectBucketCount(kPacUrlSchemeHistogram, 2, num_https); - histograms_.ExpectBucketCount(kPacUrlSchemeHistogram, 3, num_ftp); - histograms_.ExpectBucketCount(kPacUrlSchemeHistogram, 4, num_file); - histograms_.ExpectBucketCount(kPacUrlSchemeHistogram, 5, num_data); - } - } - - int num_http = 0; - int num_https = 0; - int num_ftp = 0; - int num_data = 0; - int num_file = 0; - int num_other = 0; - - private: - int GetTotal() const { - return num_http + num_https + num_ftp + num_data + num_file + num_other; - } - - base::HistogramTester histograms_; -}; - } // namespace TEST_F(ConfiguredProxyResolutionServiceTest, Direct) { @@ -3999,61 +3963,6 @@ TEST_F(ConfiguredProxyResolutionServiceTest, OnShutdownFollowedByRequest) { EXPECT_TRUE(info.is_direct()); } -// Tests that the URL scheme for PAC files gets output to the histogram. -TEST_F(ConfiguredProxyResolutionServiceTest, PacUrlSchemeHistogram) { - PacUrlSchemeHistogramTester pac_histogram; - - MockProxyConfigService* config_service = - new MockProxyConfigService(ProxyConfig::CreateDirect()); - - ConfiguredProxyResolutionService service( - base::WrapUnique(config_service), - std::make_unique<MockAsyncProxyResolverFactory>(false), nullptr, - /*quick_check_enabled=*/true); - - pac_histogram.VerifyHistogram(); - - // Set an http:// PAC. - config_service->SetPacUrlConfig("http://example.test/"); - pac_histogram.num_http++; - pac_histogram.VerifyHistogram(); - - // Set an https:// PAC. - config_service->SetPacUrlConfig("hTTps://example.test/wpad.dat"); - pac_histogram.num_https++; - pac_histogram.VerifyHistogram(); - - // Set an ftp:// PAC. - config_service->SetPacUrlConfig("ftp://example.test/pac.js"); - pac_histogram.num_ftp++; - pac_histogram.VerifyHistogram(); - - // Set an file:// PAC. - config_service->SetPacUrlConfig("file://example.test/boo"); - pac_histogram.num_file++; - pac_histogram.VerifyHistogram(); - - // Set an mailto: PAC. - config_service->SetPacUrlConfig("mailto:foo@example.test"); - pac_histogram.num_other++; - pac_histogram.VerifyHistogram(); - - // Set an data: PAC. - config_service->SetPacUrlConfig("data:,Hello%2C%20World!"); - pac_histogram.num_data++; - pac_histogram.VerifyHistogram(); - - // Set an filesystem: PAC. - config_service->SetPacUrlConfig("filesystem:http://example.test/pac.js"); - pac_histogram.num_other++; - pac_histogram.VerifyHistogram(); - - // Set another https:// as PAC. - config_service->SetPacUrlConfig("https://example2.test/wpad.dat"); - pac_histogram.num_https++; - pac_histogram.VerifyHistogram(); -} - const char* kImplicityBypassedHosts[] = { "localhost", "localhost.", diff --git a/chromium/net/proxy_resolution/network_delegate_error_observer_unittest.cc b/chromium/net/proxy_resolution/network_delegate_error_observer_unittest.cc index dff170e9e55..b0c9ff4322c 100644 --- a/chromium/net/proxy_resolution/network_delegate_error_observer_unittest.cc +++ b/chromium/net/proxy_resolution/network_delegate_error_observer_unittest.cc @@ -59,7 +59,6 @@ class TestNetworkDelegate : public NetworkDelegateImpl { got_pac_error_ = true; } bool OnCanGetCookies(const URLRequest& request, - const CookieList& cookie_list, bool allowed_from_caller) override { return allowed_from_caller; } diff --git a/chromium/net/proxy_resolution/pac_file_fetcher_impl.cc b/chromium/net/proxy_resolution/pac_file_fetcher_impl.cc index cedd67874ce..f31ae9a7b22 100644 --- a/chromium/net/proxy_resolution/pac_file_fetcher_impl.cc +++ b/chromium/net/proxy_resolution/pac_file_fetcher_impl.cc @@ -175,6 +175,8 @@ int PacFileFetcherImpl::Fetch( cur_request_ = url_request_context_->CreateRequest(url, MAXIMUM_PRIORITY, this, traffic_annotation); + cur_request_->set_isolation_info(isolation_info_); + // Make sure that the PAC script is downloaded using a direct connection, // to avoid circular dependencies (fetching is a part of proxy resolution). // Also disable the use of the disk cache. The cache is disabled so that if @@ -316,6 +318,7 @@ void PacFileFetcherImpl::OnReadCompleted(URLRequest* request, int num_bytes) { PacFileFetcherImpl::PacFileFetcherImpl(URLRequestContext* url_request_context) : url_request_context_(url_request_context), + isolation_info_(IsolationInfo::CreateTransient()), buf_(base::MakeRefCounted<IOBuffer>(kBufSize)), next_id_(0), cur_request_id_(0), diff --git a/chromium/net/proxy_resolution/pac_file_fetcher_impl.h b/chromium/net/proxy_resolution/pac_file_fetcher_impl.h index efbba739f5c..0ceea27f615 100644 --- a/chromium/net/proxy_resolution/pac_file_fetcher_impl.h +++ b/chromium/net/proxy_resolution/pac_file_fetcher_impl.h @@ -17,6 +17,7 @@ #include "base/strings/string16.h" #include "base/time/time.h" #include "net/base/completion_once_callback.h" +#include "net/base/isolation_info.h" #include "net/base/net_export.h" #include "net/proxy_resolution/pac_file_fetcher.h" #include "net/traffic_annotation/network_traffic_annotation.h" @@ -80,6 +81,8 @@ class NET_EXPORT PacFileFetcherImpl : public PacFileFetcher, void OnResponseStarted(URLRequest* request, int net_error) override; void OnReadCompleted(URLRequest* request, int num_bytes) override; + const IsolationInfo& isolation_info_for_testing() { return isolation_info_; } + private: enum { kBufSize = 4096 }; @@ -110,6 +113,9 @@ class NET_EXPORT PacFileFetcherImpl : public PacFileFetcher, // OnShutdown. URLRequestContext* url_request_context_; + // Transient IsolationInfo used to fetch PAC scripts. + const IsolationInfo isolation_info_; + // Buffer that URLRequest writes into. scoped_refptr<IOBuffer> buf_; diff --git a/chromium/net/proxy_resolution/pac_file_fetcher_impl_unittest.cc b/chromium/net/proxy_resolution/pac_file_fetcher_impl_unittest.cc index d5c60af6869..34095ea5147 100644 --- a/chromium/net/proxy_resolution/pac_file_fetcher_impl_unittest.cc +++ b/chromium/net/proxy_resolution/pac_file_fetcher_impl_unittest.cc @@ -18,8 +18,10 @@ #include "base/single_thread_task_runner.h" #include "base/stl_util.h" #include "base/strings/utf_string_conversions.h" +#include "base/test/scoped_feature_list.h" #include "base/test/task_environment.h" #include "base/threading/thread_task_runner_handle.h" +#include "net/base/features.h" #include "net/base/filename_util.h" #include "net/base/load_flags.h" #include "net/base/network_delegate_impl.h" @@ -73,13 +75,12 @@ struct FetchResult { base::string16 text; }; -// A non-mock URL request which can access http:// and file:// urls, in the case -// the tests were built with file support. +// A non-mock URL request which can access http:// urls. class RequestContext : public URLRequestContext { public: RequestContext() : storage_(this) { ProxyConfig no_proxy; - storage_.set_host_resolver(std::make_unique<MockHostResolver>()); + storage_.set_host_resolver(std::make_unique<MockCachingHostResolver>()); storage_.set_cert_verifier(std::make_unique<MockCertVerifier>()); storage_.set_transport_security_state( std::make_unique<TransportSecurityState>()); @@ -179,7 +180,6 @@ class BasicNetworkDelegate : public NetworkDelegateImpl { } bool OnCanGetCookies(const URLRequest& request, - const CookieList& cookie_list, bool allowed_from_caller) override { return allowed_from_caller; } @@ -321,6 +321,58 @@ TEST_F(PacFileFetcherImplTest, ContentDisposition) { EXPECT_EQ(ASCIIToUTF16("-downloadable.pac-\n"), text); } +// Verifies that fetches are made using the fetcher's IsolationInfo, by checking +// the DNS cache. +TEST_F(PacFileFetcherImplTest, IsolationInfo) { + base::test::ScopedFeatureList feature_list; + feature_list.InitWithFeatures( + // enabled_features + {features::kPartitionConnectionsByNetworkIsolationKey, + features::kSplitHostCacheByNetworkIsolationKey}, + // disabled_features + {}); + const char kHost[] = "foo.test"; + + ASSERT_TRUE(test_server_.Start()); + + auto pac_fetcher = PacFileFetcherImpl::Create(&context_); + + GURL url(test_server_.GetURL(kHost, "/downloadable.pac")); + base::string16 text; + TestCompletionCallback callback; + int result = pac_fetcher->Fetch(url, &text, callback.callback(), + TRAFFIC_ANNOTATION_FOR_TESTS); + EXPECT_THAT(callback.GetResult(result), IsOk()); + EXPECT_EQ(ASCIIToUTF16("-downloadable.pac-\n"), text); + + // Check that the URL in kDestination is in the HostCache, with + // the fetcher's IsolationInfo / NetworkIsolationKey, and no others. + const net::HostPortPair kHostPortPair = + net::HostPortPair(kHost, 0 /* port */); + net::HostResolver::ResolveHostParameters params; + params.source = net::HostResolverSource::LOCAL_ONLY; + std::unique_ptr<net::HostResolver::ResolveHostRequest> host_request = + context_.host_resolver()->CreateRequest( + kHostPortPair, + pac_fetcher->isolation_info_for_testing().network_isolation_key(), + net::NetLogWithSource(), params); + net::TestCompletionCallback callback2; + result = host_request->Start(callback2.callback()); + EXPECT_EQ(net::OK, callback2.GetResult(result)); + + // Make sure there are no other entries in the HostCache (which would + // potentially be associated with other NetworkIsolationKeys). + EXPECT_EQ(1u, context_.host_resolver()->GetHostCache()->size()); + + // Make sure the cache is actually returning different results based on + // NetworkIsolationKey. + host_request = context_.host_resolver()->CreateRequest( + kHostPortPair, NetworkIsolationKey(), net::NetLogWithSource(), params); + net::TestCompletionCallback callback3; + result = host_request->Start(callback3.callback()); + EXPECT_EQ(net::ERR_NAME_NOT_RESOLVED, callback3.GetResult(result)); +} + // Verifies that PAC scripts are not being cached. TEST_F(PacFileFetcherImplTest, NoCache) { ASSERT_TRUE(test_server_.Start()); diff --git a/chromium/net/proxy_resolution/proxy_resolver.h b/chromium/net/proxy_resolution/proxy_resolver.h index 6cfdb32859b..5b7e65c5ca4 100644 --- a/chromium/net/proxy_resolution/proxy_resolver.h +++ b/chromium/net/proxy_resolution/proxy_resolver.h @@ -6,7 +6,6 @@ #define NET_PROXY_RESOLUTION_PROXY_RESOLVER_H_ #include "base/callback_forward.h" -#include "base/logging.h" #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/strings/string16.h" diff --git a/chromium/net/quic/OWNERS b/chromium/net/quic/OWNERS index 9db36fa2026..4d12d7e8fff 100644 --- a/chromium/net/quic/OWNERS +++ b/chromium/net/quic/OWNERS @@ -1,6 +1,6 @@ dschinazi@chromium.org nharper@chromium.org -rch@chromium.org +vasilvv@chromium.org zhongyi@chromium.org bnc@chromium.org diff --git a/chromium/net/quic/bidirectional_stream_quic_impl_unittest.cc b/chromium/net/quic/bidirectional_stream_quic_impl_unittest.cc index 6cfc33e5862..e5410eaa44d 100644 --- a/chromium/net/quic/bidirectional_stream_quic_impl_unittest.cc +++ b/chromium/net/quic/bidirectional_stream_quic_impl_unittest.cc @@ -463,6 +463,7 @@ class BidirectionalStreamQuicImplTest printer_(version_), destination_(kDefaultServerHostName, kDefaultServerPort) { quic::QuicEnableVersion(version_); + FLAGS_quic_enable_http3_grease_randomness = false; IPAddress ip(192, 0, 2, 33); peer_addr_ = IPEndPoint(ip, 443); self_addr_ = IPEndPoint(ip, 8435); @@ -857,18 +858,14 @@ INSTANTIATE_TEST_SUITE_P(Version, ::testing::PrintToStringParamName()); TEST_P(BidirectionalStreamQuicImplTest, GetRequest) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3) { - // QUIC with TLS1.3 handshake doesn't support 0-rtt. - return; - } - SetRequest("GET", "/", DEFAULT_PRIORITY); size_t spdy_request_headers_frame_length; client_maker_.SetEncryptionLevel(quic::ENCRYPTION_ZERO_RTT); if (VersionUsesHttp3(version_.transport_version)) AddWrite(ConstructInitialSettingsPacket()); AddWrite(ConstructRequestHeadersPacketInner( - GetNthClientInitiatedBidirectionalStreamId(0), kFin, DEFAULT_PRIORITY, + GetNthClientInitiatedBidirectionalStreamId(0), kFin, + version_.UsesHttp3() ? MEDIUM : DEFAULT_PRIORITY, &spdy_request_headers_frame_length)); client_maker_.SetEncryptionLevel(quic::ENCRYPTION_FORWARD_SECURE); AddWrite(ConstructClientAckPacket(3, 1, 2)); @@ -966,22 +963,18 @@ TEST_P(BidirectionalStreamQuicImplTest, GetRequest) { } TEST_P(BidirectionalStreamQuicImplTest, LoadTimingTwoRequests) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3) { - // QUIC with TLS1.3 handshake doesn't support 0-rtt. - return; - } - SetRequest("GET", "/", DEFAULT_PRIORITY); client_maker_.SetEncryptionLevel(quic::ENCRYPTION_ZERO_RTT); if (VersionUsesHttp3(version_.transport_version)) AddWrite(ConstructInitialSettingsPacket()); AddWrite(ConstructRequestHeadersPacketInner( - GetNthClientInitiatedBidirectionalStreamId(0), kFin, DEFAULT_PRIORITY, - nullptr)); + GetNthClientInitiatedBidirectionalStreamId(0), kFin, + version_.UsesHttp3() ? MEDIUM : DEFAULT_PRIORITY, nullptr)); // SetRequest() again for second request as |request_headers_| was moved. SetRequest("GET", "/", DEFAULT_PRIORITY); AddWrite(ConstructRequestHeadersPacketInner( - GetNthClientInitiatedBidirectionalStreamId(1), kFin, DEFAULT_PRIORITY, + GetNthClientInitiatedBidirectionalStreamId(1), kFin, + version_.UsesHttp3() ? MEDIUM : DEFAULT_PRIORITY, GetNthClientInitiatedBidirectionalStreamId(0), nullptr)); client_maker_.SetEncryptionLevel(quic::ENCRYPTION_FORWARD_SECURE); AddWrite(ConstructClientAckPacket(3, 1, 2)); @@ -1045,10 +1038,6 @@ TEST_P(BidirectionalStreamQuicImplTest, LoadTimingTwoRequests) { // Tests that when request headers are not delayed, only data buffers are // coalesced. TEST_P(BidirectionalStreamQuicImplTest, CoalesceDataBuffersNotHeadersFrame) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3) { - // QUIC with TLS1.3 handshake doesn't support 0-rtt. - return; - } SetRequest("POST", "/", DEFAULT_PRIORITY); size_t spdy_request_headers_frame_length; client_maker_.SetEncryptionLevel(quic::ENCRYPTION_ZERO_RTT); @@ -1061,7 +1050,8 @@ TEST_P(BidirectionalStreamQuicImplTest, CoalesceDataBuffersNotHeadersFrame) { std::string header2 = ConstructDataHeader(kBody2.length()); std::vector<std::string> two_writes = {kBody1, kBody2}; AddWrite(ConstructRequestHeadersPacketInner( - GetNthClientInitiatedBidirectionalStreamId(0), !kFin, DEFAULT_PRIORITY, + GetNthClientInitiatedBidirectionalStreamId(0), !kFin, + version_.UsesHttp3() ? MEDIUM : DEFAULT_PRIORITY, &spdy_request_headers_frame_length)); if (!version_.UsesHttp3()) { AddWrite( @@ -1191,11 +1181,6 @@ TEST_P(BidirectionalStreamQuicImplTest, CoalesceDataBuffersNotHeadersFrame) { // request headers with data buffers. TEST_P(BidirectionalStreamQuicImplTest, SendDataCoalesceDataBufferAndHeaderFrame) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3) { - // QUIC with TLS1.3 handshake doesn't support 0-rtt. - return; - } - SetRequest("POST", "/", DEFAULT_PRIORITY); size_t spdy_request_headers_frame_length; client_maker_.SetEncryptionLevel(quic::ENCRYPTION_ZERO_RTT); @@ -1206,8 +1191,7 @@ TEST_P(BidirectionalStreamQuicImplTest, std::string header = ConstructDataHeader(strlen(kBody1)); if (version_.UsesHttp3()) { AddWrite(ConstructRequestHeadersAndMultipleDataFramesPacket( - !kFin, DEFAULT_PRIORITY, &spdy_request_headers_frame_length, - {header, kBody1})); + !kFin, MEDIUM, &spdy_request_headers_frame_length, {header, kBody1})); } else { AddWrite(ConstructRequestHeadersAndMultipleDataFramesPacket( !kFin, DEFAULT_PRIORITY, &spdy_request_headers_frame_length, {kBody1})); @@ -1312,11 +1296,6 @@ TEST_P(BidirectionalStreamQuicImplTest, // request headers with data buffers. TEST_P(BidirectionalStreamQuicImplTest, SendvDataCoalesceDataBuffersAndHeaderFrame) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3) { - // QUIC with TLS1.3 handshake doesn't support 0-rtt. - return; - } - SetRequest("POST", "/", DEFAULT_PRIORITY); size_t spdy_request_headers_frame_length; client_maker_.SetEncryptionLevel(quic::ENCRYPTION_ZERO_RTT); @@ -1330,7 +1309,7 @@ TEST_P(BidirectionalStreamQuicImplTest, if (version_.UsesHttp3()) { AddWrite(ConstructRequestHeadersAndMultipleDataFramesPacket( - !kFin, DEFAULT_PRIORITY, &spdy_request_headers_frame_length, + !kFin, MEDIUM, &spdy_request_headers_frame_length, {header + kBody1 + header2 + kBody2})); } else { AddWrite(ConstructRequestHeadersAndMultipleDataFramesPacket( @@ -1453,11 +1432,6 @@ TEST_P(BidirectionalStreamQuicImplTest, // headers to be sent, if that write fails the stream does not crash. TEST_P(BidirectionalStreamQuicImplTest, SendDataWriteErrorCoalesceDataBufferAndHeaderFrame) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3) { - // QUIC with TLS1.3 handshake doesn't support 0-rtt. - return; - } - client_maker_.SetEncryptionLevel(quic::ENCRYPTION_ZERO_RTT); if (VersionUsesHttp3(version_.transport_version)) AddWrite(ConstructInitialSettingsPacket()); @@ -1495,10 +1469,6 @@ TEST_P(BidirectionalStreamQuicImplTest, // headers to be sent, if that write fails the stream does not crash. TEST_P(BidirectionalStreamQuicImplTest, SendvDataWriteErrorCoalesceDataBufferAndHeaderFrame) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3) { - // QUIC with TLS1.3 handshake doesn't support 0-rtt. - return; - } client_maker_.SetEncryptionLevel(quic::ENCRYPTION_ZERO_RTT); if (VersionUsesHttp3(version_.transport_version)) AddWrite(ConstructInitialSettingsPacket()); @@ -1537,11 +1507,6 @@ TEST_P(BidirectionalStreamQuicImplTest, } TEST_P(BidirectionalStreamQuicImplTest, PostRequest) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3) { - // QUIC with TLS1.3 handshake doesn't support 0-rtt. - return; - } - SetRequest("POST", "/", DEFAULT_PRIORITY); size_t spdy_request_headers_frame_length; client_maker_.SetEncryptionLevel(quic::ENCRYPTION_ZERO_RTT); @@ -1549,7 +1514,8 @@ TEST_P(BidirectionalStreamQuicImplTest, PostRequest) { AddWrite(ConstructInitialSettingsPacket()); client_maker_.SetEncryptionLevel(quic::ENCRYPTION_FORWARD_SECURE); AddWrite(ConstructRequestHeadersPacketInner( - GetNthClientInitiatedBidirectionalStreamId(0), !kFin, DEFAULT_PRIORITY, + GetNthClientInitiatedBidirectionalStreamId(0), !kFin, + version_.UsesHttp3() ? MEDIUM : DEFAULT_PRIORITY, &spdy_request_headers_frame_length)); std::string header = ConstructDataHeader(strlen(kUploadData)); if (version_.UsesHttp3()) { @@ -1637,18 +1603,14 @@ TEST_P(BidirectionalStreamQuicImplTest, PostRequest) { } TEST_P(BidirectionalStreamQuicImplTest, EarlyDataOverrideRequest) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3) { - // QUIC with TLS1.3 handshake doesn't support 0-rtt. - return; - } - SetRequest("PUT", "/", DEFAULT_PRIORITY); size_t spdy_request_headers_frame_length; client_maker_.SetEncryptionLevel(quic::ENCRYPTION_ZERO_RTT); if (VersionUsesHttp3(version_.transport_version)) AddWrite(ConstructInitialSettingsPacket()); AddWrite(ConstructRequestHeadersPacketInner( - GetNthClientInitiatedBidirectionalStreamId(0), kFin, DEFAULT_PRIORITY, + GetNthClientInitiatedBidirectionalStreamId(0), kFin, + version_.UsesHttp3() ? MEDIUM : DEFAULT_PRIORITY, &spdy_request_headers_frame_length)); client_maker_.SetEncryptionLevel(quic::ENCRYPTION_FORWARD_SECURE); AddWrite(ConstructClientAckPacket(3, 1, 2)); @@ -1747,11 +1709,6 @@ TEST_P(BidirectionalStreamQuicImplTest, EarlyDataOverrideRequest) { } TEST_P(BidirectionalStreamQuicImplTest, InterleaveReadDataAndSendData) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3) { - // QUIC with TLS1.3 handshake doesn't support 0-rtt. - return; - } - SetRequest("POST", "/", DEFAULT_PRIORITY); size_t spdy_request_headers_frame_length; client_maker_.SetEncryptionLevel(quic::ENCRYPTION_ZERO_RTT); @@ -1759,7 +1716,8 @@ TEST_P(BidirectionalStreamQuicImplTest, InterleaveReadDataAndSendData) { AddWrite(ConstructInitialSettingsPacket()); client_maker_.SetEncryptionLevel(quic::ENCRYPTION_FORWARD_SECURE); AddWrite(ConstructRequestHeadersPacketInner( - GetNthClientInitiatedBidirectionalStreamId(0), !kFin, DEFAULT_PRIORITY, + GetNthClientInitiatedBidirectionalStreamId(0), !kFin, + version_.UsesHttp3() ? MEDIUM : DEFAULT_PRIORITY, &spdy_request_headers_frame_length)); std::string header = ConstructDataHeader(strlen(kUploadData)); @@ -1862,18 +1820,14 @@ TEST_P(BidirectionalStreamQuicImplTest, InterleaveReadDataAndSendData) { } TEST_P(BidirectionalStreamQuicImplTest, ServerSendsRstAfterHeaders) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3) { - // QUIC with TLS1.3 handshake doesn't support 0-rtt. - return; - } - SetRequest("GET", "/", DEFAULT_PRIORITY); size_t spdy_request_headers_frame_length; client_maker_.SetEncryptionLevel(quic::ENCRYPTION_ZERO_RTT); if (VersionUsesHttp3(version_.transport_version)) AddWrite(ConstructInitialSettingsPacket()); AddWrite(ConstructRequestHeadersPacketInner( - GetNthClientInitiatedBidirectionalStreamId(0), kFin, DEFAULT_PRIORITY, + GetNthClientInitiatedBidirectionalStreamId(0), kFin, + version_.UsesHttp3() ? MEDIUM : DEFAULT_PRIORITY, &spdy_request_headers_frame_length)); client_maker_.SetEncryptionLevel(quic::ENCRYPTION_FORWARD_SECURE); Initialize(); @@ -1913,18 +1867,14 @@ TEST_P(BidirectionalStreamQuicImplTest, ServerSendsRstAfterHeaders) { } TEST_P(BidirectionalStreamQuicImplTest, ServerSendsRstAfterReadData) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3) { - // QUIC with TLS1.3 handshake doesn't support 0-rtt. - return; - } - SetRequest("GET", "/", DEFAULT_PRIORITY); size_t spdy_request_headers_frame_length; client_maker_.SetEncryptionLevel(quic::ENCRYPTION_ZERO_RTT); if (VersionUsesHttp3(version_.transport_version)) AddWrite(ConstructInitialSettingsPacket()); AddWrite(ConstructRequestHeadersPacketInner( - GetNthClientInitiatedBidirectionalStreamId(0), kFin, DEFAULT_PRIORITY, + GetNthClientInitiatedBidirectionalStreamId(0), kFin, + version_.UsesHttp3() ? MEDIUM : DEFAULT_PRIORITY, &spdy_request_headers_frame_length)); client_maker_.SetEncryptionLevel(quic::ENCRYPTION_FORWARD_SECURE); // Why does QUIC ack Rst? Is this expected? @@ -1982,11 +1932,6 @@ TEST_P(BidirectionalStreamQuicImplTest, ServerSendsRstAfterReadData) { } TEST_P(BidirectionalStreamQuicImplTest, SessionClosedBeforeReadData) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3) { - // QUIC with TLS1.3 handshake doesn't support 0-rtt. - return; - } - SetRequest("POST", "/", DEFAULT_PRIORITY); size_t spdy_request_headers_frame_length; client_maker_.SetEncryptionLevel(quic::ENCRYPTION_ZERO_RTT); @@ -1994,7 +1939,8 @@ TEST_P(BidirectionalStreamQuicImplTest, SessionClosedBeforeReadData) { AddWrite(ConstructInitialSettingsPacket()); client_maker_.SetEncryptionLevel(quic::ENCRYPTION_FORWARD_SECURE); AddWrite(ConstructRequestHeadersPacketInner( - GetNthClientInitiatedBidirectionalStreamId(0), !kFin, DEFAULT_PRIORITY, + GetNthClientInitiatedBidirectionalStreamId(0), !kFin, + version_.UsesHttp3() ? MEDIUM : DEFAULT_PRIORITY, &spdy_request_headers_frame_length)); Initialize(); @@ -2099,11 +2045,6 @@ TEST_P(BidirectionalStreamQuicImplTest, SessionClosedBeforeStartNotConfirmed) { } TEST_P(BidirectionalStreamQuicImplTest, SessionCloseDuringOnStreamReady) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3) { - // QUIC with TLS1.3 handshake doesn't support 0-rtt. - return; - } - SetRequest("POST", "/", DEFAULT_PRIORITY); client_maker_.SetEncryptionLevel(quic::ENCRYPTION_ZERO_RTT); if (VersionUsesHttp3(version_.transport_version)) @@ -2132,11 +2073,6 @@ TEST_P(BidirectionalStreamQuicImplTest, SessionCloseDuringOnStreamReady) { } TEST_P(BidirectionalStreamQuicImplTest, DeleteStreamDuringOnStreamReady) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3) { - // QUIC with TLS1.3 handshake doesn't support 0-rtt. - return; - } - SetRequest("POST", "/", DEFAULT_PRIORITY); size_t spdy_request_headers_frame_length; client_maker_.SetEncryptionLevel(quic::ENCRYPTION_ZERO_RTT); @@ -2144,7 +2080,8 @@ TEST_P(BidirectionalStreamQuicImplTest, DeleteStreamDuringOnStreamReady) { AddWrite(ConstructInitialSettingsPacket()); client_maker_.SetEncryptionLevel(quic::ENCRYPTION_FORWARD_SECURE); AddWrite(ConstructRequestHeadersPacketInner( - GetNthClientInitiatedBidirectionalStreamId(0), !kFin, DEFAULT_PRIORITY, + GetNthClientInitiatedBidirectionalStreamId(0), !kFin, + version_.UsesHttp3() ? MEDIUM : DEFAULT_PRIORITY, &spdy_request_headers_frame_length)); AddWrite(ConstructClientEarlyRstStreamPacket()); @@ -2171,11 +2108,6 @@ TEST_P(BidirectionalStreamQuicImplTest, DeleteStreamDuringOnStreamReady) { } TEST_P(BidirectionalStreamQuicImplTest, DeleteStreamAfterReadData) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3) { - // QUIC with TLS1.3 handshake doesn't support 0-rtt. - return; - } - SetRequest("POST", "/", DEFAULT_PRIORITY); size_t spdy_request_headers_frame_length; client_maker_.SetEncryptionLevel(quic::ENCRYPTION_ZERO_RTT); @@ -2183,7 +2115,8 @@ TEST_P(BidirectionalStreamQuicImplTest, DeleteStreamAfterReadData) { AddWrite(ConstructInitialSettingsPacket()); client_maker_.SetEncryptionLevel(quic::ENCRYPTION_FORWARD_SECURE); AddWrite(ConstructRequestHeadersPacketInner( - GetNthClientInitiatedBidirectionalStreamId(0), !kFin, DEFAULT_PRIORITY, + GetNthClientInitiatedBidirectionalStreamId(0), !kFin, + version_.UsesHttp3() ? MEDIUM : DEFAULT_PRIORITY, &spdy_request_headers_frame_length)); AddWrite(ConstructClientAckAndRstStreamPacket(2, 1, 2)); @@ -2234,11 +2167,6 @@ TEST_P(BidirectionalStreamQuicImplTest, DeleteStreamAfterReadData) { } TEST_P(BidirectionalStreamQuicImplTest, DeleteStreamDuringOnHeadersReceived) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3) { - // QUIC with TLS1.3 handshake doesn't support 0-rtt. - return; - } - SetRequest("POST", "/", DEFAULT_PRIORITY); size_t spdy_request_headers_frame_length; client_maker_.SetEncryptionLevel(quic::ENCRYPTION_ZERO_RTT); @@ -2246,7 +2174,8 @@ TEST_P(BidirectionalStreamQuicImplTest, DeleteStreamDuringOnHeadersReceived) { AddWrite(ConstructInitialSettingsPacket()); client_maker_.SetEncryptionLevel(quic::ENCRYPTION_FORWARD_SECURE); AddWrite(ConstructRequestHeadersPacketInner( - GetNthClientInitiatedBidirectionalStreamId(0), !kFin, DEFAULT_PRIORITY, + GetNthClientInitiatedBidirectionalStreamId(0), !kFin, + version_.UsesHttp3() ? MEDIUM : DEFAULT_PRIORITY, &spdy_request_headers_frame_length)); AddWrite(ConstructClientAckAndRstStreamPacket(2, 1, 2)); @@ -2289,11 +2218,6 @@ TEST_P(BidirectionalStreamQuicImplTest, DeleteStreamDuringOnHeadersReceived) { } TEST_P(BidirectionalStreamQuicImplTest, DeleteStreamDuringOnDataRead) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3) { - // QUIC with TLS1.3 handshake doesn't support 0-rtt. - return; - } - SetRequest("POST", "/", DEFAULT_PRIORITY); size_t spdy_request_headers_frame_length; client_maker_.SetEncryptionLevel(quic::ENCRYPTION_ZERO_RTT); @@ -2301,7 +2225,8 @@ TEST_P(BidirectionalStreamQuicImplTest, DeleteStreamDuringOnDataRead) { AddWrite(ConstructInitialSettingsPacket()); client_maker_.SetEncryptionLevel(quic::ENCRYPTION_FORWARD_SECURE); AddWrite(ConstructRequestHeadersPacketInner( - GetNthClientInitiatedBidirectionalStreamId(0), !kFin, DEFAULT_PRIORITY, + GetNthClientInitiatedBidirectionalStreamId(0), !kFin, + version_.UsesHttp3() ? MEDIUM : DEFAULT_PRIORITY, &spdy_request_headers_frame_length)); AddWrite(ConstructClientAckPacket(3, 1, 2)); AddWrite(ConstructClientRstStreamPacket()); @@ -2355,11 +2280,6 @@ TEST_P(BidirectionalStreamQuicImplTest, DeleteStreamDuringOnDataRead) { } TEST_P(BidirectionalStreamQuicImplTest, AsyncFinRead) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3) { - // QUIC with TLS1.3 handshake doesn't support 0-rtt. - return; - } - const char kBody[] = "here is some data"; SetRequest("POST", "/", DEFAULT_PRIORITY); size_t spdy_request_headers_frame_length; @@ -2368,7 +2288,8 @@ TEST_P(BidirectionalStreamQuicImplTest, AsyncFinRead) { AddWrite(ConstructInitialSettingsPacket()); client_maker_.SetEncryptionLevel(quic::ENCRYPTION_FORWARD_SECURE); AddWrite(ConstructRequestHeadersPacketInner( - GetNthClientInitiatedBidirectionalStreamId(0), !kFin, DEFAULT_PRIORITY, + GetNthClientInitiatedBidirectionalStreamId(0), !kFin, + version_.UsesHttp3() ? MEDIUM : DEFAULT_PRIORITY, &spdy_request_headers_frame_length)); std::string header = ConstructDataHeader(strlen(kBody)); if (version_.UsesHttp3()) { @@ -2437,18 +2358,15 @@ TEST_P(BidirectionalStreamQuicImplTest, AsyncFinRead) { } TEST_P(BidirectionalStreamQuicImplTest, DeleteStreamDuringOnTrailersReceived) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3) { - // QUIC with TLS1.3 handshake doesn't support 0-rtt. - return; - } - SetRequest("GET", "/", DEFAULT_PRIORITY); size_t spdy_request_headers_frame_length; client_maker_.SetEncryptionLevel(quic::ENCRYPTION_ZERO_RTT); if (VersionUsesHttp3(version_.transport_version)) AddWrite(ConstructInitialSettingsPacket()); - AddWrite(ConstructRequestHeadersPacket(kFin, DEFAULT_PRIORITY, - &spdy_request_headers_frame_length)); + client_maker_.SetEncryptionLevel(quic::ENCRYPTION_FORWARD_SECURE); + AddWrite(ConstructRequestHeadersPacket( + kFin, version_.UsesHttp3() ? MEDIUM : DEFAULT_PRIORITY, + &spdy_request_headers_frame_length)); AddWrite(ConstructClientAckPacket(3, 1, 2)); // Ack the data packet AddWrite(ConstructClientAckAndRstStreamPacket(4, 4, 2)); @@ -2467,6 +2385,7 @@ TEST_P(BidirectionalStreamQuicImplTest, DeleteStreamDuringOnTrailersReceived) { DeleteStreamDelegate::ON_TRAILERS_RECEIVED)); delegate->Start(&request, net_log().bound(), session()->CreateHandle(destination_)); + ConfirmHandshake(); delegate->WaitUntilNextCallback(kOnStreamReady); // Server acks the request. diff --git a/chromium/net/quic/crypto/proof_verifier_chromium.cc b/chromium/net/quic/crypto/proof_verifier_chromium.cc index ee05dce91ca..d49b1db3218 100644 --- a/chromium/net/quic/crypto/proof_verifier_chromium.cc +++ b/chromium/net/quic/crypto/proof_verifier_chromium.cc @@ -16,6 +16,7 @@ #include "crypto/signature_verifier.h" #include "net/base/host_port_pair.h" #include "net/base/net_errors.h" +#include "net/base/network_isolation_key.h" #include "net/cert/cert_status_flags.h" #include "net/cert/cert_verifier.h" #include "net/cert/ct_policy_enforcer.h" @@ -459,7 +460,8 @@ int ProofVerifierChromium::Job::DoVerifyCertComplete(int result) { cert_verify_result.verified_cert.get(), cert_.get(), verify_details_->ct_verify_result.scts, TransportSecurityState::ENABLE_EXPECT_CT_REPORTS, - verify_details_->ct_verify_result.policy_compliance); + verify_details_->ct_verify_result.policy_compliance, + proof_verifier_->network_isolation_key_); if (ct_requirement_status != TransportSecurityState::CT_NOT_REQUIRED) { verify_details_->ct_verify_result.policy_compliance_required = true; if (verify_details_->cert_verify_result.is_issued_by_known_root) { @@ -594,12 +596,14 @@ ProofVerifierChromium::ProofVerifierChromium( CTPolicyEnforcer* ct_policy_enforcer, TransportSecurityState* transport_security_state, CTVerifier* cert_transparency_verifier, - std::set<std::string> hostnames_to_allow_unknown_roots) + std::set<std::string> hostnames_to_allow_unknown_roots, + const NetworkIsolationKey& network_isolation_key) : cert_verifier_(cert_verifier), ct_policy_enforcer_(ct_policy_enforcer), transport_security_state_(transport_security_state), cert_transparency_verifier_(cert_transparency_verifier), - hostnames_to_allow_unknown_roots_(hostnames_to_allow_unknown_roots) { + hostnames_to_allow_unknown_roots_(hostnames_to_allow_unknown_roots), + network_isolation_key_(network_isolation_key) { DCHECK(cert_verifier_); DCHECK(ct_policy_enforcer_); DCHECK(transport_security_state_); diff --git a/chromium/net/quic/crypto/proof_verifier_chromium.h b/chromium/net/quic/crypto/proof_verifier_chromium.h index beacd3d0d63..f05da2eb259 100644 --- a/chromium/net/quic/crypto/proof_verifier_chromium.h +++ b/chromium/net/quic/crypto/proof_verifier_chromium.h @@ -13,6 +13,7 @@ #include "base/compiler_specific.h" #include "base/macros.h" #include "net/base/net_export.h" +#include "net/base/network_isolation_key.h" #include "net/cert/cert_verify_result.h" #include "net/cert/ct_verify_result.h" #include "net/cert/x509_certificate.h" @@ -74,7 +75,8 @@ class NET_EXPORT_PRIVATE ProofVerifierChromium : public quic::ProofVerifier { CTPolicyEnforcer* ct_policy_enforcer, TransportSecurityState* transport_security_state, CTVerifier* cert_transparency_verifier, - std::set<std::string> hostnames_to_allow_unknown_roots); + std::set<std::string> hostnames_to_allow_unknown_roots, + const NetworkIsolationKey& network_isolation_key); ~ProofVerifierChromium() override; // quic::ProofVerifier interface @@ -120,6 +122,8 @@ class NET_EXPORT_PRIVATE ProofVerifierChromium : public quic::ProofVerifier { std::set<std::string> hostnames_to_allow_unknown_roots_; + const NetworkIsolationKey network_isolation_key_; + DISALLOW_COPY_AND_ASSIGN(ProofVerifierChromium); }; diff --git a/chromium/net/quic/crypto/proof_verifier_chromium_test.cc b/chromium/net/quic/crypto/proof_verifier_chromium_test.cc index 62504d05827..e04f01a8566 100644 --- a/chromium/net/quic/crypto/proof_verifier_chromium_test.cc +++ b/chromium/net/quic/crypto/proof_verifier_chromium_test.cc @@ -10,6 +10,7 @@ #include "base/test/metrics/histogram_tester.h" #include "net/base/completion_once_callback.h" #include "net/base/net_errors.h" +#include "net/base/network_isolation_key.h" #include "net/cert/cert_status_flags.h" #include "net/cert/cert_verifier.h" #include "net/cert/ct_log_verifier.h" @@ -113,6 +114,11 @@ const char kTestEmptySignature[] = ""; const char kLogDescription[] = "somelog"; +// This test exercises code that does not depend on the QUIC version in use +// but that still requires a version so we just use the first one. +const quic::QuicTransportVersion kTestTransportVersion = + quic::AllSupportedVersions().front().transport_version; + } // namespace class ProofVerifierChromiumTest : public ::testing::Test { @@ -152,7 +158,7 @@ class ProofVerifierChromiumTest : public ::testing::Test { base::FilePath()); std::string signature; source.GetProof(quic::QuicSocketAddress(), quic::QuicSocketAddress(), - kTestHostname, kTestConfig, quic::QUIC_VERSION_43, + kTestHostname, kTestConfig, kTestTransportVersion, kTestChloHash, std::make_unique<SignatureSaver>(&signature)); return signature; @@ -204,14 +210,14 @@ TEST_F(ProofVerifierChromiumTest, VerifyProof) { MockCertVerifier dummy_verifier; dummy_verifier.AddResultForCert(test_cert_.get(), dummy_result_, OK); - ProofVerifierChromium proof_verifier(&dummy_verifier, &ct_policy_enforcer_, - &transport_security_state_, - ct_verifier_.get(), {}); + ProofVerifierChromium proof_verifier( + &dummy_verifier, &ct_policy_enforcer_, &transport_security_state_, + ct_verifier_.get(), {}, NetworkIsolationKey()); std::unique_ptr<DummyProofVerifierCallback> callback( new DummyProofVerifierCallback); quic::QuicAsyncStatus status = proof_verifier.VerifyProof( - kTestHostname, kTestPort, kTestConfig, quic::QUIC_VERSION_43, + kTestHostname, kTestPort, kTestConfig, kTestTransportVersion, kTestChloHash, certs_, kTestEmptySCT, GetTestSignature(), verify_context_.get(), &error_details_, &details_, std::move(callback)); ASSERT_EQ(quic::QUIC_SUCCESS, status); @@ -238,14 +244,14 @@ TEST_F(ProofVerifierChromiumTest, VerifyProof) { // verification fails. TEST_F(ProofVerifierChromiumTest, FailsIfCertFails) { MockCertVerifier dummy_verifier; - ProofVerifierChromium proof_verifier(&dummy_verifier, &ct_policy_enforcer_, - &transport_security_state_, - ct_verifier_.get(), {}); + ProofVerifierChromium proof_verifier( + &dummy_verifier, &ct_policy_enforcer_, &transport_security_state_, + ct_verifier_.get(), {}, NetworkIsolationKey()); std::unique_ptr<DummyProofVerifierCallback> callback( new DummyProofVerifierCallback); quic::QuicAsyncStatus status = proof_verifier.VerifyProof( - kTestHostname, kTestPort, kTestConfig, quic::QUIC_VERSION_43, + kTestHostname, kTestPort, kTestConfig, kTestTransportVersion, kTestChloHash, certs_, kTestEmptySCT, GetTestSignature(), verify_context_.get(), &error_details_, &details_, std::move(callback)); ASSERT_EQ(quic::QUIC_FAILURE, status); @@ -264,14 +270,14 @@ TEST_F(ProofVerifierChromiumTest, ValidSCTList) { MockCertVerifier cert_verifier; - ProofVerifierChromium proof_verifier(&cert_verifier, &ct_policy_enforcer_, - &transport_security_state_, - ct_verifier_.get(), {}); + ProofVerifierChromium proof_verifier( + &cert_verifier, &ct_policy_enforcer_, &transport_security_state_, + ct_verifier_.get(), {}, NetworkIsolationKey()); std::unique_ptr<DummyProofVerifierCallback> callback( new DummyProofVerifierCallback); quic::QuicAsyncStatus status = proof_verifier.VerifyProof( - kTestHostname, kTestPort, kTestConfig, quic::QUIC_VERSION_43, + kTestHostname, kTestPort, kTestConfig, kTestTransportVersion, kTestChloHash, certs_, ct::GetSCTListForTesting(), kTestEmptySignature, verify_context_.get(), &error_details_, &details_, std::move(callback)); ASSERT_EQ(quic::QUIC_FAILURE, status); @@ -292,14 +298,14 @@ TEST_F(ProofVerifierChromiumTest, InvalidSCTList) { ASSERT_NO_FATAL_FAILURE(GetSCTTestCertificates(&certs_)); MockCertVerifier cert_verifier; - ProofVerifierChromium proof_verifier(&cert_verifier, &ct_policy_enforcer_, - &transport_security_state_, - ct_verifier_.get(), {}); + ProofVerifierChromium proof_verifier( + &cert_verifier, &ct_policy_enforcer_, &transport_security_state_, + ct_verifier_.get(), {}, NetworkIsolationKey()); std::unique_ptr<DummyProofVerifierCallback> callback( new DummyProofVerifierCallback); quic::QuicAsyncStatus status = proof_verifier.VerifyProof( - kTestHostname, kTestPort, kTestConfig, quic::QUIC_VERSION_43, + kTestHostname, kTestPort, kTestConfig, kTestTransportVersion, kTestChloHash, certs_, ct::GetSCTListWithInvalidSCT(), kTestEmptySignature, verify_context_.get(), &error_details_, &details_, std::move(callback)); @@ -319,14 +325,14 @@ TEST_F(ProofVerifierChromiumTest, InvalidSCTList) { // signature fails. TEST_F(ProofVerifierChromiumTest, FailsIfSignatureFails) { FailsTestCertVerifier cert_verifier; - ProofVerifierChromium proof_verifier(&cert_verifier, &ct_policy_enforcer_, - &transport_security_state_, - ct_verifier_.get(), {}); + ProofVerifierChromium proof_verifier( + &cert_verifier, &ct_policy_enforcer_, &transport_security_state_, + ct_verifier_.get(), {}, NetworkIsolationKey()); std::unique_ptr<DummyProofVerifierCallback> callback( new DummyProofVerifierCallback); quic::QuicAsyncStatus status = proof_verifier.VerifyProof( - kTestHostname, kTestPort, kTestConfig, quic::QUIC_VERSION_43, + kTestHostname, kTestPort, kTestConfig, kTestTransportVersion, kTestChloHash, certs_, kTestEmptySCT, kTestEmptySignature, verify_context_.get(), &error_details_, &details_, std::move(callback)); ASSERT_EQ(quic::QUIC_FAILURE, status); @@ -344,14 +350,14 @@ TEST_F(ProofVerifierChromiumTest, PreservesEVIfAllowed) { .WillRepeatedly( Return(ct::CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS)); - ProofVerifierChromium proof_verifier(&dummy_verifier, &ct_policy_enforcer_, - &transport_security_state_, - ct_verifier_.get(), {}); + ProofVerifierChromium proof_verifier( + &dummy_verifier, &ct_policy_enforcer_, &transport_security_state_, + ct_verifier_.get(), {}, NetworkIsolationKey()); std::unique_ptr<DummyProofVerifierCallback> callback( new DummyProofVerifierCallback); quic::QuicAsyncStatus status = proof_verifier.VerifyProof( - kTestHostname, kTestPort, kTestConfig, quic::QUIC_VERSION_43, + kTestHostname, kTestPort, kTestConfig, kTestTransportVersion, kTestChloHash, certs_, kTestEmptySCT, GetTestSignature(), verify_context_.get(), &error_details_, &details_, std::move(callback)); ASSERT_EQ(quic::QUIC_SUCCESS, status); @@ -387,14 +393,14 @@ TEST_F(ProofVerifierChromiumTest, StripsEVIfNotAllowed) { .WillRepeatedly( Return(ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS)); - ProofVerifierChromium proof_verifier(&dummy_verifier, &ct_policy_enforcer_, - &transport_security_state_, - ct_verifier_.get(), {}); + ProofVerifierChromium proof_verifier( + &dummy_verifier, &ct_policy_enforcer_, &transport_security_state_, + ct_verifier_.get(), {}, NetworkIsolationKey()); std::unique_ptr<DummyProofVerifierCallback> callback( new DummyProofVerifierCallback); quic::QuicAsyncStatus status = proof_verifier.VerifyProof( - kTestHostname, kTestPort, kTestConfig, quic::QUIC_VERSION_43, + kTestHostname, kTestPort, kTestConfig, kTestTransportVersion, kTestChloHash, certs_, kTestEmptySCT, GetTestSignature(), verify_context_.get(), &error_details_, &details_, std::move(callback)); ASSERT_EQ(quic::QUIC_SUCCESS, status); @@ -436,14 +442,14 @@ TEST_F(ProofVerifierChromiumTest, CTEVHistogramNonCompliant) { .WillRepeatedly( Return(ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS)); - ProofVerifierChromium proof_verifier(&dummy_verifier, &ct_policy_enforcer_, - &transport_security_state_, - ct_verifier_.get(), {}); + ProofVerifierChromium proof_verifier( + &dummy_verifier, &ct_policy_enforcer_, &transport_security_state_, + ct_verifier_.get(), {}, NetworkIsolationKey()); std::unique_ptr<DummyProofVerifierCallback> callback( new DummyProofVerifierCallback); quic::QuicAsyncStatus status = proof_verifier.VerifyProof( - kTestHostname, kTestPort, kTestConfig, quic::QUIC_VERSION_43, + kTestHostname, kTestPort, kTestConfig, kTestTransportVersion, kTestChloHash, certs_, kTestEmptySCT, GetTestSignature(), verify_context_.get(), &error_details_, &details_, std::move(callback)); ASSERT_EQ(quic::QUIC_SUCCESS, status); @@ -492,14 +498,14 @@ TEST_F(ProofVerifierChromiumTest, CTEVHistogramCompliant) { .WillRepeatedly( Return(ct::CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS)); - ProofVerifierChromium proof_verifier(&dummy_verifier, &ct_policy_enforcer_, - &transport_security_state_, - ct_verifier_.get(), {}); + ProofVerifierChromium proof_verifier( + &dummy_verifier, &ct_policy_enforcer_, &transport_security_state_, + ct_verifier_.get(), {}, NetworkIsolationKey()); std::unique_ptr<DummyProofVerifierCallback> callback( new DummyProofVerifierCallback); quic::QuicAsyncStatus status = proof_verifier.VerifyProof( - kTestHostname, kTestPort, kTestConfig, quic::QUIC_VERSION_43, + kTestHostname, kTestPort, kTestConfig, kTestTransportVersion, kTestChloHash, certs_, kTestEmptySCT, GetTestSignature(), verify_context_.get(), &error_details_, &details_, std::move(callback)); ASSERT_EQ(quic::QUIC_SUCCESS, status); @@ -544,14 +550,14 @@ TEST_F(ProofVerifierChromiumTest, IsFatalErrorNotSetForNonFatalError) { dummy_verifier.AddResultForCert(test_cert_.get(), dummy_result_, ERR_CERT_DATE_INVALID); - ProofVerifierChromium proof_verifier(&dummy_verifier, &ct_policy_enforcer_, - &transport_security_state_, - ct_verifier_.get(), {}); + ProofVerifierChromium proof_verifier( + &dummy_verifier, &ct_policy_enforcer_, &transport_security_state_, + ct_verifier_.get(), {}, NetworkIsolationKey()); std::unique_ptr<DummyProofVerifierCallback> callback( new DummyProofVerifierCallback); quic::QuicAsyncStatus status = proof_verifier.VerifyProof( - kTestHostname, kTestPort, kTestConfig, quic::QUIC_VERSION_43, + kTestHostname, kTestPort, kTestConfig, kTestTransportVersion, kTestChloHash, certs_, kTestEmptySCT, GetTestSignature(), verify_context_.get(), &error_details_, &details_, std::move(callback)); ASSERT_EQ(quic::QUIC_FAILURE, status); @@ -581,14 +587,14 @@ TEST_F(ProofVerifierChromiumTest, IsFatalErrorSetForFatalError) { base::Time::Now() + base::TimeDelta::FromSeconds(1000); transport_security_state_.AddHSTS(kTestHostname, expiry, true); - ProofVerifierChromium proof_verifier(&dummy_verifier, &ct_policy_enforcer_, - &transport_security_state_, - ct_verifier_.get(), {}); + ProofVerifierChromium proof_verifier( + &dummy_verifier, &ct_policy_enforcer_, &transport_security_state_, + ct_verifier_.get(), {}, NetworkIsolationKey()); std::unique_ptr<DummyProofVerifierCallback> callback( new DummyProofVerifierCallback); quic::QuicAsyncStatus status = proof_verifier.VerifyProof( - kTestHostname, kTestPort, kTestConfig, quic::QUIC_VERSION_43, + kTestHostname, kTestPort, kTestConfig, kTestTransportVersion, kTestChloHash, certs_, kTestEmptySCT, GetTestSignature(), verify_context_.get(), &error_details_, &details_, std::move(callback)); ASSERT_EQ(quic::QUIC_FAILURE, status); @@ -616,14 +622,14 @@ TEST_F(ProofVerifierChromiumTest, PKPEnforced) { transport_security_state_.EnableStaticPinsForTesting(); ScopedTransportSecurityStateSource scoped_security_state_source; - ProofVerifierChromium proof_verifier(&dummy_verifier, &ct_policy_enforcer_, - &transport_security_state_, - ct_verifier_.get(), {}); + ProofVerifierChromium proof_verifier( + &dummy_verifier, &ct_policy_enforcer_, &transport_security_state_, + ct_verifier_.get(), {}, NetworkIsolationKey()); std::unique_ptr<DummyProofVerifierCallback> callback( new DummyProofVerifierCallback); quic::QuicAsyncStatus status = proof_verifier.VerifyProof( - kCTAndPKPHost, kTestPort, kTestConfig, quic::QUIC_VERSION_43, + kCTAndPKPHost, kTestPort, kTestConfig, kTestTransportVersion, kTestChloHash, certs_, kTestEmptySCT, GetTestSignature(), verify_context_.get(), &error_details_, &details_, std::move(callback)); ASSERT_EQ(quic::QUIC_FAILURE, status); @@ -662,14 +668,14 @@ TEST_F(ProofVerifierChromiumTest, PKPBypassFlagSet) { transport_security_state_.EnableStaticPinsForTesting(); ScopedTransportSecurityStateSource scoped_security_state_source; - ProofVerifierChromium proof_verifier(&dummy_verifier, &ct_policy_enforcer_, - &transport_security_state_, - ct_verifier_.get(), {kCTAndPKPHost}); + ProofVerifierChromium proof_verifier( + &dummy_verifier, &ct_policy_enforcer_, &transport_security_state_, + ct_verifier_.get(), {kCTAndPKPHost}, NetworkIsolationKey()); std::unique_ptr<DummyProofVerifierCallback> callback( new DummyProofVerifierCallback); quic::QuicAsyncStatus status = proof_verifier.VerifyProof( - kCTAndPKPHost, kTestPort, kTestConfig, quic::QUIC_VERSION_43, + kCTAndPKPHost, kTestPort, kTestConfig, kTestTransportVersion, kTestChloHash, certs_, kTestEmptySCT, GetTestSignature(), verify_context_.get(), &error_details_, &details_, std::move(callback)); ASSERT_EQ(quic::QUIC_SUCCESS, status); @@ -712,14 +718,14 @@ TEST_F(ProofVerifierChromiumTest, CTIsRequired) { .WillRepeatedly( Return(ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS)); - ProofVerifierChromium proof_verifier(&dummy_verifier, &ct_policy_enforcer_, - &transport_security_state_, - ct_verifier_.get(), {}); + ProofVerifierChromium proof_verifier( + &dummy_verifier, &ct_policy_enforcer_, &transport_security_state_, + ct_verifier_.get(), {}, NetworkIsolationKey()); std::unique_ptr<DummyProofVerifierCallback> callback( new DummyProofVerifierCallback); quic::QuicAsyncStatus status = proof_verifier.VerifyProof( - kTestHostname, kTestPort, kTestConfig, quic::QUIC_VERSION_43, + kTestHostname, kTestPort, kTestConfig, kTestTransportVersion, kTestChloHash, certs_, kTestEmptySCT, GetTestSignature(), verify_context_.get(), &error_details_, &details_, std::move(callback)); ASSERT_EQ(quic::QUIC_FAILURE, status); @@ -769,14 +775,14 @@ TEST_F(ProofVerifierChromiumTest, CTIsRequiredHistogramNonCompliant) { .WillRepeatedly( Return(ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS)); - ProofVerifierChromium proof_verifier(&dummy_verifier, &ct_policy_enforcer_, - &transport_security_state_, - ct_verifier_.get(), {}); + ProofVerifierChromium proof_verifier( + &dummy_verifier, &ct_policy_enforcer_, &transport_security_state_, + ct_verifier_.get(), {}, NetworkIsolationKey()); std::unique_ptr<DummyProofVerifierCallback> callback( new DummyProofVerifierCallback); quic::QuicAsyncStatus status = proof_verifier.VerifyProof( - kTestHostname, kTestPort, kTestConfig, quic::QUIC_VERSION_43, + kTestHostname, kTestPort, kTestConfig, kTestTransportVersion, kTestChloHash, certs_, kTestEmptySCT, GetTestSignature(), verify_context_.get(), &error_details_, &details_, std::move(callback)); ASSERT_EQ(quic::QUIC_FAILURE, status); @@ -824,14 +830,14 @@ TEST_F(ProofVerifierChromiumTest, CTIsRequiredHistogramCompliant) { { MockCertVerifier dummy_verifier; dummy_verifier.AddResultForCert(test_cert_.get(), dummy_result_, OK); - ProofVerifierChromium proof_verifier(&dummy_verifier, &ct_policy_enforcer_, - &transport_security_state_, - ct_verifier_.get(), {kTestHostname}); + ProofVerifierChromium proof_verifier( + &dummy_verifier, &ct_policy_enforcer_, &transport_security_state_, + ct_verifier_.get(), {kTestHostname}, NetworkIsolationKey()); std::unique_ptr<DummyProofVerifierCallback> callback( new DummyProofVerifierCallback); quic::QuicAsyncStatus status = proof_verifier.VerifyProof( - kTestHostname, kTestPort, kTestConfig, quic::QUIC_VERSION_43, + kTestHostname, kTestPort, kTestConfig, kTestTransportVersion, kTestChloHash, certs_, kTestEmptySCT, GetTestSignature(), verify_context_.get(), &error_details_, &details_, std::move(callback)); ASSERT_EQ(quic::QUIC_SUCCESS, status); @@ -849,14 +855,14 @@ TEST_F(ProofVerifierChromiumTest, CTIsRequiredHistogramCompliant) { dummy_result_.is_issued_by_known_root = true; MockCertVerifier dummy_verifier; dummy_verifier.AddResultForCert(test_cert_.get(), dummy_result_, OK); - ProofVerifierChromium proof_verifier(&dummy_verifier, &ct_policy_enforcer_, - &transport_security_state_, - ct_verifier_.get(), {}); + ProofVerifierChromium proof_verifier( + &dummy_verifier, &ct_policy_enforcer_, &transport_security_state_, + ct_verifier_.get(), {}, NetworkIsolationKey()); std::unique_ptr<DummyProofVerifierCallback> callback( new DummyProofVerifierCallback); quic::QuicAsyncStatus status = proof_verifier.VerifyProof( - kTestHostname, kTestPort, kTestConfig, quic::QUIC_VERSION_43, + kTestHostname, kTestPort, kTestConfig, kTestTransportVersion, kTestChloHash, certs_, kTestEmptySCT, GetTestSignature(), verify_context_.get(), &error_details_, &details_, std::move(callback)); ASSERT_EQ(quic::QUIC_SUCCESS, status); @@ -892,14 +898,14 @@ TEST_F(ProofVerifierChromiumTest, CTIsNotRequiredHistogram) { MockCertVerifier dummy_verifier; dummy_verifier.AddResultForCert(test_cert_.get(), dummy_result_, OK); - ProofVerifierChromium proof_verifier(&dummy_verifier, &ct_policy_enforcer_, - &transport_security_state_, - ct_verifier_.get(), {kTestHostname}); + ProofVerifierChromium proof_verifier( + &dummy_verifier, &ct_policy_enforcer_, &transport_security_state_, + ct_verifier_.get(), {kTestHostname}, NetworkIsolationKey()); std::unique_ptr<DummyProofVerifierCallback> callback( new DummyProofVerifierCallback); quic::QuicAsyncStatus status = proof_verifier.VerifyProof( - kTestHostname, kTestPort, kTestConfig, quic::QUIC_VERSION_43, + kTestHostname, kTestPort, kTestConfig, kTestTransportVersion, kTestChloHash, certs_, kTestEmptySCT, GetTestSignature(), verify_context_.get(), &error_details_, &details_, std::move(callback)); ASSERT_EQ(quic::QUIC_SUCCESS, status); @@ -938,14 +944,14 @@ TEST_F(ProofVerifierChromiumTest, PKPAndCTBothTested) { .WillRepeatedly( Return(ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS)); - ProofVerifierChromium proof_verifier(&dummy_verifier, &ct_policy_enforcer_, - &transport_security_state_, - ct_verifier_.get(), {}); + ProofVerifierChromium proof_verifier( + &dummy_verifier, &ct_policy_enforcer_, &transport_security_state_, + ct_verifier_.get(), {}, NetworkIsolationKey()); std::unique_ptr<DummyProofVerifierCallback> callback( new DummyProofVerifierCallback); quic::QuicAsyncStatus status = proof_verifier.VerifyProof( - kCTAndPKPHost, kTestPort, kTestConfig, quic::QUIC_VERSION_43, + kCTAndPKPHost, kTestPort, kTestConfig, kTestTransportVersion, kTestChloHash, certs_, kTestEmptySCT, GetTestSignature(), verify_context_.get(), &error_details_, &details_, std::move(callback)); ASSERT_EQ(quic::QUIC_FAILURE, status); @@ -989,14 +995,14 @@ TEST_F(ProofVerifierChromiumTest, CTComplianceStatusHistogram) { { MockCertVerifier dummy_verifier; dummy_verifier.AddResultForCert(test_cert_.get(), dummy_result_, OK); - ProofVerifierChromium proof_verifier(&dummy_verifier, &ct_policy_enforcer_, - &transport_security_state_, - ct_verifier_.get(), {kTestHostname}); + ProofVerifierChromium proof_verifier( + &dummy_verifier, &ct_policy_enforcer_, &transport_security_state_, + ct_verifier_.get(), {kTestHostname}, NetworkIsolationKey()); std::unique_ptr<DummyProofVerifierCallback> callback( new DummyProofVerifierCallback); quic::QuicAsyncStatus status = proof_verifier.VerifyProof( - kTestHostname, kTestPort, kTestConfig, quic::QUIC_VERSION_43, + kTestHostname, kTestPort, kTestConfig, kTestTransportVersion, kTestChloHash, certs_, kTestEmptySCT, GetTestSignature(), verify_context_.get(), &error_details_, &details_, std::move(callback)); ASSERT_EQ(quic::QUIC_SUCCESS, status); @@ -1016,14 +1022,14 @@ TEST_F(ProofVerifierChromiumTest, CTComplianceStatusHistogram) { dummy_result_.is_issued_by_known_root = true; MockCertVerifier dummy_verifier; dummy_verifier.AddResultForCert(test_cert_.get(), dummy_result_, OK); - ProofVerifierChromium proof_verifier(&dummy_verifier, &ct_policy_enforcer_, - &transport_security_state_, - ct_verifier_.get(), {}); + ProofVerifierChromium proof_verifier( + &dummy_verifier, &ct_policy_enforcer_, &transport_security_state_, + ct_verifier_.get(), {}, NetworkIsolationKey()); std::unique_ptr<DummyProofVerifierCallback> callback( new DummyProofVerifierCallback); quic::QuicAsyncStatus status = proof_verifier.VerifyProof( - kTestHostname, kTestPort, kTestConfig, quic::QUIC_VERSION_43, + kTestHostname, kTestPort, kTestConfig, kTestTransportVersion, kTestChloHash, certs_, kTestEmptySCT, GetTestSignature(), verify_context_.get(), &error_details_, &details_, std::move(callback)); ASSERT_EQ(quic::QUIC_SUCCESS, status); @@ -1065,15 +1071,15 @@ TEST_F(ProofVerifierChromiumTest, CTRequirementsFlagNotMet) { .WillRepeatedly( Return(ct::CTPolicyCompliance::CT_POLICY_NOT_DIVERSE_SCTS)); - ProofVerifierChromium proof_verifier(&dummy_verifier, &ct_policy_enforcer_, - &transport_security_state_, - ct_verifier_.get(), {}); + ProofVerifierChromium proof_verifier( + &dummy_verifier, &ct_policy_enforcer_, &transport_security_state_, + ct_verifier_.get(), {}, NetworkIsolationKey()); { std::unique_ptr<DummyProofVerifierCallback> callback( new DummyProofVerifierCallback); proof_verifier.VerifyProof( - kTestHostname, kTestPort, kTestConfig, quic::QUIC_VERSION_43, + kTestHostname, kTestPort, kTestConfig, kTestTransportVersion, kTestChloHash, certs_, kTestEmptySCT, GetTestSignature(), verify_context_.get(), &error_details_, &details_, std::move(callback)); @@ -1118,15 +1124,15 @@ TEST_F(ProofVerifierChromiumTest, CTRequirementsFlagMet) { .WillRepeatedly( Return(ct::CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS)); - ProofVerifierChromium proof_verifier(&dummy_verifier, &ct_policy_enforcer_, - &transport_security_state_, - ct_verifier_.get(), {}); + ProofVerifierChromium proof_verifier( + &dummy_verifier, &ct_policy_enforcer_, &transport_security_state_, + ct_verifier_.get(), {}, NetworkIsolationKey()); { std::unique_ptr<DummyProofVerifierCallback> callback( new DummyProofVerifierCallback); proof_verifier.VerifyProof( - kTestHostname, kTestPort, kTestConfig, quic::QUIC_VERSION_43, + kTestHostname, kTestPort, kTestConfig, kTestTransportVersion, kTestChloHash, certs_, kTestEmptySCT, GetTestSignature(), verify_context_.get(), &error_details_, &details_, std::move(callback)); @@ -1160,14 +1166,14 @@ TEST_F(ProofVerifierChromiumTest, UnknownRootRejected) { MockCertVerifier dummy_verifier; dummy_verifier.AddResultForCert(test_cert_.get(), dummy_result_, OK); - ProofVerifierChromium proof_verifier(&dummy_verifier, &ct_policy_enforcer_, - &transport_security_state_, - ct_verifier_.get(), {}); + ProofVerifierChromium proof_verifier( + &dummy_verifier, &ct_policy_enforcer_, &transport_security_state_, + ct_verifier_.get(), {}, NetworkIsolationKey()); std::unique_ptr<DummyProofVerifierCallback> callback( new DummyProofVerifierCallback); quic::QuicAsyncStatus status = proof_verifier.VerifyProof( - kTestHostname, kTestPort, kTestConfig, quic::QUIC_VERSION_43, + kTestHostname, kTestPort, kTestConfig, kTestTransportVersion, kTestChloHash, certs_, kTestEmptySCT, GetTestSignature(), verify_context_.get(), &error_details_, &details_, std::move(callback)); ASSERT_EQ(quic::QUIC_FAILURE, status); @@ -1191,14 +1197,14 @@ TEST_F(ProofVerifierChromiumTest, UnknownRootAcceptedWithOverride) { MockCertVerifier dummy_verifier; dummy_verifier.AddResultForCert(test_cert_.get(), dummy_result_, OK); - ProofVerifierChromium proof_verifier(&dummy_verifier, &ct_policy_enforcer_, - &transport_security_state_, - ct_verifier_.get(), {kTestHostname}); + ProofVerifierChromium proof_verifier( + &dummy_verifier, &ct_policy_enforcer_, &transport_security_state_, + ct_verifier_.get(), {kTestHostname}, NetworkIsolationKey()); std::unique_ptr<DummyProofVerifierCallback> callback( new DummyProofVerifierCallback); quic::QuicAsyncStatus status = proof_verifier.VerifyProof( - kTestHostname, kTestPort, kTestConfig, quic::QUIC_VERSION_43, + kTestHostname, kTestPort, kTestConfig, kTestTransportVersion, kTestChloHash, certs_, kTestEmptySCT, GetTestSignature(), verify_context_.get(), &error_details_, &details_, std::move(callback)); ASSERT_EQ(quic::QUIC_SUCCESS, status); @@ -1227,14 +1233,14 @@ TEST_F(ProofVerifierChromiumTest, UnknownRootAcceptedWithWildcardOverride) { MockCertVerifier dummy_verifier; dummy_verifier.AddResultForCert(test_cert_.get(), dummy_result_, OK); - ProofVerifierChromium proof_verifier(&dummy_verifier, &ct_policy_enforcer_, - &transport_security_state_, - ct_verifier_.get(), {""}); + ProofVerifierChromium proof_verifier( + &dummy_verifier, &ct_policy_enforcer_, &transport_security_state_, + ct_verifier_.get(), {""}, NetworkIsolationKey()); std::unique_ptr<DummyProofVerifierCallback> callback( new DummyProofVerifierCallback); quic::QuicAsyncStatus status = proof_verifier.VerifyProof( - kTestHostname, kTestPort, kTestConfig, quic::QUIC_VERSION_43, + kTestHostname, kTestPort, kTestConfig, kTestTransportVersion, kTestChloHash, certs_, kTestEmptySCT, GetTestSignature(), verify_context_.get(), &error_details_, &details_, std::move(callback)); ASSERT_EQ(quic::QUIC_SUCCESS, status); diff --git a/chromium/net/quic/crypto_test_utils_chromium.cc b/chromium/net/quic/crypto_test_utils_chromium.cc index f284f7c4cdb..256dc0e28f5 100644 --- a/chromium/net/quic/crypto_test_utils_chromium.cc +++ b/chromium/net/quic/crypto_test_utils_chromium.cc @@ -11,6 +11,7 @@ #include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "net/base/net_errors.h" +#include "net/base/network_isolation_key.h" #include "net/base/test_completion_callback.h" #include "net/cert/cert_status_flags.h" #include "net/cert/cert_verifier.h" @@ -53,7 +54,8 @@ class TestProofVerifierChromium : public ProofVerifierChromium { ct_policy_enforcer.get(), transport_security_state.get(), cert_transparency_verifier.get(), - {"test.example.com"}), + {"test.example.com"}, + NetworkIsolationKey()), cert_verifier_(std::move(cert_verifier)), transport_security_state_(std::move(transport_security_state)), cert_transparency_verifier_(std::move(cert_transparency_verifier)), diff --git a/chromium/net/quic/mock_crypto_client_stream.cc b/chromium/net/quic/mock_crypto_client_stream.cc index 9a8d2b55e39..3eb98fdef89 100644 --- a/chromium/net/quic/mock_crypto_client_stream.cc +++ b/chromium/net/quic/mock_crypto_client_stream.cc @@ -11,6 +11,7 @@ #include "net/third_party/quiche/src/quic/core/crypto/quic_decrypter.h" #include "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h" #include "net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.h" +#include "net/third_party/quiche/src/quic/core/quic_utils.h" #include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" #include "net/third_party/quiche/src/quic/test_tools/quic_config_peer.h" #include "testing/gtest/include/gtest/gtest.h" @@ -32,7 +33,6 @@ using quic::NullEncrypter; using quic::PACKET_8BYTE_CONNECTION_ID; using quic::Perspective; using quic::ProofVerifyContext; -using quic::PROTOCOL_TLS1_3; using quic::QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE; using quic::QUIC_NO_ERROR; using quic::QUIC_PROOF_INVALID; @@ -49,6 +49,19 @@ using quic::TransportParameters; using quiche::QuicheStringPiece; using std::string; +namespace { + +// TODO(crbug.com/1085541): Consider moving this method into QuicTestUtils. +quic::QuicConnectionId TestConnectionId(uint64_t connection_number) { + const uint64_t connection_id64_net = + quiche::QuicheEndian::HostToNet64(connection_number); + return quic::QuicConnectionId( + reinterpret_cast<const char*>(&connection_id64_net), + sizeof(connection_id64_net)); +} + +} // namespace + namespace net { MockCryptoClientStream::MockCryptoClientStream( @@ -138,13 +151,17 @@ bool MockCryptoClientStream::CryptoConnect() { ENCRYPTION_ZERO_RTT, std::make_unique<NullDecrypter>(Perspective::IS_CLIENT)); } - session()->connection()->SetEncrypter( + if (session()->version().UsesHttp3()) { + SetConfigNegotiated(); + } + session()->OnNewEncryptionKeyAvailable( ENCRYPTION_ZERO_RTT, std::make_unique<NullEncrypter>(Perspective::IS_CLIENT)); } - if (session()->connection()->version().handshake_protocol == - quic::PROTOCOL_QUIC_CRYPTO) { + if (session()->version().UsesQuicCrypto()) { session()->SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT); + } else { + session()->DiscardOldEncryptionKey(ENCRYPTION_INITIAL); } break; } @@ -186,8 +203,7 @@ bool MockCryptoClientStream::CryptoConnect() { ENCRYPTION_FORWARD_SECURE, std::make_unique<NullEncrypter>(Perspective::IS_CLIENT)); } - if (session()->connection()->version().handshake_protocol == - quic::PROTOCOL_TLS1_3) { + if (session()->version().UsesTls()) { session()->OnOneRttKeysAvailable(); } else { session()->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); @@ -238,44 +254,48 @@ void MockCryptoClientStream::OnOneRttPacketAcknowledged() {} void MockCryptoClientStream::NotifySessionOneRttKeyAvailable() { encryption_established_ = true; - handshake_confirmed_ = true; + handshake_confirmed_ = true; + if (session()->version().UsesQuicCrypto()) SetConfigNegotiated(); - if (use_mock_crypter_) { - if (session()->connection()->version().KnowsWhichDecrypterToUse()) { - session()->connection()->InstallDecrypter( - ENCRYPTION_FORWARD_SECURE, - std::make_unique<MockDecrypter>(Perspective::IS_CLIENT)); - } else { - session()->connection()->SetDecrypter( - ENCRYPTION_FORWARD_SECURE, - std::make_unique<MockDecrypter>(Perspective::IS_CLIENT)); - } - session()->connection()->SetEncrypter( + if (use_mock_crypter_) { + if (session()->connection()->version().KnowsWhichDecrypterToUse()) { + session()->connection()->InstallDecrypter( ENCRYPTION_FORWARD_SECURE, - std::make_unique<MockEncrypter>(Perspective::IS_CLIENT)); + std::make_unique<MockDecrypter>(Perspective::IS_CLIENT)); } else { - if (session()->connection()->version().KnowsWhichDecrypterToUse()) { - session()->connection()->InstallDecrypter( - ENCRYPTION_FORWARD_SECURE, - std::make_unique<NullDecrypter>(Perspective::IS_CLIENT)); - } else { - session()->connection()->SetDecrypter( - ENCRYPTION_FORWARD_SECURE, - std::make_unique<NullDecrypter>(Perspective::IS_CLIENT)); - } - session()->connection()->SetEncrypter(ENCRYPTION_INITIAL, nullptr); - session()->OnNewEncryptionKeyAvailable( + session()->connection()->SetDecrypter( ENCRYPTION_FORWARD_SECURE, - std::make_unique<NullEncrypter>(Perspective::IS_CLIENT)); + std::make_unique<MockDecrypter>(Perspective::IS_CLIENT)); } - if (session()->connection()->version().handshake_protocol == - quic::PROTOCOL_TLS1_3) { - session()->OnOneRttKeysAvailable(); + session()->connection()->SetEncrypter( + ENCRYPTION_FORWARD_SECURE, + std::make_unique<MockEncrypter>(Perspective::IS_CLIENT)); + } else { + if (session()->connection()->version().KnowsWhichDecrypterToUse()) { + session()->connection()->InstallDecrypter( + ENCRYPTION_FORWARD_SECURE, + std::make_unique<NullDecrypter>(Perspective::IS_CLIENT)); } else { - session()->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); + session()->connection()->SetDecrypter( + ENCRYPTION_FORWARD_SECURE, + std::make_unique<NullDecrypter>(Perspective::IS_CLIENT)); } - session()->DiscardOldEncryptionKey(ENCRYPTION_INITIAL); - session()->NeuterHandshakeData(); + session()->connection()->SetEncrypter(ENCRYPTION_INITIAL, nullptr); + session()->OnNewEncryptionKeyAvailable( + ENCRYPTION_FORWARD_SECURE, + std::make_unique<NullEncrypter>(Perspective::IS_CLIENT)); + } + if (session()->version().UsesTls()) { + SetConfigNegotiated(); + session()->OnOneRttKeysAvailable(); + } else { + session()->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); + } + session()->DiscardOldEncryptionKey(ENCRYPTION_INITIAL); + if (session()->version().UsesTls()) { + session()->DiscardOldEncryptionKey(ENCRYPTION_ZERO_RTT); + } + session()->NeuterHandshakeData(); } // static @@ -286,7 +306,8 @@ CryptoHandshakeMessage MockCryptoClientStream::GetDummyCHLOMessage() { } void MockCryptoClientStream::SetConfigNegotiated() { - ASSERT_FALSE(session()->config()->negotiated()); + if (!session()->version().UsesHttp3()) + ASSERT_FALSE(session()->config()->negotiated()); QuicTagVector cgst; // TODO(rtenneti): Enable the following code after BBR code is checked in. #if 0 @@ -304,10 +325,27 @@ void MockCryptoClientStream::SetConfigNegotiated() { config.SetInitialMaxStreamDataBytesUnidirectionalToSend( quic::kMinimumFlowControlSendWindow); + if (quic::VersionHasIetfInvariantHeader( + session()->connection()->transport_version())) { + auto connection_id = TestConnectionId(0x1337); + config.SetStatelessResetTokenToSend( + quic::QuicUtils::GenerateStatelessResetToken(connection_id)); + } + if (session()->version().AuthenticatesHandshakeConnectionIds()) { + if (session()->perspective() == Perspective::IS_CLIENT) { + config.SetOriginalConnectionIdToSend( + session()->connection()->connection_id()); + config.SetInitialSourceConnectionIdToSend( + session()->connection()->connection_id()); + } else { + config.SetInitialSourceConnectionIdToSend( + session()->connection()->client_connection_id()); + } + } + QuicErrorCode error; std::string error_details; - if (session()->connection()->version().handshake_protocol == - PROTOCOL_TLS1_3) { + if (session()->version().UsesTls()) { TransportParameters params; ASSERT_TRUE(config.FillTransportParameters(¶ms)); error = session()->config()->ProcessTransportParameters( @@ -324,8 +362,7 @@ void MockCryptoClientStream::SetConfigNegotiated() { } void MockCryptoClientStream::FillCryptoParams() { - if (session()->connection()->version().handshake_protocol == - quic::PROTOCOL_QUIC_CRYPTO) { + if (session()->version().UsesQuicCrypto()) { crypto_negotiated_params_->key_exchange = kC255; crypto_negotiated_params_->aead = kAESG; return; diff --git a/chromium/net/quic/mock_quic_data.cc b/chromium/net/quic/mock_quic_data.cc index 9c71eff9c95..d1b5cbc41cb 100644 --- a/chromium/net/quic/mock_quic_data.cc +++ b/chromium/net/quic/mock_quic_data.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "net/quic/mock_quic_data.h" +#include "net/base/hex_utils.h" namespace net { namespace test { diff --git a/chromium/net/quic/network_connection.cc b/chromium/net/quic/network_connection.cc index 6cf3d116f65..9c36d366445 100644 --- a/chromium/net/quic/network_connection.cc +++ b/chromium/net/quic/network_connection.cc @@ -4,6 +4,7 @@ #include "net/quic/network_connection.h" +#include "base/logging.h" #include "net/base/network_interfaces.h" namespace net { diff --git a/chromium/net/quic/platform/impl/quic_default_proof_providers_impl.cc b/chromium/net/quic/platform/impl/quic_default_proof_providers_impl.cc index 28ec2766c6a..bbe4a7069e7 100644 --- a/chromium/net/quic/platform/impl/quic_default_proof_providers_impl.cc +++ b/chromium/net/quic/platform/impl/quic_default_proof_providers_impl.cc @@ -9,6 +9,7 @@ #include "base/files/file_path.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" +#include "net/base/network_isolation_key.h" #include "net/cert/cert_verifier.h" #include "net/cert/ct_log_verifier.h" #include "net/cert/ct_policy_enforcer.h" @@ -64,7 +65,10 @@ class ProofVerifierChromiumWithOwnership : public net::ProofVerifierChromium { &ct_policy_enforcer_, &transport_security_state_, &ct_verifier_, - UnknownRootAllowlistForHost(host)), + UnknownRootAllowlistForHost(host), + // Fine to use an empty NetworkIsolationKey + // here, since this isn't used in Chromium. + net::NetworkIsolationKey()), cert_verifier_(std::move(cert_verifier)) {} private: diff --git a/chromium/net/quic/platform/impl/quic_socket_utils.cc b/chromium/net/quic/platform/impl/quic_socket_utils.cc index bb062039fe5..9fe56a19040 100644 --- a/chromium/net/quic/platform/impl/quic_socket_utils.cc +++ b/chromium/net/quic/platform/impl/quic_socket_utils.cc @@ -14,6 +14,7 @@ #include <unistd.h> #include <string> +#include "base/notreached.h" #include "net/third_party/quiche/src/common/platform/api/quiche_arraysize.h" #include "net/third_party/quiche/src/quic/core/quic_packets.h" #include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" diff --git a/chromium/net/quic/platform/impl/quic_test_impl.h b/chromium/net/quic/platform/impl/quic_test_impl.h index 98bc7b27c29..1bcda9fde67 100644 --- a/chromium/net/quic/platform/impl/quic_test_impl.h +++ b/chromium/net/quic/platform/impl/quic_test_impl.h @@ -5,7 +5,7 @@ #ifndef NET_QUIC_PLATFORM_IMPL_QUIC_TEST_IMPL_H_ #define NET_QUIC_PLATFORM_IMPL_QUIC_TEST_IMPL_H_ -#include "base/logging.h" +#include "base/check_op.h" #include "net/test/test_with_task_environment.h" #include "net/third_party/quiche/src/quic/core/quic_versions.h" #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" diff --git a/chromium/net/quic/quic_chromium_client_session.cc b/chromium/net/quic/quic_chromium_client_session.cc index 780b8507c71..da5ac629afc 100644 --- a/chromium/net/quic/quic_chromium_client_session.cc +++ b/chromium/net/quic/quic_chromium_client_session.cc @@ -136,7 +136,7 @@ void RecordConnectionCloseErrorCode(const quic::QuicConnectionCloseFrame& frame, quic::ConnectionCloseSource source, const std::string& hostname, bool handshake_confirmed) { - bool is_google_host = HasGoogleHost(GURL("https://" + hostname)); + bool is_google_host = IsGoogleHost(hostname); std::string histogram = "Net.QuicSession.ConnectionCloseErrorCode"; if (source == quic::ConnectionCloseSource::FROM_SELF) { @@ -161,10 +161,20 @@ void RecordConnectionCloseErrorCode(const quic::QuicConnectionCloseFrame& frame, histogram += "IetfTransport"; RecordConnectionCloseErrorCodeImpl(histogram, frame.wire_error_code, is_google_host, handshake_confirmed); + if (frame.quic_error_code == quic::QUIC_IETF_GQUIC_ERROR_MISSING) { + histogram += "GQuicErrorMissing"; + RecordConnectionCloseErrorCodeImpl(histogram, frame.wire_error_code, + is_google_host, handshake_confirmed); + } } else if (frame.close_type == quic::IETF_QUIC_APPLICATION_CONNECTION_CLOSE) { histogram += "IetfApplication"; RecordConnectionCloseErrorCodeImpl(histogram, frame.wire_error_code, is_google_host, handshake_confirmed); + if (frame.quic_error_code == quic::QUIC_IETF_GQUIC_ERROR_MISSING) { + histogram += "GQuicErrorMissing"; + RecordConnectionCloseErrorCodeImpl(histogram, frame.wire_error_code, + is_google_host, handshake_confirmed); + } } } @@ -826,8 +836,7 @@ QuicChromiumClientSession::QuicChromiumClientSession( wait_for_new_network_(false), ignore_read_error_(false), headers_include_h2_stream_dependency_( - headers_include_h2_stream_dependency && - this->connection()->transport_version() >= quic::QUIC_VERSION_43), + headers_include_h2_stream_dependency), max_allowed_push_id_(max_allowed_push_id) { // Make sure connection migration and goaway on path degrading are not turned // on at the same time. @@ -880,6 +889,9 @@ QuicChromiumClientSession::QuicChromiumClientSession( QuicChromiumClientSession::~QuicChromiumClientSession() { DCHECK(callback_.is_null()); + for (auto& observer : connectivity_observer_list_) + observer.OnSessionRemoved(this); + net_log_.EndEvent(NetLogEventType::QUIC_SESSION); DCHECK(waiting_for_confirmation_callbacks_.empty()); if (HasActiveRequestStreams()) @@ -995,6 +1007,13 @@ void QuicChromiumClientSession::Initialize() { quic::QuicSpdyClientSessionBase::SetMaxPushId(max_allowed_push_id_); } set_max_inbound_header_list_size(kQuicMaxHeaderListSize); + if (config()->HasClientRequestedIndependentOption( + quic::kQLVE, quic::Perspective::IS_CLIENT)) { + connection()->EnableLegacyVersionEncapsulation(session_key_.host()); + // Legacy Version Encapsulation needs CHLO padding to be disabled. + // TODO(dschinazi) remove this line once we deprecate quic_dont_pad_chlo. + crypto_config_->GetConfig()->set_disable_chlo_padding(true); + } quic::QuicSpdyClientSessionBase::Initialize(); SetHpackEncoderDebugVisitor(std::make_unique<HpackEncoderDebugVisitor>()); SetHpackDecoderDebugVisitor(std::make_unique<HpackDecoderDebugVisitor>()); @@ -1078,6 +1097,16 @@ void QuicChromiumClientSession::RemoveHandle(Handle* handle) { handles_.erase(handle); } +void QuicChromiumClientSession::AddConnectivityObserver( + ConnectivityObserver* observer) { + connectivity_observer_list_.AddObserver(observer); +} + +void QuicChromiumClientSession::RemoveConnectivityObserver( + ConnectivityObserver* observer) { + connectivity_observer_list_.RemoveObserver(observer); +} + // TODO(zhongyi): replace migration_session_* booleans with // ConnectionMigrationMode. ConnectionMigrationMode QuicChromiumClientSession::connection_migration_mode() @@ -1363,7 +1392,7 @@ bool QuicChromiumClientSession::CanPool( return SpdySession::CanPool(transport_security_state_, ssl_info, *ssl_config_service_, session_key_.host(), - hostname); + hostname, network_isolation_key); } bool QuicChromiumClientSession::ShouldCreateIncomingStream( @@ -1383,7 +1412,7 @@ bool QuicChromiumClientSession::ShouldCreateIncomingStream( if (quic::QuicUtils::IsClientInitiatedStreamId( connection()->transport_version(), id) || (connection()->version().HasIetfQuicFrames() && - quic::QuicUtils::IsBidirectionalStreamId(id))) { + quic::QuicUtils::IsBidirectionalStreamId(id, connection()->version()))) { LOG(WARNING) << "Received invalid push stream id " << id; connection()->CloseConnection( quic::QUIC_INVALID_STREAM_ID, @@ -1537,36 +1566,26 @@ void QuicChromiumClientSession::OnConfigNegotiated() { IPEndPoint old_address; GetDefaultSocket()->GetPeerAddress(&old_address); - // Migrate only if address families match, or if new address family is v6, - // since a v4 address should be reachable over a v6 network (using a - // v4-mapped v6 address). + // Migrate only if address families match. IPEndPoint new_address; if (old_address.GetFamily() == ADDRESS_FAMILY_IPV6) { - if (config()->HasReceivedIPv6AlternateServerAddress()) { + if (!config()->HasReceivedIPv6AlternateServerAddress()) { + return; + } new_address = ToIPEndPoint(config()->ReceivedIPv6AlternateServerAddress()); - } else { - new_address = - ToIPEndPoint(config()->ReceivedIPv4AlternateServerAddress()); - // Use a v4-mapped v6 address. - new_address = - IPEndPoint(ConvertIPv4ToIPv4MappedIPv6(new_address.address()), - new_address.port()); - } } else if (old_address.GetFamily() == ADDRESS_FAMILY_IPV4) { - if (config()->HasReceivedIPv4AlternateServerAddress()) { - new_address = - ToIPEndPoint(config()->ReceivedIPv4AlternateServerAddress()); - } else { + if (!config()->HasReceivedIPv4AlternateServerAddress()) { return; } + new_address = ToIPEndPoint(config()->ReceivedIPv4AlternateServerAddress()); } DCHECK_EQ(new_address.GetFamily(), old_address.GetFamily()); // Specifying kInvalidNetworkHandle for the |network| parameter // causes the session to use the default network for the new socket. Migrate(NetworkChangeNotifier::kInvalidNetworkHandle, new_address, - /*close_session_on_error=*/true, net_log_); + /*close_session_on_error=*/true); } void QuicChromiumClientSession::SetDefaultEncryptionLevel( @@ -1694,6 +1713,10 @@ void QuicChromiumClientSession::OnConnectionClosed( UMA_HISTOGRAM_COUNTS_1000( "Net.QuicSession.ClosedByRtoAtClient.SentPacketCount", connection()->GetStats().packets_sent); + UMA_HISTOGRAM_COUNTS_100( + "Net.QuicSession." + "MaxConsecutiveRtoWithForwardProgressAndBlackholeDetected", + connection()->GetStats().max_consecutive_rto_with_forward_progress); } } @@ -1740,6 +1763,9 @@ void QuicChromiumClientSession::OnConnectionClosed( UMA_HISTOGRAM_COUNTS_100( "Net.QuicSession.CryptoRetransmitCount.HandshakeConfirmed", connection()->GetStats().crypto_retransmit_count); + UMA_HISTOGRAM_COUNTS_100( + "Net.QuicSession.MaxConsecutiveRtoWithForwardProgress", + connection()->GetStats().max_consecutive_rto_with_forward_progress); } else { if (error == quic::QUIC_PUBLIC_RESET) { RecordHandshakeFailureReason(HANDSHAKE_FAILURE_PUBLIC_RESET); @@ -1812,8 +1838,7 @@ int QuicChromiumClientSession::HandleWriteError( return error_code; } - NetworkChangeNotifier::NetworkHandle current_network = - GetDefaultSocket()->GetBoundNetwork(); + NetworkChangeNotifier::NetworkHandle current_network = GetCurrentNetwork(); net_log_.AddEventWithInt64Params( NetLogEventType::QUIC_CONNECTION_MIGRATION_ON_WRITE_ERROR, "network", @@ -1867,8 +1892,7 @@ void QuicChromiumClientSession::MigrateSessionOnWriteError( if (migrate_idle_session_ && CheckIdleTimeExceedsIdleMigrationPeriod()) return; - if (!migrate_idle_session_ && GetNumActiveStreams() == 0 && - GetNumDrainingStreams() == 0) { + if (!migrate_idle_session_ && !HasActiveRequestStreams()) { // connection close packet to be sent since socket may be borked. connection()->CloseConnection(quic::QUIC_PACKET_WRITE_ERROR, "Write error for non-migratable session", @@ -1878,9 +1902,9 @@ void QuicChromiumClientSession::MigrateSessionOnWriteError( // Do not migrate if connection migration is disabled. if (config()->DisableConnectionMigration()) { - HistogramAndLogMigrationFailure( - net_log_, MIGRATION_STATUS_DISABLED_BY_CONFIG, connection_id(), - "Migration disabled by config"); + HistogramAndLogMigrationFailure(MIGRATION_STATUS_DISABLED_BY_CONFIG, + connection_id(), + "Migration disabled by config"); // Close the connection since migration was disabled. Do not cause a // connection close packet to be sent since socket may be borked. connection()->CloseConnection(quic::QUIC_PACKET_WRITE_ERROR, @@ -1890,22 +1914,21 @@ void QuicChromiumClientSession::MigrateSessionOnWriteError( } NetworkChangeNotifier::NetworkHandle new_network = - stream_factory_->FindAlternateNetwork( - GetDefaultSocket()->GetBoundNetwork()); + stream_factory_->FindAlternateNetwork(GetCurrentNetwork()); if (new_network == NetworkChangeNotifier::kInvalidNetworkHandle) { // No alternate network found. - HistogramAndLogMigrationFailure( - net_log_, MIGRATION_STATUS_NO_ALTERNATE_NETWORK, connection_id(), - "No alternate network found"); + HistogramAndLogMigrationFailure(MIGRATION_STATUS_NO_ALTERNATE_NETWORK, + connection_id(), + "No alternate network found"); OnNoNewNetwork(); return; } - if (GetDefaultSocket()->GetBoundNetwork() == default_network_ && + if (GetCurrentNetwork() == default_network_ && current_migrations_to_non_default_network_on_write_error_ >= max_migrations_to_non_default_network_on_write_error_) { HistogramAndLogMigrationFailure( - net_log_, MIGRATION_STATUS_ON_WRITE_ERROR_DISABLED, connection_id(), + MIGRATION_STATUS_ON_WRITE_ERROR_DISABLED, connection_id(), "Exceeds maximum number of migrations on write error"); connection()->CloseConnection( quic::QUIC_PACKET_WRITE_ERROR, @@ -1915,16 +1938,13 @@ void QuicChromiumClientSession::MigrateSessionOnWriteError( } current_migrations_to_non_default_network_on_write_error_++; - const NetLogWithSource migration_net_log = NetLogWithSource::Make( - net_log_.net_log(), NetLogSourceType::QUIC_CONNECTION_MIGRATION); - migration_net_log.BeginEventWithStringParams( + net_log_.BeginEventWithStringParams( NetLogEventType::QUIC_CONNECTION_MIGRATION_TRIGGERED, "trigger", "WriteError"); MigrationResult result = Migrate(new_network, ToIPEndPoint(connection()->peer_address()), - /*close_session_on_error=*/false, migration_net_log); - migration_net_log.EndEvent( - NetLogEventType::QUIC_CONNECTION_MIGRATION_TRIGGERED); + /*close_session_on_error=*/false); + net_log_.EndEvent(NetLogEventType::QUIC_CONNECTION_MIGRATION_TRIGGERED); if (result == MigrationResult::FAILURE) { // Close the connection if migration failed. Do not cause a @@ -2019,8 +2039,7 @@ void QuicChromiumClientSession::OnProbeSucceeded( // Close streams that are not migratable to the probed |network|. ResetNonMigratableStreams(); - if (!migrate_idle_session_ && GetNumActiveStreams() == 0 && - GetNumDrainingStreams() == 0) { + if (!migrate_idle_session_ && !HasActiveRequestStreams()) { // If idle sessions won't be migrated, close the connection. CloseSessionOnErrorLater( ERR_NETWORK_CHANGED, @@ -2041,10 +2060,14 @@ void QuicChromiumClientSession::OnProbeSucceeded( return; } + // Notify the connection that migration succeeds after probing. + if (connection()->IsPathDegrading()) + connection()->OnSuccessfulMigrationAfterProbing(); + net_log_.AddEventWithInt64Params( NetLogEventType::QUIC_CONNECTION_MIGRATION_SUCCESS_AFTER_PROBING, "migrate_to_network", network); - HistogramAndLogMigrationSuccess(net_log_, connection_id()); + HistogramAndLogMigrationSuccess(connection_id()); if (network == default_network_) { DVLOG(1) << "Client successfully migrated to default network: " << default_network_; @@ -2080,7 +2103,7 @@ void QuicChromiumClientSession::OnProbeFailed( DVLOG(1) << "Connectivity probing failed on <network: " << network << ", peer_address: " << peer_address.ToString() << ">."; DVLOG_IF(1, network == default_network_ && - GetDefaultSocket()->GetBoundNetwork() != default_network_) + GetCurrentNetwork() != default_network_) << "Client probing failed on the default network, still using " "non-default network."; } @@ -2093,9 +2116,17 @@ bool QuicChromiumClientSession::OnSendConnectivityProbingPacket( } void QuicChromiumClientSession::OnNetworkConnected( - NetworkChangeNotifier::NetworkHandle network, - const NetLogWithSource& net_log) { - DCHECK(migrate_session_on_network_change_v2_); + NetworkChangeNotifier::NetworkHandle network) { + if (connection()->IsPathDegrading()) { + base::TimeDelta duration = + tick_clock_->NowTicks() - most_recent_path_degrading_timestamp_; + UMA_HISTOGRAM_CUSTOM_TIMES("Net.QuicNetworkDegradingDurationTillConnected", + duration, base::TimeDelta::FromMilliseconds(1), + base::TimeDelta::FromMinutes(10), 50); + } + if (!migrate_session_on_network_change_v2_) + return; + net_log_.AddEventWithInt64Params( NetLogEventType::QUIC_CONNECTION_MIGRATION_ON_NETWORK_CONNECTED, "connected_network", network); @@ -2104,15 +2135,8 @@ void QuicChromiumClientSession::OnNetworkConnected( if (!wait_for_new_network_ && !connection()->IsPathDegrading()) return; - if (connection()->IsPathDegrading()) { - base::TimeDelta duration = - tick_clock_->NowTicks() - most_recent_path_degrading_timestamp_; - UMA_HISTOGRAM_CUSTOM_TIMES("Net.QuicNetworkDegradingDurationTillConnected", - duration, base::TimeDelta::FromMilliseconds(1), - base::TimeDelta::FromMinutes(10), 50); - + if (connection()->IsPathDegrading()) current_migration_cause_ = NEW_NETWORK_CONNECTED_POST_PATH_DEGRADING; - } if (wait_for_new_network_) { wait_for_new_network_ = false; @@ -2124,18 +2148,18 @@ void QuicChromiumClientSession::OnNetworkConnected( } else { // The connection is path degrading. DCHECK(connection()->IsPathDegrading()); - OnPathDegrading(); + MaybeMigrateToAlternateNetworkOnPathDegrading(); } } void QuicChromiumClientSession::OnNetworkDisconnectedV2( - NetworkChangeNotifier::NetworkHandle disconnected_network, - const NetLogWithSource& migration_net_log) { - DCHECK(migrate_session_on_network_change_v2_); + NetworkChangeNotifier::NetworkHandle disconnected_network) { + LogMetricsOnNetworkDisconnected(); + if (!migrate_session_on_network_change_v2_) + return; net_log_.AddEventWithInt64Params( NetLogEventType::QUIC_CONNECTION_MIGRATION_ON_NETWORK_DISCONNECTED, "disconnected_network", disconnected_network); - LogMetricsOnNetworkDisconnected(); // Stop probing the disconnected network if there is one. probing_manager_.CancelProbing(disconnected_network, peer_address()); @@ -2146,7 +2170,7 @@ void QuicChromiumClientSession::OnNetworkDisconnectedV2( } // Ignore the signal if the current active network is not affected. - if (GetDefaultSocket()->GetBoundNetwork() != disconnected_network) { + if (GetCurrentNetwork() != disconnected_network) { DVLOG(1) << "Client's current default network is not affected by the " << "disconnected one."; return; @@ -2179,29 +2203,31 @@ void QuicChromiumClientSession::OnNetworkDisconnectedV2( } void QuicChromiumClientSession::OnNetworkMadeDefault( - NetworkChangeNotifier::NetworkHandle new_network, - const NetLogWithSource& migration_net_log) { - DCHECK(migrate_session_on_network_change_v2_); + NetworkChangeNotifier::NetworkHandle new_network) { + LogMetricsOnNetworkMadeDefault(); + + if (!migrate_session_on_network_change_v2_) + return; + + DCHECK_NE(NetworkChangeNotifier::kInvalidNetworkHandle, new_network); net_log_.AddEventWithInt64Params( NetLogEventType::QUIC_CONNECTION_MIGRATION_ON_NETWORK_MADE_DEFAULT, "new_default_network", new_network); - LogMetricsOnNetworkMadeDefault(); + default_network_ = new_network; - DCHECK_NE(NetworkChangeNotifier::kInvalidNetworkHandle, new_network); DVLOG(1) << "Network: " << new_network << " becomes default, old default: " << default_network_; - default_network_ = new_network; current_migration_cause_ = ON_NETWORK_MADE_DEFAULT; current_migrations_to_non_default_network_on_write_error_ = 0; current_migrations_to_non_default_network_on_path_degrading_ = 0; // Simply cancel the timer to migrate back to the default network if session // is already on the default network. - if (GetDefaultSocket()->GetBoundNetwork() == new_network) { + if (GetCurrentNetwork() == new_network) { CancelMigrateBackToDefaultNetworkTimer(); - HistogramAndLogMigrationFailure( - migration_net_log, MIGRATION_STATUS_ALREADY_MIGRATED, connection_id(), - "Already migrated on the new network"); + HistogramAndLogMigrationFailure(MIGRATION_STATUS_ALREADY_MIGRATED, + connection_id(), + "Already migrated on the new network"); return; } @@ -2221,10 +2247,8 @@ void QuicChromiumClientSession::MigrateNetworkImmediately( // - otherwise, it's brought to default network, cancel the running timer to // migrate back. - if (!migrate_idle_session_ && GetNumActiveStreams() == 0 && - GetNumDrainingStreams() == 0) { - HistogramAndLogMigrationFailure(net_log_, - MIGRATION_STATUS_NO_MIGRATABLE_STREAMS, + if (!migrate_idle_session_ && !HasActiveRequestStreams()) { + HistogramAndLogMigrationFailure(MIGRATION_STATUS_NO_MIGRATABLE_STREAMS, connection_id(), "No active streams"); CloseSessionOnErrorLater( ERR_NETWORK_CHANGED, @@ -2238,17 +2262,17 @@ void QuicChromiumClientSession::MigrateNetworkImmediately( // Do not migrate if connection migration is disabled. if (config()->DisableConnectionMigration()) { - HistogramAndLogMigrationFailure( - net_log_, MIGRATION_STATUS_DISABLED_BY_CONFIG, connection_id(), - "Migration disabled by config"); + HistogramAndLogMigrationFailure(MIGRATION_STATUS_DISABLED_BY_CONFIG, + connection_id(), + "Migration disabled by config"); CloseSessionOnErrorLater(ERR_NETWORK_CHANGED, quic::QUIC_CONNECTION_MIGRATION_DISABLED_BY_CONFIG, quic::ConnectionCloseBehavior::SILENT_CLOSE); return; } - if (network == GetDefaultSocket()->GetBoundNetwork()) { - HistogramAndLogMigrationFailure(net_log_, MIGRATION_STATUS_ALREADY_MIGRATED, + if (network == GetCurrentNetwork()) { + HistogramAndLogMigrationFailure(MIGRATION_STATUS_ALREADY_MIGRATED, connection_id(), "Already bound to new network"); return; @@ -2259,7 +2283,7 @@ void QuicChromiumClientSession::MigrateNetworkImmediately( MigrationResult result = Migrate(network, ToIPEndPoint(connection()->peer_address()), - /*close_session_on_error=*/true, net_log_); + /*close_session_on_error=*/true); if (result == MigrationResult::FAILURE) return; @@ -2308,6 +2332,9 @@ void QuicChromiumClientSession::OnWriteUnblocked() { } void QuicChromiumClientSession::OnPathDegrading() { + if (most_recent_path_degrading_timestamp_ == base::TimeTicks()) + most_recent_path_degrading_timestamp_ = tick_clock_->NowTicks(); + if (go_away_on_path_degrading_ && OneRttKeysAvailable()) { net_log_.AddEvent( NetLogEventType::QUIC_SESSION_CLIENT_GOAWAY_ON_PATH_DEGRADING); @@ -2317,14 +2344,15 @@ void QuicChromiumClientSession::OnPathDegrading() { GetNumActiveStreams()); UMA_HISTOGRAM_COUNTS_1M( "Net.QuicSession.DrainingStreamsOnGoAwayAfterPathDegrading", - GetNumDrainingStreams()); + num_outgoing_draining_streams()); return; } - net_log_.AddEvent( - NetLogEventType::QUIC_CONNECTION_MIGRATION_ON_PATH_DEGRADING); - if (most_recent_path_degrading_timestamp_ == base::TimeTicks()) - most_recent_path_degrading_timestamp_ = tick_clock_->NowTicks(); + if (!go_away_on_path_degrading_) { + NetworkChangeNotifier::NetworkHandle current_network = GetCurrentNetwork(); + for (auto& observer : connectivity_observer_list_) + observer.OnSessionPathDegrading(this, current_network); + } if (!stream_factory_) return; @@ -2335,21 +2363,16 @@ void QuicChromiumClientSession::OnPathDegrading() { return; } - current_migration_cause_ = CHANGE_NETWORK_ON_PATH_DEGRADING; + MaybeMigrateToAlternateNetworkOnPathDegrading(); +} - if (migrate_session_early_v2_) { - MaybeMigrateToAlternateNetworkOnPathDegrading(); +void QuicChromiumClientSession::OnForwardProgressMadeAfterPathDegrading() { + if (go_away_on_path_degrading_) return; - } - - HistogramAndLogMigrationFailure( - net_log_, MIGRATION_STATUS_PATH_DEGRADING_NOT_ENABLED, connection_id(), - "Migration on path degrading not enabled"); -} -bool QuicChromiumClientSession::ShouldKeepConnectionAlive() const { - return quic::QuicSpdySession::ShouldKeepConnectionAlive() || - GetNumDrainingOutgoingStreams() > 0; + NetworkChangeNotifier::NetworkHandle current_network = GetCurrentNetwork(); + for (auto& observer : connectivity_observer_list_) + observer.OnSessionResumedPostPathDegrading(this, current_network); } void QuicChromiumClientSession::OnProofValid( @@ -2488,43 +2511,50 @@ void QuicChromiumClientSession::MaybeMigrateToDifferentPortOnPathDegrading() { // Migration before handshake is not allowed. if (!OneRttKeysAvailable()) { HistogramAndLogMigrationFailure( - net_log_, MIGRATION_STATUS_PATH_DEGRADING_BEFORE_HANDSHAKE_CONFIRMED, + MIGRATION_STATUS_PATH_DEGRADING_BEFORE_HANDSHAKE_CONFIRMED, connection_id(), "Path degrading before handshake confirmed"); return; } - const NetLogWithSource migration_net_log = NetLogWithSource::Make( - net_log_.net_log(), NetLogSourceType::QUIC_PORT_MIGRATION); - migration_net_log.BeginEvent(NetLogEventType::QUIC_PORT_MIGRATION_TRIGGERED); + net_log_.BeginEvent(NetLogEventType::QUIC_PORT_MIGRATION_TRIGGERED); if (!stream_factory_) return; // Probe a different port, session will migrate to the probed port on success. - StartProbing(default_network_, peer_address(), migration_net_log); - migration_net_log.EndEvent(NetLogEventType::QUIC_PORT_MIGRATION_TRIGGERED); + StartProbing(default_network_, peer_address()); + net_log_.EndEvent(NetLogEventType::QUIC_PORT_MIGRATION_TRIGGERED); } void QuicChromiumClientSession:: MaybeMigrateToAlternateNetworkOnPathDegrading() { - DCHECK(migrate_session_early_v2_); + net_log_.AddEvent( + NetLogEventType::QUIC_CONNECTION_MIGRATION_ON_PATH_DEGRADING); + + current_migration_cause_ = CHANGE_NETWORK_ON_PATH_DEGRADING; - if (GetDefaultSocket()->GetBoundNetwork() == default_network_ && + if (!migrate_session_early_v2_) { + HistogramAndLogMigrationFailure(MIGRATION_STATUS_PATH_DEGRADING_NOT_ENABLED, + connection_id(), + "Migration on path degrading not enabled"); + return; + } + + if (GetCurrentNetwork() == default_network_ && current_migrations_to_non_default_network_on_path_degrading_ >= max_migrations_to_non_default_network_on_path_degrading_) { HistogramAndLogMigrationFailure( - net_log_, MIGRATION_STATUS_ON_PATH_DEGRADING_DISABLED, connection_id(), + MIGRATION_STATUS_ON_PATH_DEGRADING_DISABLED, connection_id(), "Exceeds maximum number of migrations on path degrading"); return; } NetworkChangeNotifier::NetworkHandle alternate_network = - stream_factory_->FindAlternateNetwork( - GetDefaultSocket()->GetBoundNetwork()); + stream_factory_->FindAlternateNetwork(GetCurrentNetwork()); if (alternate_network == NetworkChangeNotifier::kInvalidNetworkHandle) { - HistogramAndLogMigrationFailure( - net_log_, MIGRATION_STATUS_NO_ALTERNATE_NETWORK, connection_id(), - "No alternative network on path degrading"); + HistogramAndLogMigrationFailure(MIGRATION_STATUS_NO_ALTERNATE_NETWORK, + connection_id(), + "No alternative network on path degrading"); return; } @@ -2532,37 +2562,31 @@ void QuicChromiumClientSession:: if (!OneRttKeysAvailable()) { HistogramAndLogMigrationFailure( - net_log_, MIGRATION_STATUS_PATH_DEGRADING_BEFORE_HANDSHAKE_CONFIRMED, + MIGRATION_STATUS_PATH_DEGRADING_BEFORE_HANDSHAKE_CONFIRMED, connection_id(), "Path degrading before handshake confirmed"); return; } - const NetLogWithSource migration_net_log = NetLogWithSource::Make( - net_log_.net_log(), NetLogSourceType::QUIC_CONNECTION_MIGRATION); - migration_net_log.BeginEventWithStringParams( + net_log_.BeginEventWithStringParams( NetLogEventType::QUIC_CONNECTION_MIGRATION_TRIGGERED, "trigger", "PathDegrading"); // Probe the alternative network, session will migrate to the probed // network and decide whether it wants to migrate back to the default // network on success. - MaybeStartProbing(alternate_network, peer_address(), migration_net_log); - migration_net_log.EndEvent( - NetLogEventType::QUIC_CONNECTION_MIGRATION_TRIGGERED); + MaybeStartProbing(alternate_network, peer_address()); + net_log_.EndEvent(NetLogEventType::QUIC_CONNECTION_MIGRATION_TRIGGERED); } ProbingResult QuicChromiumClientSession::MaybeStartProbing( NetworkChangeNotifier::NetworkHandle network, - const quic::QuicSocketAddress& peer_address, - const NetLogWithSource& migration_net_log) { + const quic::QuicSocketAddress& peer_address) { if (!stream_factory_) return ProbingResult::FAILURE; CHECK_NE(NetworkChangeNotifier::kInvalidNetworkHandle, network); - if (!migrate_idle_session_ && GetNumActiveStreams() == 0 && - GetNumDrainingStreams() == 0) { - HistogramAndLogMigrationFailure(migration_net_log, - MIGRATION_STATUS_NO_MIGRATABLE_STREAMS, + if (!migrate_idle_session_ && !HasActiveRequestStreams()) { + HistogramAndLogMigrationFailure(MIGRATION_STATUS_NO_MIGRATABLE_STREAMS, connection_id(), "No active streams"); CloseSessionOnErrorLater( ERR_NETWORK_CHANGED, @@ -2578,19 +2602,18 @@ ProbingResult QuicChromiumClientSession::MaybeStartProbing( if (config()->DisableConnectionMigration()) { DVLOG(1) << "Client disables probing network with connection migration " << "disabled by config"; - HistogramAndLogMigrationFailure( - migration_net_log, MIGRATION_STATUS_DISABLED_BY_CONFIG, connection_id(), - "Migration disabled by config"); + HistogramAndLogMigrationFailure(MIGRATION_STATUS_DISABLED_BY_CONFIG, + connection_id(), + "Migration disabled by config"); return ProbingResult::DISABLED_BY_CONFIG; } - return StartProbing(network, peer_address, migration_net_log); + return StartProbing(network, peer_address); } ProbingResult QuicChromiumClientSession::StartProbing( NetworkChangeNotifier::NetworkHandle network, - const quic::QuicSocketAddress& peer_address, - const NetLogWithSource& migration_net_log) { + const quic::QuicSocketAddress& peer_address) { // Check if probing manager is probing the same path. if (probing_manager_.IsUnderProbing(network, peer_address)) return ProbingResult::PENDING; @@ -2601,9 +2624,9 @@ ProbingResult QuicChromiumClientSession::StartProbing( if (stream_factory_->ConfigureSocket(probing_socket.get(), ToIPEndPoint(peer_address), network, session_key_.socket_tag()) != OK) { - HistogramAndLogMigrationFailure( - migration_net_log, MIGRATION_STATUS_INTERNAL_ERROR, connection_id(), - "Socket configuration failed"); + HistogramAndLogMigrationFailure(MIGRATION_STATUS_INTERNAL_ERROR, + connection_id(), + "Socket configuration failed"); return ProbingResult::INTERNAL_ERROR; } @@ -2664,8 +2687,7 @@ void QuicChromiumClientSession::TryMigrateBackToDefaultNetwork( // the same network, this will be a no-op. Otherwise, previous probe // will be cancelled and manager starts to probe |default_network_| // immediately. - ProbingResult result = - MaybeStartProbing(default_network_, peer_address(), net_log_); + ProbingResult result = MaybeStartProbing(default_network_, peer_address()); if (result == ProbingResult::DISABLED_WITH_IDLE_SESSION) return; @@ -2689,7 +2711,7 @@ void QuicChromiumClientSession::TryMigrateBackToDefaultNetwork( void QuicChromiumClientSession::MaybeRetryMigrateBackToDefaultNetwork() { base::TimeDelta retry_migrate_back_timeout = base::TimeDelta::FromSeconds(UINT64_C(1) << retry_migrate_back_count_); - if (default_network_ == GetDefaultSocket()->GetBoundNetwork()) { + if (default_network_ == GetCurrentNetwork()) { // If session has been back on the default already by other direct // migration attempt, cancel migrate back now. CancelMigrateBackToDefaultNetworkTimer(); @@ -2707,7 +2729,7 @@ bool QuicChromiumClientSession::CheckIdleTimeExceedsIdleMigrationPeriod() { if (!migrate_idle_session_) return false; - if (GetNumActiveStreams() != 0 || GetNumDrainingStreams() != 0) { + if (HasActiveRequestStreams()) { return false; } @@ -2718,9 +2740,9 @@ bool QuicChromiumClientSession::CheckIdleTimeExceedsIdleMigrationPeriod() { return false; } - HistogramAndLogMigrationFailure( - net_log_, MIGRATION_STATUS_IDLE_MIGRATION_TIMEOUT, connection_id(), - "Ilde migration period exceeded"); + HistogramAndLogMigrationFailure(MIGRATION_STATUS_IDLE_MIGRATION_TIMEOUT, + connection_id(), + "Ilde migration period exceeded"); CloseSessionOnErrorLater(ERR_NETWORK_CHANGED, quic::QUIC_NETWORK_IDLE_TIMEOUT, quic::ConnectionCloseBehavior::SILENT_CLOSE); return true; @@ -2840,7 +2862,6 @@ void QuicChromiumClientSession::LogHandshakeStatusOnMigrationSignal() const { } void QuicChromiumClientSession::HistogramAndLogMigrationFailure( - const NetLogWithSource& net_log, QuicConnectionMigrationStatus status, quic::QuicConnectionId connection_id, const char* reason) { @@ -2849,7 +2870,7 @@ void QuicChromiumClientSession::HistogramAndLogMigrationFailure( ? NetLogEventType::QUIC_PORT_MIGRATION_FAILURE : NetLogEventType::QUIC_CONNECTION_MIGRATION_FAILURE; - net_log.AddEvent(event_type, [&] { + net_log_.AddEvent(event_type, [&] { return NetLogQuicMigrationFailureParams(connection_id, reason); }); @@ -2858,14 +2879,13 @@ void QuicChromiumClientSession::HistogramAndLogMigrationFailure( } void QuicChromiumClientSession::HistogramAndLogMigrationSuccess( - const NetLogWithSource& net_log, quic::QuicConnectionId connection_id) { NetLogEventType event_type = current_migration_cause_ == CHANGE_PORT_ON_PATH_DEGRADING ? NetLogEventType::QUIC_PORT_MIGRATION_SUCCESS : NetLogEventType::QUIC_CONNECTION_MIGRATION_SUCCESS; - net_log.AddEvent(event_type, [&] { + net_log_.AddEvent(event_type, [&] { return NetLogQuicMigrationSuccessParams(connection_id); }); @@ -3030,7 +3050,7 @@ void QuicChromiumClientSession::OnCryptoHandshakeComplete() { // confirmed if the session is not created on the default network. if (migrate_session_on_network_change_v2_ && default_network_ != NetworkChangeNotifier::kInvalidNetworkHandle && - GetDefaultSocket()->GetBoundNetwork() != default_network_) { + GetCurrentNetwork() != default_network_) { current_migration_cause_ = ON_MIGRATE_BACK_TO_DEFAULT_NETWORK; StartMigrateBackToDefaultNetworkTimer( base::TimeDelta::FromSeconds(kMinRetryTimeForDefaultNetworkSecs)); @@ -3040,16 +3060,14 @@ void QuicChromiumClientSession::OnCryptoHandshakeComplete() { MigrationResult QuicChromiumClientSession::Migrate( NetworkChangeNotifier::NetworkHandle network, IPEndPoint peer_address, - bool close_session_on_error, - const NetLogWithSource& migration_net_log) { + bool close_session_on_error) { if (!stream_factory_) return MigrationResult::FAILURE; if (network != NetworkChangeNotifier::kInvalidNetworkHandle) { // This is a migration attempt from connection migration. ResetNonMigratableStreams(); - if (!migrate_idle_session_ && GetNumActiveStreams() == 0 && - GetNumDrainingStreams() == 0) { + if (!migrate_idle_session_ && !HasActiveRequestStreams()) { // If idle sessions can not be migrated, close the session if needed. if (close_session_on_error) { CloseSessionOnErrorLater( @@ -3066,9 +3084,9 @@ MigrationResult QuicChromiumClientSession::Migrate( stream_factory_->CreateSocket(net_log_.net_log(), net_log_.source())); if (stream_factory_->ConfigureSocket(socket.get(), peer_address, network, session_key_.socket_tag()) != OK) { - HistogramAndLogMigrationFailure( - migration_net_log, MIGRATION_STATUS_INTERNAL_ERROR, connection_id(), - "Socket configuration failed"); + HistogramAndLogMigrationFailure(MIGRATION_STATUS_INTERNAL_ERROR, + connection_id(), + "Socket configuration failed"); if (close_session_on_error) { if (migrate_session_on_network_change_v2_) { CloseSessionOnErrorLater(ERR_NETWORK_CHANGED, @@ -3099,8 +3117,7 @@ MigrationResult QuicChromiumClientSession::Migrate( // Migrate to the new socket. if (!MigrateToSocket(std::move(socket), std::move(new_reader), std::move(new_writer))) { - HistogramAndLogMigrationFailure(migration_net_log, - MIGRATION_STATUS_TOO_MANY_CHANGES, + HistogramAndLogMigrationFailure(MIGRATION_STATUS_TOO_MANY_CHANGES, connection_id(), "Too many changes"); if (close_session_on_error) { if (migrate_session_on_network_change_v2_) { @@ -3116,7 +3133,7 @@ MigrationResult QuicChromiumClientSession::Migrate( } return MigrationResult::FAILURE; } - HistogramAndLogMigrationSuccess(migration_net_log, connection_id()); + HistogramAndLogMigrationSuccess(connection_id()); return MigrationResult::SUCCESS; } @@ -3165,6 +3182,16 @@ const DatagramClientSocket* QuicChromiumClientSession::GetDefaultSocket() return sockets_.back().get(); } +NetworkChangeNotifier::NetworkHandle +QuicChromiumClientSession::GetCurrentNetwork() const { + // If connection migration is enabled, alternate network interface may be + // used to send packet, it is identified as the bound network of the default + // socket. Otherwise, always use |default_network_|. + return migrate_session_on_network_change_v2_ + ? GetDefaultSocket()->GetBoundNetwork() + : default_network_; +} + bool QuicChromiumClientSession::IsAuthorized(const std::string& hostname) { bool result = CanPool( hostname, session_key_.privacy_mode(), session_key_.socket_tag(), @@ -3268,4 +3295,17 @@ size_t QuicChromiumClientSession::EstimateMemoryUsage() const { return base::trace_event::EstimateMemoryUsage(packet_readers_); } +bool QuicChromiumClientSession::ValidateStatelessReset( + const quic::QuicSocketAddress& self_address, + const quic::QuicSocketAddress& peer_address) { + if (probing_manager_.ValidateStatelessReset(self_address, peer_address)) { + // The stateless reset is received from probing path. We shouldn't close the + // connection, but should disable further port migration attempt. + if (allow_port_migration_) + allow_port_migration_ = false; + return false; + } + return true; +} + } // namespace net diff --git a/chromium/net/quic/quic_chromium_client_session.h b/chromium/net/quic/quic_chromium_client_session.h index 34ea4fda6eb..3b1c2fda0ac 100644 --- a/chromium/net/quic/quic_chromium_client_session.h +++ b/chromium/net/quic/quic_chromium_client_session.h @@ -20,6 +20,7 @@ #include "base/containers/mru_cache.h" #include "base/macros.h" +#include "base/observer_list_types.h" #include "base/time/time.h" #include "base/timer/timer.h" #include "net/base/completion_once_callback.h" @@ -139,6 +140,25 @@ class NET_EXPORT_PRIVATE QuicChromiumClientSession public: class StreamRequest; + // An interface that when implemented and added via + // AddConnectivityObserver(), provides notifications when connectivity + // quality changes. + class NET_EXPORT_PRIVATE ConnectivityObserver : public base::CheckedObserver { + public: + // Called when path degrading is detected on |network|. + virtual void OnSessionPathDegrading( + QuicChromiumClientSession* session, + NetworkChangeNotifier::NetworkHandle network) = 0; + + // Called when forward progress is made after path degrading on |network|. + virtual void OnSessionResumedPostPathDegrading( + QuicChromiumClientSession* session, + NetworkChangeNotifier::NetworkHandle network) = 0; + + // Called when |session| is removed. + virtual void OnSessionRemoved(QuicChromiumClientSession* session) = 0; + }; + // Wrapper for interacting with the session in a restricted fashion which // hides the details of the underlying session's lifetime. All methods of // the Handle are safe to use even after the underlying session is destroyed. @@ -422,6 +442,9 @@ class NET_EXPORT_PRIVATE QuicChromiumClientSession void AddHandle(Handle* handle); void RemoveHandle(Handle* handle); + void AddConnectivityObserver(ConnectivityObserver* observer); + void RemoveConnectivityObserver(ConnectivityObserver* observer); + // Returns the session's connection migration mode. ConnectionMigrationMode connection_migration_mode() const; @@ -503,6 +526,9 @@ class NET_EXPORT_PRIVATE QuicChromiumClientSession void OnGoAway(const quic::QuicGoAwayFrame& frame) override; void OnRstStream(const quic::QuicRstStreamFrame& frame) override; void OnCanCreateNewOutgoingStream(bool unidirectional) override; + bool ValidateStatelessReset( + const quic::QuicSocketAddress& self_address, + const quic::QuicSocketAddress& peer_address) override; // QuicClientSessionBase methods: void OnConfigNegotiated() override; @@ -520,7 +546,7 @@ class NET_EXPORT_PRIVATE QuicChromiumClientSession const quic::QuicSocketAddress& peer_address, bool is_connectivity_probe) override; void OnPathDegrading() override; - bool ShouldKeepConnectionAlive() const override; + void OnForwardProgressMadeAfterPathDegrading() override; // QuicChromiumPacketReader::Visitor methods: void OnReadError(int result, const DatagramClientSocket* socket) override; @@ -599,8 +625,7 @@ class NET_EXPORT_PRIVATE QuicChromiumClientSession // closed. MigrationResult Migrate(NetworkChangeNotifier::NetworkHandle network, IPEndPoint peer_address, - bool close_session_on_error, - const NetLogWithSource& migration_net_log); + bool close_session_on_error); // Migrates session onto new socket, i.e., sets |writer| to be the new // default writer and post a task to write to |socket|. |reader| *must* @@ -617,19 +642,16 @@ class NET_EXPORT_PRIVATE QuicChromiumClientSession // Called when NetworkChangeNotifier notifies observers of a newly // connected network. Migrates this session to the newly connected // network if the session has a pending migration. - void OnNetworkConnected(NetworkChangeNotifier::NetworkHandle network, - const NetLogWithSource& net_log); + void OnNetworkConnected(NetworkChangeNotifier::NetworkHandle network); // Called when NetworkChangeNotifier broadcasts to observers of // |disconnected_network|. void OnNetworkDisconnectedV2( - NetworkChangeNotifier::NetworkHandle disconnected_network, - const NetLogWithSource& migration_net_log); + NetworkChangeNotifier::NetworkHandle disconnected_network); // Called when NetworkChangeNotifier broadcats to observers of a new default // network. Migrates this session to |new_network| if appropriate. - void OnNetworkMadeDefault(NetworkChangeNotifier::NetworkHandle new_network, - const NetLogWithSource& migration_net_log); + void OnNetworkMadeDefault(NetworkChangeNotifier::NetworkHandle new_network); // Schedules a migration alarm to wait for a new network. void OnNoNewNetwork(); @@ -646,6 +668,11 @@ class NET_EXPORT_PRIVATE QuicChromiumClientSession // returned socket. const DatagramClientSocket* GetDefaultSocket() const; + // Returns the network interface that is currently used to send packets. + // If NetworkHandle is not supported, always return + // NetworkChangeNotifier::kInvalidNetworkHandle. + NetworkChangeNotifier::NetworkHandle GetCurrentNetwork() const; + bool IsAuthorized(const std::string& hostname) override; bool HandlePromised(quic::QuicStreamId associated_id, @@ -710,17 +737,17 @@ class NET_EXPORT_PRIVATE QuicChromiumClientSession // If <network, peer_addres> is identical to the current path, the probe // is sent on a different port. ProbingResult StartProbing(NetworkChangeNotifier::NetworkHandle network, - const quic::QuicSocketAddress& peer_address, - const NetLogWithSource& migration_net_log); + const quic::QuicSocketAddress& peer_address); // Perform a few checks before StartProbing. If any of those checks fails, // StartProbing will be skipped. ProbingResult MaybeStartProbing(NetworkChangeNotifier::NetworkHandle network, - const quic::QuicSocketAddress& peer_address, - const NetLogWithSource& migration_net_log); + const quic::QuicSocketAddress& peer_address); // Helper method to perform a few checks and initiate connection migration // attempt when path degrading is detected. + // Called when path is degrading and there is an alternate network or a new + // network is connected after path degrading. void MaybeMigrateToAlternateNetworkOnPathDegrading(); // Helper method to initiate a port migration on path degrading is detected. @@ -754,12 +781,10 @@ class NET_EXPORT_PRIVATE QuicChromiumClientSession void LogMetricsOnNetworkMadeDefault(); void LogMigrationResultToHistogram(QuicConnectionMigrationStatus status); void LogHandshakeStatusOnMigrationSignal() const; - void HistogramAndLogMigrationFailure(const NetLogWithSource& net_log, - QuicConnectionMigrationStatus status, + void HistogramAndLogMigrationFailure(QuicConnectionMigrationStatus status, quic::QuicConnectionId connection_id, const char* reason); - void HistogramAndLogMigrationSuccess(const NetLogWithSource& net_log, - quic::QuicConnectionId connection_id); + void HistogramAndLogMigrationSuccess(quic::QuicConnectionId connection_id); // Notifies the factory that this session is going away and no more streams // should be created from it. This needs to be called before closing any @@ -810,6 +835,7 @@ class NET_EXPORT_PRIVATE QuicChromiumClientSession std::unique_ptr<quic::QuicCryptoClientStream> crypto_stream_; QuicStreamFactory* stream_factory_; + base::ObserverList<ConnectivityObserver> connectivity_observer_list_; std::vector<std::unique_ptr<DatagramClientSocket>> sockets_; TransportSecurityState* transport_security_state_; SSLConfigService* ssl_config_service_; @@ -847,7 +873,8 @@ class NET_EXPORT_PRIVATE QuicChromiumClientSession // written to an alternate socket when the migration completes and the // alternate socket is unblocked. scoped_refptr<QuicChromiumPacketWriter::ReusableIOBuffer> packet_; - // Stores the latest default network platform marks. + // Stores the latest default network platform marks if migration is enabled. + // Otherwise, stores the network interface that is used by the connection. NetworkChangeNotifier::NetworkHandle default_network_; QuicConnectivityProbingManager probing_manager_; int retry_migrate_back_count_; diff --git a/chromium/net/quic/quic_chromium_client_session_peer.cc b/chromium/net/quic/quic_chromium_client_session_peer.cc index 2c460a8c34f..8d4747f8ac5 100644 --- a/chromium/net/quic/quic_chromium_client_session_peer.cc +++ b/chromium/net/quic/quic_chromium_client_session_peer.cc @@ -48,5 +48,10 @@ bool QuicChromiumClientSessionPeer::GetSessionGoingAway( return session->going_away_; } +bool QuicChromiumClientSessionPeer::DoesSessionAllowPortMigration( + QuicChromiumClientSession* session) { + return session->allow_port_migration_; +} + } // namespace test } // namespace net diff --git a/chromium/net/quic/quic_chromium_client_session_peer.h b/chromium/net/quic/quic_chromium_client_session_peer.h index 8b057727eb4..4832017dc31 100644 --- a/chromium/net/quic/quic_chromium_client_session_peer.h +++ b/chromium/net/quic/quic_chromium_client_session_peer.h @@ -34,6 +34,8 @@ class QuicChromiumClientSessionPeer { static bool GetSessionGoingAway(QuicChromiumClientSession* session); + static bool DoesSessionAllowPortMigration(QuicChromiumClientSession* session); + private: DISALLOW_COPY_AND_ASSIGN(QuicChromiumClientSessionPeer); }; diff --git a/chromium/net/quic/quic_chromium_client_session_test.cc b/chromium/net/quic/quic_chromium_client_session_test.cc index 404d815f3af..075e6111ac9 100644 --- a/chromium/net/quic/quic_chromium_client_session_test.cc +++ b/chromium/net/quic/quic_chromium_client_session_test.cc @@ -31,6 +31,7 @@ #include "net/quic/quic_chromium_connection_helper.h" #include "net/quic/quic_chromium_packet_reader.h" #include "net/quic/quic_chromium_packet_writer.h" +#include "net/quic/quic_connectivity_monitor.h" #include "net/quic/quic_crypto_client_config_handle.h" #include "net/quic/quic_crypto_client_stream_factory.h" #include "net/quic/quic_http_utils.h" @@ -77,6 +78,9 @@ const char kServerHostname[] = "test.example.com"; const uint16_t kServerPort = 443; const size_t kMaxReadersPerQuicSession = 5; +const NetworkChangeNotifier::NetworkHandle kDefaultNetworkForTests = 1; +const NetworkChangeNotifier::NetworkHandle kNewNetworkForTests = 2; + struct TestParams { quic::ParsedQuicVersion version; bool client_headers_include_h2_stream_dependency; @@ -128,6 +132,7 @@ class QuicChromiumClientSessionTest base::span<MockWrite>())), random_(0), helper_(&clock_, &random_), + transport_security_state_(std::make_unique<TransportSecurityState>()), session_key_(kServerHostname, kServerPort, PRIVACY_MODE_DISABLED, @@ -135,6 +140,7 @@ class QuicChromiumClientSessionTest NetworkIsolationKey(), false /* disable_secure_dns */), destination_(kServerHostname, kServerPort), + default_network_(NetworkChangeNotifier::kInvalidNetworkHandle), client_maker_(version_, quic::QuicUtils::CreateRandomConnectionId(&random_), &clock_, @@ -180,12 +186,11 @@ class QuicChromiumClientSessionTest session_.reset(new TestingQuicChromiumClientSession( connection, std::move(socket), /*stream_factory=*/nullptr, &crypto_client_stream_factory_, &clock_, - &transport_security_state_, /*ssl_config_service=*/nullptr, + transport_security_state_.get(), /*ssl_config_service=*/nullptr, base::WrapUnique(static_cast<QuicServerInfo*>(nullptr)), session_key_, /*require_confirmation=*/false, /*max_allowed_push_id=*/0, migrate_session_early_v2_, - /*migrate_session_on_network_change_v2=*/false, - /*defaulet_network=*/NetworkChangeNotifier::kInvalidNetworkHandle, + /*migrate_session_on_network_change_v2=*/false, default_network_, quic::QuicTime::Delta::FromMilliseconds( kDefaultRetransmittableOnWireTimeout.InMilliseconds()), /*migrate_idle_session=*/false, /*allow_port_migration=*/false, @@ -204,6 +209,10 @@ class QuicChromiumClientSessionTest base::DefaultTickClock::GetInstance(), base::ThreadTaskRunnerHandle::Get().get(), /*socket_performance_watcher=*/nullptr, &net_log_)); + if (connectivity_monitor_) { + connectivity_monitor_->SetInitialDefaultNetwork(default_network_); + session_->AddConnectivityObserver(connectivity_monitor_.get()); + } scoped_refptr<X509Certificate> cert( ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem")); @@ -220,10 +229,13 @@ class QuicChromiumClientSessionTest } void TearDown() override { - if (session_) + if (session_) { + if (connectivity_monitor_) + session_->RemoveConnectivityObserver(connectivity_monitor_.get()); session_->CloseSessionOnError( ERR_ABORTED, quic::QUIC_INTERNAL_ERROR, quic::ConnectionCloseBehavior::SILENT_CLOSE); + } } void CompleteCryptoHandshake() { @@ -277,12 +289,14 @@ class QuicChromiumClientSessionTest quic::test::MockRandom random_; QuicChromiumConnectionHelper helper_; quic::test::MockAlarmFactory alarm_factory_; - TransportSecurityState transport_security_state_; + std::unique_ptr<TransportSecurityState> transport_security_state_; MockCryptoClientStreamFactory crypto_client_stream_factory_; quic::QuicClientPushPromiseIndex push_promise_index_; QuicSessionKey session_key_; HostPortPair destination_; std::unique_ptr<TestingQuicChromiumClientSession> session_; + NetworkChangeNotifier::NetworkHandle default_network_; + std::unique_ptr<QuicConnectivityMonitor> connectivity_monitor_; TestServerPushDelegate test_push_delegate_; quic::QuicConnectionVisitorInterface* visitor_; TestCompletionCallback callback_; @@ -299,8 +313,88 @@ INSTANTIATE_TEST_SUITE_P(VersionIncludeStreamDependencySequence, ::testing::ValuesIn(GetTestParams()), ::testing::PrintToStringParamName()); -// TODO(950069): Add testing for frame_origin in NetworkIsolationKey using -// kAppendInitiatingFrameOriginToNetworkIsolationKey. +// TODO(crbug.com/950069): Add testing for frame_origin in NetworkIsolationKey +// using kAppendInitiatingFrameOriginToNetworkIsolationKey. + +// Basic test of ProofVerifyDetailsChromium is converted to SSLInfo retrieved +// through QuicChromiumClientSession::GetSSLInfo(). Doesn't test some of the +// more complicated fields. +TEST_P(QuicChromiumClientSessionTest, GetSSLInfo1) { + MockQuicData quic_data(version_); + if (VersionUsesHttp3(version_.transport_version)) + quic_data.AddWrite(SYNCHRONOUS, client_maker_.MakeInitialSettingsPacket(1)); + quic_data.AddRead(ASYNC, ERR_IO_PENDING); + quic_data.AddRead(ASYNC, OK); // EOF + quic_data.AddSocketDataToFactory(&socket_factory_); + + Initialize(); + + ProofVerifyDetailsChromium details; + details.is_fatal_cert_error = false; + details.cert_verify_result.verified_cert = + ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem"); + details.cert_verify_result.is_issued_by_known_root = true; + details.ct_verify_result.policy_compliance = + ct::CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS; + details.ct_verify_result.policy_compliance_required = true; + + CompleteCryptoHandshake(); + session_->OnProofVerifyDetailsAvailable(details); + + SSLInfo ssl_info; + ASSERT_TRUE(session_->GetSSLInfo(&ssl_info)); + EXPECT_TRUE(ssl_info.is_valid()); + + EXPECT_EQ(details.is_fatal_cert_error, ssl_info.is_fatal_cert_error); + EXPECT_TRUE(ssl_info.cert->EqualsIncludingChain( + details.cert_verify_result.verified_cert.get())); + EXPECT_EQ(details.cert_verify_result.cert_status, ssl_info.cert_status); + EXPECT_EQ(details.cert_verify_result.is_issued_by_known_root, + ssl_info.is_issued_by_known_root); + EXPECT_EQ(details.ct_verify_result.policy_compliance, + ssl_info.ct_policy_compliance); + EXPECT_EQ(details.ct_verify_result.policy_compliance_required, + ssl_info.ct_policy_compliance_required); +} + +// Just like GetSSLInfo1, but uses different values. +TEST_P(QuicChromiumClientSessionTest, GetSSLInfo2) { + MockQuicData quic_data(version_); + if (VersionUsesHttp3(version_.transport_version)) + quic_data.AddWrite(SYNCHRONOUS, client_maker_.MakeInitialSettingsPacket(1)); + quic_data.AddRead(ASYNC, ERR_IO_PENDING); + quic_data.AddRead(ASYNC, OK); // EOF + quic_data.AddSocketDataToFactory(&socket_factory_); + + Initialize(); + + ProofVerifyDetailsChromium details; + details.is_fatal_cert_error = false; + details.cert_verify_result.verified_cert = + ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem"); + details.cert_verify_result.is_issued_by_known_root = false; + details.ct_verify_result.policy_compliance = + ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS; + details.ct_verify_result.policy_compliance_required = false; + + CompleteCryptoHandshake(); + session_->OnProofVerifyDetailsAvailable(details); + + SSLInfo ssl_info; + ASSERT_TRUE(session_->GetSSLInfo(&ssl_info)); + EXPECT_TRUE(ssl_info.is_valid()); + + EXPECT_EQ(details.is_fatal_cert_error, ssl_info.is_fatal_cert_error); + EXPECT_TRUE(ssl_info.cert->EqualsIncludingChain( + details.cert_verify_result.verified_cert.get())); + EXPECT_EQ(details.cert_verify_result.cert_status, ssl_info.cert_status); + EXPECT_EQ(details.cert_verify_result.is_issued_by_known_root, + ssl_info.is_issued_by_known_root); + EXPECT_EQ(details.ct_verify_result.policy_compliance, + ssl_info.ct_policy_compliance); + EXPECT_EQ(details.ct_verify_result.policy_compliance_required, + ssl_info.ct_policy_compliance_required); +} TEST_P(QuicChromiumClientSessionTest, IsFatalErrorNotSetForNonFatalError) { MockQuicData quic_data(version_); @@ -872,7 +966,7 @@ TEST_P(QuicChromiumClientSessionTest, ConnectionCloseBeforeStreamRequest) { } TEST_P(QuicChromiumClientSessionTest, ConnectionCloseBeforeHandshakeConfirmed) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3) { + if (version_.UsesTls()) { // TODO(nharper, b/112643533): Figure out why this test fails when TLS is // enabled and fix it. return; @@ -1539,6 +1633,81 @@ TEST_P(QuicChromiumClientSessionTest, CanPool) { } } +TEST_P(QuicChromiumClientSessionTest, CanPoolExpectCT) { + base::test::ScopedFeatureList feature_list; + feature_list.InitWithFeatures( + /* enabled_features */ + {TransportSecurityState::kDynamicExpectCTFeature, + features::kPartitionExpectCTStateByNetworkIsolationKey}, + /* disabled_features */ + {}); + + NetworkIsolationKey network_isolation_key = + NetworkIsolationKey::CreateTransient(); + // Need to create a session key after setting + // kPartitionExpectCTStateByNetworkIsolationKey, otherwise, it will ignore the + // NetworkIsolationKey value. + session_key_ = QuicSessionKey( + kServerHostname, kServerPort, PRIVACY_MODE_DISABLED, SocketTag(), + network_isolation_key, false /* disable_secure_dns */); + + // Need to create this after enabling + // kPartitionExpectCTStateByNetworkIsolationKey. + transport_security_state_ = std::make_unique<TransportSecurityState>(); + + MockQuicData quic_data(version_); + if (VersionUsesHttp3(version_.transport_version)) + quic_data.AddWrite(SYNCHRONOUS, client_maker_.MakeInitialSettingsPacket(1)); + quic_data.AddRead(ASYNC, ERR_IO_PENDING); + quic_data.AddRead(ASYNC, OK); // EOF + quic_data.AddSocketDataToFactory(&socket_factory_); + Initialize(); + + // Load a cert that is valid for: + // www.example.org + // mail.example.org + // www.example.com + + // Details with a CT error. + ProofVerifyDetailsChromium details; + details.cert_verify_result.verified_cert = + ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem"); + ASSERT_TRUE(details.cert_verify_result.verified_cert.get()); + details.cert_verify_result.is_issued_by_known_root = true; + details.ct_verify_result.policy_compliance = + ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS; + + CompleteCryptoHandshake(); + session_->OnProofVerifyDetailsAvailable(details); + + // Pooling succeeds if CT isn't required. + EXPECT_TRUE(session_->CanPool("www.example.org", PRIVACY_MODE_DISABLED, + SocketTag(), network_isolation_key, + false /* disable_secure_dns */)); + + // Adding Expect-CT data for different NetworkIsolationKeys should have no + // effect. + base::Time expiry = base::Time::Now() + base::TimeDelta::FromDays(1); + transport_security_state_->AddExpectCT( + "www.example.org", expiry, true /* enforce */, GURL() /* report_url */, + NetworkIsolationKey::CreateTransient()); + transport_security_state_->AddExpectCT( + "www.example.org", expiry, true /* enforce */, GURL() /* report_url */, + NetworkIsolationKey()); + EXPECT_TRUE(session_->CanPool("www.example.org", PRIVACY_MODE_DISABLED, + SocketTag(), network_isolation_key, + false /* disable_secure_dns */)); + + // Adding Expect-CT data for the same NetworkIsolationKey should prevent + // pooling. + transport_security_state_->AddExpectCT( + "www.example.org", expiry, true /* enforce */, GURL() /* report_url */, + network_isolation_key); + EXPECT_FALSE(session_->CanPool("www.example.org", PRIVACY_MODE_DISABLED, + SocketTag(), network_isolation_key, + false /* disable_secure_dns */)); +} + // Much as above, but uses a non-empty NetworkIsolationKey. TEST_P(QuicChromiumClientSessionTest, CanPoolWithNetworkIsolationKey) { base::test::ScopedFeatureList feature_list; @@ -1629,7 +1798,7 @@ TEST_P(QuicChromiumClientSessionTest, ConnectionNotPooledWithDifferentPin) { quic_data.AddSocketDataToFactory(&socket_factory_); Initialize(); - transport_security_state_.EnableStaticPinsForTesting(); + transport_security_state_->EnableStaticPinsForTesting(); ProofVerifyDetailsChromium details; details.cert_verify_result.verified_cert = @@ -1661,7 +1830,7 @@ TEST_P(QuicChromiumClientSessionTest, ConnectionPooledWithMatchingPin) { quic_data.AddSocketDataToFactory(&socket_factory_); Initialize(); - transport_security_state_.EnableStaticPinsForTesting(); + transport_security_state_->EnableStaticPinsForTesting(); ProofVerifyDetailsChromium details; details.cert_verify_result.verified_cert = @@ -1752,7 +1921,7 @@ TEST_P(QuicChromiumClientSessionTest, MigrateToSocket) { quic::test::QuicStreamPeer::SendBuffer(stream).SaveStreamData(iov, 1, 0, 4); quic::test::QuicStreamPeer::SetStreamBytesWritten(4, stream); session_->WritevData(stream->id(), 4, 0, quic::NO_FIN, - quic::NOT_RETRANSMISSION, QuicheNullOpt); + quic::NOT_RETRANSMISSION, QUICHE_NULLOPT); EXPECT_TRUE(socket_data.AllReadDataConsumed()); EXPECT_TRUE(socket_data.AllWriteDataConsumed()); @@ -2033,6 +2202,174 @@ TEST_P(QuicChromiumClientSessionTest, ResetOnEmptyResponseHeaders) { EXPECT_TRUE(quic_data.AllWriteDataConsumed()); } +// This test verifies that when NetworkHandle is not supported and there is no +// network change, session reports to the connectivity monitor correctly on path +// degrading detection and recovery. +TEST_P(QuicChromiumClientSessionTest, + DegradingWithoutNetworkChange_NoNetworkHandle) { + // Add a connectivity monitor for testing. + default_network_ = NetworkChangeNotifier::kInvalidNetworkHandle; + connectivity_monitor_ = + std::make_unique<QuicConnectivityMonitor>(default_network_); + + Initialize(); + + // Fire path degrading detection. + session_->ReallyOnPathDegrading(); + EXPECT_EQ(1u, connectivity_monitor_->GetNumDegradingSessions()); + + session_->OnForwardProgressMadeAfterPathDegrading(); + EXPECT_EQ(0u, connectivity_monitor_->GetNumDegradingSessions()); + + // Fire again. + session_->ReallyOnPathDegrading(); + EXPECT_EQ(1u, connectivity_monitor_->GetNumDegradingSessions()); + + // Close the session but keep the session around, the connectivity monitor + // will not remove the tracking immediately. + session_->CloseSessionOnError(ERR_ABORTED, quic::QUIC_INTERNAL_ERROR, + quic::ConnectionCloseBehavior::SILENT_CLOSE); + EXPECT_EQ(1u, connectivity_monitor_->GetNumDegradingSessions()); + + // Delete the session will remove the degrading count in connectivity + // monitor. + session_.reset(); + EXPECT_EQ(0u, connectivity_monitor_->GetNumDegradingSessions()); +} + +// This test verifies that when the NetworkHandle is not supported, and there +// are speculated network change reported via OnIPAddressChange, session +// still reports to the connectivity monitor correctly on path degrading +// detection and recovery. +TEST_P(QuicChromiumClientSessionTest, DegradingWithIPAddressChange) { + // Default network is always set to kInvalidNetworkHandle. + default_network_ = NetworkChangeNotifier::kInvalidNetworkHandle; + connectivity_monitor_ = + std::make_unique<QuicConnectivityMonitor>(default_network_); + + Initialize(); + + session_->ReallyOnPathDegrading(); + EXPECT_EQ(1u, connectivity_monitor_->GetNumDegradingSessions()); + + session_->OnForwardProgressMadeAfterPathDegrading(); + EXPECT_EQ(0u, connectivity_monitor_->GetNumDegradingSessions()); + + session_->ReallyOnPathDegrading(); + EXPECT_EQ(1u, connectivity_monitor_->GetNumDegradingSessions()); + + // When NetworkHandle is not supported, network change is notified via + // IP address change. + connectivity_monitor_->OnIPAddressChanged(); + EXPECT_EQ(0u, connectivity_monitor_->GetNumDegradingSessions()); + + // When NetworkHandle is not supported and IP address changes, + // session either goes away or gets closed. When it goes away, + // reporting to connectivity monitor is disabled. + connectivity_monitor_->OnSessionGoingAwayOnIPAddressChange(session_.get()); + + // Even if session detects recovery or degradation, this session is no longer + // on the default network and connectivity monitor will not update. + session_->OnForwardProgressMadeAfterPathDegrading(); + EXPECT_EQ(0u, connectivity_monitor_->GetNumDegradingSessions()); + session_->ReallyOnPathDegrading(); + EXPECT_EQ(0u, connectivity_monitor_->GetNumDegradingSessions()); + + session_->CloseSessionOnError(ERR_ABORTED, quic::QUIC_INTERNAL_ERROR, + quic::ConnectionCloseBehavior::SILENT_CLOSE); + EXPECT_EQ(0u, connectivity_monitor_->GetNumDegradingSessions()); + + session_.reset(); + EXPECT_EQ(0u, connectivity_monitor_->GetNumDegradingSessions()); +} + +// This test verifies that when NetworkHandle is supported but migration is +// not supported and there's no network change, session reports to +// connectivity monitor correctly on path degrading detection or recovery. +// Default network change is currently reported with valid NetworkHandles +// while session's current network interface is tracked by |default_network_|. +TEST_P(QuicChromiumClientSessionTest, + DegradingOnDeafultNetwork_WithoutMigration) { + default_network_ = kDefaultNetworkForTests; + connectivity_monitor_ = + std::make_unique<QuicConnectivityMonitor>(default_network_); + + Initialize(); + + session_->ReallyOnPathDegrading(); + EXPECT_EQ(1u, connectivity_monitor_->GetNumDegradingSessions()); + + session_->OnForwardProgressMadeAfterPathDegrading(); + EXPECT_EQ(0u, connectivity_monitor_->GetNumDegradingSessions()); + + session_->ReallyOnPathDegrading(); + EXPECT_EQ(1u, connectivity_monitor_->GetNumDegradingSessions()); + // Close the session but keep the session around, the connectivity monitor + // should not remove the count immediately. + session_->CloseSessionOnError(ERR_ABORTED, quic::QUIC_INTERNAL_ERROR, + quic::ConnectionCloseBehavior::SILENT_CLOSE); + EXPECT_EQ(1u, connectivity_monitor_->GetNumDegradingSessions()); + + // Delete the session will remove the degrading count in connectivity + // monitor. + session_.reset(); + EXPECT_EQ(0u, connectivity_monitor_->GetNumDegradingSessions()); +} + +// This test verifies that when NetworkHandle is supported but migrations is not +// supported and there is network changes, session reports to the connectivity +// monitor correctly on path degrading detection or recovery. +TEST_P(QuicChromiumClientSessionTest, + DegradingWithDeafultNetworkChange_WithoutMigration) { + default_network_ = kDefaultNetworkForTests; + connectivity_monitor_ = + std::make_unique<QuicConnectivityMonitor>(default_network_); + + Initialize(); + + session_->ReallyOnPathDegrading(); + EXPECT_EQ(1u, connectivity_monitor_->GetNumDegradingSessions()); + + session_->OnForwardProgressMadeAfterPathDegrading(); + EXPECT_EQ(0u, connectivity_monitor_->GetNumDegradingSessions()); + + session_->ReallyOnPathDegrading(); + EXPECT_EQ(1u, connectivity_monitor_->GetNumDegradingSessions()); + + // Simulate the default network change. + connectivity_monitor_->OnDefaultNetworkUpdated(kNewNetworkForTests); + EXPECT_EQ(0u, connectivity_monitor_->GetNumDegradingSessions()); + session_->OnNetworkMadeDefault(kNewNetworkForTests); + + // Session stays on the old default network, and recovers. + session_->OnForwardProgressMadeAfterPathDegrading(); + EXPECT_EQ(0u, connectivity_monitor_->GetNumDegradingSessions()); + + // Session degrades again on the old default. + session_->ReallyOnPathDegrading(); + EXPECT_EQ(0u, connectivity_monitor_->GetNumDegradingSessions()); + + // Simulate that default network switches back to the old default. + connectivity_monitor_->OnDefaultNetworkUpdated(kDefaultNetworkForTests); + EXPECT_EQ(0u, connectivity_monitor_->GetNumDegradingSessions()); + session_->OnNetworkMadeDefault(kDefaultNetworkForTests); + + // Session recovers again on the (old) default. + session_->OnForwardProgressMadeAfterPathDegrading(); + EXPECT_EQ(0u, connectivity_monitor_->GetNumDegradingSessions()); + + // Session degrades again on the (old) default. + session_->ReallyOnPathDegrading(); + EXPECT_EQ(1u, connectivity_monitor_->GetNumDegradingSessions()); + + session_->CloseSessionOnError(ERR_ABORTED, quic::QUIC_INTERNAL_ERROR, + quic::ConnectionCloseBehavior::SILENT_CLOSE); + EXPECT_EQ(1u, connectivity_monitor_->GetNumDegradingSessions()); + + session_.reset(); + EXPECT_EQ(0u, connectivity_monitor_->GetNumDegradingSessions()); +} + } // namespace } // namespace test } // namespace net diff --git a/chromium/net/quic/quic_chromium_client_stream.h b/chromium/net/quic/quic_chromium_client_stream.h index 71372a16f52..6399b92a5e3 100644 --- a/chromium/net/quic/quic_chromium_client_stream.h +++ b/chromium/net/quic/quic_chromium_client_stream.h @@ -9,10 +9,10 @@ #include <stddef.h> +#include <memory> #include <vector> #include "base/callback_forward.h" -#include "base/containers/circular_deque.h" #include "base/macros.h" #include "net/base/completion_once_callback.h" #include "net/base/ip_endpoint.h" diff --git a/chromium/net/quic/quic_chromium_packet_writer.cc b/chromium/net/quic/quic_chromium_packet_writer.cc index 2c5d194df73..e45613b9511 100644 --- a/chromium/net/quic/quic_chromium_packet_writer.cc +++ b/chromium/net/quic/quic_chromium_packet_writer.cc @@ -263,10 +263,10 @@ bool QuicChromiumPacketWriter::IsBatchMode() const { return false; } -char* QuicChromiumPacketWriter::GetNextWriteLocation( +quic::QuicPacketBuffer QuicChromiumPacketWriter::GetNextWriteLocation( const quic::QuicIpAddress& self_address, const quic::QuicSocketAddress& peer_address) { - return nullptr; + return {nullptr, nullptr}; } quic::WriteResult QuicChromiumPacketWriter::Flush() { diff --git a/chromium/net/quic/quic_chromium_packet_writer.h b/chromium/net/quic/quic_chromium_packet_writer.h index 82acb30f367..2f03d3914dc 100644 --- a/chromium/net/quic/quic_chromium_packet_writer.h +++ b/chromium/net/quic/quic_chromium_packet_writer.h @@ -94,7 +94,7 @@ class NET_EXPORT_PRIVATE QuicChromiumPacketWriter const quic::QuicSocketAddress& peer_address) const override; bool SupportsReleaseTime() const override; bool IsBatchMode() const override; - char* GetNextWriteLocation( + quic::QuicPacketBuffer GetNextWriteLocation( const quic::QuicIpAddress& self_address, const quic::QuicSocketAddress& peer_address) override; quic::WriteResult Flush() override; diff --git a/chromium/net/quic/quic_client_session_cache.cc b/chromium/net/quic/quic_client_session_cache.cc index 7bc5945225a..64e8d962993 100644 --- a/chromium/net/quic/quic_client_session_cache.cc +++ b/chromium/net/quic/quic_client_session_cache.cc @@ -46,9 +46,9 @@ QuicClientSessionCache::QuicClientSessionCache() QuicClientSessionCache::QuicClientSessionCache(size_t max_entries) : clock_(base::DefaultClock::GetInstance()), cache_(max_entries) { - memory_pressure_listener_.reset( - new base::MemoryPressureListener(base::BindRepeating( - &QuicClientSessionCache::OnMemoryPressure, base::Unretained(this)))); + memory_pressure_listener_ = std::make_unique<base::MemoryPressureListener>( + FROM_HERE, base::BindRepeating(&QuicClientSessionCache::OnMemoryPressure, + base::Unretained(this))); } QuicClientSessionCache::~QuicClientSessionCache() { @@ -103,6 +103,18 @@ std::unique_ptr<quic::QuicResumptionState> QuicClientSessionCache::Lookup( return state; } +void QuicClientSessionCache::ClearEarlyData( + const quic::QuicServerId& server_id) { + auto iter = cache_.Get(server_id); + if (iter == cache_.end()) + return; + for (auto& session : iter->second.sessions) { + if (session) { + session.reset(SSL_SESSION_copy_without_early_data(session.get())); + } + } +} + void QuicClientSessionCache::FlushInvalidEntries() { time_t now = clock_->Now().ToTimeT(); auto iter = cache_.begin(); diff --git a/chromium/net/quic/quic_client_session_cache.h b/chromium/net/quic/quic_client_session_cache.h index 8d7506ee4ec..c59c28a2937 100644 --- a/chromium/net/quic/quic_client_session_cache.h +++ b/chromium/net/quic/quic_client_session_cache.h @@ -39,6 +39,8 @@ class NET_EXPORT_PRIVATE QuicClientSessionCache : public quic::SessionCache { const quic::QuicServerId& server_id, const SSL_CTX* ctx) override; + void ClearEarlyData(const quic::QuicServerId& server_id) override; + void SetClockForTesting(base::Clock* clock) { clock_ = clock; } size_t size() const { return cache_.size(); } diff --git a/chromium/net/quic/quic_client_session_cache_unittests.cc b/chromium/net/quic/quic_client_session_cache_unittests.cc index 0fac11c6840..c1e241df403 100644 --- a/chromium/net/quic/quic_client_session_cache_unittests.cc +++ b/chromium/net/quic/quic_client_session_cache_unittests.cc @@ -8,6 +8,8 @@ #include "base/test/simple_test_clock.h" #include "base/test/task_environment.h" #include "base/time/time.h" +#include "build/build_config.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_text_utils.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/boringssl/src/include/openssl/ssl.h" @@ -15,6 +17,7 @@ namespace net { namespace { +const base::TimeDelta kTimeout = base::TimeDelta::FromSeconds(1000); const quic::QuicVersionLabel kFakeVersionLabel = 0x01234567; const quic::QuicVersionLabel kFakeVersionLabel2 = 0x89ABCDEF; const uint64_t kFakeIdleTimeoutMilliseconds = 12012; @@ -53,37 +56,96 @@ std::unique_ptr<quic::TransportParameters> MakeFakeTransportParams() { params->version = kFakeVersionLabel; params->supported_versions.push_back(kFakeVersionLabel); params->supported_versions.push_back(kFakeVersionLabel2); - params->idle_timeout_milliseconds.set_value(kFakeIdleTimeoutMilliseconds); + params->max_idle_timeout_ms.set_value(kFakeIdleTimeoutMilliseconds); params->stateless_reset_token = CreateFakeStatelessResetToken(); - params->max_packet_size.set_value(kFakeMaxPacketSize); + params->max_udp_payload_size.set_value(kFakeMaxPacketSize); params->initial_max_data.set_value(kFakeInitialMaxData); - params->disable_migration = kFakeDisableMigration; + params->disable_active_migration = kFakeDisableMigration; params->custom_parameters[kCustomParameter1] = kCustomParameter1Value; params->custom_parameters[kCustomParameter2] = kCustomParameter2Value; return params; } +namespace { + +// Generated by running TlsClientHandshakerTest.ZeroRttResumption and in +// TlsClientHandshaker::InsertSession calling SSL_SESSION_to_bytes to serialize +// the received 0-RTT capable ticket. +static const char kCachedSession[] = + "3082068702010102020304040213010420b9c2a657e565db0babd09e192a9fc4d768fbd706" + "9f03f9278a4a0be62392e55b0420d87ed2ab8cafc986fd2e288bd2d654cd57c3a2bed1d532" + "20726e55fed39d021ea10602045ed16771a205020302a300a382025f3082025b30820143a0" + "03020102020104300d06092a864886f70d01010b0500302c3110300e060355040a13074163" + "6d6520436f311830160603550403130f496e7465726d656469617465204341301e170d3133" + "303130313130303030305a170d3233313233313130303030305a302d3110300e060355040a" + "130741636d6520436f3119301706035504031310746573742e6578616d706c652e636f6d30" + "59301306072a8648ce3d020106082a8648ce3d030107034200040526220e77278300d06bc0" + "86aff4f999a828a2ed5cc75adc2972794befe885aa3a9b843de321b36b0a795289cebff1a5" + "428bad5e34665ce5e36daad08fb3ffd8a3523050300e0603551d0f0101ff04040302078030" + "130603551d25040c300a06082b06010505070301300c0603551d130101ff04023000301b06" + "03551d11041430128210746573742e6578616d706c652e636f6d300d06092a864886f70d01" + "010b050003820101008c1f1e380831b6437a8b9284d28d4ead38d9503a9fc936db89048aa2" + "edd6ec2fb830d962ef7a4f384e679504f4d5520f3272e0b9e702b110aff31711578fa5aeb1" + "11e9d184c994b0f97e7b17d1995f3f477f25bc1258398ec0ec729caed55d594a009f48093a" + "17f33a7f3bb6e420cc3499838398a421d93c7132efa8bee5ed2645cbc55179c400da006feb" + "761badd356cac3bd7a0e6b22a511106a355ec62a4c0ac2541d2996adb4a918c866d10c3e31" + "62039a91d4ce600b276740d833380b37f66866d261bf6efa8855e7ae6c7d12a8a864cd9a1f" + "4663e07714b0204e51bbc189a2d04c2a5043202379ff1c8cbf30cbb44fde4ee9a1c0c976dc" + "4943df2c132ca4020400aa7f047d494e534543555245003072020101020203040402130104" + "000420d87ed2ab8cafc986fd2e288bd2d654cd57c3a2bed1d53220726e55fed39d021ea106" + "02045ed16771a205020302a300a4020400b20302011db5060404bd909308b807020500ffff" + "ffffb9050203093a80ba07040568332d3238bb030101ffbc03040100b20302011db3820307" + "30820303308201eba003020102020102300d06092a864886f70d01010b050030243110300e" + "060355040a130741636d6520436f3110300e06035504031307526f6f74204341301e170d31" + "33303130313130303030305a170d3233313233313130303030305a302c3110300e06035504" + "0a130741636d6520436f311830160603550403130f496e7465726d65646961746520434130" + "820122300d06092a864886f70d01010105000382010f003082010a0282010100cd3550e70a" + "6880e52bf0012b93110c50f723e1d8d2ed489aea3b649f82fae4ad2396a8a19b31d1d64ab2" + "79f1c18003184154a5303a82bd57109cfd5d34fd19d3211bcb06e76640e1278998822dd72e" + "0d5c059a740d45de325e784e81b4c86097f08b2a8ce057f6b9db5a53641d27e09347d993ee" + "acf67be7d297b1a6853775ffaaf78fae924e300b5654fd32f99d3cd82e95f56417ff26d265" + "e2b1786c835d67a4d8ae896b6eb34b35a5b1033c209779ed0bf8de25a13a507040ae9e0475" + "a26a2f15845b08c3e0554e47dbbc7925b02e580dbcaaa6f2eecde6b8028c5b00b33d44d0a6" + "bfb3e72e9d4670de45d1bd79bdc0f2470b71286091c29873152db4b1f30203010001a33830" + "36300e0603551d0f0101ff04040302020430130603551d25040c300a06082b060105050703" + "01300f0603551d130101ff040530030101ff300d06092a864886f70d01010b050003820101" + "00bc4f8234860558dd404a626403819bfc759029d625a002143e75ebdb2898d1befdd326c3" + "4b14dc3507d732bb29af7e6af31552db53052a2be0d950efee5e0f699304231611ed8bf73a" + "6f216a904c6c2f1a2186d1ed08a8005a7914394d71e7d4b643c808f86365c5fecad8b52934" + "2d3b3f03447126d278d75b1dab3ed53f23e36e9b3d695f28727916e5ee56ce22d387c81f05" + "919b2a37bd4981eb67d9f57b7072285dbbb61f48b6b14768c069a092aad5a094cf295dafd2" + "3ca008f89a5f5ab37a56e5f68df45091c7cb85574677127087a2887ba3baa6d4fc436c6e40" + "40885e81621d38974f0c7f0d792418c5adebb10e92a165f8d79b169617ff575c0d4a85b506" + "0404bd909308b603010100b70402020403b807020500ffffffffb9050203093a80ba070405" + "68332d3238bb030101ff"; + +} // namespace + class QuicClientSessionCacheTest : public testing::Test { public: - QuicClientSessionCacheTest() : ssl_ctx_(SSL_CTX_new(TLS_method())) {} + QuicClientSessionCacheTest() + : ssl_ctx_(SSL_CTX_new(TLS_method())), clock_(MakeTestClock()) {} protected: bssl::UniquePtr<SSL_SESSION> NewSSLSession() { - SSL_SESSION* session = SSL_SESSION_new(ssl_ctx_.get()); - if (!SSL_SESSION_set_protocol_version(session, TLS1_3_VERSION)) - return nullptr; + std::string cached_session = + quiche::QuicheTextUtils::HexDecode(kCachedSession); + SSL_SESSION* session = SSL_SESSION_from_bytes( + reinterpret_cast<const uint8_t*>(cached_session.data()), + cached_session.size(), ssl_ctx_.get()); return bssl::UniquePtr<SSL_SESSION>(session); } - bssl::UniquePtr<SSL_SESSION> MakeTestSession(base::Time now, - base::TimeDelta timeout) { + bssl::UniquePtr<SSL_SESSION> MakeTestSession( + base::TimeDelta timeout = kTimeout) { bssl::UniquePtr<SSL_SESSION> session = NewSSLSession(); - SSL_SESSION_set_time(session.get(), now.ToTimeT()); + SSL_SESSION_set_time(session.get(), clock_->Now().ToTimeT()); SSL_SESSION_set_timeout(session.get(), timeout.InSeconds()); return session; } bssl::UniquePtr<SSL_CTX> ssl_ctx_; + std::unique_ptr<base::SimpleTestClock> clock_; }; } // namespace @@ -91,13 +153,14 @@ class QuicClientSessionCacheTest : public testing::Test { // Tests that simple insertion and lookup work correctly. TEST_F(QuicClientSessionCacheTest, SingleSession) { QuicClientSessionCache cache; + cache.SetClockForTesting(clock_.get()); auto params = MakeFakeTransportParams(); - auto session = NewSSLSession(); + auto session = MakeTestSession(); quic::QuicServerId id1("a.com", 443); auto params2 = MakeFakeTransportParams(); - auto session2 = NewSSLSession(); + auto session2 = MakeTestSession(); SSL_SESSION* unowned2 = session2.get(); quic::QuicServerId id2("b.com", 443); @@ -115,7 +178,7 @@ TEST_F(QuicClientSessionCacheTest, SingleSession) { // Lookup() will trigger a deletion of invalid entry. EXPECT_EQ(0u, cache.size()); - auto session3 = NewSSLSession(); + auto session3 = MakeTestSession(); SSL_SESSION* unowned3 = session3.get(); quic::QuicServerId id3("c.com", 443); cache.Insert(id3, std::move(session3), *params, nullptr); @@ -133,13 +196,14 @@ TEST_F(QuicClientSessionCacheTest, SingleSession) { TEST_F(QuicClientSessionCacheTest, MultipleSessions) { QuicClientSessionCache cache; + cache.SetClockForTesting(clock_.get()); auto params = MakeFakeTransportParams(); - auto session = NewSSLSession(); + auto session = MakeTestSession(); quic::QuicServerId id1("a.com", 443); - auto session2 = NewSSLSession(); + auto session2 = MakeTestSession(); SSL_SESSION* unowned2 = session2.get(); - auto session3 = NewSSLSession(); + auto session3 = MakeTestSession(); SSL_SESSION* unowned3 = session3.get(); cache.Insert(id1, std::move(session), *params, nullptr); @@ -156,12 +220,13 @@ TEST_F(QuicClientSessionCacheTest, MultipleSessions) { // the same server id, the existing entry is removed. TEST_F(QuicClientSessionCacheTest, DifferentTransportParams) { QuicClientSessionCache cache; + cache.SetClockForTesting(clock_.get()); auto params = MakeFakeTransportParams(); - auto session = NewSSLSession(); + auto session = MakeTestSession(); quic::QuicServerId id1("a.com", 443); - auto session2 = NewSSLSession(); - auto session3 = NewSSLSession(); + auto session2 = MakeTestSession(); + auto session3 = MakeTestSession(); SSL_SESSION* unowned3 = session3.get(); cache.Insert(id1, std::move(session), *params, nullptr); @@ -177,12 +242,13 @@ TEST_F(QuicClientSessionCacheTest, DifferentTransportParams) { TEST_F(QuicClientSessionCacheTest, DifferentApplicationState) { QuicClientSessionCache cache; + cache.SetClockForTesting(clock_.get()); auto params = MakeFakeTransportParams(); - auto session = NewSSLSession(); + auto session = MakeTestSession(); quic::QuicServerId id1("a.com", 443); - auto session2 = NewSSLSession(); - auto session3 = NewSSLSession(); + auto session2 = MakeTestSession(); + auto session3 = MakeTestSession(); SSL_SESSION* unowned3 = session3.get(); quic::ApplicationState state; state.push_back('a'); @@ -198,12 +264,13 @@ TEST_F(QuicClientSessionCacheTest, DifferentApplicationState) { TEST_F(QuicClientSessionCacheTest, BothStatesDifferent) { QuicClientSessionCache cache; + cache.SetClockForTesting(clock_.get()); auto params = MakeFakeTransportParams(); - auto session = NewSSLSession(); + auto session = MakeTestSession(); quic::QuicServerId id1("a.com", 443); - auto session2 = NewSSLSession(); - auto session3 = NewSSLSession(); + auto session2 = MakeTestSession(); + auto session3 = MakeTestSession(); SSL_SESSION* unowned3 = session3.get(); quic::ApplicationState state; state.push_back('a'); @@ -222,16 +289,17 @@ TEST_F(QuicClientSessionCacheTest, BothStatesDifferent) { // When the size limit is exceeded, the oldest entry should be erased. TEST_F(QuicClientSessionCacheTest, SizeLimit) { QuicClientSessionCache cache(2); + cache.SetClockForTesting(clock_.get()); auto params = MakeFakeTransportParams(); - auto session = NewSSLSession(); + auto session = MakeTestSession(); quic::QuicServerId id1("a.com", 443); - auto session2 = NewSSLSession(); + auto session2 = MakeTestSession(); SSL_SESSION* unowned2 = session2.get(); quic::QuicServerId id2("b.com", 443); - auto session3 = NewSSLSession(); + auto session3 = MakeTestSession(); SSL_SESSION* unowned3 = session3.get(); quic::QuicServerId id3("c.com", 443); @@ -245,19 +313,43 @@ TEST_F(QuicClientSessionCacheTest, SizeLimit) { EXPECT_EQ(nullptr, cache.Lookup(id1, ssl_ctx_.get())); } +TEST_F(QuicClientSessionCacheTest, ClearEarlyData) { + QuicClientSessionCache cache; + cache.SetClockForTesting(clock_.get()); + SSL_CTX_set_early_data_enabled(ssl_ctx_.get(), 1); + auto params = MakeFakeTransportParams(); + auto session = MakeTestSession(); + quic::QuicServerId id1("a.com", 443); + auto session2 = MakeTestSession(); + + EXPECT_TRUE(SSL_SESSION_early_data_capable(session.get())); + EXPECT_TRUE(SSL_SESSION_early_data_capable(session2.get())); + + cache.Insert(id1, std::move(session), *params, nullptr); + cache.Insert(id1, std::move(session2), *params, nullptr); + + cache.ClearEarlyData(id1); + + auto resumption_state = cache.Lookup(id1, ssl_ctx_.get()); + EXPECT_FALSE( + SSL_SESSION_early_data_capable(resumption_state->tls_session.get())); + resumption_state = cache.Lookup(id1, ssl_ctx_.get()); + EXPECT_FALSE( + SSL_SESSION_early_data_capable(resumption_state->tls_session.get())); + EXPECT_EQ(nullptr, cache.Lookup(id1, ssl_ctx_.get())); +} + // Expired session isn't considered valid and nullptr will be returned upon // Lookup. TEST_F(QuicClientSessionCacheTest, Expiration) { - const base::TimeDelta kTimeout = base::TimeDelta::FromSeconds(1000); QuicClientSessionCache cache; - std::unique_ptr<base::SimpleTestClock> clock = MakeTestClock(); - cache.SetClockForTesting(clock.get()); + cache.SetClockForTesting(clock_.get()); auto params = MakeFakeTransportParams(); - auto session = MakeTestSession(clock->Now(), kTimeout); + auto session = MakeTestSession(); quic::QuicServerId id1("a.com", 443); - auto session2 = MakeTestSession(clock->Now(), 3 * kTimeout); + auto session2 = MakeTestSession(3 * kTimeout); SSL_SESSION* unowned2 = session2.get(); quic::QuicServerId id2("b.com", 443); @@ -266,7 +358,7 @@ TEST_F(QuicClientSessionCacheTest, Expiration) { EXPECT_EQ(2u, cache.size()); // Expire the session. - clock->Advance(kTimeout * 2); + clock_->Advance(kTimeout * 2); // The entry has not been removed yet. EXPECT_EQ(2u, cache.size()); @@ -278,16 +370,14 @@ TEST_F(QuicClientSessionCacheTest, Expiration) { TEST_F(QuicClientSessionCacheTest, FlushOnMemoryNotifications) { base::test::TaskEnvironment task_environment; - const base::TimeDelta kTimeout = base::TimeDelta::FromSeconds(1000); QuicClientSessionCache cache; - std::unique_ptr<base::SimpleTestClock> clock = MakeTestClock(); - cache.SetClockForTesting(clock.get()); + cache.SetClockForTesting(clock_.get()); auto params = MakeFakeTransportParams(); - auto session = MakeTestSession(clock->Now(), kTimeout); + auto session = MakeTestSession(); quic::QuicServerId id1("a.com", 443); - auto session2 = MakeTestSession(clock->Now(), 3 * kTimeout); + auto session2 = MakeTestSession(3 * kTimeout); quic::QuicServerId id2("b.com", 443); cache.Insert(id1, std::move(session), *params, nullptr); @@ -295,7 +385,7 @@ TEST_F(QuicClientSessionCacheTest, FlushOnMemoryNotifications) { EXPECT_EQ(2u, cache.size()); // Expire the session. - clock->Advance(kTimeout * 2); + clock_->Advance(kTimeout * 2); // The entry has not been removed yet. EXPECT_EQ(2u, cache.size()); diff --git a/chromium/net/quic/quic_connection_logger.cc b/chromium/net/quic/quic_connection_logger.cc index 1293fac42ac..71803309b69 100644 --- a/chromium/net/quic/quic_connection_logger.cc +++ b/chromium/net/quic/quic_connection_logger.cc @@ -227,6 +227,14 @@ base::Value NetLogQuicCryptoHandshakeMessageParams( return dict; } +base::Value NetLogQuicTransportParametersParams( + const quic::TransportParameters& transport_parameters) { + base::Value dict(base::Value::Type::DICTIONARY); + dict.SetStringKey("quic_transport_parameters", + transport_parameters.ToString()); + return dict; +} + base::Value NetLogQuicOnConnectionClosedParams( quic::QuicErrorCode error, string error_details, @@ -877,8 +885,6 @@ void QuicConnectionLogger::OnIncomingAck( return; net_log_.AddEvent(NetLogEventType::QUIC_SESSION_ACK_FRAME_RECEIVED, [&] { return NetLogQuicAckFrameParams(&frame); }); - - // TODO(rch, rtenneti) sort out histograms for QUIC_VERSION_34 and above. } void QuicConnectionLogger::OnStopWaitingFrame( @@ -1142,6 +1148,26 @@ void QuicConnectionLogger::OnRttChanged(quic::QuicTime::Delta rtt) const { } } +void QuicConnectionLogger::OnTransportParametersSent( + const quic::TransportParameters& transport_parameters) { + if (!net_log_.IsCapturing()) + return; + net_log_.AddEvent( + NetLogEventType::QUIC_SESSION_TRANSPORT_PARAMETERS_SENT, [&] { + return NetLogQuicTransportParametersParams(transport_parameters); + }); +} + +void QuicConnectionLogger::OnTransportParametersReceived( + const quic::TransportParameters& transport_parameters) { + if (!net_log_.IsCapturing()) + return; + net_log_.AddEvent( + NetLogEventType::QUIC_SESSION_TRANSPORT_PARAMETERS_RECEIVED, [&] { + return NetLogQuicTransportParametersParams(transport_parameters); + }); +} + void QuicConnectionLogger::RecordAggregatePacketLossRate() const { // For short connections under 22 packets in length, we'll rely on the // Net.QuicSession.21CumulativePacketsReceived_* histogram to indicate packet diff --git a/chromium/net/quic/quic_connection_logger.h b/chromium/net/quic/quic_connection_logger.h index 9c45bf983d9..879ebf1c986 100644 --- a/chromium/net/quic/quic_connection_logger.h +++ b/chromium/net/quic/quic_connection_logger.h @@ -109,6 +109,10 @@ class NET_EXPORT_PRIVATE QuicConnectionLogger void OnSuccessfulVersionNegotiation( const quic::ParsedQuicVersion& version) override; void OnRttChanged(quic::QuicTime::Delta rtt) const override; + void OnTransportParametersSent( + const quic::TransportParameters& transport_parameters) override; + void OnTransportParametersReceived( + const quic::TransportParameters& transport_parameters) override; void OnCryptoHandshakeMessageReceived( const quic::CryptoHandshakeMessage& message); diff --git a/chromium/net/quic/quic_connectivity_monitor.cc b/chromium/net/quic/quic_connectivity_monitor.cc new file mode 100644 index 00000000000..00d0a774465 --- /dev/null +++ b/chromium/net/quic/quic_connectivity_monitor.cc @@ -0,0 +1,71 @@ +// Copyright (c) 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/quic/quic_connectivity_monitor.h" + +#include "base/metrics/histogram_macros.h" + +namespace net { + +QuicConnectivityMonitor::QuicConnectivityMonitor( + NetworkChangeNotifier::NetworkHandle default_network) + : default_network_(default_network) {} + +QuicConnectivityMonitor::~QuicConnectivityMonitor() = default; + +size_t QuicConnectivityMonitor::GetNumDegradingSessions() const { + return degrading_sessions_.size(); +} + +void QuicConnectivityMonitor::SetInitialDefaultNetwork( + NetworkChangeNotifier::NetworkHandle default_network) { + default_network_ = default_network; +} + +void QuicConnectivityMonitor::OnSessionPathDegrading( + QuicChromiumClientSession* session, + NetworkChangeNotifier::NetworkHandle network) { + if (network == default_network_) + degrading_sessions_.insert(session); +} + +void QuicConnectivityMonitor::OnSessionResumedPostPathDegrading( + QuicChromiumClientSession* session, + NetworkChangeNotifier::NetworkHandle network) { + if (network == default_network_) + degrading_sessions_.erase(session); +} + +void QuicConnectivityMonitor::OnSessionRemoved( + QuicChromiumClientSession* session) { + degrading_sessions_.erase(session); +} + +void QuicConnectivityMonitor::OnDefaultNetworkUpdated( + NetworkChangeNotifier::NetworkHandle default_network) { + default_network_ = default_network; + degrading_sessions_.clear(); +} + +void QuicConnectivityMonitor::OnIPAddressChanged() { + // If NetworkHandle is supported, connectivity monitor will receive + // notifications via OnDefaultNetworkUpdated. + if (NetworkChangeNotifier::AreNetworkHandlesSupported()) + return; + + DCHECK_EQ(default_network_, NetworkChangeNotifier::kInvalidNetworkHandle); + degrading_sessions_.clear(); +} + +void QuicConnectivityMonitor::OnSessionGoingAwayOnIPAddressChange( + QuicChromiumClientSession* session) { + // This should only be called after ConnectivityMonitor gets notified via + // OnIPAddressChanged(). + DCHECK(degrading_sessions_.empty()); + // |session| that encounters IP address change will lose track which network + // it is bound to. Future connectivity monitoring may be misleading. + session->RemoveConnectivityObserver(this); +} + +} // namespace net diff --git a/chromium/net/quic/quic_connectivity_monitor.h b/chromium/net/quic/quic_connectivity_monitor.h new file mode 100644 index 00000000000..b8b7274a8d8 --- /dev/null +++ b/chromium/net/quic/quic_connectivity_monitor.h @@ -0,0 +1,74 @@ +// Copyright (c) 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NET_QUIC_QUIC_CONNECTIVITY_MONITOR_H_ +#define NET_QUIC_QUIC_CONNECTIVITY_MONITOR_H_ + +#include "net/base/network_change_notifier.h" +#include "net/quic/quic_chromium_client_session.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h" + +namespace net { + +// Responsible for monitoring path degrading detection/recovery events on the +// default network interface. +// Reset all raw observations (reported by sessions) when the default network +// is changed, which happens either: +// - via OnDefaultNetworkUpdated if NetworkHandle is supported on the platform; +// - via OnIPAddressChanged otherwise. +class NET_EXPORT_PRIVATE QuicConnectivityMonitor + : public QuicChromiumClientSession::ConnectivityObserver { + public: + explicit QuicConnectivityMonitor( + NetworkChangeNotifier::NetworkHandle default_network); + + ~QuicConnectivityMonitor() override; + + // Returns the number of sessions that are currently degrading on the default + // network interface. + size_t GetNumDegradingSessions() const; + + // Called to set up the initial default network, which happens when the + // default network tracking is lost upon |this| creation. + void SetInitialDefaultNetwork( + NetworkChangeNotifier::NetworkHandle default_network); + + // Called when NetworkHandle is supported and the default network interface + // used by the platform is updated. + void OnDefaultNetworkUpdated( + NetworkChangeNotifier::NetworkHandle default_network); + + // Called when NetworkHandle is NOT supported and the IP address of the + // primary interface changes. This includes when the primary interface itself + // changes. + void OnIPAddressChanged(); + + // Called when |session| is marked as going away due to IP address change. + void OnSessionGoingAwayOnIPAddressChange(QuicChromiumClientSession* session); + + // QuicChromiumClientSession::ConnectivityObserver implementation. + void OnSessionPathDegrading( + QuicChromiumClientSession* session, + NetworkChangeNotifier::NetworkHandle network) override; + + void OnSessionResumedPostPathDegrading( + QuicChromiumClientSession* session, + NetworkChangeNotifier::NetworkHandle network) override; + + void OnSessionRemoved(QuicChromiumClientSession* session) override; + + private: + // If NetworkHandle is not supported, always set to + // NetworkChangeNotifier::kInvalidNetworkHandle. + NetworkChangeNotifier::NetworkHandle default_network_; + // Sessions that are currently degrading on the |default_network_|. + quic::QuicHashSet<QuicChromiumClientSession*> degrading_sessions_; + + base::WeakPtrFactory<QuicConnectivityMonitor> weak_factory_{this}; + DISALLOW_COPY_AND_ASSIGN(QuicConnectivityMonitor); +}; + +} // namespace net + +#endif // NET_QUIC_QUIC_CONNECTIVITY_MONITOR_H_ diff --git a/chromium/net/quic/quic_connectivity_probing_manager.cc b/chromium/net/quic/quic_connectivity_probing_manager.cc index 9f0d16fbee4..dd240252bf6 100644 --- a/chromium/net/quic/quic_connectivity_probing_manager.cc +++ b/chromium/net/quic/quic_connectivity_probing_manager.cc @@ -60,7 +60,9 @@ QuicConnectivityProbingManager::QuicConnectivityProbingManager( network_(NetworkChangeNotifier::kInvalidNetworkHandle), retry_count_(0), probe_start_time_(base::TimeTicks()), - task_runner_(task_runner) { + task_runner_(task_runner), + last_self_address_(IPEndPoint()), + stateless_reset_received_(false) { retransmit_timer_.SetTaskRunner(task_runner_); } @@ -98,14 +100,19 @@ void QuicConnectivityProbingManager::CancelProbing( void QuicConnectivityProbingManager::CancelProbingIfAny() { if (is_running_) { + UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.StatelessResetDuringProbing", + stateless_reset_received_); net_log_.AddEvent( NetLogEventType::QUIC_CONNECTIVITY_PROBING_MANAGER_CANCEL_PROBING, [&] { return NetLogProbingDestinationParams(network_, &peer_address_); }); } is_running_ = false; + if (socket_ != nullptr) { + socket_->GetLocalAddress(&last_self_address_); + } network_ = NetworkChangeNotifier::kInvalidNetworkHandle; - peer_address_ = quic::QuicSocketAddress(); + stateless_reset_received_ = false; socket_.reset(); writer_.reset(); reader_.reset(); @@ -198,6 +205,43 @@ void QuicConnectivityProbingManager::OnPacketReceived( CancelProbingIfAny(); } +bool QuicConnectivityProbingManager::ValidateStatelessReset( + const quic::QuicSocketAddress& self_address, + const quic::QuicSocketAddress& peer_address) { + IPEndPoint local_address; + if (!socket_) { + local_address = last_self_address_; + } else { + socket_->GetLocalAddress(&local_address); + } + + if (local_address != ToIPEndPoint(self_address) || + peer_address_ != peer_address) { + DVLOG(1) << "Probing lives at different path:"; + DVLOG(1) << " peer_address: " << local_address.ToString(); + DVLOG(1) << " self_address: " << self_address.ToString(); + return false; + } + + if (is_running_) { + stateless_reset_received_ = true; + } else { + UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.StatelessResetAfterProbingCancelled", + true); + } + + net_log_.AddEvent( + NetLogEventType:: + QUIC_CONNECTIVITY_PROBING_MANAGER_STATELESS_RESET_RECEIVED, + [&] { + return NetLogProbeReceivedParams(network_, &local_address, + &peer_address_); + }); + + NotifyDelegateProbeFailed(); + return true; +} + void QuicConnectivityProbingManager::SendConnectivityProbingPacket( base::TimeDelta timeout) { net_log_.AddEventWithInt64Params( diff --git a/chromium/net/quic/quic_connectivity_probing_manager.h b/chromium/net/quic/quic_connectivity_probing_manager.h index 9d4de8e25bb..d7e0a9c5067 100644 --- a/chromium/net/quic/quic_connectivity_probing_manager.h +++ b/chromium/net/quic/quic_connectivity_probing_manager.h @@ -7,6 +7,7 @@ #include "base/time/time.h" #include "base/timer/timer.h" +#include "net/base/ip_endpoint.h" #include "net/base/net_export.h" #include "net/log/net_log_with_source.h" #include "net/quic/quic_chromium_packet_reader.h" @@ -95,6 +96,11 @@ class NET_EXPORT_PRIVATE QuicConnectivityProbingManager peer_address == peer_address_); } + // Returns true if both |self_address| and |peer_address| + // match with the probing manager's socket address. Returns false otherwise. + bool ValidateStatelessReset(const quic::QuicSocketAddress& self_address, + const quic::QuicSocketAddress& peer_address); + private: // Cancels undergoing probing. void CancelProbingIfAny(); @@ -116,6 +122,8 @@ class NET_EXPORT_PRIVATE QuicConnectivityProbingManager // if |is_running_| is true. bool is_running_; NetworkChangeNotifier::NetworkHandle network_; + // If |is_running| is false, |peer_address_| caches the peer address of the + // last probing path. quic::QuicSocketAddress peer_address_; std::unique_ptr<DatagramClientSocket> socket_; @@ -129,6 +137,11 @@ class NET_EXPORT_PRIVATE QuicConnectivityProbingManager base::SequencedTaskRunner* task_runner_; + // The cached local address set when probing is cancelled. + IPEndPoint last_self_address_; + + bool stateless_reset_received_; + base::WeakPtrFactory<QuicConnectivityProbingManager> weak_factory_{this}; DISALLOW_COPY_AND_ASSIGN(QuicConnectivityProbingManager); }; diff --git a/chromium/net/quic/quic_connectivity_probing_manager_test.cc b/chromium/net/quic/quic_connectivity_probing_manager_test.cc index 15bd236a20a..abce3d51857 100644 --- a/chromium/net/quic/quic_connectivity_probing_manager_test.cc +++ b/chromium/net/quic/quic_connectivity_probing_manager_test.cc @@ -378,6 +378,89 @@ TEST_F(QuicConnectivityProbingManagerTest, RetryProbingWithExponentailBackoff) { EXPECT_EQ(0u, test_task_runner_->GetPendingTaskCount()); } +TEST_F(QuicConnectivityProbingManagerTest, ProbingReceivedStatelessReset) { + int initial_timeout_ms = 100; + EXPECT_CALL(session_, OnSendConnectivityProbingPacket(_, testPeerAddress)) + .WillOnce(Return(true)); + probing_manager_.StartProbing( + testNetworkHandle, testPeerAddress, std::move(socket_), + std::move(writer_), std::move(reader_), + base::TimeDelta::FromMilliseconds(initial_timeout_ms), + bound_test_net_log_.bound()); + EXPECT_EQ(1u, test_task_runner_->GetPendingTaskCount()); + + // Fast forward initial_timeout_ms, timeout the first connectivity probing + // packet, cause another probing packet to be sent with timeout set to + // 2 * initial_timeout_ms. + EXPECT_CALL(session_, OnSendConnectivityProbingPacket(_, testPeerAddress)) + .WillOnce(Return(true)); + test_task_runner_->FastForwardBy( + base::TimeDelta::FromMilliseconds(initial_timeout_ms)); + EXPECT_EQ(1u, test_task_runner_->GetPendingTaskCount()); + + // Fast forward initial_timeout_ms, should be no-op. + EXPECT_CALL(session_, OnSendConnectivityProbingPacket(_, testPeerAddress)) + .Times(0); + test_task_runner_->FastForwardBy( + base::TimeDelta::FromMilliseconds(initial_timeout_ms)); + EXPECT_EQ(1u, test_task_runner_->GetPendingTaskCount()); + + EXPECT_CALL(session_, OnProbeFailed(testNetworkHandle, testPeerAddress)) + .Times(1); + EXPECT_TRUE( + probing_manager_.ValidateStatelessReset(self_address_, testPeerAddress)); + EXPECT_FALSE(session_.is_successfully_probed()); + EXPECT_FALSE( + probing_manager_.IsUnderProbing(testNetworkHandle, testPeerAddress)); + test_task_runner_->RunUntilIdle(); +} + +TEST_F(QuicConnectivityProbingManagerTest, + StatelessResetReceivedAfterProbingCancelled) { + int initial_timeout_ms = 100; + + EXPECT_CALL(session_, OnSendConnectivityProbingPacket(_, testPeerAddress)) + .WillOnce(Return(true)); + probing_manager_.StartProbing( + testNetworkHandle, testPeerAddress, std::move(socket_), + std::move(writer_), std::move(reader_), + base::TimeDelta::FromMilliseconds(initial_timeout_ms), + bound_test_net_log_.bound()); + EXPECT_EQ(1u, test_task_runner_->GetPendingTaskCount()); + + // Fast forward initial_timeout_ms, timeout the first connectivity probing + // packet, cause another probing packet to be sent with timeout set to + // 2 * initial_timeout_ms. + EXPECT_CALL(session_, OnSendConnectivityProbingPacket(_, testPeerAddress)) + .WillOnce(Return(true)); + test_task_runner_->FastForwardBy( + base::TimeDelta::FromMilliseconds(initial_timeout_ms)); + EXPECT_EQ(1u, test_task_runner_->GetPendingTaskCount()); + + // Fast forward initial_timeout_ms, should be no-op. + EXPECT_CALL(session_, OnSendConnectivityProbingPacket(_, testPeerAddress)) + .Times(0); + test_task_runner_->FastForwardBy( + base::TimeDelta::FromMilliseconds(initial_timeout_ms)); + EXPECT_EQ(1u, test_task_runner_->GetPendingTaskCount()); + + // Request cancel probing, manager will no longer send connectivity probes. + EXPECT_CALL(session_, OnSendConnectivityProbingPacket(_, _)).Times(0); + EXPECT_CALL(session_, OnProbeFailed(_, _)).Times(0); + probing_manager_.CancelProbing(testNetworkHandle, testPeerAddress); + EXPECT_FALSE( + probing_manager_.IsUnderProbing(testNetworkHandle, testPeerAddress)); + + // Verify that the probing manager is still able to verify STATELESS_RESET + // received on the previous probing path. + EXPECT_TRUE( + probing_manager_.ValidateStatelessReset(self_address_, testPeerAddress)); + EXPECT_FALSE(session_.is_successfully_probed()); + EXPECT_FALSE( + probing_manager_.IsUnderProbing(testNetworkHandle, testPeerAddress)); + test_task_runner_->RunUntilIdle(); +} + TEST_F(QuicConnectivityProbingManagerTest, CancelProbing) { int initial_timeout_ms = 100; diff --git a/chromium/net/quic/quic_context.h b/chromium/net/quic/quic_context.h index 1f3ece3c0c7..e27af55433a 100644 --- a/chromium/net/quic/quic_context.h +++ b/chromium/net/quic/quic_context.h @@ -13,8 +13,8 @@ namespace net { // Default QUIC version used in absence of any external configuration. -constexpr quic::ParsedQuicVersion kDefaultSupportedQuicVersion{ - quic::PROTOCOL_QUIC_CRYPTO, quic::QUIC_VERSION_46}; +constexpr quic::ParsedQuicVersion kDefaultSupportedQuicVersion = + quic::ParsedQuicVersion::Q050(); // Returns a list containing only the current default version. inline NET_EXPORT_PRIVATE quic::ParsedQuicVersionVector @@ -165,6 +165,8 @@ struct NET_EXPORT QuicParams { // The initial rtt that will be used in crypto handshake if no cached // smoothed rtt is present. base::TimeDelta initial_rtt_for_handshake; + // If true, QUIC with TLS will not try 0-RTT connection. + bool disable_tls_zero_rtt = false; }; // QuicContext contains QUIC-related variables that are shared across all of the @@ -187,6 +189,11 @@ class NET_EXPORT_PRIVATE QuicContext { return params_.supported_versions; } + void SetHelperForTesting( + std::unique_ptr<quic::QuicConnectionHelperInterface> helper) { + helper_ = std::move(helper); + } + private: std::unique_ptr<quic::QuicConnectionHelperInterface> helper_; diff --git a/chromium/net/quic/quic_flags_list.h b/chromium/net/quic/quic_flags_list.h index e90d9ee34b2..8275a075e38 100644 --- a/chromium/net/quic/quic_flags_list.h +++ b/chromium/net/quic/quic_flags_list.h @@ -166,9 +166,6 @@ QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_allow_client_enabled_bbr_v2, false) -// If true, will negotiate the ACK delay time. -QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_negotiate_ack_delay_time, true) - // If true, QuicFramer::WriteClientVersionNegotiationProbePacket uses // length-prefixed connection IDs. QUIC_FLAG(bool, FLAGS_quic_prober_uses_length_prefixed_connection_ids, false) @@ -212,7 +209,7 @@ QUIC_FLAG(int32_t, FLAGS_quic_bbr2_default_probe_rtt_period_ms, 10000) // The default loss threshold for QUIC BBRv2, should be a value // between 0 and 1. -QUIC_FLAG(double, FLAGS_quic_bbr2_default_loss_threshold, 0.3) +QUIC_FLAG(double, FLAGS_quic_bbr2_default_loss_threshold, 0.02) // The default minimum number of loss marking events to exit STARTUP. QUIC_FLAG(int32_t, FLAGS_quic_bbr2_default_startup_full_loss_count, 8) @@ -228,20 +225,26 @@ QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_disable_version_q043, false) QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_disable_version_q046, false) // If true, disable QUIC version Q048. -QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_disable_version_q048, false) +QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_disable_version_q048, true) // If true, disable QUIC version Q049. -QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_disable_version_q049, false) +QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_disable_version_q049, true) // If true, disable QUIC version Q050. QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_disable_version_q050, false) -// If true, enable QUIC version T050. -QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_enable_version_t050_v2, true) - // A testonly reloadable flag that will always default to false. QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_testonly_default_false, false) +// A testonly reloadable flag that will always default to true. +QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_testonly_default_true, true) + +// A testonly restart flag that will always default to false. +QUIC_FLAG(bool, FLAGS_quic_restart_flag_quic_testonly_default_false, false) + +// A testonly restart flag that will always default to true. +QUIC_FLAG(bool, FLAGS_quic_restart_flag_quic_testonly_default_true, true) + // In BBR, slow pacing rate if it is likely causing overshoot. QUIC_FLAG( bool, @@ -263,20 +266,11 @@ QUIC_FLAG(bool, // If true, use predictable grease settings identifiers and values. QUIC_FLAG(bool, FLAGS_quic_enable_http3_grease_randomness, true) -// If true, enable QUIC version h3-25. -QUIC_FLAG(bool, - FLAGS_quic_reloadable_flag_quic_enable_version_draft_25_v3, - true) +// If true, disable QUIC version h3-25. +QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_disable_version_draft_25, false) -// If true, enable QUIC version h3-27. -QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_enable_version_draft_27, true) - -// If true, fix QUIC bandwidth sampler to avoid over estimating bandwidth in -// the presence of ack aggregation. -QUIC_FLAG( - bool, - FLAGS_quic_reloadable_flag_quic_avoid_overestimate_bandwidth_with_aggregation, - true) +// If true, disable QUIC version h3-27. +QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_disable_version_draft_27, false) // If true, QUIC BBRv2 to take ack height into account when calculating // queuing_threshold in PROBE_UP. @@ -285,38 +279,13 @@ QUIC_FLAG( FLAGS_quic_reloadable_flag_quic_bbr2_add_ack_height_to_queueing_threshold, true) -// If true, quic::BandwidthSampler will start in application limited phase. -QUIC_FLAG(bool, - FLAGS_quic_reloadable_flag_quic_bw_sampler_app_limited_starting_value, - true) - // If true, use idle network detector to detect handshake timeout and idle // network timeout. -QUIC_FLAG(bool, - FLAGS_quic_reloadable_flag_quic_use_idle_network_detector, - false) - -// If true, QUIC will enable connection options LRTT+BBQ2 by default. -QUIC_FLAG(bool, - FLAGS_quic_reloadable_flag_quic_bbr_default_exit_startup_on_loss, - false) +QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_use_idle_network_detector, true) // If true, server push will be allowed in QUIC versions using HTTP/3. QUIC_FLAG(bool, FLAGS_quic_enable_http3_server_push, false) -// If true, disable QuicDispatcher workaround that replies to invalid QUIC -// packets from the Android Conformance Test. -QUIC_FLAG( - bool, - FLAGS_quic_reloadable_flag_quic_remove_android_conformance_test_workaround, - true) - -// If true, lower the CWND gain in BBRv2 STARTUP to 2 when BBQ2 is in connection -// options. -QUIC_FLAG(bool, - FLAGS_quic_reloadable_flag_quic_bbr2_lower_startup_cwnd_gain, - true) - // The divisor that controls how often MAX_STREAMS frames are sent. QUIC_FLAG(int32_t, FLAGS_quic_max_streams_window_divisor, 2) @@ -333,25 +302,10 @@ QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_bbr2_fewer_startup_round_trips, false) -// If true, remove draining_streams_ from QuicSession. -QUIC_FLAG(bool, - FLAGS_quic_reloadable_flag_quic_deprecate_draining_streams, - true) - -// If true, break session/stream close loop. -QUIC_FLAG(bool, - FLAGS_quic_reloadable_flag_quic_break_session_stream_close_loop, - true) - // Replace the usage of ConnectionData::encryption_level in // quic_time_wait_list_manager with a new TimeWaitAction. QUIC_FLAG(bool, FLAGS_quic_restart_flag_quic_replace_time_wait_list_encryption_level, - false) - -// If true, move Goolge QUIC stream accounting to LegacyQuicStreamIdManager. -QUIC_FLAG(bool, - FLAGS_quic_reloadable_flag_quic_stream_id_manager_handles_accounting, true) // If true, enables support for TLS resumption in QUIC. @@ -360,58 +314,153 @@ QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_enable_tls_resumption, false) // When true, QUIC's BBRv2 ignores inflight_lo in PROBE_BW. QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_bbr2_ignore_inflight_lo, false) -// If true, returns min_rtt in rtt_stats_ if it is available. -QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_bbr_use_available_min_rtt, true) +// If true, do not change ACK in PostProcessAckFrame if an ACK has been queued. +QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_donot_change_queued_ack, true) + +// If true, reject IETF QUIC connections with invalid SNI. +QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_tls_enforce_valid_sni, true) + +// If true, support for IETF QUIC 0-rtt is enabled. +QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_enable_zero_rtt_for_tls, true) + +// If true, default on PTO which unifies TLP + RTO loss recovery. +QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_default_on_pto, false) -// If true, notify handshakers when connection closes. +// When true, QUIC+TLS will not send nor parse the old-format Google-specific +// transport parameters. QUIC_FLAG(bool, - FLAGS_quic_reloadable_flag_quic_notify_handshaker_on_connection_close, + FLAGS_quic_restart_flag_quic_google_transport_param_omit_old, + false) + +// When true, QUIC+TLS will send and parse the new-format Google-specific +// transport parameters. +QUIC_FLAG(bool, + FLAGS_quic_restart_flag_quic_google_transport_param_send_new, true) -// If true, for QUIC + TLS, change default encryption level when new encryption -// key is available. +// If true, check ShouldGeneratePacket for every crypto packet. QUIC_FLAG(bool, - FLAGS_quic_reloadable_flag_quic_change_default_encryption_level, + FLAGS_quic_reloadable_flag_quic_fix_checking_should_generate_packet, true) -// If true, do not change ACK in PostProcessAckFrame if an ACK has been queued. -QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_donot_change_queued_ack, false) +// If true, notify stream ID manager even connection disconnects. +QUIC_FLAG( + bool, + FLAGS_quic_reloadable_flag_quic_notify_stream_id_manager_when_disconnected, + true) -// If true, reject IETF QUIC connections with invalid SNI. -QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_tls_enforce_valid_sni, false) +// If true, return from QuicCryptoStream::WritePendingCryptoRetransmission after +// partial writes. +QUIC_FLAG( + bool, + FLAGS_quic_reloadable_flag_quic_fix_write_pending_crypto_retransmission, + true) -// If true, update ack timeout upon receiving an retransmittable frame. +// If true, clear last_inflight_packets_sent_time_ of a packet number space when +// there is no bytes in flight. QUIC_FLAG(bool, - FLAGS_quic_reloadable_flag_quic_advance_ack_timeout_update, - false) + FLAGS_quic_reloadable_flag_quic_fix_last_inflight_packets_sent_time, + true) -// If true, only extend idle time on decryptable packets. +// If true, QUIC will free writer-allocated packet buffer if writer->WritePacket +// is not called. +QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_avoid_leak_writer_buffer, false) + +// If true, QuicConnection::SendAllPendingAcks will Update instead of Set the +// ack alarm. QUIC_FLAG( bool, - FLAGS_quic_reloadable_flag_quic_extend_idle_time_on_decryptable_packets, - false) + FLAGS_quic_reloadable_flag_quic_update_ack_alarm_in_send_all_pending_acks, + true) -// If true, support for IETF QUIC 0-rtt is enabled. -QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_enable_zero_rtt_for_tls, false) +// If true, the B2HI connection option limits reduction of inflight_hi to +// (1-Beta)*CWND. +QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_bbr2_limit_inflight_hi, false) -// If true, default on PTO which unifies TLP + RTO loss recovery. -QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_default_on_pto, false) +// When true, always check the amplification limit before writing, not just for +// handshake packets. +QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_move_amplification_limit, true) -// When true, QUIC+TLS will not send nor parse the old-format Google-specific -// transport parameters. +// If true, SendAllPendingAcks always send the earliest ACK. +QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_always_send_earliest_ack, true) + +// If true, check connection level flow control for send control stream and +// qpack streams in QuicSession::WillingAndAbleToWrite. QUIC_FLAG(bool, - FLAGS_quic_restart_flag_quic_google_transport_param_omit_old, + FLAGS_quic_reloadable_flag_quic_fix_willing_and_able_to_write, + true) + +// If true, disable QUIC version h3-T050. +QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_disable_version_t050, false) + +// If true, do not arm PTO on half RTT packets if they are the only ones in +// flight. +QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_fix_server_pto_timeout, true) + +// If true, default-enable 5RTO blachole detection. +QUIC_FLAG( + bool, + FLAGS_quic_reloadable_flag_quic_default_enable_5rto_blackhole_detection2, + true) + +// If true, session does not send duplicate MAX_STREAMS. +QUIC_FLAG(bool, + FLAGS_quic_reloadable_flag_quic_stop_sending_duplicate_max_streams, + true) + +// If true, enable QUIC version h3-29. +QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_enable_version_draft_29, true) + +// If true, support HANDSHAKE_DONE frame in T050 +QUIC_FLAG(bool, + FLAGS_quic_reloadable_flag_quic_support_handshake_done_in_t050, + true) + +// If true, save user agent into in QuicSession. +QUIC_FLAG(bool, + FLAGS_quic_reloadable_flag_quic_save_user_agent_in_quic_session, false) -// When true, QUIC+TLS will send and parse the new-format Google-specific -// transport parameters. +// When true, QUIC_CRYPTO versions of QUIC will not send the max ACK delay +// unless it is configured to a non-default value. QUIC_FLAG(bool, - FLAGS_quic_restart_flag_quic_google_transport_param_send_new, + FLAGS_quic_reloadable_flag_quic_dont_send_max_ack_delay_if_default, true) -// If true, if a buffered MTU packet causes a write to return MSG_TOO_BIG, this -// error will be ignored. +// If true, remove the head of line blocking caused by an unprocessable packet +// in the undecryptable packets list. +QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_fix_undecryptable_packets, true) + +// If true, QUIC client only tries to retransmit data when 1-RTT key is +// available. QUIC_FLAG( bool, - FLAGS_quic_reloadable_flag_quic_ignore_msg_too_big_from_buffered_packets, + FLAGS_quic_reloadable_flag_quic_do_not_retransmit_immediately_on_zero_rtt_reject, true) + +// If true, try to bundle INITIAL data when trying to send INITIAL ACK. +QUIC_FLAG(bool, + FLAGS_quic_reloadable_flag_quic_bundle_crypto_data_with_initial_ack, + true) + +// If true, do not use QuicUtil::IsBidirectionalStreamId() to determine gQUIC +// stream type. +QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_fix_gquic_stream_type, true) + +// When true, do not pad the QUIC_CRYPTO CHLO message itself. Note that the +// packet containing the CHLO will still be padded. +QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_dont_pad_chlo, false) + +// If true, include MinPlaintextPacketSize when determine whether removing soft +// limit for crypto frames. +QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_fix_min_crypto_frame_size, true) + +// When true, QuicDispatcher supports decapsulation of Legacy Version +// Encapsulation packets. +QUIC_FLAG( + bool, + FLAGS_quic_reloadable_flag_quic_dispatcher_legacy_version_encapsulation, + false) + +// If true, update packet size when the first frame gets queued. +QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_update_packet_size, false) diff --git a/chromium/net/quic/quic_http3_logger.cc b/chromium/net/quic/quic_http3_logger.cc index c190156ff45..e93ff2987ea 100644 --- a/chromium/net/quic/quic_http3_logger.cc +++ b/chromium/net/quic/quic_http3_logger.cc @@ -9,10 +9,13 @@ #include <vector> #include "base/metrics/histogram_macros.h" +#include "base/strings/strcat.h" #include "base/strings/string_number_conversions.h" +#include "net/http/http_log_util.h" #include "net/log/net_log_capture_mode.h" #include "net/log/net_log_event_type.h" #include "net/log/net_log_values.h" +#include "net/spdy/spdy_log_util.h" namespace net { @@ -64,20 +67,19 @@ base::Value NetLogThreeIntParams(base::StringPiece name1, return dict; } -base::Value NetLogHeadersToDict(const quic::QuicHeaderList& headers) { - base::Value dict(base::Value::Type::DICTIONARY); - for (auto header : headers) { - dict.SetStringKey(header.first, header.second); - } - return dict; -} - -base::Value NetLogHeadersToDict(const spdy::SpdyHeaderBlock& headers) { - base::Value dict(base::Value::Type::DICTIONARY); - for (auto header : headers) { - dict.SetStringKey(header.first, header.second); +base::ListValue ElideQuicHeaderListForNetLog( + const quic::QuicHeaderList& headers, + NetLogCaptureMode capture_mode) { + base::ListValue headers_list; + for (const auto& header : headers) { + base::StringPiece key = header.first; + base::StringPiece value = header.second; + headers_list.Append(NetLogStringValue( + base::StrCat({key, ": ", + ElideHeaderValueForNetLog(capture_mode, key.as_string(), + value.as_string())}))); } - return dict; + return headers_list; } } // namespace @@ -248,11 +250,13 @@ void QuicHttp3Logger::OnHeadersDecoded(quic::QuicStreamId stream_id, return; } net_log_.AddEvent( - NetLogEventType::HTTP3_HEADERS_DECODED, [stream_id, &headers] { + NetLogEventType::HTTP3_HEADERS_DECODED, + [stream_id, &headers](NetLogCaptureMode capture_mode) { base::Value dict(base::Value::Type::DICTIONARY); dict.SetKey("stream_id", NetLogNumberValue(static_cast<uint64_t>(stream_id))); - dict.SetKey("headers", NetLogHeadersToDict(headers)); + dict.SetKey("headers", + ElideQuicHeaderListForNetLog(headers, capture_mode)); return dict; }); } @@ -279,16 +283,18 @@ void QuicHttp3Logger::OnPushPromiseDecoded(quic::QuicStreamId stream_id, if (!net_log_.IsCapturing()) { return; } - net_log_.AddEvent(NetLogEventType::HTTP3_PUSH_PROMISE_DECODED, [stream_id, - push_id, - &headers] { - base::Value dict(base::Value::Type::DICTIONARY); - dict.SetKey("stream_id", - NetLogNumberValue(static_cast<uint64_t>(stream_id))); - dict.SetKey("push_id", NetLogNumberValue(static_cast<uint64_t>(push_id))); - dict.SetKey("headers", NetLogHeadersToDict(headers)); - return dict; - }); + net_log_.AddEvent( + NetLogEventType::HTTP3_PUSH_PROMISE_DECODED, + [stream_id, push_id, &headers](NetLogCaptureMode capture_mode) { + base::Value dict(base::Value::Type::DICTIONARY); + dict.SetKey("stream_id", + NetLogNumberValue(static_cast<uint64_t>(stream_id))); + dict.SetKey("push_id", + NetLogNumberValue(static_cast<uint64_t>(push_id))); + dict.SetKey("headers", + ElideQuicHeaderListForNetLog(headers, capture_mode)); + return dict; + }); } void QuicHttp3Logger::OnUnknownFrameReceived( @@ -357,11 +363,13 @@ void QuicHttp3Logger::OnHeadersFrameSent( return; } net_log_.AddEvent( - NetLogEventType::HTTP3_HEADERS_SENT, [stream_id, &header_block] { + NetLogEventType::HTTP3_HEADERS_SENT, + [stream_id, &header_block](NetLogCaptureMode capture_mode) { base::Value dict(base::Value::Type::DICTIONARY); dict.SetKey("stream_id", NetLogNumberValue(static_cast<uint64_t>(stream_id))); - dict.SetKey("headers", NetLogHeadersToDict(header_block)); + dict.SetKey("headers", + ElideSpdyHeaderBlockForNetLog(header_block, capture_mode)); return dict; }); } @@ -373,16 +381,18 @@ void QuicHttp3Logger::OnPushPromiseFrameSent( if (!net_log_.IsCapturing()) { return; } - net_log_.AddEvent(NetLogEventType::HTTP3_PUSH_PROMISE_SENT, [stream_id, - push_id, - &header_block] { - base::Value dict(base::Value::Type::DICTIONARY); - dict.SetKey("stream_id", - NetLogNumberValue(static_cast<uint64_t>(stream_id))); - dict.SetKey("push_id", NetLogNumberValue(static_cast<uint64_t>(push_id))); - dict.SetKey("headers", NetLogHeadersToDict(header_block)); - return dict; - }); + net_log_.AddEvent( + NetLogEventType::HTTP3_PUSH_PROMISE_SENT, + [stream_id, push_id, &header_block](NetLogCaptureMode capture_mode) { + base::Value dict(base::Value::Type::DICTIONARY); + dict.SetKey("stream_id", + NetLogNumberValue(static_cast<uint64_t>(stream_id))); + dict.SetKey("push_id", + NetLogNumberValue(static_cast<uint64_t>(push_id))); + dict.SetKey("headers", + ElideSpdyHeaderBlockForNetLog(header_block, capture_mode)); + return dict; + }); } } // namespace net diff --git a/chromium/net/quic/quic_http_stream.cc b/chromium/net/quic/quic_http_stream.cc index 2107b89a840..5b21bb9e067 100644 --- a/chromium/net/quic/quic_http_stream.cc +++ b/chromium/net/quic/quic_http_stream.cc @@ -94,23 +94,26 @@ HttpResponseInfo::ConnectionInfo QuicHttpStream::ConnectionInfoFromQuicVersion( case quic::QUIC_VERSION_46: return HttpResponseInfo::CONNECTION_INFO_QUIC_46; case quic::QUIC_VERSION_48: - return quic_version.handshake_protocol == quic::PROTOCOL_TLS1_3 + return quic_version.UsesTls() ? HttpResponseInfo::CONNECTION_INFO_QUIC_T048 : HttpResponseInfo::CONNECTION_INFO_QUIC_Q048; case quic::QUIC_VERSION_49: - return quic_version.handshake_protocol == quic::PROTOCOL_TLS1_3 + return quic_version.UsesTls() ? HttpResponseInfo::CONNECTION_INFO_QUIC_T049 : HttpResponseInfo::CONNECTION_INFO_QUIC_Q049; case quic::QUIC_VERSION_50: - return quic_version.handshake_protocol == quic::PROTOCOL_TLS1_3 + return quic_version.UsesTls() ? HttpResponseInfo::CONNECTION_INFO_QUIC_T050 : HttpResponseInfo::CONNECTION_INFO_QUIC_Q050; case quic::QUIC_VERSION_IETF_DRAFT_25: - DCHECK(quic_version.handshake_protocol == quic::PROTOCOL_TLS1_3); + DCHECK(quic_version.UsesTls()); return HttpResponseInfo::CONNECTION_INFO_QUIC_DRAFT_25; case quic::QUIC_VERSION_IETF_DRAFT_27: - DCHECK(quic_version.handshake_protocol == quic::PROTOCOL_TLS1_3); + DCHECK(quic_version.UsesTls()); return HttpResponseInfo::CONNECTION_INFO_QUIC_DRAFT_27; + case quic::QUIC_VERSION_IETF_DRAFT_29: + DCHECK(quic_version.UsesTls()); + return HttpResponseInfo::CONNECTION_INFO_QUIC_DRAFT_29; case quic::QUIC_VERSION_RESERVED_FOR_NEGOTIATION: return HttpResponseInfo::CONNECTION_INFO_QUIC_999; } diff --git a/chromium/net/quic/quic_http_stream_test.cc b/chromium/net/quic/quic_http_stream_test.cc index c5638861d8c..7432512b4d8 100644 --- a/chromium/net/quic/quic_http_stream_test.cc +++ b/chromium/net/quic/quic_http_stream_test.cc @@ -1111,7 +1111,7 @@ TEST_P(QuicHttpStreamTest, LogGranularQuicConnectionError) { TEST_P(QuicHttpStreamTest, LogGranularQuicErrorIfHandshakeNotConfirmed) { // TODO(nharper): Figure out why this test does not send packets // when TLS is used. - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3) { + if (version_.UsesTls()) { Initialize(); return; @@ -1615,10 +1615,11 @@ TEST_P(QuicHttpStreamTest, SendChunkedPostRequestAbortedByResetStream) { kIncludeVersion, !kFin, DEFAULT_PRIORITY, 0, &spdy_request_headers_frame_length, {header, kUploadData})); AddWrite(ConstructClientAckPacket(packet_number++, 3, 1, 2)); - AddWrite(client_maker_.MakeRstPacket( - packet_number++, - /* include_version = */ true, stream_id_, quic::QUIC_STREAM_NO_ERROR, - /* include_stop_sending_if_v99 = */ false)); + AddWrite(client_maker_.MakeAckAndRstPacket( + packet_number++, + /* include_version = */ true, stream_id_, quic::QUIC_STREAM_NO_ERROR, + 4, 1, 1, + /* include_stop_sending_if_v99 = */ false)); } else { AddWrite(ConstructRequestHeadersAndDataFramesPacket( packet_number++, GetNthClientInitiatedBidirectionalStreamId(0), diff --git a/chromium/net/quic/quic_http_utils.cc b/chromium/net/quic/quic_http_utils.cc index 077bd50335e..1faf58cce2f 100644 --- a/chromium/net/quic/quic_http_utils.cc +++ b/chromium/net/quic/quic_http_utils.cc @@ -64,8 +64,9 @@ quic::ParsedQuicVersionVector FilterSupportedAltSvcVersions( << quic_alt_svc.protocol_id; for (uint32_t quic_version : quic_alt_svc.version) { - for (quic::ParsedQuicVersion supported : supported_versions) { - if (supported.handshake_protocol == quic::PROTOCOL_QUIC_CRYPTO && + for (const quic::ParsedQuicVersion& supported : supported_versions) { + if (supported.UsesQuicCrypto() && + supported.SupportsGoogleAltSvcFormat() && static_cast<uint32_t>(supported.transport_version) == quic_version) { supported_alt_svc_versions.push_back(supported); RecordAltSvcFormat(GOOGLE_FORMAT); diff --git a/chromium/net/quic/quic_http_utils_test.cc b/chromium/net/quic/quic_http_utils_test.cc index d1609675277..34356cf2db1 100644 --- a/chromium/net/quic/quic_http_utils_test.cc +++ b/chromium/net/quic/quic_http_utils_test.cc @@ -11,9 +11,6 @@ #include "net/third_party/quiche/src/spdy/core/spdy_alt_svc_wire_format.h" #include "testing/gtest/include/gtest/gtest.h" -using quic::ParsedQuicVersion; -using quic::PROTOCOL_QUIC_CRYPTO; - namespace net { namespace test { @@ -45,20 +42,18 @@ TEST(QuicHttpUtilsTest, FilterSupportedAltSvcVersions) { // finds the intersection of the two sets ... version C. Note that // as QUIC versions are defined/undefined, the exact version numbers // used may need to change. The actual version numbers are not - // important. + // important. Note that FilterSupportedAltSvcVersions is only used + // for the old Google-specific Alt-Svc format which is now deprecated. quic::ParsedQuicVersionVector supported_versions = { - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, quic::QUIC_VERSION_48), - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, quic::QUIC_VERSION_43), + quic::ParsedQuicVersion::Q050(), + quic::ParsedQuicVersion::Q043(), }; - std::vector<uint32_t> alt_svc_versions_google = {quic::QUIC_VERSION_48, - quic::QUIC_VERSION_46}; - std::vector<uint32_t> alt_svc_versions_ietf = { - QuicVersionToQuicVersionLabel(quic::QUIC_VERSION_48), - QuicVersionToQuicVersionLabel(quic::QUIC_VERSION_46)}; + std::vector<uint32_t> alt_svc_versions_google = { + 33, quic::ParsedQuicVersion::Q043().transport_version}; quic::ParsedQuicVersionVector supported_alt_svc_versions = { - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, quic::QUIC_VERSION_48)}; + quic::ParsedQuicVersion::Q043()}; spdy::SpdyAltSvcWireFormat::AlternativeService altsvc; altsvc.protocol_id = "quic"; diff --git a/chromium/net/quic/quic_network_transaction_unittest.cc b/chromium/net/quic/quic_network_transaction_unittest.cc index 5dc3abdbe8c..e1068b88a76 100644 --- a/chromium/net/quic/quic_network_transaction_unittest.cc +++ b/chromium/net/quic/quic_network_transaction_unittest.cc @@ -38,6 +38,7 @@ #include "net/http/http_stream.h" #include "net/http/http_stream_factory.h" #include "net/http/http_transaction_test_util.h" +#include "net/http/test_upload_data_stream_not_allow_http1.h" #include "net/http/transport_security_state.h" #include "net/log/net_log_event_type.h" #include "net/log/test_net_log.h" @@ -449,6 +450,16 @@ class QuicNetworkTransactionTest } std::unique_ptr<quic::QuicEncryptedPacket> + ConstructClientPriorityFramesPacket( + uint64_t packet_number, + bool should_include_version, + const std::vector<QuicTestPacketMaker::Http2StreamDependency>& + priority_frames) { + return client_maker_->MakeMultiplePriorityFramesPacket( + packet_number, should_include_version, priority_frames); + } + + std::unique_ptr<quic::QuicEncryptedPacket> ConstructClientAckAndPriorityFramesPacket( uint64_t packet_number, bool should_include_version, @@ -462,6 +473,20 @@ class QuicNetworkTransactionTest smallest_received, least_unacked, priority_frames); } + std::unique_ptr<quic::QuicReceivedPacket> ConstructClientAckAndPriorityPacket( + uint64_t packet_number, + bool should_include_version, + uint64_t largest_received, + uint64_t smallest_received, + quic::QuicStreamId id, + quic::QuicStreamId parent_stream_id, + RequestPriority request_priority) { + return client_maker_->MakeAckAndPriorityPacket( + packet_number, should_include_version, largest_received, + smallest_received, id, parent_stream_id, + ConvertRequestPriorityToQuicPriority(request_priority)); + } + // Uses default QuicTestPacketMaker. spdy::SpdyHeaderBlock GetRequestHeaders(const std::string& method, const std::string& scheme, @@ -1723,7 +1748,8 @@ TEST_P(QuicNetworkTransactionTest, AlternativeServicesDifferentHost) { } TEST_P(QuicNetworkTransactionTest, DoNotUseQuicForUnsupportedVersion) { - quic::ParsedQuicVersion unsupported_version = quic::UnsupportedQuicVersion(); + quic::ParsedQuicVersion unsupported_version = + quic::ParsedQuicVersion::Unsupported(); // Add support for another QUIC version besides |version_|. Also find an // unsupported version. for (const quic::ParsedQuicVersion& version : quic::AllSupportedVersions()) { @@ -1737,7 +1763,7 @@ TEST_P(QuicNetworkTransactionTest, DoNotUseQuicForUnsupportedVersion) { break; } ASSERT_EQ(2u, supported_versions_.size()); - ASSERT_NE(quic::UnsupportedQuicVersion(), unsupported_version); + ASSERT_NE(quic::ParsedQuicVersion::Unsupported(), unsupported_version); // Set up alternative service to use QUIC with a version that is not // supported. @@ -1816,10 +1842,10 @@ TEST_P(QuicNetworkTransactionTest, DoNotUseQuicForUnsupportedVersion) { alt_svc_info_vector = session_->http_server_properties()->GetAlternativeServiceInfos( server, NetworkIsolationKey()); - // All PROTOCOL_QUIC_CRYPTO versions are sent in a single Alt-Svc entry, - // therefore they aer accumulated in a single AlternativeServiceInfo, whereas - // each PROTOCOL_TLS1_3 version has its own Alt-Svc entry and - // AlternativeServiceInfo entry. Flatten to compare. + // Versions that support the legacy Google-specific Alt-Svc format are sent in + // a single Alt-Svc entry, therefore they are accumulated in a single + // AlternativeServiceInfo, whereas more recent versions all have their own + // Alt-Svc entry and AlternativeServiceInfo entry. Flatten to compare. quic::ParsedQuicVersionVector alt_svc_negotiated_versions; for (const auto& alt_svc_info : alt_svc_info_vector) { EXPECT_EQ(kProtoQUIC, alt_svc_info.alternative_service().protocol); @@ -2177,7 +2203,8 @@ TEST_P(QuicNetworkTransactionTest, UseAlternativeServiceWithVersionForQuic1) { // Add support for another QUIC version besides |version_| on the client side. // Also find a different version advertised by the server. - quic::ParsedQuicVersion advertised_version_2 = quic::UnsupportedQuicVersion(); + quic::ParsedQuicVersion advertised_version_2 = + quic::ParsedQuicVersion::Unsupported(); for (const quic::ParsedQuicVersion& version : quic::AllSupportedVersions()) { if (version == version_) continue; @@ -2189,7 +2216,7 @@ TEST_P(QuicNetworkTransactionTest, UseAlternativeServiceWithVersionForQuic1) { break; } ASSERT_EQ(2u, supported_versions_.size()); - ASSERT_NE(quic::UnsupportedQuicVersion(), advertised_version_2); + ASSERT_NE(quic::ParsedQuicVersion::Unsupported(), advertised_version_2); std::string QuicAltSvcWithVersionHeader = base::StringPrintf("Alt-Svc: %s=\":443\", %s=\":443\"\r\n\r\n", @@ -2251,23 +2278,15 @@ TEST_P(QuicNetworkTransactionTest, // TestPacketMakers and the response. // Find an alternative commonly supported version other than |version_|. - quic::ParsedQuicVersion common_version_2 = quic::UnsupportedQuicVersion(); - if (version_.handshake_protocol == quic::PROTOCOL_QUIC_CRYPTO) { - for (const quic::ParsedQuicVersion& version : - quic::AllSupportedVersions()) { - if (version == version_) - continue; + quic::ParsedQuicVersion common_version_2 = + quic::ParsedQuicVersion::Unsupported(); + for (const quic::ParsedQuicVersion& version : quic::AllSupportedVersions()) { + if (version != version_) { common_version_2 = version; break; } - } else if (version_.transport_version == quic::QUIC_VERSION_IETF_DRAFT_27) { - common_version_2 = quic::ParsedQuicVersion( - quic::PROTOCOL_TLS1_3, quic::QUIC_VERSION_IETF_DRAFT_25); - } else { - common_version_2 = quic::ParsedQuicVersion( - quic::PROTOCOL_TLS1_3, quic::QUIC_VERSION_IETF_DRAFT_27); } - ASSERT_NE(quic::UnsupportedQuicVersion(), common_version_2); + ASSERT_NE(common_version_2, quic::ParsedQuicVersion::Unsupported()); // Setting up client's preference list: {|version_|, |common_version_2|}. supported_versions_.clear(); @@ -2277,12 +2296,13 @@ TEST_P(QuicNetworkTransactionTest, // Setting up server's Alt-Svc header in the following preference order: // |common_version_2|, |version_|. std::string QuicAltSvcWithVersionHeader; - quic::ParsedQuicVersion picked_version = quic::UnsupportedQuicVersion(); - QuicAltSvcWithVersionHeader = - "Alt-Svc: " + quic::AlpnForVersion(common_version_2) + - "=\":443\"; ma=3600, " + quic::AlpnForVersion(version_) + - "=\":443\"; ma=3600\r\n\r\n"; - picked_version = common_version_2; // Use server's preference. + quic::ParsedQuicVersion picked_version = + quic::ParsedQuicVersion::Unsupported(); + QuicAltSvcWithVersionHeader = + "Alt-Svc: " + quic::AlpnForVersion(common_version_2) + + "=\":443\"; ma=3600, " + quic::AlpnForVersion(version_) + + "=\":443\"; ma=3600\r\n\r\n"; + picked_version = common_version_2; // Use server's preference. MockRead http_reads[] = { MockRead("HTTP/1.1 200 OK\r\n"), @@ -2534,10 +2554,10 @@ TEST_P(QuicNetworkTransactionTest, const AlternativeServiceInfoVector alt_svc_info_vector = session_->http_server_properties()->GetAlternativeServiceInfos( https_server, NetworkIsolationKey()); - // However, all PROTOCOL_QUIC_CRYPTO versions are sent in a single Alt-Svc - // entry, therefore they aer accumulated in a single AlternativeServiceInfo, - // whereas each PROTOCOL_TLS1_3 version has its own Alt-Svc entry and - // AlternativeServiceInfo entry. Flatten to compare. + // Versions that support the legacy Google-specific Alt-Svc format are sent in + // a single Alt-Svc entry, therefore they are accumulated in a single + // AlternativeServiceInfo, whereas more recent versions all have their own + // Alt-Svc entry and AlternativeServiceInfo entry. Flatten to compare. quic::ParsedQuicVersionVector alt_svc_negotiated_versions; for (const auto& alt_svc_info : alt_svc_info_vector) { EXPECT_EQ(kProtoQUIC, alt_svc_info.alternative_service().protocol); @@ -2696,7 +2716,7 @@ TEST_P(QuicNetworkTransactionTest, GoAwayWithConnectionMigrationOnPortsOnly) { // alternate network as well, QUIC is marked as broken and the brokenness will // not expire when default network changes. TEST_P(QuicNetworkTransactionTest, QuicFailsOnBothNetworksWhileTCPSucceeds) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3 || + if (version_.UsesTls() || GetQuicReloadableFlag(quic_use_idle_network_detector)) { // QUIC with TLS1.3 handshake doesn't support 0-rtt. // TODO(fayang): Add time driven idle network detection test. @@ -2806,7 +2826,7 @@ TEST_P(QuicNetworkTransactionTest, QuicFailsOnBothNetworksWhileTCPSucceeds) { // alternate network, QUIC is marked as broken. The brokenness will expire when // the default network changes. TEST_P(QuicNetworkTransactionTest, RetryOnAlternateNetworkWhileTCPSucceeds) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3 || + if (version_.UsesTls() || GetQuicReloadableFlag(quic_use_idle_network_detector)) { // QUIC with TLS1.3 handshake doesn't support 0-rtt. // TODO(fayang): Add time driven idle network detection test. @@ -2928,7 +2948,7 @@ TEST_P(QuicNetworkTransactionTest, RetryOnAlternateNetworkWhileTCPSucceeds) { // Much like above test, but verifies NetworkIsolationKeys are respected. TEST_P(QuicNetworkTransactionTest, RetryOnAlternateNetworkWhileTCPSucceedsWithNetworkIsolationKey) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3 || + if (version_.UsesTls() || GetQuicReloadableFlag(quic_use_idle_network_detector)) { // QUIC with TLS1.3 handshake doesn't support 0-rtt. // TODO(fayang): Add time driven idle network detection test. @@ -3076,7 +3096,7 @@ TEST_P(QuicNetworkTransactionTest, // before handshake is confirmed. If TCP doesn't succeed but QUIC on the // alternative network succeeds, QUIC is not marked as broken. TEST_P(QuicNetworkTransactionTest, RetryOnAlternateNetworkWhileTCPHanging) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3 || + if (version_.UsesTls() || GetQuicReloadableFlag(quic_use_idle_network_detector)) { // QUIC with TLS1.3 handshake doesn't support 0-rtt. // TODO(fayang): Add time driven idle network detection test. @@ -3201,7 +3221,7 @@ TEST_P(QuicNetworkTransactionTest, RetryOnAlternateNetworkWhileTCPHanging) { // Verify that if a QUIC connection times out, the QuicHttpStream will // return QUIC_PROTOCOL_ERROR. TEST_P(QuicNetworkTransactionTest, TimeoutAfterHandshakeConfirmed) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3) { + if (version_.UsesTls()) { // QUIC with TLS1.3 handshake doesn't support 0-rtt. return; } @@ -3327,11 +3347,6 @@ TEST_P(QuicNetworkTransactionTest, TimeoutAfterHandshakeConfirmed) { // Verify that if a QUIC protocol error occurs after the handshake is confirmed // the request fails with QUIC_PROTOCOL_ERROR. TEST_P(QuicNetworkTransactionTest, ProtocolErrorAfterHandshakeConfirmed) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3) { - // QUIC with TLS1.3 handshake doesn't support 0-rtt. - return; - } - context_.params()->retry_without_alt_svc_on_quic_errors = false; // The request will initially go out over QUIC. MockQuicData quic_data(version_); @@ -3355,10 +3370,13 @@ TEST_P(QuicNetworkTransactionTest, ProtocolErrorAfterHandshakeConfirmed) { 1, false, GetNthClientInitiatedBidirectionalStreamId(47), quic::QUIC_STREAM_LAST_ERROR)); std::string quic_error_details = "Data for nonexistent stream"; - quic_data.AddWrite(SYNCHRONOUS, - ConstructClientAckAndConnectionClosePacket( - packet_num++, 1, 1, 1, quic::QUIC_INVALID_STREAM_ID, - quic_error_details, quic::IETF_RST_STREAM)); + quic_data.AddWrite( + SYNCHRONOUS, + ConstructClientAckAndConnectionClosePacket( + packet_num++, 1, 1, 1, + version_.HasIetfQuicFrames() ? quic::QUIC_HTTP_STREAM_WRONG_DIRECTION + : quic::QUIC_INVALID_STREAM_ID, + quic_error_details, quic::IETF_RST_STREAM)); quic_data.AddSocketDataToFactory(&socket_factory_); // In order for a new QUIC session to be established via alternate-protocol @@ -3402,7 +3420,7 @@ TEST_P(QuicNetworkTransactionTest, ProtocolErrorAfterHandshakeConfirmed) { // connection times out, then QUIC will be marked as broken and the request // retried over TCP. TEST_P(QuicNetworkTransactionTest, TimeoutAfterHandshakeConfirmedThenBroken2) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3) { + if (version_.UsesTls()) { // QUIC with TLS1.3 handshake doesn't support 0-rtt. return; } @@ -3550,11 +3568,6 @@ TEST_P(QuicNetworkTransactionTest, TimeoutAfterHandshakeConfirmedThenBroken2) { // retried over TCP and the QUIC will be marked as broken. TEST_P(QuicNetworkTransactionTest, ProtocolErrorAfterHandshakeConfirmedThenBroken) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3) { - // QUIC with TLS1.3 handshake doesn't support 0-rtt. - return; - } - context_.params()->idle_connection_timeout = base::TimeDelta::FromSeconds(5); // The request will initially go out over QUIC. @@ -3580,10 +3593,13 @@ TEST_P(QuicNetworkTransactionTest, 1, false, GetNthClientInitiatedBidirectionalStreamId(47), quic::QUIC_STREAM_LAST_ERROR)); std::string quic_error_details = "Data for nonexistent stream"; - quic_data.AddWrite(SYNCHRONOUS, - ConstructClientAckAndConnectionClosePacket( - packet_num++, 1, 1, 1, quic::QUIC_INVALID_STREAM_ID, - quic_error_details, quic::IETF_RST_STREAM)); + quic_data.AddWrite( + SYNCHRONOUS, + ConstructClientAckAndConnectionClosePacket( + packet_num++, 1, 1, 1, + version_.HasIetfQuicFrames() ? quic::QUIC_HTTP_STREAM_WRONG_DIRECTION + : quic::QUIC_INVALID_STREAM_ID, + quic_error_details, quic::IETF_RST_STREAM)); quic_data.AddSocketDataToFactory(&socket_factory_); // After that fails, it will be resent via TCP. @@ -3648,7 +3664,7 @@ TEST_P(QuicNetworkTransactionTest, // Much like above test, but verifies that NetworkIsolationKey is respected. TEST_P(QuicNetworkTransactionTest, ProtocolErrorAfterHandshakeConfirmedThenBrokenWithNetworkIsolationKey) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3) { + if (version_.UsesTls()) { // QUIC with TLS1.3 handshake doesn't support 0-rtt. return; } @@ -3779,11 +3795,6 @@ TEST_P(QuicNetworkTransactionTest, // request is reset from, then QUIC will be marked as broken and the request // retried over TCP. TEST_P(QuicNetworkTransactionTest, ResetAfterHandshakeConfirmedThenBroken) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3) { - // QUIC with TLS1.3 handshake doesn't support 0-rtt. - return; - } - // The request will initially go out over QUIC. MockQuicData quic_data(version_); spdy::SpdyPriority priority = @@ -3810,10 +3821,10 @@ TEST_P(QuicNetworkTransactionTest, ResetAfterHandshakeConfirmedThenBroken) { quic::QUIC_HEADERS_TOO_LARGE)); if (VersionUsesHttp3(version_.transport_version)) { - quic_data.AddWrite(SYNCHRONOUS, - ConstructClientDataPacket( - packet_num++, GetQpackDecoderStreamId(), true, false, - StreamCancellationQpackDecoderInstruction(0))); + quic_data.AddWrite( + SYNCHRONOUS, ConstructClientAckAndDataPacket( + packet_num++, true, GetQpackDecoderStreamId(), 1, 1, 1, + false, StreamCancellationQpackDecoderInstruction(0))); } quic_data.AddRead(ASYNC, OK); @@ -4079,10 +4090,12 @@ TEST_P(QuicNetworkTransactionTest, quic::QUIC_HEADERS_TOO_LARGE)); if (VersionUsesHttp3(version_.transport_version)) { - mock_quic_data.AddWrite( - SYNCHRONOUS, ConstructClientDataPacket( - packet_num++, GetQpackDecoderStreamId(), true, false, - StreamCancellationQpackDecoderInstruction(1))); + mock_quic_data.AddWrite( + SYNCHRONOUS, + ConstructClientAckAndDataPacket( + packet_num++, /*include_version=*/true, GetQpackDecoderStreamId(), + 3, 2, 1, + /*fin=*/false, StreamCancellationQpackDecoderInstruction(1))); } mock_quic_data.AddRead(ASYNC, ERR_IO_PENDING); // No more data to read @@ -4992,7 +5005,7 @@ TEST_P(QuicNetworkTransactionTest, HungAlternativeService) { } TEST_P(QuicNetworkTransactionTest, ZeroRTTWithHttpRace) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3) { + if (version_.UsesTls()) { // QUIC with TLS1.3 handshake doesn't support 0-rtt. return; } @@ -5039,7 +5052,7 @@ TEST_P(QuicNetworkTransactionTest, ZeroRTTWithHttpRace) { } TEST_P(QuicNetworkTransactionTest, ZeroRTTWithNoHttpRace) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3) { + if (version_.UsesTls()) { // QUIC with TLS1.3 handshake doesn't support 0-rtt. return; } @@ -5117,11 +5130,6 @@ TEST_P(QuicNetworkTransactionTest, ZeroRTTWithProxy) { } TEST_P(QuicNetworkTransactionTest, ZeroRTTWithConfirmationRequired) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3) { - // QUIC with TLS1.3 handshake doesn't support 0-rtt. - return; - } - MockQuicData mock_quic_data(version_); int packet_num = 1; client_maker_->SetEncryptionLevel(quic::ENCRYPTION_ZERO_RTT); @@ -5181,11 +5189,6 @@ TEST_P(QuicNetworkTransactionTest, ZeroRTTWithConfirmationRequired) { } TEST_P(QuicNetworkTransactionTest, ZeroRTTWithTooEarlyResponse) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3) { - // QUIC with TLS1.3 handshake doesn't support 0-rtt. - return; - } - uint64_t packet_number = 1; MockQuicData mock_quic_data(version_); client_maker_->SetEncryptionLevel(quic::ENCRYPTION_ZERO_RTT); @@ -5282,11 +5285,6 @@ TEST_P(QuicNetworkTransactionTest, ZeroRTTWithTooEarlyResponse) { } TEST_P(QuicNetworkTransactionTest, ZeroRTTWithMultipleTooEarlyResponse) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3) { - // QUIC with TLS1.3 handshake doesn't support 0-rtt. - return; - } - uint64_t packet_number = 1; MockQuicData mock_quic_data(version_); client_maker_->SetEncryptionLevel(quic::ENCRYPTION_ZERO_RTT); @@ -5339,7 +5337,7 @@ TEST_P(QuicNetworkTransactionTest, ZeroRTTWithMultipleTooEarlyResponse) { SYNCHRONOUS, ConstructClientAckAndDataPacket( packet_number++, false, GetQpackDecoderStreamId(), 2, 1, 1, false, - StreamCancellationQpackDecoderInstruction(1))); + StreamCancellationQpackDecoderInstruction(1, false))); mock_quic_data.AddWrite(SYNCHRONOUS, client_maker_->MakeRstPacket( packet_number++, false, @@ -5400,11 +5398,6 @@ TEST_P(QuicNetworkTransactionTest, ZeroRTTWithMultipleTooEarlyResponse) { TEST_P(QuicNetworkTransactionTest, LogGranularQuicErrorCodeOnQuicProtocolErrorLocal) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3) { - // QUIC with TLS1.3 handshake doesn't support 0-rtt. - return; - } - context_.params()->retry_without_alt_svc_on_quic_errors = false; MockQuicData mock_quic_data(version_); int packet_num = 1; @@ -5462,11 +5455,6 @@ TEST_P(QuicNetworkTransactionTest, TEST_P(QuicNetworkTransactionTest, LogGranularQuicErrorCodeOnQuicProtocolErrorRemote) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3) { - // QUIC with TLS1.3 handshake doesn't support 0-rtt. - return; - } - context_.params()->retry_without_alt_svc_on_quic_errors = false; MockQuicData mock_quic_data(version_); int packet_num = 1; @@ -5489,9 +5477,12 @@ TEST_P(QuicNetworkTransactionTest, quic::QUIC_STREAM_LAST_ERROR)); std::string quic_error_details = "Data for nonexistent stream"; mock_quic_data.AddWrite( - SYNCHRONOUS, ConstructClientAckAndConnectionClosePacket( - packet_num++, 1, 1, 1, quic::QUIC_INVALID_STREAM_ID, - quic_error_details, quic::IETF_RST_STREAM)); + SYNCHRONOUS, + ConstructClientAckAndConnectionClosePacket( + packet_num++, 1, 1, 1, + version_.HasIetfQuicFrames() ? quic::QUIC_HTTP_STREAM_WRONG_DIRECTION + : quic::QUIC_INVALID_STREAM_ID, + quic_error_details, quic::IETF_RST_STREAM)); mock_quic_data.AddSocketDataToFactory(&socket_factory_); // The non-alternate protocol job needs to hang in order to guarantee that @@ -5524,15 +5515,13 @@ TEST_P(QuicNetworkTransactionTest, EXPECT_EQ(quic::QUIC_NO_ERROR, details.quic_connection_error); trans.PopulateNetErrorDetails(&details); - EXPECT_EQ(quic::QUIC_INVALID_STREAM_ID, details.quic_connection_error); + EXPECT_EQ(version_.HasIetfQuicFrames() + ? quic::QUIC_HTTP_STREAM_WRONG_DIRECTION + : quic::QUIC_INVALID_STREAM_ID, + details.quic_connection_error); } TEST_P(QuicNetworkTransactionTest, RstStreamErrorHandling) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3) { - // QUIC with TLS1.3 handshake doesn't support 0-rtt. - return; - } - MockQuicData mock_quic_data(version_); int packet_num = 1; client_maker_->SetEncryptionLevel(quic::ENCRYPTION_ZERO_RTT); @@ -5611,11 +5600,6 @@ TEST_P(QuicNetworkTransactionTest, RstStreamErrorHandling) { } TEST_P(QuicNetworkTransactionTest, RstStreamBeforeHeaders) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3) { - // QUIC with TLS1.3 handshake doesn't support 0-rtt. - return; - } - context_.params()->retry_without_alt_svc_on_quic_errors = false; MockQuicData mock_quic_data(version_); int packet_num = 1; @@ -5637,9 +5621,10 @@ TEST_P(QuicNetworkTransactionTest, RstStreamBeforeHeaders) { if (VersionUsesHttp3(version_.transport_version)) { mock_quic_data.AddWrite( - SYNCHRONOUS, ConstructClientDataPacket( - packet_num++, GetQpackDecoderStreamId(), true, false, - StreamCancellationQpackDecoderInstruction(0))); + SYNCHRONOUS, + ConstructClientAckAndDataPacket( + packet_num++, false, GetQpackDecoderStreamId(), 1, 1, 1, false, + StreamCancellationQpackDecoderInstruction(0))); } mock_quic_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); // No more read data. @@ -5810,7 +5795,7 @@ TEST_P(QuicNetworkTransactionTest, NoBrokenAlternateProtocolIfTcpFails) { } TEST_P(QuicNetworkTransactionTest, DelayTCPOnStartWithQuicSupportOnSameIP) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3) { + if (version_.UsesTls()) { // QUIC with TLS1.3 handshake doesn't support 0-rtt. return; } @@ -5881,11 +5866,6 @@ TEST_P(QuicNetworkTransactionTest, DelayTCPOnStartWithQuicSupportOnSameIP) { TEST_P(QuicNetworkTransactionTest, DelayTCPOnStartWithQuicSupportOnDifferentIP) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3) { - // QUIC with TLS1.3 handshake doesn't support 0-rtt. - return; - } - // Tests that TCP job is delayed and QUIC job requires confirmation if QUIC // was recently supported on a different IP address on start. @@ -6031,7 +6011,7 @@ TEST_P(QuicNetworkTransactionTest, FailedZeroRttBrokenAlternateProtocol) { TEST_P(QuicNetworkTransactionTest, FailedZeroRttBrokenAlternateProtocolWithNetworkIsolationKey) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3) { + if (version_.UsesTls()) { // QUIC with TLS1.3 handshake doesn't support 0-rtt. return; } @@ -6656,38 +6636,52 @@ TEST_P(QuicNetworkTransactionTest, QuicServerPush) { 1, GetNthClientInitiatedBidirectionalStreamId(0), GetNthServerInitiatedUnidirectionalStreamId(0), false, GetRequestHeaders("GET", "https", "/pushed.jpg"), &server_maker_)); - if ((client_headers_include_h2_stream_dependency_ && - version_.transport_version >= quic::QUIC_VERSION_43 && - !VersionUsesHttp3(version_.transport_version))) { - mock_quic_data.AddWrite( - SYNCHRONOUS, - ConstructClientPriorityPacket( - client_packet_number++, false, - GetNthServerInitiatedUnidirectionalStreamId(0), - GetNthClientInitiatedBidirectionalStreamId(0), DEFAULT_PRIORITY)); + const bool should_send_priority_packet = + client_headers_include_h2_stream_dependency_ && + !VersionUsesHttp3(version_.transport_version); + if (should_send_priority_packet) { + mock_quic_data.AddWrite( + SYNCHRONOUS, + ConstructClientAckAndPriorityPacket( + client_packet_number++, false, + /*largest_received=*/1, /*smallest_received=*/1, + GetNthServerInitiatedUnidirectionalStreamId(0), + GetNthClientInitiatedBidirectionalStreamId(0), DEFAULT_PRIORITY)); } mock_quic_data.AddRead( ASYNC, ConstructServerResponseHeadersPacket( 2, GetNthClientInitiatedBidirectionalStreamId(0), false, false, GetResponseHeaders("200 OK"))); - mock_quic_data.AddWrite( - SYNCHRONOUS, ConstructClientAckPacket(client_packet_number++, 2, 1, 1)); + if (!should_send_priority_packet) { + mock_quic_data.AddWrite( + SYNCHRONOUS, ConstructClientAckPacket(client_packet_number++, 2, 1, 1)); + } mock_quic_data.AddRead( ASYNC, ConstructServerResponseHeadersPacket( 3, GetNthServerInitiatedUnidirectionalStreamId(0), false, false, GetResponseHeaders("200 OK"))); + if (should_send_priority_packet) { + mock_quic_data.AddWrite( + SYNCHRONOUS, ConstructClientAckPacket(client_packet_number++, 3, 1, 1)); + } std::string header = ConstructDataHeader(6); mock_quic_data.AddRead( ASYNC, ConstructServerDataPacket( 4, GetNthClientInitiatedBidirectionalStreamId(0), false, true, header + "hello!")); - mock_quic_data.AddWrite( - SYNCHRONOUS, ConstructClientAckPacket(client_packet_number++, 4, 3, 1)); + if (!should_send_priority_packet) { + mock_quic_data.AddWrite( + SYNCHRONOUS, ConstructClientAckPacket(client_packet_number++, 4, 3, 1)); + } std::string header2 = ConstructDataHeader(10); mock_quic_data.AddRead( ASYNC, ConstructServerDataPacket( 5, GetNthServerInitiatedUnidirectionalStreamId(0), false, true, header2 + "and hello!")); + if (should_send_priority_packet) { + mock_quic_data.AddWrite( + SYNCHRONOUS, ConstructClientAckPacket(client_packet_number++, 5, 3, 1)); + } if (!VersionUsesHttp3(version_.transport_version)) { mock_quic_data.AddWrite(SYNCHRONOUS, ConstructClientAckAndRstPacket( @@ -6757,30 +6751,39 @@ TEST_P(QuicNetworkTransactionTest, CancelServerPushAfterConnectionClose) { 1, GetNthClientInitiatedBidirectionalStreamId(0), GetNthServerInitiatedUnidirectionalStreamId(0), false, GetRequestHeaders("GET", "https", "/pushed.jpg"), &server_maker_)); - if ((client_headers_include_h2_stream_dependency_ && - version_.transport_version >= quic::QUIC_VERSION_43 && - !VersionUsesHttp3(version_.transport_version))) { - mock_quic_data.AddWrite( - SYNCHRONOUS, - ConstructClientPriorityPacket( - client_packet_number++, false, - GetNthServerInitiatedUnidirectionalStreamId(0), - GetNthClientInitiatedBidirectionalStreamId(0), DEFAULT_PRIORITY)); + const bool should_send_priority_packet = + client_headers_include_h2_stream_dependency_ && + !VersionUsesHttp3(version_.transport_version); + if (should_send_priority_packet) { + mock_quic_data.AddWrite( + SYNCHRONOUS, + ConstructClientAckAndPriorityPacket( + client_packet_number++, false, + /*largest_received=*/1, /*smallest_received=*/1, + GetNthServerInitiatedUnidirectionalStreamId(0), + GetNthClientInitiatedBidirectionalStreamId(0), DEFAULT_PRIORITY)); } // Response headers for first request. mock_quic_data.AddRead( ASYNC, ConstructServerResponseHeadersPacket( 2, GetNthClientInitiatedBidirectionalStreamId(0), false, false, GetResponseHeaders("200 OK"))); - // Client ACKs the response headers. - mock_quic_data.AddWrite( - SYNCHRONOUS, ConstructClientAckPacket(client_packet_number++, 2, 1, 1)); + if (!should_send_priority_packet) { + // Client ACKs the response headers. + mock_quic_data.AddWrite( + SYNCHRONOUS, ConstructClientAckPacket(client_packet_number++, 2, 1, 1)); + } // Response body for first request. std::string header = ConstructDataHeader(6); mock_quic_data.AddRead( ASYNC, ConstructServerDataPacket( 3, GetNthClientInitiatedBidirectionalStreamId(0), false, true, header + "hello!")); + if (should_send_priority_packet) { + // Client ACKs the response headers. + mock_quic_data.AddWrite( + SYNCHRONOUS, ConstructClientAckPacket(client_packet_number++, 3, 1, 1)); + } // Write error for the third request. mock_quic_data.AddWrite(SYNCHRONOUS, ERR_FAILED); mock_quic_data.AddRead(ASYNC, ERR_IO_PENDING); // No more data to read @@ -7027,15 +7030,17 @@ TEST_P(QuicNetworkTransactionTest, RawHeaderSizeSuccessfullPushHeadersFirst) { initial; } - if ((client_headers_include_h2_stream_dependency_ && - version_.transport_version >= quic::QUIC_VERSION_43 && - !VersionUsesHttp3(version_.transport_version))) { - mock_quic_data.AddWrite( - SYNCHRONOUS, - ConstructClientPriorityPacket( - client_packet_number++, false, - GetNthServerInitiatedUnidirectionalStreamId(0), - GetNthClientInitiatedBidirectionalStreamId(0), DEFAULT_PRIORITY)); + const bool should_send_priority_packet = + client_headers_include_h2_stream_dependency_ && + !VersionUsesHttp3(version_.transport_version); + if (should_send_priority_packet) { + mock_quic_data.AddWrite( + SYNCHRONOUS, + ConstructClientAckAndPriorityPacket( + client_packet_number++, false, + /*largest_received=*/1, /*smallest_received=*/1, + GetNthServerInitiatedUnidirectionalStreamId(0), + GetNthClientInitiatedBidirectionalStreamId(0), DEFAULT_PRIORITY)); } const quic::QuicStreamOffset initial_offset = server_maker_.stream_offset( @@ -7053,26 +7058,38 @@ TEST_P(QuicNetworkTransactionTest, RawHeaderSizeSuccessfullPushHeadersFirst) { quic::QuicStreamOffset expected_raw_header_response_size = final_offset - initial_offset; - mock_quic_data.AddWrite( - SYNCHRONOUS, ConstructClientAckPacket(client_packet_number++, 2, 1, 1)); + if (!should_send_priority_packet) { + mock_quic_data.AddWrite( + SYNCHRONOUS, ConstructClientAckPacket(client_packet_number++, 2, 1, 1)); + } mock_quic_data.AddRead( ASYNC, ConstructServerResponseHeadersPacket( 3, GetNthServerInitiatedUnidirectionalStreamId(0), false, false, GetResponseHeaders("200 OK"))); + if (should_send_priority_packet) { + mock_quic_data.AddWrite( + SYNCHRONOUS, ConstructClientAckPacket(client_packet_number++, 3, 1, 1)); + } std::string header = ConstructDataHeader(20); mock_quic_data.AddRead( ASYNC, ConstructServerDataPacket( 4, GetNthServerInitiatedUnidirectionalStreamId(0), false, true, header + "Pushed Resource Data")); - mock_quic_data.AddWrite( - SYNCHRONOUS, ConstructClientAckPacket(client_packet_number++, 4, 3, 1)); + if (!should_send_priority_packet) { + mock_quic_data.AddWrite( + SYNCHRONOUS, ConstructClientAckPacket(client_packet_number++, 4, 3, 1)); + } std::string header2 = ConstructDataHeader(18); mock_quic_data.AddRead( ASYNC, ConstructServerDataPacket( 5, GetNthClientInitiatedBidirectionalStreamId(0), false, true, header2 + "Main Resource Data")); + if (should_send_priority_packet) { + mock_quic_data.AddWrite( + SYNCHRONOUS, ConstructClientAckPacket(client_packet_number++, 5, 3, 1)); + } mock_quic_data.AddRead(ASYNC, ConstructServerConnectionClosePacket(6)); @@ -7709,48 +7726,70 @@ TEST_P(QuicNetworkTransactionTest, QuicServerPushMatchesRequestWithBody) { GetNthServerInitiatedUnidirectionalStreamId(0), false, GetRequestHeaders("GET", "https", "/pushed.jpg"), &server_maker_)); - if ((client_headers_include_h2_stream_dependency_ && - version_.transport_version >= quic::QUIC_VERSION_43 && - !VersionUsesHttp3(version_.transport_version))) { - mock_quic_data.AddWrite( - SYNCHRONOUS, - ConstructClientPriorityPacket( - client_packet_number++, false, - GetNthServerInitiatedUnidirectionalStreamId(0), - GetNthClientInitiatedBidirectionalStreamId(0), DEFAULT_PRIORITY)); + const bool should_send_priority_packet = + client_headers_include_h2_stream_dependency_ && + !VersionUsesHttp3(version_.transport_version); + if (should_send_priority_packet) { + mock_quic_data.AddWrite( + SYNCHRONOUS, + ConstructClientAckAndPriorityPacket( + client_packet_number++, false, + /*largest_received=*/1, /*smallest_received=*/1, + GetNthServerInitiatedUnidirectionalStreamId(0), + GetNthClientInitiatedBidirectionalStreamId(0), DEFAULT_PRIORITY)); } mock_quic_data.AddRead( ASYNC, ConstructServerResponseHeadersPacket( 2, GetNthClientInitiatedBidirectionalStreamId(0), false, false, GetResponseHeaders("200 OK"))); - mock_quic_data.AddWrite( - SYNCHRONOUS, ConstructClientAckPacket(client_packet_number++, 2, 1, 1)); + if (!should_send_priority_packet) { + mock_quic_data.AddWrite( + SYNCHRONOUS, ConstructClientAckPacket(client_packet_number++, 2, 1, 1)); + } mock_quic_data.AddRead( ASYNC, ConstructServerResponseHeadersPacket( 3, GetNthServerInitiatedUnidirectionalStreamId(0), false, false, GetResponseHeaders("200 OK"))); + if (should_send_priority_packet) { + mock_quic_data.AddWrite( + SYNCHRONOUS, ConstructClientAckPacket(client_packet_number++, 3, 1, 1)); + } std::string header = ConstructDataHeader(6); mock_quic_data.AddRead( ASYNC, ConstructServerDataPacket( 4, GetNthClientInitiatedBidirectionalStreamId(0), false, true, header + "hello!")); - mock_quic_data.AddWrite( - SYNCHRONOUS, ConstructClientAckPacket(client_packet_number++, 4, 3, 1)); + if (!should_send_priority_packet) { + mock_quic_data.AddWrite( + SYNCHRONOUS, ConstructClientAckPacket(client_packet_number++, 4, 3, 1)); + } std::string header2 = ConstructDataHeader(10); mock_quic_data.AddRead( ASYNC, ConstructServerDataPacket( 5, GetNthServerInitiatedUnidirectionalStreamId(0), false, true, header2 + "and hello!")); + if (should_send_priority_packet) { + mock_quic_data.AddWrite( + SYNCHRONOUS, ConstructClientAckPacket(client_packet_number++, 5, 3, 1)); + } // Because the matching request has a body, we will see the push // stream get cancelled, and the matching request go out on the // wire. - mock_quic_data.AddWrite(SYNCHRONOUS, - ConstructClientAckAndRstPacket( - client_packet_number++, - GetNthServerInitiatedUnidirectionalStreamId(0), - quic::QUIC_STREAM_CANCELLED, 5, 5, 1)); + if (should_send_priority_packet) { + mock_quic_data.AddWrite( + SYNCHRONOUS, + ConstructClientRstPacket(client_packet_number++, + GetNthServerInitiatedUnidirectionalStreamId(0), + quic::QUIC_STREAM_CANCELLED)); + } else { + mock_quic_data.AddWrite(SYNCHRONOUS, + ConstructClientAckAndRstPacket( + client_packet_number++, + GetNthServerInitiatedUnidirectionalStreamId(0), + quic::QUIC_STREAM_CANCELLED, 5, 5, 1)); + } const char kBody[] = "1"; std::string header3 = ConstructDataHeader(1); if (!version_.HasIetfQuicFrames()) { @@ -7839,30 +7878,28 @@ TEST_P(QuicNetworkTransactionTest, QuicServerPushWithEmptyHostname) { 1, GetNthClientInitiatedBidirectionalStreamId(0), GetNthServerInitiatedUnidirectionalStreamId(0), false, std::move(pushed_request_headers), &server_maker_)); - mock_quic_data.AddWrite( - SYNCHRONOUS, - ConstructClientRstPacket(packet_num++, - GetNthServerInitiatedUnidirectionalStreamId(0), - quic::QUIC_INVALID_PROMISE_URL)); + mock_quic_data.AddWrite( + SYNCHRONOUS, + ConstructClientAckAndRstPacket( + packet_num++, GetNthServerInitiatedUnidirectionalStreamId(0), + quic::QUIC_INVALID_PROMISE_URL, 1, 1, 1)); mock_quic_data.AddRead( ASYNC, ConstructServerResponseHeadersPacket( 2, GetNthClientInitiatedBidirectionalStreamId(0), false, false, GetResponseHeaders("200 OK"))); - mock_quic_data.AddWrite(SYNCHRONOUS, - ConstructClientAckPacket(packet_num++, 2, 1, 1)); mock_quic_data.AddRead( ASYNC, ConstructServerResponseHeadersPacket( 3, GetNthServerInitiatedUnidirectionalStreamId(0), false, false, GetResponseHeaders("200 OK"))); + mock_quic_data.AddWrite(SYNCHRONOUS, + ConstructClientAckPacket(packet_num++, 3, 1, 1)); std::string header = ConstructDataHeader(6); mock_quic_data.AddRead( ASYNC, ConstructServerDataPacket( 4, GetNthClientInitiatedBidirectionalStreamId(0), false, true, header + "hello!")); - mock_quic_data.AddWrite(SYNCHRONOUS, - ConstructClientAckPacket(packet_num++, 4, 3, 1)); mock_quic_data.AddRead(ASYNC, 0); mock_quic_data.AddSocketDataToFactory(&socket_factory_); @@ -9120,8 +9157,7 @@ TEST_P(QuicNetworkTransactionTest, QuicServerPushUpdatesPriority) { // Only run this test if HTTP/2 stream dependency info is sent by client (sent // in HEADERS frames for requests and PRIORITY frames). - if (version_.transport_version < quic::QUIC_VERSION_43 || - !client_headers_include_h2_stream_dependency_) { + if (!client_headers_include_h2_stream_dependency_) { return; } @@ -9199,31 +9235,33 @@ TEST_P(QuicNetworkTransactionTest, QuicServerPushUpdatesPriority) { ConstructServerPushPromisePacket( 5, client_stream_0, push_stream_1, false, GetRequestHeaders("GET", "https", "/pushed_1.jpg"), &server_maker_)); - mock_quic_data.AddWrite(SYNCHRONOUS, ConstructClientPriorityPacket( - packet_num++, false, push_stream_1, - push_stream_0, DEFAULT_PRIORITY)); + mock_quic_data.AddWrite( + SYNCHRONOUS, ConstructClientAckAndPriorityPacket( + packet_num++, false, + /*largest_received=*/5, /*smallest_received=*/4, + push_stream_1, push_stream_0, DEFAULT_PRIORITY)); // Server sends the response headers for the two push promises. mock_quic_data.AddRead( ASYNC, ConstructServerResponseHeadersPacket( 6, push_stream_0, false, false, GetResponseHeaders("200 OK"))); - mock_quic_data.AddWrite(SYNCHRONOUS, - ConstructClientAckPacket(packet_num++, 6, 5, 1)); mock_quic_data.AddRead( ASYNC, ConstructServerResponseHeadersPacket( 7, push_stream_1, false, false, GetResponseHeaders("200 OK"))); + mock_quic_data.AddWrite(SYNCHRONOUS, + ConstructClientAckPacket(packet_num++, 7, 5, 1)); // Request for "pushed_0.jpg" matches |push_stream_0|. |push_stream_0|'s // priority updates to match the request's priority. Client sends PRIORITY // frames to inform server of new HTTP/2 stream dependencies. - mock_quic_data.AddWrite( - SYNCHRONOUS, - ConstructClientAckAndPriorityFramesPacket( - packet_num++, false, 7, 7, 1, - {{push_stream_1, client_stream_2, - ConvertRequestPriorityToQuicPriority(DEFAULT_PRIORITY)}, - {push_stream_0, client_stream_0, - ConvertRequestPriorityToQuicPriority(HIGHEST)}})); + mock_quic_data.AddWrite( + SYNCHRONOUS, + ConstructClientPriorityFramesPacket( + packet_num++, false, + {{push_stream_1, client_stream_2, + ConvertRequestPriorityToQuicPriority(DEFAULT_PRIORITY)}, + {push_stream_0, client_stream_0, + ConvertRequestPriorityToQuicPriority(HIGHEST)}})); // Server sends data for the three requests and the two push promises. std::string header = ConstructDataHeader(8); @@ -9730,5 +9768,260 @@ TEST_P(QuicNetworkTransactionTest, NetworkIsolationTunnel) { EXPECT_TRUE(mock_quic_data[1]->AllWriteDataConsumed()); } +TEST_P(QuicNetworkTransactionTest, AllowHTTP1FalseProhibitsH1) { + MockRead http_reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING), + MockRead(ASYNC, OK)}; + StaticSocketDataProvider http_data(http_reads, base::span<MockWrite>()); + socket_factory_.AddSocketDataProvider(&http_data); + AddCertificate(&ssl_data_); + socket_factory_.AddSSLSocketDataProvider(&ssl_data_); + + CreateSession(); + + request_.method = "POST"; + UploadDataStreamNotAllowHTTP1 upload_data(""); + request_.upload_data_stream = &upload_data; + + HttpNetworkTransaction trans(DEFAULT_PRIORITY, session_.get()); + TestCompletionCallback callback; + int rv = trans.Start(&request_, callback.callback(), net_log_.bound()); + EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); + EXPECT_THAT(callback.WaitForResult(), IsError(ERR_H2_OR_QUIC_REQUIRED)); +} + +// Confirm mock class UploadDataStreamNotAllowHTTP1 can upload content over +// QUIC. +TEST_P(QuicNetworkTransactionTest, AllowHTTP1MockTest) { + context_.params()->origins_to_force_quic_on.insert( + HostPortPair::FromString("mail.example.org:443")); + + MockQuicData mock_quic_data(version_); + int write_packet_index = 1; + if (VersionUsesHttp3(version_.transport_version)) { + mock_quic_data.AddWrite( + SYNCHRONOUS, ConstructInitialSettingsPacket(write_packet_index++)); + } + const std::string upload_content = "foo"; + if (!version_.HasIetfQuicFrames()) { + mock_quic_data.AddWrite( + SYNCHRONOUS, + ConstructClientRequestHeadersAndDataFramesPacket( + write_packet_index++, GetNthClientInitiatedBidirectionalStreamId(0), + true, true, DEFAULT_PRIORITY, + GetRequestHeaders("POST", "https", "/"), 0, nullptr, + {upload_content})); + } else { + mock_quic_data.AddWrite( + SYNCHRONOUS, + ConstructClientRequestHeadersAndDataFramesPacket( + write_packet_index++, GetNthClientInitiatedBidirectionalStreamId(0), + true, true, DEFAULT_PRIORITY, + GetRequestHeaders("POST", "https", "/"), 0, nullptr, + {ConstructDataHeader(upload_content.length()), upload_content})); + } + mock_quic_data.AddRead( + ASYNC, ConstructServerResponseHeadersPacket( + 1, GetNthClientInitiatedBidirectionalStreamId(0), false, false, + GetResponseHeaders("200 OK"))); + + std::string header2 = ConstructDataHeader(6); + mock_quic_data.AddRead( + ASYNC, ConstructServerDataPacket( + 2, GetNthClientInitiatedBidirectionalStreamId(0), false, true, + header2 + "hello!")); + + mock_quic_data.AddWrite( + SYNCHRONOUS, ConstructClientAckPacket(write_packet_index++, 2, 1, 1)); + + mock_quic_data.AddRead(ASYNC, ERR_IO_PENDING); // No more data to read + mock_quic_data.AddRead(ASYNC, 0); // EOF + mock_quic_data.AddSocketDataToFactory(&socket_factory_); + + // The non-alternate protocol job needs to hang in order to guarantee that + // the alternate-protocol job will "win". + AddHangingNonAlternateProtocolSocketData(); + + CreateSession(); + request_.method = "POST"; + UploadDataStreamNotAllowHTTP1 upload_data(upload_content); + request_.upload_data_stream = &upload_data; + + SendRequestAndExpectQuicResponse("hello!"); +} + +TEST_P(QuicNetworkTransactionTest, AllowHTTP1UploadPauseAndResume) { + context_.params()->origins_to_force_quic_on.insert( + HostPortPair::FromString("mail.example.org:443")); + + MockQuicData mock_quic_data(version_); + mock_quic_data.AddRead(ASYNC, ERR_IO_PENDING); // Hanging read + int write_packet_index = 1; + mock_quic_data.AddWrite( + ASYNC, client_maker_->MakeDummyCHLOPacket(write_packet_index++)); + client_maker_->SetEncryptionLevel(quic::ENCRYPTION_FORWARD_SECURE); + if (VersionUsesHttp3(version_.transport_version)) { + mock_quic_data.AddWrite( + SYNCHRONOUS, ConstructInitialSettingsPacket(write_packet_index++)); + } + const std::string upload_content = "foo"; + if (!version_.HasIetfQuicFrames()) { + mock_quic_data.AddWrite( + SYNCHRONOUS, + ConstructClientRequestHeadersAndDataFramesPacket( + write_packet_index++, GetNthClientInitiatedBidirectionalStreamId(0), + true, true, DEFAULT_PRIORITY, + GetRequestHeaders("POST", "https", "/"), 0, nullptr, + {upload_content})); + } else { + mock_quic_data.AddWrite( + SYNCHRONOUS, + ConstructClientRequestHeadersAndDataFramesPacket( + write_packet_index++, GetNthClientInitiatedBidirectionalStreamId(0), + true, true, DEFAULT_PRIORITY, + GetRequestHeaders("POST", "https", "/"), 0, nullptr, + {ConstructDataHeader(upload_content.length()), upload_content})); + } + mock_quic_data.AddRead( + SYNCHRONOUS, ConstructServerResponseHeadersPacket( + 1, GetNthClientInitiatedBidirectionalStreamId(0), false, + false, GetResponseHeaders("200 OK"))); + std::string header2 = ConstructDataHeader(6); + mock_quic_data.AddRead( + SYNCHRONOUS, ConstructServerDataPacket( + 2, GetNthClientInitiatedBidirectionalStreamId(0), false, + true, header2 + "hello!")); + + mock_quic_data.AddWrite( + SYNCHRONOUS, ConstructClientAckPacket(write_packet_index++, 2, 1, 1)); + mock_quic_data.AddRead(ASYNC, ERR_IO_PENDING); // No more data to read + mock_quic_data.AddRead(ASYNC, 0); // EOF + mock_quic_data.AddSocketDataToFactory(&socket_factory_); + SequencedSocketData* socket_data = mock_quic_data.GetSequencedSocketData(); + + CreateSession(); + + AddQuicAlternateProtocolMapping( + MockCryptoClientStream::COLD_START_WITH_CHLO_SENT); + + // Set up request. + request_.method = "POST"; + UploadDataStreamNotAllowHTTP1 upload_data(upload_content); + request_.upload_data_stream = &upload_data; + + HttpNetworkTransaction trans(DEFAULT_PRIORITY, session_.get()); + TestCompletionCallback callback; + int rv = trans.Start(&request_, callback.callback(), net_log_.bound()); + EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); + base::RunLoop().RunUntilIdle(); + // Resume QUIC job + crypto_client_stream_factory_.last_stream() + ->NotifySessionOneRttKeyAvailable(); + socket_data->Resume(); + + base::RunLoop().RunUntilIdle(); + CheckResponseData(&trans, "hello!"); +} + +TEST_P(QuicNetworkTransactionTest, AllowHTTP1UploadFailH1AndResumeQuic) { + // This test confirms failed main job should not bother quic job. + MockRead http_reads[] = { + MockRead("HTTP/1.1 200 OK\r\n"), MockRead(kQuicAlternativeServiceHeader), + MockRead("1.1 Body"), + MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ), + MockRead(ASYNC, OK)}; + StaticSocketDataProvider http_data(http_reads, base::span<MockWrite>()); + socket_factory_.AddSocketDataProvider(&http_data); + AddCertificate(&ssl_data_); + socket_factory_.AddSSLSocketDataProvider(&ssl_data_); + + MockQuicData mock_quic_data(version_); + mock_quic_data.AddRead(ASYNC, ERR_IO_PENDING); // Hanging read + int write_packet_index = 1; + mock_quic_data.AddWrite( + ASYNC, client_maker_->MakeDummyCHLOPacket(write_packet_index++)); + client_maker_->SetEncryptionLevel(quic::ENCRYPTION_FORWARD_SECURE); + if (VersionUsesHttp3(version_.transport_version)) { + mock_quic_data.AddWrite( + SYNCHRONOUS, ConstructInitialSettingsPacket(write_packet_index++)); + } + const std::string upload_content = "foo"; + if (!version_.HasIetfQuicFrames()) { + mock_quic_data.AddWrite( + SYNCHRONOUS, + ConstructClientRequestHeadersAndDataFramesPacket( + write_packet_index++, GetNthClientInitiatedBidirectionalStreamId(0), + true, true, DEFAULT_PRIORITY, + GetRequestHeaders("POST", "https", "/"), 0, nullptr, + {upload_content})); + } else { + mock_quic_data.AddWrite( + SYNCHRONOUS, + ConstructClientRequestHeadersAndDataFramesPacket( + write_packet_index++, GetNthClientInitiatedBidirectionalStreamId(0), + true, true, DEFAULT_PRIORITY, + GetRequestHeaders("POST", "https", "/"), 0, nullptr, + {ConstructDataHeader(upload_content.length()), upload_content})); + } + mock_quic_data.AddRead( + SYNCHRONOUS, ConstructServerResponseHeadersPacket( + 1, GetNthClientInitiatedBidirectionalStreamId(0), false, + false, GetResponseHeaders("200 OK"))); + std::string header = ConstructDataHeader(6); + mock_quic_data.AddRead( + SYNCHRONOUS, ConstructServerDataPacket( + 2, GetNthClientInitiatedBidirectionalStreamId(0), false, + true, header + "hello!")); + mock_quic_data.AddWrite( + SYNCHRONOUS, ConstructClientAckPacket(write_packet_index++, 2, 1, 1)); + mock_quic_data.AddRead(ASYNC, ERR_IO_PENDING); // No more data to read + mock_quic_data.AddRead(ASYNC, 0); // EOF + mock_quic_data.AddSocketDataToFactory(&socket_factory_); + SequencedSocketData* socket_data = mock_quic_data.GetSequencedSocketData(); + + // This packet won't be read because AllowHTTP1:false doesn't allow H/1 + // connection. + MockRead http_reads2[] = {MockRead("HTTP/1.1 200 OK\r\n")}; + StaticSocketDataProvider http_data2(http_reads2, base::span<MockWrite>()); + socket_factory_.AddSocketDataProvider(&http_data2); + socket_factory_.AddSSLSocketDataProvider(&ssl_data_); + + CreateSession(); + + // Send the first request via TCP and set up alternative service (QUIC) for + // the origin. + SendRequestAndExpectHttpResponse("1.1 Body"); + + // Settings to resume main H/1 job quickly while pausing quic job. + AddQuicAlternateProtocolMapping( + MockCryptoClientStream::COLD_START_WITH_CHLO_SENT); + ServerNetworkStats stats1; + stats1.srtt = base::TimeDelta::FromMicroseconds(10); + http_server_properties_->SetServerNetworkStats( + url::SchemeHostPort(request_.url), NetworkIsolationKey(), stats1); + + // Set up request. + request_.method = "POST"; + UploadDataStreamNotAllowHTTP1 upload_data(upload_content); + request_.upload_data_stream = &upload_data; + + HttpNetworkTransaction trans(DEFAULT_PRIORITY, session_.get()); + TestCompletionCallback callback; + int rv = trans.Start(&request_, callback.callback(), net_log_.bound()); + EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); + // Confirm TCP job was resumed. + // We can not check its failure because HttpStreamFactory::JobController. + // main_job_net_error is not exposed. + while (socket_factory_.mock_data().next_index() < 3u) + base::RunLoop().RunUntilIdle(); + // Resume QUIC job. + crypto_client_stream_factory_.last_stream() + ->NotifySessionOneRttKeyAvailable(); + socket_data->Resume(); + base::RunLoop().RunUntilIdle(); + CheckResponseData(&trans, "hello!"); +} + +// TODO(yoichio): Add the TCP job reuse case. See crrev.com/c/2174099. + } // namespace test } // namespace net diff --git a/chromium/net/quic/quic_proxy_client_socket.cc b/chromium/net/quic/quic_proxy_client_socket.cc index 2d87902522c..dad704704ac 100644 --- a/chromium/net/quic/quic_proxy_client_socket.cc +++ b/chromium/net/quic/quic_proxy_client_socket.cc @@ -458,25 +458,7 @@ int QuicProxyClientSocket::ProcessResponseHeaders( DLOG(WARNING) << "Invalid headers"; return ERR_QUIC_PROTOCOL_ERROR; } - // Populate |connect_timing_| when response headers are received. This - // should take care of 0-RTT where request is sent before handshake is - // confirmed. - connect_timing_ = session_->GetConnectTiming(); return OK; } -bool QuicProxyClientSocket::GetLoadTimingInfo( - LoadTimingInfo* load_timing_info) const { - bool is_first_stream = stream_->IsFirstStream(); - if (stream_) - is_first_stream = stream_->IsFirstStream(); - if (is_first_stream) { - load_timing_info->socket_reused = false; - load_timing_info->connect_timing = connect_timing_; - } else { - load_timing_info->socket_reused = true; - } - return true; -} - } // namespace net diff --git a/chromium/net/quic/quic_proxy_client_socket.h b/chromium/net/quic/quic_proxy_client_socket.h index 723b6670401..a65d0cc4bbb 100644 --- a/chromium/net/quic/quic_proxy_client_socket.h +++ b/chromium/net/quic/quic_proxy_client_socket.h @@ -10,7 +10,6 @@ #include <string> #include "net/base/completion_once_callback.h" -#include "net/base/load_timing_info.h" #include "net/base/proxy_server.h" #include "net/http/proxy_client_socket.h" #include "net/quic/quic_chromium_client_session.h" @@ -109,8 +108,6 @@ class NET_EXPORT_PRIVATE QuicProxyClientSocket : public ProxyClientSocket { int DoReadReply(); int DoReadReplyComplete(int result); - bool GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const; - State next_state_; // Handle to the QUIC Stream that this sits on top of. @@ -148,9 +145,6 @@ class NET_EXPORT_PRIVATE QuicProxyClientSocket : public ProxyClientSocket { std::string user_agent_; - // Session connect timing info. - LoadTimingInfo::ConnectTiming connect_timing_; - const NetLogWithSource net_log_; // The default weak pointer factory. diff --git a/chromium/net/quic/quic_proxy_client_socket_unittest.cc b/chromium/net/quic/quic_proxy_client_socket_unittest.cc index 045cfeec480..0129108e9fa 100644 --- a/chromium/net/quic/quic_proxy_client_socket_unittest.cc +++ b/chromium/net/quic/quic_proxy_client_socket_unittest.cc @@ -187,9 +187,7 @@ class QuicProxyClientSocketTest : public ::testing::TestWithParam<TestParams>, IPAddress ip(192, 0, 2, 33); peer_addr_ = IPEndPoint(ip, 443); clock_.AdvanceTime(quic::QuicTime::Delta::FromMilliseconds(20)); - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3) { - quic::QuicEnableVersion(version_); - } + quic::QuicEnableVersion(version_); } void SetUp() override {} diff --git a/chromium/net/quic/quic_session_key.cc b/chromium/net/quic/quic_session_key.cc index b2393c547a7..ff1a8f524fc 100644 --- a/chromium/net/quic/quic_session_key.cc +++ b/chromium/net/quic/quic_session_key.cc @@ -30,7 +30,12 @@ QuicSessionKey::QuicSessionKey(const std::string& host, const NetworkIsolationKey& network_isolation_key, bool disable_secure_dns) : QuicSessionKey( - quic::QuicServerId(host, port, privacy_mode == PRIVACY_MODE_ENABLED), + // TODO(crbug.com/1103350): Handle non-boolean privacy modes. + quic::QuicServerId( + host, + port, + privacy_mode == PRIVACY_MODE_ENABLED_WITHOUT_CLIENT_CERTS || + privacy_mode == PRIVACY_MODE_ENABLED), socket_tag, network_isolation_key, disable_secure_dns) {} diff --git a/chromium/net/quic/quic_stream_factory.cc b/chromium/net/quic/quic_stream_factory.cc index 3358bd3d4be..6361607eb00 100644 --- a/chromium/net/quic/quic_stream_factory.cc +++ b/chromium/net/quic/quic_stream_factory.cc @@ -45,6 +45,7 @@ #include "net/quic/quic_chromium_connection_helper.h" #include "net/quic/quic_chromium_packet_reader.h" #include "net/quic/quic_chromium_packet_writer.h" +#include "net/quic/quic_client_session_cache.h" #include "net/quic/quic_context.h" #include "net/quic/quic_crypto_client_stream_factory.h" #include "net/quic/quic_http_stream.h" @@ -118,39 +119,31 @@ base::Value NetLogQuicStreamFactoryJobParams( return std::move(dict); } -// Helper class that is used to log a connection migration event. -class ScopedConnectionMigrationEventLog { - public: - ScopedConnectionMigrationEventLog(NetLog* net_log, const char* trigger) - : net_log_(NetLogWithSource::Make( - net_log, - NetLogSourceType::QUIC_CONNECTION_MIGRATION)) { - net_log_.BeginEventWithStringParams( - NetLogEventType::QUIC_CONNECTION_MIGRATION_TRIGGERED, "trigger", - trigger); - } - - ~ScopedConnectionMigrationEventLog() { - net_log_.EndEvent(NetLogEventType::QUIC_CONNECTION_MIGRATION_TRIGGERED); +std::string QuicPlatformNotificationToString( + QuicPlatformNotification notification) { + switch (notification) { + case NETWORK_CONNECTED: + return "OnNetworkConnected"; + case NETWORK_MADE_DEFAULT: + return "OnNetworkMadeDefault"; + case NETWORK_DISCONNECTED: + return "OnNetworkDisconnected"; + case NETWORK_SOON_TO_DISCONNECT: + return "OnNetworkSoonToDisconnect"; + case NETWORK_IP_ADDRESS_CHANGED: + return "OnIPAddressChanged"; + default: + QUIC_NOTREACHED(); + break; } - - const NetLogWithSource& net_log() { return net_log_; } - - private: - const NetLogWithSource net_log_; -}; + return "InvalidNotification"; +} void HistogramCreateSessionFailure(enum CreateSessionFailure error) { UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.CreationError", error, CREATION_ERROR_MAX); } -void LogPlatformNotificationInHistogram( - enum QuicPlatformNotification notification) { - UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.PlatformNotification", - notification, NETWORK_NOTIFICATION_MAX); -} - void LogConnectionIpPooling(bool pooled) { UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.ConnectionIpPooled", pooled); } @@ -225,8 +218,9 @@ class QuicStreamFactory::QuicCryptoClientConfigOwner { public: QuicCryptoClientConfigOwner( std::unique_ptr<quic::ProofVerifier> proof_verifier, + std::unique_ptr<QuicClientSessionCache> session_cache, QuicStreamFactory* quic_stream_factory) - : config_(std::move(proof_verifier)), + : config_(std::move(proof_verifier), std::move(session_cache)), quic_stream_factory_(quic_stream_factory) { DCHECK(quic_stream_factory_); } @@ -390,8 +384,11 @@ class QuicStreamFactory::Job { if (session_) { QuicChromiumClientSession* session = session_; session_ = nullptr; + // Use ERR_FAILED instead of ERR_ABORTED out of paranoia - ERR_ABORTED + // should only be used when the next layer up cancels a request, and has + // special semantic meaning for some consumers when they see it. session->CloseSessionOnErrorLater( - ERR_ABORTED, quic::QUIC_STALE_CONNECTION_CANCELLED, + ERR_FAILED, quic::QUIC_STALE_CONNECTION_CANCELLED, quic::ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); } } @@ -769,7 +766,7 @@ int QuicStreamFactory::Job::DoConnect() { NetLogEventType::QUIC_STREAM_FACTORY_JOB_CONNECT, NetLogEventPhase::BEGIN, "require_confirmation", require_confirmation); - DCHECK_NE(quic_version_.transport_version, quic::QUIC_VERSION_UNSUPPORTED); + DCHECK_NE(quic_version_, quic::ParsedQuicVersion::Unsupported()); int rv = factory_->CreateSession( key_, quic_version_, cert_verify_flags_, require_confirmation, resolve_host_request_->GetAddressResults().value(), @@ -956,7 +953,7 @@ int QuicStreamRequest::Request( NetErrorDetails* net_error_details, CompletionOnceCallback failed_on_default_network_callback, CompletionOnceCallback callback) { - DCHECK_NE(quic_version.transport_version, quic::QUIC_VERSION_UNSUPPORTED); + DCHECK_NE(quic_version, quic::ParsedQuicVersion::Unsupported()); DCHECK(net_error_details); DCHECK(callback_.is_null()); DCHECK(host_resolution_callback_.is_null()); @@ -1106,6 +1103,7 @@ QuicStreamFactory::QuicStreamFactory( need_to_check_persisted_supports_quic_(true), prefer_aes_gcm_recorded_(false), num_push_streams_created_(0), + connectivity_monitor_(default_network_), tick_clock_(nullptr), task_runner_(nullptr), ssl_config_service_(ssl_config_service), @@ -1114,6 +1112,8 @@ QuicStreamFactory::QuicStreamFactory( features::kPartitionHttpServerPropertiesByNetworkIsolationKey)) { DCHECK(transport_security_state_); DCHECK(http_server_properties_); + if (params_.disable_tls_zero_rtt) + SetQuicReloadableFlag(quic_enable_zero_rtt_for_tls, false); InitializeMigrationOptions(); } @@ -1174,7 +1174,7 @@ int QuicStreamFactory::Create(const QuicSessionKey& session_key, QuicStreamRequest* request) { if (clock_skew_detector_.ClockSkewDetected(base::TimeTicks::Now(), base::Time::Now())) { - MarkAllActiveSessionsGoingAway(); + MarkAllActiveSessionsGoingAway(kClockSkewDetected); } DCHECK(HostPortPair(session_key.server_id().host(), session_key.server_id().port()) @@ -1308,7 +1308,6 @@ void QuicStreamFactory::OnSessionGoingAway(QuicChromiumClientSession* session) { void QuicStreamFactory::OnSessionClosed(QuicChromiumClientSession* session) { DCHECK_EQ(0u, session->GetNumActiveStreams()); OnSessionGoingAway(session); - for (const auto& iter : active_jobs_) { if (iter.first == session->quic_session_key()) { iter.second->OnSessionClosed(session); @@ -1478,63 +1477,72 @@ std::unique_ptr<DatagramClientSocket> QuicStreamFactory::CreateSocket( } void QuicStreamFactory::OnIPAddressChanged() { - LogPlatformNotificationInHistogram(NETWORK_IP_ADDRESS_CHANGED); + CollectDataOnPlatformNotification( + NETWORK_IP_ADDRESS_CHANGED, NetworkChangeNotifier::kInvalidNetworkHandle); // Do nothing if connection migration is turned on. if (params_.migrate_sessions_on_network_change_v2) return; + connectivity_monitor_.OnIPAddressChanged(); + set_is_quic_known_to_work_on_current_network(false); if (params_.close_sessions_on_ip_change) { CloseAllSessions(ERR_NETWORK_CHANGED, quic::QUIC_IP_ADDRESS_CHANGED); } else { DCHECK(params_.goaway_sessions_on_ip_change); - MarkAllActiveSessionsGoingAway(); + MarkAllActiveSessionsGoingAway(kIPAddressChanged); } } void QuicStreamFactory::OnNetworkConnected(NetworkHandle network) { - LogPlatformNotificationInHistogram(NETWORK_CONNECTED); - if (!params_.migrate_sessions_on_network_change_v2) - return; - - ScopedConnectionMigrationEventLog scoped_event_log(net_log_, - "OnNetworkConnected"); + CollectDataOnPlatformNotification(NETWORK_CONNECTED, network); + if (params_.migrate_sessions_on_network_change_v2) { + NetLogWithSource net_log = NetLogWithSource::Make( + net_log_, NetLogSourceType::QUIC_CONNECTION_MIGRATION); + net_log.AddEventWithStringParams( + NetLogEventType::QUIC_CONNECTION_MIGRATION_PLATFORM_NOTIFICATION, + "signal", "OnNetworkConnected"); + } + // Broadcast network connected to all sessions. + // If migration is not turned on, session will not migrate but collect data. auto it = all_sessions_.begin(); // Sessions may be deleted while iterating through the map. while (it != all_sessions_.end()) { QuicChromiumClientSession* session = it->first; ++it; - session->OnNetworkConnected(network, scoped_event_log.net_log()); + session->OnNetworkConnected(network); } } void QuicStreamFactory::OnNetworkDisconnected(NetworkHandle network) { - LogPlatformNotificationInHistogram(NETWORK_DISCONNECTED); - if (!params_.migrate_sessions_on_network_change_v2) - return; - - ScopedConnectionMigrationEventLog scoped_event_log(net_log_, - "OnNetworkDisconnected"); + CollectDataOnPlatformNotification(NETWORK_DISCONNECTED, network); + if (params_.migrate_sessions_on_network_change_v2) { + NetLogWithSource net_log = NetLogWithSource::Make( + net_log_, NetLogSourceType::QUIC_CONNECTION_MIGRATION); + net_log.AddEventWithStringParams( + NetLogEventType::QUIC_CONNECTION_MIGRATION_PLATFORM_NOTIFICATION, + "signal", "OnNetworkDisconnected"); + } + // Broadcast network disconnected to all sessions. + // If migration is not turned on, session will not migrate but collect data. auto it = all_sessions_.begin(); // Sessions may be deleted while iterating through the map. while (it != all_sessions_.end()) { QuicChromiumClientSession* session = it->first; ++it; - session->OnNetworkDisconnectedV2(/*disconnected_network*/ network, - scoped_event_log.net_log()); + session->OnNetworkDisconnectedV2(/*disconnected_network*/ network); } } // This method is expected to only be called when migrating from Cellular to // WiFi on Android, and should always be preceded by OnNetworkMadeDefault(). void QuicStreamFactory::OnNetworkSoonToDisconnect(NetworkHandle network) { - LogPlatformNotificationInHistogram(NETWORK_SOON_TO_DISCONNECT); + CollectDataOnPlatformNotification(NETWORK_SOON_TO_DISCONNECT, network); } void QuicStreamFactory::OnNetworkMadeDefault(NetworkHandle network) { - LogPlatformNotificationInHistogram(NETWORK_MADE_DEFAULT); - if (!params_.migrate_sessions_on_network_change_v2) - return; + CollectDataOnPlatformNotification(NETWORK_MADE_DEFAULT, network); + connectivity_monitor_.OnDefaultNetworkUpdated(network); // Clear alternative services that were marked as broken until default network // changes. @@ -1546,17 +1554,24 @@ void QuicStreamFactory::OnNetworkMadeDefault(NetworkHandle network) { DCHECK_NE(NetworkChangeNotifier::kInvalidNetworkHandle, network); default_network_ = network; - ScopedConnectionMigrationEventLog scoped_event_log(net_log_, - "OnNetworkMadeDefault"); + + if (params_.migrate_sessions_on_network_change_v2) { + NetLogWithSource net_log = NetLogWithSource::Make( + net_log_, NetLogSourceType::QUIC_CONNECTION_MIGRATION); + net_log.AddEventWithStringParams( + NetLogEventType::QUIC_CONNECTION_MIGRATION_PLATFORM_NOTIFICATION, + "signal", "OnNetworkMadeDefault"); + } auto it = all_sessions_.begin(); // Sessions may be deleted while iterating through the map. while (it != all_sessions_.end()) { QuicChromiumClientSession* session = it->first; ++it; - session->OnNetworkMadeDefault(network, scoped_event_log.net_log()); + session->OnNetworkMadeDefault(network); } - set_is_quic_known_to_work_on_current_network(false); + if (params_.migrate_sessions_on_network_change_v2) + set_is_quic_known_to_work_on_current_network(false); } void QuicStreamFactory::OnCertDBChanged() { @@ -1569,7 +1584,7 @@ void QuicStreamFactory::OnCertDBChanged() { // Since the OnCertDBChanged method doesn't tell us what // kind of change it is, we have to flush the socket // pools to be safe. - MarkAllActiveSessionsGoingAway(); + MarkAllActiveSessionsGoingAway(kCertDBChanged); } void QuicStreamFactory::set_is_quic_known_to_work_on_current_network( @@ -1742,6 +1757,7 @@ int QuicStreamFactory::CreateSession( // creation, update |default_network_| when the first socket is bound // to the default network. default_network_ = *network; + connectivity_monitor_.SetInitialDefaultNetwork(default_network_); } else { UMA_HISTOGRAM_BOOLEAN("Net.QuicStreamFactory.DefaultNetworkMatch", default_network_ == *network); @@ -1782,7 +1798,9 @@ int QuicStreamFactory::CreateSession( quic::QuicConfig config = config_; ConfigureInitialRttEstimate( server_id, key.session_key().network_isolation_key(), &config); - if (quic_version.transport_version <= quic::QUIC_VERSION_43 && + // QUIC versions that use the IETF invariant header all have NSTP + // enabled by default, so we only need to add it for those that don't. + if (!quic_version.HasIetfInvariantHeader() && !config.HasClientSentConnectionOption(quic::kNSTP, quic::Perspective::IS_CLIENT)) { // Enable the no stop waiting frames connection option by default. @@ -1827,6 +1845,7 @@ int QuicStreamFactory::CreateSession( all_sessions_[*session] = key; // owning pointer writer->set_delegate(*session); + (*session)->AddConnectivityObserver(&connectivity_monitor_); (*session)->Initialize(); bool closed_during_initialize = !base::Contains(all_sessions_, *session) || @@ -1855,9 +1874,14 @@ void QuicStreamFactory::ActivateSession(const QuicSessionAliasKey& key, session_peer_ip_[session] = peer_address; } -void QuicStreamFactory::MarkAllActiveSessionsGoingAway() { +void QuicStreamFactory::MarkAllActiveSessionsGoingAway( + AllActiveSessionsGoingAwayReason reason) { while (!active_sessions_.empty()) { QuicChromiumClientSession* session = active_sessions_.begin()->second; + // If IP address change is detected, disable session's connectivity + // monitoring by remove the Delegate. + if (reason == kIPAddressChanged) + connectivity_monitor_.OnSessionGoingAwayOnIPAddressChange(session); OnSessionGoingAway(session); } } @@ -2014,8 +2038,6 @@ void QuicStreamFactory::InitializeCachedStateInCryptoConfig( quic::QuicConnectionId* connection_id) { quic::QuicCryptoClientConfig::CachedState* cached = crypto_config_handle.GetConfig()->LookupOrCreate(server_id); - if (cached->has_server_designated_connection_id()) - *connection_id = cached->GetNextServerDesignatedConnectionId(); if (!cached->IsEmpty()) { return; @@ -2133,8 +2155,9 @@ QuicStreamFactory::CreateCryptoConfigHandle( std::make_unique<ProofVerifierChromium>( cert_verifier_, ct_policy_enforcer_, transport_security_state_, cert_transparency_verifier_, - HostsFromOrigins(params_.origins_to_force_quic_on)), - this); + HostsFromOrigins(params_.origins_to_force_quic_on), + actual_network_isolation_key), + std::make_unique<QuicClientSessionCache>(), this); quic::QuicCryptoClientConfig* crypto_config = crypto_config_owner->config(); crypto_config->set_user_agent_id(params_.user_agent_id); @@ -2165,6 +2188,38 @@ void QuicStreamFactory::OnAllCryptoClientRefReleased( active_crypto_config_map_.erase(map_iterator); } +void QuicStreamFactory::CollectDataOnPlatformNotification( + enum QuicPlatformNotification notification, + NetworkChangeNotifier::NetworkHandle affected_network) const { + UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.PlatformNotification", + notification, NETWORK_NOTIFICATION_MAX); + if (notification == NETWORK_SOON_TO_DISCONNECT || + notification == NETWORK_DISCONNECTED) { + // If the disconnected network is not the default network, ignore + // stats collections. + if (affected_network != default_network_) + return; + } + + // Skip degrading session collection if there are less than two sessions. + if (all_sessions_.size() < 2) + return; + + size_t num_degrading_sessions = + connectivity_monitor_.GetNumDegradingSessions(); + const std::string raw_histogram_name = + "Net.QuicStreamFactory.NumDegradingSessions." + + QuicPlatformNotificationToString(notification); + base::UmaHistogramExactLinear(raw_histogram_name, num_degrading_sessions, + 101); + + int percentage = num_degrading_sessions * 100 / all_sessions_.size(); + const std::string percentage_histogram_name = + "Net.QuicStreamFactory.PercentageDegradingSessions." + + QuicPlatformNotificationToString(notification); + base::UmaHistogramExactLinear(percentage_histogram_name, percentage, 101); +} + std::unique_ptr<QuicCryptoClientConfigHandle> QuicStreamFactory::GetCryptoConfigForTesting( const NetworkIsolationKey& network_isolation_key) { diff --git a/chromium/net/quic/quic_stream_factory.h b/chromium/net/quic/quic_stream_factory.h index 6e33a290557..9dd5bb2ca03 100644 --- a/chromium/net/quic/quic_stream_factory.h +++ b/chromium/net/quic/quic_stream_factory.h @@ -17,7 +17,6 @@ #include "base/containers/mru_cache.h" #include "base/gtest_prod_util.h" -#include "base/logging.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/time/tick_clock.h" @@ -35,6 +34,7 @@ #include "net/quic/network_connection.h" #include "net/quic/quic_chromium_client_session.h" #include "net/quic/quic_clock_skew_detector.h" +#include "net/quic/quic_connectivity_monitor.h" #include "net/quic/quic_context.h" #include "net/quic/quic_crypto_client_config_handle.h" #include "net/quic/quic_session_key.h" @@ -101,6 +101,12 @@ enum QuicPlatformNotification { NETWORK_NOTIFICATION_MAX }; +enum AllActiveSessionsGoingAwayReason { + kClockSkewDetected, + kIPAddressChanged, + kCertDBChanged +}; + // Encapsulates a pending request for a QuicChromiumClientSession. // If the request is still pending when it is destroyed, it will // cancel the request with the factory. @@ -396,7 +402,9 @@ class NET_EXPORT_PRIVATE QuicStreamFactory NetworkChangeNotifier::NetworkHandle* network); void ActivateSession(const QuicSessionAliasKey& key, QuicChromiumClientSession* session); - void MarkAllActiveSessionsGoingAway(); + // Go away all active sessions. May disable session's connectivity monitoring + // based on the |reason|. + void MarkAllActiveSessionsGoingAway(AllActiveSessionsGoingAwayReason reason); void ConfigureInitialRttEstimate( const quic::QuicServerId& server_id, @@ -457,6 +465,14 @@ class NET_EXPORT_PRIVATE QuicStreamFactory void OnAllCryptoClientRefReleased( QuicCryptoClientConfigMap::iterator& map_iterator); + // Called when a network change happens. + // Collect platform notification metrics, and if the change affects the + // original default network interface, collect connectivity degradation + // metrics from |connectivity_monitor_| and add to histograms. + void CollectDataOnPlatformNotification( + enum QuicPlatformNotification notification, + NetworkChangeNotifier::NetworkHandle affected_network) const; + std::unique_ptr<QuicCryptoClientConfigHandle> GetCryptoConfigForTesting( const NetworkIsolationKey& network_isolation_key); @@ -556,6 +572,8 @@ class NET_EXPORT_PRIVATE QuicStreamFactory int num_push_streams_created_; + QuicConnectivityMonitor connectivity_monitor_; + quic::QuicClientPushPromiseIndex push_promise_index_; const base::TickClock* tick_clock_; diff --git a/chromium/net/quic/quic_stream_factory_peer.cc b/chromium/net/quic/quic_stream_factory_peer.cc index ac673b84b67..63b316a5e30 100644 --- a/chromium/net/quic/quic_stream_factory_peer.cc +++ b/chromium/net/quic/quic_stream_factory_peer.cc @@ -185,6 +185,11 @@ int QuicStreamFactoryPeer::GetNumPushStreamsCreated( return factory->num_push_streams_created_; } +size_t QuicStreamFactoryPeer::GetNumDegradingSessions( + QuicStreamFactory* factory) { + return factory->connectivity_monitor_.GetNumDegradingSessions(); +} + void QuicStreamFactoryPeer::SetAlarmFactory( QuicStreamFactory* factory, std::unique_ptr<quic::QuicAlarmFactory> alarm_factory) { diff --git a/chromium/net/quic/quic_stream_factory_peer.h b/chromium/net/quic/quic_stream_factory_peer.h index 507aedda772..7e2a59922fd 100644 --- a/chromium/net/quic/quic_stream_factory_peer.h +++ b/chromium/net/quic/quic_stream_factory_peer.h @@ -103,6 +103,8 @@ class QuicStreamFactoryPeer { static int GetNumPushStreamsCreated(QuicStreamFactory* factory); + static size_t GetNumDegradingSessions(QuicStreamFactory* factory); + static void SetAlarmFactory( QuicStreamFactory* factory, std::unique_ptr<quic::QuicAlarmFactory> alarm_factory); diff --git a/chromium/net/quic/quic_stream_factory_test.cc b/chromium/net/quic/quic_stream_factory_test.cc index a4dd7ce26d3..031cfe38238 100644 --- a/chromium/net/quic/quic_stream_factory_test.cc +++ b/chromium/net/quic/quic_stream_factory_test.cc @@ -42,6 +42,7 @@ #include "net/quic/mock_quic_data.h" #include "net/quic/properties_based_quic_server_info.h" #include "net/quic/quic_chromium_alarm_factory.h" +#include "net/quic/quic_chromium_client_session_peer.h" #include "net/quic/quic_http_stream.h" #include "net/quic/quic_http_utils.h" #include "net/quic/quic_server_info.h" @@ -1002,11 +1003,6 @@ TEST_P(QuicStreamFactoryTest, Create) { } TEST_P(QuicStreamFactoryTest, CreateZeroRtt) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3 && - version_.HasIetfQuicFrames()) { - // 0-rtt is not supported in IETF QUIC yet. - return; - } Initialize(); factory_->set_is_quic_known_to_work_on_current_network(true); ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); @@ -1097,11 +1093,6 @@ TEST_P(QuicStreamFactoryTest, FactoryDestroyedWhenJobPending) { } TEST_P(QuicStreamFactoryTest, RequireConfirmation) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3 && - version_.HasIetfQuicFrames()) { - // 0-rtt is not supported in IETF QUIC yet. - return; - } crypto_client_stream_factory_.set_handshake_mode( MockCryptoClientStream::ZERO_RTT); host_resolver_->set_synchronous_mode(true); @@ -1144,11 +1135,6 @@ TEST_P(QuicStreamFactoryTest, RequireConfirmation) { } TEST_P(QuicStreamFactoryTest, DontRequireConfirmationFromSameIP) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3 && - version_.HasIetfQuicFrames()) { - // 0-rtt is not supported in IETF QUIC yet. - return; - } crypto_client_stream_factory_.set_handshake_mode( MockCryptoClientStream::ZERO_RTT); host_resolver_->set_synchronous_mode(true); @@ -3152,24 +3138,24 @@ void QuicStreamFactoryTestBase::TestOnNetworkMadeDefaultNonMigratableStream( quic_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING); // Hanging read. // A RESET will be sent to the peer to cancel the non-migratable stream. if (VersionUsesHttp3(version_.transport_version)) { - quic_data1.AddWrite(SYNCHRONOUS, - client_maker_.MakeDataAndRstPacket( - packet_num++, true, GetQpackDecoderStreamId(), - StreamCancellationQpackDecoderInstruction(0), - GetNthClientInitiatedBidirectionalStreamId(0), - quic::QUIC_STREAM_CANCELLED)); + quic_data1.AddWrite(SYNCHRONOUS, + client_maker_.MakeDataRstAndAckPacket( + packet_num++, true, GetQpackDecoderStreamId(), + StreamCancellationQpackDecoderInstruction(0), + GetNthClientInitiatedBidirectionalStreamId(0), + quic::QUIC_STREAM_CANCELLED, 1, 1)); } else { - quic_data1.AddWrite(SYNCHRONOUS, - client_maker_.MakeRstPacket( - packet_num++, false, - GetNthClientInitiatedBidirectionalStreamId(0), - quic::QUIC_STREAM_CANCELLED)); + quic_data1.AddWrite(SYNCHRONOUS, + client_maker_.MakeAckAndRstPacket( + packet_num++, false, + GetNthClientInitiatedBidirectionalStreamId(0), + quic::QUIC_STREAM_CANCELLED, 1, 1, 1)); } // Ping packet to send after migration is completed. - quic_data1.AddWrite(SYNCHRONOUS, client_maker_.MakeAckAndPingPacket( - packet_num++, false, 1, 1, 1)); + quic_data1.AddWrite(SYNCHRONOUS, + client_maker_.MakePingPacket(packet_num++, false)); } else { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3) { + if (version_.UsesTls()) { if (VersionUsesHttp3(version_.transport_version)) { socket_data.AddWrite( SYNCHRONOUS, @@ -3586,8 +3572,7 @@ void QuicStreamFactoryTestBase::TestOnNetworkMadeDefaultNoOpenStreams( QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); EXPECT_TRUE(HasActiveSession(host_port_pair_)); - EXPECT_EQ(0u, session->GetNumActiveStreams()); - EXPECT_EQ(0u, session->GetNumDrainingStreams()); + EXPECT_FALSE(session->HasActiveRequestStreams()); // Trigger connection migration. scoped_mock_network_change_notifier_->mock_network_change_notifier() @@ -4079,9 +4064,11 @@ TEST_P(QuicStreamFactoryTest, MigrateToProbingSocket) { EXPECT_EQ(OK, stream->SendRequest(request_headers, &response, callback_.callback())); + EXPECT_EQ(0u, QuicStreamFactoryPeer::GetNumDegradingSessions(factory_.get())); // Cause the connection to report path degrading to the session. // Session will start to probe the alternate network. - session->connection()->OnPathDegradingTimeout(); + session->connection()->OnPathDegradingDetected(); + EXPECT_EQ(1u, QuicStreamFactoryPeer::GetNumDegradingSessions(factory_.get())); // Next connectivity probe is scheduled to be sent in 2 * // kDefaultRTTMilliSecs. @@ -4111,6 +4098,8 @@ TEST_P(QuicStreamFactoryTest, MigrateToProbingSocket) { EXPECT_EQ(base::TimeDelta(), next_task_delay); task_runner->FastForwardBy(next_task_delay); + EXPECT_EQ(1u, QuicStreamFactoryPeer::GetNumDegradingSessions(factory_.get())); + // Response headers are received over the new network. EXPECT_THAT(callback_.WaitForResult(), IsOk()); EXPECT_EQ(200, response.headers->response_code()); @@ -4136,6 +4125,8 @@ TEST_P(QuicStreamFactoryTest, MigrateToProbingSocket) { scoped_mock_network_change_notifier_->mock_network_change_notifier() ->NotifyNetworkMadeDefault(kNewNetworkForTests); + EXPECT_EQ(0u, QuicStreamFactoryPeer::GetNumDegradingSessions(factory_.get())); + task_runner->FastForwardBy(next_task_delay); EXPECT_EQ(0u, task_runner->GetPendingTaskCount()); @@ -4271,9 +4262,11 @@ void QuicStreamFactoryTestBase::TestMigrationOnPathDegrading( if (async_write_before) session->SendPing(); + EXPECT_EQ(0u, QuicStreamFactoryPeer::GetNumDegradingSessions(factory_.get())); // Cause the connection to report path degrading to the session. // Session will start to probe the alternate network. - session->connection()->OnPathDegradingTimeout(); + session->connection()->OnPathDegradingDetected(); + EXPECT_EQ(1u, QuicStreamFactoryPeer::GetNumDegradingSessions(factory_.get())); // Next connectivity probe is scheduled to be sent in 2 * // kDefaultRTTMilliSecs. @@ -4303,10 +4296,14 @@ void QuicStreamFactoryTestBase::TestMigrationOnPathDegrading( EXPECT_EQ(base::TimeDelta(), next_task_delay); task_runner->FastForwardBy(next_task_delay); + EXPECT_EQ(1u, QuicStreamFactoryPeer::GetNumDegradingSessions(factory_.get())); + // Response headers are received over the new network. EXPECT_THAT(callback_.WaitForResult(), IsOk()); EXPECT_EQ(200, response.headers->response_code()); + EXPECT_EQ(1u, QuicStreamFactoryPeer::GetNumDegradingSessions(factory_.get())); + // Now there are two pending tasks, the nearest one was to send connectivity // probe and has been cancelled due to successful migration. EXPECT_EQ(2u, task_runner->GetPendingTaskCount()); @@ -4328,6 +4325,8 @@ void QuicStreamFactoryTestBase::TestMigrationOnPathDegrading( scoped_mock_network_change_notifier_->mock_network_change_notifier() ->NotifyNetworkMadeDefault(kNewNetworkForTests); + EXPECT_EQ(0u, QuicStreamFactoryPeer::GetNumDegradingSessions(factory_.get())); + task_runner->FastForwardBy(next_task_delay); EXPECT_EQ(0u, task_runner->GetPendingTaskCount()); @@ -4352,6 +4351,143 @@ TEST_P(QuicStreamFactoryTest, MigratePortOnPathDegrading_WithoutNetworkHandle) { TestSimplePortMigrationOnPathDegrading(); } +// Verifies that if a stateless reset is received on port migration probing +// path, the session is still alive and probing is considered failed. +TEST_P(QuicStreamFactoryTest, PortMigrationProbingReceivedStatelessReset) { + if (!VersionHasIetfInvariantHeader(version_.transport_version)) { + // STATELESS_RESET is only supported after QUIC V46. + return; + } + quic_params_->allow_port_migration = true; + socket_factory_.reset(new TestMigrationSocketFactory); + Initialize(); + ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); + + // Using a testing task runner so that we can control time. + auto task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>(); + QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), task_runner.get()); + + int packet_number = 1; + MockQuicData quic_data1(version_); + quic_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING); // hanging read + if (VersionUsesHttp3(version_.transport_version)) { + quic_data1.AddWrite(SYNCHRONOUS, + ConstructInitialSettingsPacket(packet_number++)); + } + quic_data1.AddWrite( + SYNCHRONOUS, + ConstructGetRequestPacket(packet_number++, + GetNthClientInitiatedBidirectionalStreamId(0), + true, true)); + if (VersionUsesHttp3(version_.transport_version)) { + quic_data1.AddWrite( + SYNCHRONOUS, client_maker_.MakeDataPacket( + packet_number + 1, GetQpackDecoderStreamId(), true, + false, StreamCancellationQpackDecoderInstruction(0))); + quic_data1.AddWrite(SYNCHRONOUS, + client_maker_.MakeRstPacket( + packet_number + 2, false, + GetNthClientInitiatedBidirectionalStreamId(0), + quic::QUIC_STREAM_CANCELLED)); + } else { + quic_data1.AddWrite(SYNCHRONOUS, + client_maker_.MakeRstPacket( + packet_number + 1, false, + GetNthClientInitiatedBidirectionalStreamId(0), + quic::QUIC_STREAM_CANCELLED)); + } + quic_data1.AddSocketDataToFactory(socket_factory_.get()); + + // Set up the second socket data provider that is used after migration. + // The response to the earlier request is read on the new socket. + MockQuicData quic_data2(version_); + // Connectivity probe to be sent on the new path. + quic_data2.AddWrite(SYNCHRONOUS, client_maker_.MakeConnectivityProbingPacket( + packet_number, true)); + quic_data2.AddRead(ASYNC, ERR_IO_PENDING); // Pause + // Stateless reset to receive from the server. + quic_data2.AddRead(ASYNC, server_maker_.MakeStatelessResetPacket()); + quic_data2.AddSocketDataToFactory(socket_factory_.get()); + + // Create request and QuicHttpStream. + QuicStreamRequest request(factory_.get()); + EXPECT_EQ( + ERR_IO_PENDING, + request.Request( + host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, + SocketTag(), NetworkIsolationKey(), false /* disable_secure_dns */, + /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, + failed_on_default_network_callback_, callback_.callback())); + EXPECT_THAT(callback_.WaitForResult(), IsOk()); + std::unique_ptr<HttpStream> stream = CreateStream(&request); + EXPECT_TRUE(stream.get()); + + // Cause QUIC stream to be created. + HttpRequestInfo request_info; + request_info.method = "GET"; + request_info.url = url_; + request_info.traffic_annotation = + MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); + EXPECT_EQ(OK, stream->InitializeStream(&request_info, true, DEFAULT_PRIORITY, + net_log_, CompletionOnceCallback())); + + // Ensure that session is alive and active. + QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); + EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); + EXPECT_TRUE(HasActiveSession(host_port_pair_)); + + // Send GET request on stream. + HttpResponseInfo response; + HttpRequestHeaders request_headers; + EXPECT_EQ(OK, stream->SendRequest(request_headers, &response, + callback_.callback())); + + EXPECT_EQ(0u, QuicStreamFactoryPeer::GetNumDegradingSessions(factory_.get())); + + // Cause the connection to report path degrading to the session. + // Session will start to probe a different port. + session->connection()->OnPathDegradingDetected(); + + EXPECT_EQ(1u, QuicStreamFactoryPeer::GetNumDegradingSessions(factory_.get())); + + // Next connectivity probe is scheduled to be sent in 2 * + // kDefaultRTTMilliSecs. + EXPECT_EQ(1u, task_runner->GetPendingTaskCount()); + base::TimeDelta next_task_delay = task_runner->NextPendingTaskDelay(); + EXPECT_EQ(base::TimeDelta::FromMilliseconds(2 * kDefaultRTTMilliSecs), + next_task_delay); + + // The connection should still be alive, and not marked as going away. + EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); + EXPECT_TRUE(HasActiveSession(host_port_pair_)); + EXPECT_EQ(1u, session->GetNumActiveStreams()); + EXPECT_EQ(ERR_IO_PENDING, stream->ReadResponseHeaders(callback_.callback())); + + // Resume quic data and a STATELESS_RESET is read from the probing path. + quic_data2.Resume(); + + EXPECT_EQ(1u, QuicStreamFactoryPeer::GetNumDegradingSessions(factory_.get())); + + // Verify that the session is still active, and the request stream is active. + EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); + EXPECT_TRUE(HasActiveSession(host_port_pair_)); + EXPECT_EQ(1u, session->GetNumActiveStreams()); + EXPECT_FALSE( + QuicChromiumClientSessionPeer::DoesSessionAllowPortMigration(session)); + + // The task to resend connectivity probe is cancelled due to probe failure. + task_runner->FastForwardBy(next_task_delay); + EXPECT_EQ(0u, task_runner->GetPendingTaskCount()); + + stream.reset(); + EXPECT_TRUE(quic_data1.AllReadDataConsumed()); + EXPECT_TRUE(quic_data1.AllWriteDataConsumed()); + EXPECT_TRUE(quic_data2.AllReadDataConsumed()); + EXPECT_TRUE(quic_data2.AllWriteDataConsumed()); +} + // Verifies that port migration can be attempted on the default network and // succeed when path degrading is detected. NetworkHandle is supported. TEST_P(QuicStreamFactoryTest, MigratePortOnPathDegrading_WithNetworkHandle) { @@ -4488,9 +4624,13 @@ void QuicStreamFactoryTestBase::TestSimplePortMigrationOnPathDegrading() { EXPECT_EQ(OK, stream->SendRequest(request_headers, &response, callback_.callback())); + EXPECT_EQ(0u, QuicStreamFactoryPeer::GetNumDegradingSessions(factory_.get())); + // Cause the connection to report path degrading to the session. // Session will start to probe a different port. - session->connection()->OnPathDegradingTimeout(); + session->connection()->OnPathDegradingDetected(); + + EXPECT_EQ(1u, QuicStreamFactoryPeer::GetNumDegradingSessions(factory_.get())); // Next connectivity probe is scheduled to be sent in 2 * // kDefaultRTTMilliSecs. @@ -4512,6 +4652,9 @@ void QuicStreamFactoryTestBase::TestSimplePortMigrationOnPathDegrading() { EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); EXPECT_TRUE(HasActiveSession(host_port_pair_)); EXPECT_EQ(1u, session->GetNumActiveStreams()); + // Successful port migration causes the path no longer degrading on the same + // network. + EXPECT_EQ(0u, QuicStreamFactoryPeer::GetNumDegradingSessions(factory_.get())); // There should be pending tasks, the nearest one will complete // migration to the new port. @@ -4524,6 +4667,8 @@ void QuicStreamFactoryTestBase::TestSimplePortMigrationOnPathDegrading() { EXPECT_THAT(callback_.WaitForResult(), IsOk()); EXPECT_EQ(200, response.headers->response_code()); + EXPECT_EQ(0u, QuicStreamFactoryPeer::GetNumDegradingSessions(factory_.get())); + // Now there is one pending task to send connectivity probe and has been // cancelled due to successful migration. EXPECT_EQ(1u, task_runner->GetPendingTaskCount()); @@ -4660,9 +4805,15 @@ TEST_P(QuicStreamFactoryTest, MultiplePortMigrationsExceedsMaxLimit) { quic_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING); // EOF. quic_data2.AddSocketDataToFactory(socket_factory_.get()); + EXPECT_EQ(0u, + QuicStreamFactoryPeer::GetNumDegradingSessions(factory_.get())); + // Cause the connection to report path degrading to the session. // Session will start to probe a different port. - session->connection()->OnPathDegradingTimeout(); + session->connection()->OnPathDegradingDetected(); + + EXPECT_EQ(1u, + QuicStreamFactoryPeer::GetNumDegradingSessions(factory_.get())); // Next connectivity probe is scheduled to be sent in 2 * // kDefaultRTTMilliSecs. @@ -4784,9 +4935,15 @@ TEST_P(QuicStreamFactoryTest, GoawayOnPathDegrading) { EXPECT_EQ(OK, stream->SendRequest(request_headers, &response, callback_.callback())); + EXPECT_EQ(0u, QuicStreamFactoryPeer::GetNumDegradingSessions(factory_.get())); + // Trigger the connection to report path degrading to the session. // Session will mark itself GOAWAY. - session->connection()->OnPathDegradingTimeout(); + session->connection()->OnPathDegradingDetected(); + + /// Path degrading detection on go_away_on_path_degrading detection is + // disabled. + EXPECT_EQ(0u, QuicStreamFactoryPeer::GetNumDegradingSessions(factory_.get())); // The connection should still be alive, but marked as going away. EXPECT_FALSE(HasActiveSession(host_port_pair_)); @@ -4920,9 +5077,11 @@ TEST_P(QuicStreamFactoryTest, DoNotMigrateToBadSocketOnPathDegrading) { EXPECT_EQ(OK, stream->SendRequest(request_headers, &response, callback_.callback())); + EXPECT_EQ(0u, QuicStreamFactoryPeer::GetNumDegradingSessions(factory_.get())); // Cause the connection to report path degrading to the session. // Session will start to probe the alternate network. - session->connection()->OnPathDegradingTimeout(); + session->connection()->OnPathDegradingDetected(); + EXPECT_EQ(1u, QuicStreamFactoryPeer::GetNumDegradingSessions(factory_.get())); // The connection should still be alive, and not marked as going away. EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); @@ -5063,10 +5222,12 @@ void QuicStreamFactoryTestBase::TestMigrateSessionWithDrainingStream( base::RunLoop().RunUntilIdle(); EXPECT_EQ(0u, session->GetNumActiveStreams()); + EXPECT_EQ(0u, QuicStreamFactoryPeer::GetNumDegradingSessions(factory_.get())); // Cause the connection to report path degrading to the session. // Session should still start to probe the alternate network. - session->connection()->OnPathDegradingTimeout(); + session->connection()->OnPathDegradingDetected(); EXPECT_TRUE(HasActiveSession(host_port_pair_)); + EXPECT_EQ(1u, QuicStreamFactoryPeer::GetNumDegradingSessions(factory_.get())); // Next connectivity probe is scheduled to be sent in 2 * // kDefaultRTTMilliSecs. @@ -5085,7 +5246,7 @@ void QuicStreamFactoryTestBase::TestMigrateSessionWithDrainingStream( EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); EXPECT_TRUE(HasActiveSession(host_port_pair_)); EXPECT_EQ(0u, session->GetNumActiveStreams()); - EXPECT_EQ(1u, session->GetNumDrainingStreams()); + EXPECT_TRUE(session->HasActiveRequestStreams()); // There should be three pending tasks, the nearest one will complete // migration to the new network. @@ -5233,12 +5394,18 @@ TEST_P(QuicStreamFactoryTest, MigrateOnNewNetworkConnectAfterPathDegrading) { EXPECT_EQ(OK, stream->SendRequest(request_headers, &response, callback_.callback())); + EXPECT_EQ(0u, QuicStreamFactoryPeer::GetNumDegradingSessions(factory_.get())); + // Cause the connection to report path degrading to the session. // Due to lack of alternate network, session will not mgirate connection. EXPECT_EQ(0u, task_runner->GetPendingTaskCount()); - session->connection()->OnPathDegradingTimeout(); + EXPECT_EQ(0u, QuicStreamFactoryPeer::GetNumDegradingSessions(factory_.get())); + session->connection()->OnPathDegradingDetected(); + EXPECT_EQ(1u, QuicStreamFactoryPeer::GetNumDegradingSessions(factory_.get())); EXPECT_EQ(0u, task_runner->GetPendingTaskCount()); + EXPECT_EQ(1u, QuicStreamFactoryPeer::GetNumDegradingSessions(factory_.get())); + // Deliver a signal that a alternate network is connected now, this should // cause the connection to start early migration on path degrading. scoped_mock_network_change_notifier_->mock_network_change_notifier() @@ -5275,6 +5442,10 @@ TEST_P(QuicStreamFactoryTest, MigrateOnNewNetworkConnectAfterPathDegrading) { EXPECT_EQ(base::TimeDelta(), next_task_delay); task_runner->FastForwardBy(next_task_delay); + // Although the session successfully migrates, it is still considered + // degrading sessions. + EXPECT_EQ(1u, QuicStreamFactoryPeer::GetNumDegradingSessions(factory_.get())); + // Response headers are received over the new network. EXPECT_THAT(callback_.WaitForResult(), IsOk()); EXPECT_EQ(200, response.headers->response_code()); @@ -5523,8 +5694,10 @@ TEST_P(QuicStreamFactoryTest, MigrateOnPathDegradingWithNoNewNetwork) { // Trigger connection migration on path degrading. Since there are no networks // to migrate to, the session will remain on the original network, not marked // as going away. - session->connection()->OnPathDegradingTimeout(); + EXPECT_EQ(0u, QuicStreamFactoryPeer::GetNumDegradingSessions(factory_.get())); + session->connection()->OnPathDegradingDetected(); EXPECT_TRUE(session->connection()->IsPathDegrading()); + EXPECT_EQ(1u, QuicStreamFactoryPeer::GetNumDegradingSessions(factory_.get())); EXPECT_TRUE(HasActiveSession(host_port_pair_)); EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); @@ -5586,24 +5759,25 @@ void QuicStreamFactoryTestBase::TestMigrateSessionEarlyNonMigratableStream( quic_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING); // Hanging read. // A RESET will be sent to the peer to cancel the non-migratable stream. if (VersionUsesHttp3(version_.transport_version)) { - quic_data1.AddWrite(SYNCHRONOUS, - client_maker_.MakeDataAndRstPacket( - packet_num++, true, GetQpackDecoderStreamId(), - StreamCancellationQpackDecoderInstruction(0), - GetNthClientInitiatedBidirectionalStreamId(0), - quic::QUIC_STREAM_CANCELLED)); + quic_data1.AddWrite(SYNCHRONOUS, + client_maker_.MakeDataRstAndAckPacket( + packet_num++, true, GetQpackDecoderStreamId(), + StreamCancellationQpackDecoderInstruction(0), + GetNthClientInitiatedBidirectionalStreamId(0), + quic::QUIC_STREAM_CANCELLED, 1, 1)); } else { - quic_data1.AddWrite(SYNCHRONOUS, - client_maker_.MakeRstPacket( - packet_num++, false, - GetNthClientInitiatedBidirectionalStreamId(0), - quic::QUIC_STREAM_CANCELLED)); + quic_data1.AddWrite(SYNCHRONOUS, + client_maker_.MakeAckAndRstPacket( + packet_num++, false, + GetNthClientInitiatedBidirectionalStreamId(0), + quic::QUIC_STREAM_CANCELLED, 1, 1, 1)); } // Ping packet to send after migration is completed. - quic_data1.AddWrite(SYNCHRONOUS, client_maker_.MakeAckAndPingPacket( - packet_num++, false, 1, 1, 1)); + quic_data1.AddWrite(SYNCHRONOUS, + client_maker_.MakePingPacket(packet_num++, false)); + } else { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3) { + if (version_.UsesTls()) { if (VersionUsesHttp3(version_.transport_version)) { socket_data.AddWrite( SYNCHRONOUS, @@ -6152,8 +6326,10 @@ TEST_P(QuicStreamFactoryTest, // Cause the connection to report path degrading to the session. // Session will ignore the signal as handshake is not completed. - session->connection()->OnPathDegradingTimeout(); + EXPECT_EQ(0u, QuicStreamFactoryPeer::GetNumDegradingSessions(factory_.get())); + session->connection()->OnPathDegradingDetected(); EXPECT_EQ(0u, task_runner->GetPendingTaskCount()); + EXPECT_EQ(1u, QuicStreamFactoryPeer::GetNumDegradingSessions(factory_.get())); EXPECT_FALSE(HasActiveSession(host_port_pair_)); EXPECT_TRUE(HasActiveJob(host_port_pair_, privacy_mode_)); @@ -6212,9 +6388,11 @@ void QuicStreamFactoryTestBase::TestNoAlternateNetworkBeforeHandshake( EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); EXPECT_EQ(0u, task_runner->GetPendingTaskCount()); + EXPECT_EQ(0u, QuicStreamFactoryPeer::GetNumDegradingSessions(factory_.get())); // Cause the connection to report path degrading to the session. // Session will ignore the signal as handshake is not completed. - session->connection()->OnPathDegradingTimeout(); + session->connection()->OnPathDegradingDetected(); + EXPECT_EQ(1u, QuicStreamFactoryPeer::GetNumDegradingSessions(factory_.get())); EXPECT_EQ(0u, task_runner->GetPendingTaskCount()); EXPECT_FALSE(HasActiveSession(host_port_pair_)); EXPECT_TRUE(HasActiveJob(host_port_pair_, privacy_mode_)); @@ -10135,8 +10313,7 @@ TEST_P(QuicStreamFactoryTest, ServerMigration) { const uint8_t kTestIpAddress[] = {1, 2, 3, 4}; const uint16_t kTestPort = 123; session->Migrate(NetworkChangeNotifier::kInvalidNetworkHandle, - IPEndPoint(IPAddress(kTestIpAddress), kTestPort), true, - net_log_); + IPEndPoint(IPAddress(kTestIpAddress), kTestPort), true); session->GetDefaultSocket()->GetPeerAddress(&ip); DVLOG(1) << "Socket migrated to: " << ip.address().ToString() << " " @@ -10184,7 +10361,10 @@ TEST_P(QuicStreamFactoryTest, ServerMigrationIPv6ToIPv6) { VerifyServerMigration(config, alt_address); } -TEST_P(QuicStreamFactoryTest, ServerMigrationIPv6ToIPv4) { +TEST_P(QuicStreamFactoryTest, ServerMigrationIPv6ToIPv4Fails) { + quic_params_->allow_server_migration = true; + Initialize(); + // Add a resolver rule to make initial connection to an IPv6 address. host_resolver_->rules()->AddIPLiteralRule(host_port_pair_.host(), "fe80::aebc:32ff:febb:1e33", ""); @@ -10192,9 +10372,75 @@ TEST_P(QuicStreamFactoryTest, ServerMigrationIPv6ToIPv4) { IPEndPoint alt_address = IPEndPoint(IPAddress(1, 2, 3, 4), 123); quic::QuicConfig config; config.SetIPv4AlternateServerAddressToSend(ToQuicSocketAddress(alt_address)); - IPEndPoint expected_address( - ConvertIPv4ToIPv4MappedIPv6(alt_address.address()), alt_address.port()); - VerifyServerMigration(config, expected_address); + + ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); + + crypto_client_stream_factory_.SetConfig(config); + + // Set up only socket data provider. + MockQuicData socket_data1(version_); + socket_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING); + int packet_num = 1; + if (VersionUsesHttp3(version_.transport_version)) { + socket_data1.AddWrite(SYNCHRONOUS, + ConstructInitialSettingsPacket(packet_num++)); + socket_data1.AddWrite( + SYNCHRONOUS, client_maker_.MakeDataPacket( + packet_num++, GetQpackDecoderStreamId(), true, false, + StreamCancellationQpackDecoderInstruction(0))); + } + socket_data1.AddWrite( + SYNCHRONOUS, + client_maker_.MakeRstPacket(packet_num++, true, + GetNthClientInitiatedBidirectionalStreamId(0), + quic::QUIC_STREAM_CANCELLED)); + socket_data1.AddSocketDataToFactory(socket_factory_.get()); + + // Create request and QuicHttpStream. + QuicStreamRequest request(factory_.get()); + EXPECT_EQ( + ERR_IO_PENDING, + request.Request( + host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, + SocketTag(), NetworkIsolationKey(), false /* disable_secure_dns */, + /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, + failed_on_default_network_callback_, callback_.callback())); + EXPECT_EQ(OK, callback_.WaitForResult()); + std::unique_ptr<HttpStream> stream = CreateStream(&request); + EXPECT_TRUE(stream.get()); + + // Cause QUIC stream to be created. + HttpRequestInfo request_info; + request_info.method = "GET"; + request_info.url = GURL("https://www.example.org/"); + request_info.traffic_annotation = + MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); + EXPECT_EQ(OK, stream->InitializeStream(&request_info, true, DEFAULT_PRIORITY, + net_log_, CompletionOnceCallback())); + + // Ensure that session is alive and active. + QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); + EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); + EXPECT_TRUE(HasActiveSession(host_port_pair_)); + + IPEndPoint actual_address; + session->GetDefaultSocket()->GetPeerAddress(&actual_address); + // No migration should have happened. + IPEndPoint expected_address = + IPEndPoint(IPAddress(0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0xae, 0xbc, 0x32, 0xff, + 0xfe, 0xbb, 0x1e, 0x33), + kDefaultServerPort); + EXPECT_EQ(actual_address, expected_address); + DVLOG(1) << "Socket connected to: " << actual_address.address().ToString() + << " " << actual_address.port(); + DVLOG(1) << "Expected address: " << expected_address.address().ToString() + << " " << expected_address.port(); + + stream.reset(); + EXPECT_TRUE(socket_data1.AllReadDataConsumed()); + EXPECT_TRUE(socket_data1.AllWriteDataConsumed()); } TEST_P(QuicStreamFactoryTest, ServerMigrationIPv4ToIPv6Fails) { @@ -10431,11 +10677,6 @@ TEST_P(QuicStreamFactoryTest, CryptoConfigWhenProofIsInvalid) { } TEST_P(QuicStreamFactoryTest, EnableNotLoadFromDiskCache) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3 && - version_.HasIetfQuicFrames()) { - // 0-rtt is not supported in IETF QUIC yet. - return; - } Initialize(); factory_->set_is_quic_known_to_work_on_current_network(true); ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); @@ -10581,20 +10822,10 @@ TEST_P(QuicStreamFactoryTest, ReducePingTimeoutOnConnectionTimeOutOpenStreams) { // Verifies that the QUIC stream factory is initialized correctly. TEST_P(QuicStreamFactoryTest, MaybeInitialize) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3 && - version_.HasIetfQuicFrames()) { - // 0-rtt is not supported in IETF QUIC yet. - return; - } VerifyInitialization(false /* vary_network_isolation_key */); } TEST_P(QuicStreamFactoryTest, MaybeInitializeWithNetworkIsolationKey) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3 && - version_.HasIetfQuicFrames()) { - // 0-rtt is not supported in IETF QUIC yet. - return; - } base::test::ScopedFeatureList feature_list; feature_list.InitWithFeatures( // enabled_features @@ -10822,11 +11053,6 @@ TEST_P(QuicStreamFactoryTest, CryptoConfigCacheMRUWithNetworkIsolationKey) { // around, so evictions happen immediately. TEST_P(QuicStreamFactoryTest, CryptoConfigCacheMRUWithRealRequestsAndWithNetworkIsolationKey) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3 && - version_.HasIetfQuicFrames()) { - // 0-rtt is not supported in IETF QUIC yet. - return; - } const int kNumSessionsToMake = kMaxRecentCryptoConfigs + 5; base::test::ScopedFeatureList feature_list; @@ -10968,11 +11194,6 @@ TEST_P(QuicStreamFactoryTest, } TEST_P(QuicStreamFactoryTest, YieldAfterPackets) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3 && - version_.HasIetfQuicFrames()) { - // 0-rtt is not supported in IETF QUIC yet. - return; - } Initialize(); factory_->set_is_quic_known_to_work_on_current_network(true); ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); @@ -11025,11 +11246,6 @@ TEST_P(QuicStreamFactoryTest, YieldAfterPackets) { } TEST_P(QuicStreamFactoryTest, YieldAfterDuration) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3 && - version_.HasIetfQuicFrames()) { - // 0-rtt is not supported in IETF QUIC yet. - return; - } Initialize(); factory_->set_is_quic_known_to_work_on_current_network(true); ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); @@ -12306,11 +12522,6 @@ TEST_P(QuicStreamFactoryTest, ResultAfterDNSRaceHostResolveAsyncStaleMatch) { // async, and then the result matches. TEST_P(QuicStreamFactoryTest, ResultAfterDNSRaceHostResolveAsyncConnectAsyncStaleMatch) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3 && - version_.HasIetfQuicFrames()) { - // 0-rtt is not supported in IETF QUIC yet. - return; - } quic_params_->race_stale_dns_on_connection = true; host_resolver_ = std::make_unique<MockCachingHostResolver>(); Initialize(); @@ -12382,11 +12593,6 @@ TEST_P(QuicStreamFactoryTest, // return, then connection finishes and matches with the result. TEST_P(QuicStreamFactoryTest, ResultAfterDNSRaceHostResolveAsyncStaleMatchConnectAsync) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3 && - version_.HasIetfQuicFrames()) { - // 0-rtt is not supported in IETF QUIC yet. - return; - } quic_params_->race_stale_dns_on_connection = true; host_resolver_ = std::make_unique<MockCachingHostResolver>(); Initialize(); @@ -12532,10 +12738,6 @@ TEST_P(QuicStreamFactoryTest, // With dns race experiment on, dns resolve async, stale used and connects // async, finishes before dns, but no match TEST_P(QuicStreamFactoryTest, ResultAfterDNSRaceStaleAsyncResolveAsyncNoMatch) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3) { - // TODO(fayang): 0-rtt is not supported in IETF QUIC yet. Fix it. - return; - } quic_params_->race_stale_dns_on_connection = true; host_resolver_ = std::make_unique<MockCachingHostResolver>(); Initialize(); @@ -12550,7 +12752,7 @@ TEST_P(QuicStreamFactoryTest, ResultAfterDNSRaceStaleAsyncResolveAsyncNoMatch) { host_resolver_->rules()->AddIPLiteralRule(host_port_pair_.host(), kNonCachedIPAddress, ""); - // Set up a different address in the stale resolvercache. + // Set up a different address in the stale resolver cache. HostCache::Key key(host_port_pair_.host(), DnsQueryType::UNSPECIFIED, 0, HostResolverSource::ANY, NetworkIsolationKey()); HostCache::Entry entry(OK, @@ -12621,10 +12823,6 @@ TEST_P(QuicStreamFactoryTest, ResultAfterDNSRaceStaleAsyncResolveAsyncNoMatch) { // With dns race experiment on, dns resolve async, stale used and connects // async, dns finishes first, but no match TEST_P(QuicStreamFactoryTest, ResultAfterDNSRaceResolveAsyncStaleAsyncNoMatch) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3) { - // TODO(fayang): 0-rtt is not supported in IETF QUIC yet. Fix it. - return; - } quic_params_->race_stale_dns_on_connection = true; host_resolver_ = std::make_unique<MockCachingHostResolver>(); Initialize(); @@ -12988,10 +13186,6 @@ TEST_P(QuicStreamFactoryTest, ResultAfterDNSRaceStaleErrorDNSNoMatchError) { // With dns race experiment on, dns resolve async and stale connect async, dns // resolve returns error and then preconnect finishes TEST_P(QuicStreamFactoryTest, ResultAfterDNSRaceResolveAsyncErrorStaleAsync) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3) { - // TODO(fayang): 0-rtt is not supported in IETF QUIC yet. Fix it. - return; - } quic_params_->race_stale_dns_on_connection = true; host_resolver_ = std::make_unique<MockCachingHostResolver>(); Initialize(); @@ -13002,8 +13196,6 @@ TEST_P(QuicStreamFactoryTest, ResultAfterDNSRaceResolveAsyncErrorStaleAsync) { host_resolver_->set_ondemand_mode(true); host_resolver_->rules()->AddSimulatedFailure(host_port_pair_.host()); factory_->set_is_quic_known_to_work_on_current_network(false); - crypto_client_stream_factory_.set_handshake_mode( - MockCryptoClientStream::ZERO_RTT); // Set up an address in stale resolver cache. HostCache::Key key(host_port_pair_.host(), DnsQueryType::UNSPECIFIED, 0, @@ -13020,7 +13212,6 @@ TEST_P(QuicStreamFactoryTest, ResultAfterDNSRaceResolveAsyncErrorStaleAsync) { // Socket data for stale connection which is supposed to disconnect. MockQuicData quic_data(version_); quic_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); - client_maker_.SetEncryptionLevel(quic::ENCRYPTION_ZERO_RTT); int packet_number = 1; if (VersionUsesHttp3(version_.transport_version)) { quic_data.AddWrite(SYNCHRONOUS, @@ -13053,10 +13244,6 @@ TEST_P(QuicStreamFactoryTest, ResultAfterDNSRaceResolveAsyncErrorStaleAsync) { // resolve returns error and then preconnect fails. TEST_P(QuicStreamFactoryTest, ResultAfterDNSRaceResolveAsyncErrorStaleAsyncError) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3) { - // TODO(fayang): 0-rtt is not supported in IETF QUIC yet. Fix it. - return; - } quic_params_->race_stale_dns_on_connection = true; host_resolver_ = std::make_unique<MockCachingHostResolver>(); Initialize(); @@ -13066,8 +13253,6 @@ TEST_P(QuicStreamFactoryTest, // Add asynchronous failure to host resolver. host_resolver_->set_ondemand_mode(true); factory_->set_is_quic_known_to_work_on_current_network(false); - crypto_client_stream_factory_.set_handshake_mode( - MockCryptoClientStream::ZERO_RTT); host_resolver_->rules()->AddSimulatedFailure(host_port_pair_.host()); // Set up an address in stale resolver cache. @@ -13084,7 +13269,6 @@ TEST_P(QuicStreamFactoryTest, MockQuicData quic_data(version_); quic_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); - client_maker_.SetEncryptionLevel(quic::ENCRYPTION_ZERO_RTT); int packet_number = 1; if (VersionUsesHttp3(version_.transport_version)) { quic_data.AddWrite(SYNCHRONOUS, @@ -13163,11 +13347,6 @@ TEST_P(QuicStreamFactoryTest, ResultAfterDNSRaceHostResolveAsync) { // With stale dns and migration before handshake experiment on, migration failed // after handshake confirmed, and then fresh resolve returns. TEST_P(QuicStreamFactoryTest, StaleNetworkFailedAfterHandshake) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3 && - version_.HasIetfQuicFrames()) { - // 0-rtt is not supported in IETF QUIC yet. - return; - } quic_params_->race_stale_dns_on_connection = true; host_resolver_ = std::make_unique<MockCachingHostResolver>(); @@ -13243,11 +13422,6 @@ TEST_P(QuicStreamFactoryTest, StaleNetworkFailedAfterHandshake) { // With stale dns experiment on, the stale session is killed while waiting for // handshake TEST_P(QuicStreamFactoryTest, StaleNetworkFailedBeforeHandshake) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3 && - version_.HasIetfQuicFrames()) { - // 0-rtt is not supported in IETF QUIC yet. - return; - } quic_params_->race_stale_dns_on_connection = true; host_resolver_ = std::make_unique<MockCachingHostResolver>(); InitializeConnectionMigrationV2Test( @@ -13326,7 +13500,7 @@ TEST_P(QuicStreamFactoryTest, StaleNetworkFailedBeforeHandshake) { } TEST_P(QuicStreamFactoryTest, ConfigInitialRttForHandshake) { - if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3) { + if (version_.UsesTls()) { // IETF QUIC uses a different handshake timeout management system. return; } diff --git a/chromium/net/quic/quic_test_packet_maker.cc b/chromium/net/quic/quic_test_packet_maker.cc index db63151afa8..7539328b11e 100644 --- a/chromium/net/quic/quic_test_packet_maker.cc +++ b/chromium/net/quic/quic_test_packet_maker.cc @@ -91,6 +91,10 @@ quic::QuicFrames CloneFrames(const quic::QuicFrames& frames) { frame.new_token_frame = new quic::QuicNewTokenFrame(*frame.new_token_frame); break; + case quic::ACK_FREQUENCY_FRAME: + frame.ack_frequency_frame = + new quic::QuicAckFrequencyFrame(*frame.ack_frequency_frame); + break; case quic::NUM_FRAME_TYPES: DCHECK(false) << "Cannot clone frame type: " << frame.type; @@ -99,6 +103,15 @@ quic::QuicFrames CloneFrames(const quic::QuicFrames& frames) { return new_frames; } +// TODO(crbug.com/1085541): Consider moving this method into QuicTestUtils. +quic::QuicConnectionId TestConnectionId(uint64_t connection_number) { + const uint64_t connection_id64_net = + quiche::QuicheEndian::HostToNet64(connection_number); + return quic::QuicConnectionId( + reinterpret_cast<const char*>(&connection_id64_net), + sizeof(connection_id64_net)); +} + } // namespace QuicTestPacketMaker::QuicTestPacketMaker( @@ -120,8 +133,7 @@ QuicTestPacketMaker::QuicTestPacketMaker( encryption_level_(quic::ENCRYPTION_FORWARD_SECURE), long_header_type_(quic::INVALID_PACKET_TYPE), client_headers_include_h2_stream_dependency_( - client_headers_include_h2_stream_dependency && - version.transport_version >= quic::QUIC_VERSION_43), + client_headers_include_h2_stream_dependency), save_packet_frames_(false) { DCHECK(!(perspective_ == quic::Perspective::IS_SERVER && client_headers_include_h2_stream_dependency_)); @@ -246,7 +258,7 @@ std::unique_ptr<quic::QuicReceivedPacket> QuicTestPacketMaker::MakeRstPacket( InitializeHeader(num, include_version); if (!version_.HasIetfQuicFrames() || - quic::QuicUtils::IsBidirectionalStreamId(stream_id)) { + quic::QuicUtils::IsBidirectionalStreamId(stream_id, version_)) { AddQuicRstStreamFrame(stream_id, error_code); } @@ -299,6 +311,30 @@ QuicTestPacketMaker::MakeDataAndRstPacket( } std::unique_ptr<quic::QuicReceivedPacket> +QuicTestPacketMaker::MakeDataRstAndAckPacket( + uint64_t num, + bool include_version, + quic::QuicStreamId data_stream_id, + quiche::QuicheStringPiece data, + quic::QuicStreamId rst_stream_id, + quic::QuicRstStreamErrorCode rst_error_code, + uint64_t largest_received, + uint64_t smallest_received) { + InitializeHeader(num, include_version); + + AddQuicAckFrame(largest_received, smallest_received); + + AddQuicStreamFrame(data_stream_id, /* fin = */ false, data); + AddQuicRstStreamFrame(rst_stream_id, rst_error_code); + + if (version_.HasIetfQuicFrames()) { + AddQuicStopSendingFrame(rst_stream_id, rst_error_code); + } + + return BuildPacket(); +} + +std::unique_ptr<quic::QuicReceivedPacket> QuicTestPacketMaker::MakeAckAndRstPacket( uint64_t num, bool include_version, @@ -327,7 +363,7 @@ QuicTestPacketMaker::MakeAckAndRstPacket( AddQuicAckFrame(largest_received, smallest_received); if (!version_.HasIetfQuicFrames() || - quic::QuicUtils::IsBidirectionalStreamId(stream_id)) { + quic::QuicUtils::IsBidirectionalStreamId(stream_id, version_)) { AddQuicRstStreamFrame(stream_id, error_code); } @@ -351,6 +387,8 @@ QuicTestPacketMaker::MakeRstAckAndConnectionClosePacket( const std::string& quic_error_details) { InitializeHeader(num, include_version); + AddQuicAckFrame(largest_received, smallest_received); + AddQuicRstStreamFrame(stream_id, error_code); if (version_.HasIetfQuicFrames()) { @@ -423,6 +461,8 @@ QuicTestPacketMaker::MakeDataRstAckAndConnectionClosePacket( const std::string& quic_error_details) { InitializeHeader(num, include_version); + AddQuicAckFrame(largest_received, smallest_received); + AddQuicStreamFrame(data_stream_id, /* fin = */ false, data); AddQuicRstStreamFrame(rst_stream_id, error_code); @@ -790,6 +830,44 @@ QuicTestPacketMaker::MakePriorityPacket(uint64_t packet_number, } std::unique_ptr<quic::QuicReceivedPacket> +QuicTestPacketMaker::MakeAckAndPriorityPacket( + uint64_t packet_number, + bool should_include_version, + uint64_t largest_received, + uint64_t smallest_received, + quic::QuicStreamId id, + quic::QuicStreamId parent_stream_id, + spdy::SpdyPriority priority) { + InitializeHeader(packet_number, should_include_version); + + AddQuicAckFrame(largest_received, smallest_received); + + if (!client_headers_include_h2_stream_dependency_) { + parent_stream_id = 0; + } + int weight = spdy::Spdy3PriorityToHttp2Weight(priority); + bool exclusive = client_headers_include_h2_stream_dependency_; + + if (!VersionUsesHttp3(version_.transport_version)) { + spdy::SpdyPriorityIR priority_frame(id, parent_stream_id, weight, + exclusive); + spdy::SpdySerializedFrame spdy_frame( + spdy_request_framer_.SerializeFrame(priority_frame)); + AddQuicStreamFrame( + GetHeadersStreamId(), false, + quiche::QuicheStringPiece(spdy_frame.data(), spdy_frame.size())); + + return BuildPacket(); + } + if (priority != quic::QuicStream::kDefaultUrgency) { + std::string priority_data = GenerateHttp3PriorityData(priority, id); + AddQuicStreamFrame(2, false, priority_data); + } + + return BuildPacket(); +} + +std::unique_ptr<quic::QuicReceivedPacket> QuicTestPacketMaker::MakeAckAndPriorityUpdatePacket( uint64_t packet_number, bool should_include_version, @@ -809,6 +887,30 @@ QuicTestPacketMaker::MakeAckAndPriorityUpdatePacket( } std::unique_ptr<quic::QuicReceivedPacket> +QuicTestPacketMaker::MakeMultiplePriorityFramesPacket( + uint64_t packet_number, + bool should_include_version, + const std::vector<Http2StreamDependency>& priority_frames) { + InitializeHeader(packet_number, should_include_version); + + const bool exclusive = client_headers_include_h2_stream_dependency_; + std::string coalesced_data; + for (const Http2StreamDependency& info : priority_frames) { + spdy::SpdyPriorityIR priority_frame( + info.stream_id, info.parent_stream_id, + spdy::Spdy3PriorityToHttp2Weight(info.spdy_priority), exclusive); + auto spdy_frame = spdy_request_framer_.SerializeFrame(priority_frame); + coalesced_data += std::string(spdy_frame.data(), spdy_frame.size()); + } + AddQuicStreamFrame(quic::VersionUsesHttp3(version_.transport_version) + ? GetFirstBidirectionalStreamId() + : GetHeadersStreamId(), + false, coalesced_data); + + return BuildPacket(); +} + +std::unique_ptr<quic::QuicReceivedPacket> QuicTestPacketMaker::MakeAckAndMultiplePriorityFramesPacket( uint64_t packet_number, bool should_include_version, @@ -847,6 +949,14 @@ QuicTestPacketMaker::MakeRetransmissionPacket(uint64_t original_packet_number, saved_frames_[quic::QuicPacketNumber(original_packet_number)], nullptr); } +std::unique_ptr<quic::QuicEncryptedPacket> +QuicTestPacketMaker::MakeStatelessResetPacket() { + auto connection_id = TestConnectionId(0x1337); + return quic::QuicFramer::BuildIetfStatelessResetPacket( + connection_id, + quic::QuicUtils::GenerateStatelessResetToken(connection_id)); +} + void QuicTestPacketMaker::RemoveSavedStreamFrames( quic::QuicStreamId stream_id) { for (auto& kv : saved_frames_) { @@ -939,7 +1049,7 @@ std::string QuicTestPacketMaker::QpackEncodeHeaders( &headers_frame_header); // Possible add a PUSH stream type. - if (!quic::QuicUtils::IsBidirectionalStreamId(stream_id) && + if (!quic::QuicUtils::IsBidirectionalStreamId(stream_id, version_) && stream_offsets_[stream_id] == 0) { // Push stream type header data += "\x01"; @@ -1223,7 +1333,7 @@ spdy::SpdySerializedFrame QuicTestPacketMaker::MakeSpdyHeadersFrame( } bool QuicTestPacketMaker::ShouldIncludeVersion(bool include_version) const { - if (version_.transport_version > quic::QUIC_VERSION_43) { + if (version_.HasIetfInvariantHeader()) { return encryption_level_ < quic::ENCRYPTION_FORWARD_SECURE; } return include_version; @@ -1231,7 +1341,7 @@ bool QuicTestPacketMaker::ShouldIncludeVersion(bool include_version) const { quic::QuicPacketNumberLength QuicTestPacketMaker::GetPacketNumberLength() const { - if (version_.transport_version > quic::QUIC_VERSION_43 && + if (version_.HasIetfInvariantHeader() && encryption_level_ < quic::ENCRYPTION_FORWARD_SECURE && !version_.SendsVariableLengthPacketNumberInLongHeader()) { return quic::PACKET_4BYTE_PACKET_NUMBER; diff --git a/chromium/net/quic/quic_test_packet_maker.h b/chromium/net/quic/quic_test_packet_maker.h index 8df27cfbdb6..d0549ec20b2 100644 --- a/chromium/net/quic/quic_test_packet_maker.h +++ b/chromium/net/quic/quic_test_packet_maker.h @@ -116,6 +116,16 @@ class QuicTestPacketMaker { quic::QuicStreamId rst_stream_id, quic::QuicRstStreamErrorCode rst_error_code); + std::unique_ptr<quic::QuicReceivedPacket> MakeDataRstAndAckPacket( + uint64_t num, + bool include_version, + quic::QuicStreamId data_stream_id, + quiche::QuicheStringPiece data, + quic::QuicStreamId rst_stream_id, + quic::QuicRstStreamErrorCode rst_error_code, + uint64_t largest_received, + uint64_t smallest_received); + std::unique_ptr<quic::QuicReceivedPacket> MakeAckAndRstPacket( uint64_t num, bool include_version, @@ -297,6 +307,20 @@ class QuicTestPacketMaker { quic::QuicStreamId parent_stream_id, spdy::SpdyPriority priority); + std::unique_ptr<quic::QuicReceivedPacket> MakeAckAndPriorityPacket( + uint64_t packet_number, + bool should_include_version, + uint64_t largest_received, + uint64_t smallest_received, + quic::QuicStreamId id, + quic::QuicStreamId parent_stream_id, + spdy::SpdyPriority priority); + + std::unique_ptr<quic::QuicReceivedPacket> MakeMultiplePriorityFramesPacket( + uint64_t packet_number, + bool should_include_version, + const std::vector<Http2StreamDependency>& priority_frames); + std::unique_ptr<quic::QuicReceivedPacket> MakeAckAndMultiplePriorityFramesPacket( uint64_t packet_number, @@ -320,6 +344,8 @@ class QuicTestPacketMaker { quic::QuicStreamId id, spdy::SpdyPriority priority); + std::unique_ptr<quic::QuicEncryptedPacket> MakeStatelessResetPacket(); + // Removes all stream frames associated with |stream_id|. void RemoveSavedStreamFrames(quic::QuicStreamId stream_id); diff --git a/chromium/net/quic/quic_test_packet_printer.cc b/chromium/net/quic/quic_test_packet_printer.cc index 2a5741df791..86edab085bd 100644 --- a/chromium/net/quic/quic_test_packet_printer.cc +++ b/chromium/net/quic/quic_test_packet_printer.cc @@ -180,6 +180,10 @@ class QuicPacketPrinter : public QuicFramerVisitorInterface { *output_ << "OnHandshakeDoneFrame: " << frame; return true; } + bool OnAckFrequencyFrame(const QuicAckFrequencyFrame& frame) override { + *output_ << "OnAckFrequencyFrame: " << frame; + return true; + } void OnPacketComplete() override { *output_ << "OnPacketComplete\n"; } bool IsValidStatelessResetToken(QuicUint128 token) const override { *output_ << "IsValidStatelessResetToken\n"; diff --git a/chromium/net/quic/quic_transport_client.cc b/chromium/net/quic/quic_transport_client.cc index 6da53b0ac2e..8b2c4f3ea69 100644 --- a/chromium/net/quic/quic_transport_client.cc +++ b/chromium/net/quic/quic_transport_client.cc @@ -4,6 +4,8 @@ #include "net/quic/quic_transport_client.h" +#include "base/metrics/histogram_functions.h" +#include "base/stl_util.h" #include "base/threading/thread_task_runner_handle.h" #include "net/proxy_resolution/configured_proxy_resolution_service.h" #include "net/proxy_resolution/proxy_resolution_request.h" @@ -17,6 +19,10 @@ namespace net { namespace { +// From +// https://wicg.github.io/web-transport/#dom-quictransportconfiguration-server_certificate_fingerprints +constexpr int kCustomCertificateMaxValidityDays = 14; + std::set<std::string> HostsFromOrigins(std::set<HostPortPair> origins) { std::set<std::string> hosts; for (const auto& origin : origins) { @@ -24,17 +30,47 @@ std::set<std::string> HostsFromOrigins(std::set<HostPortPair> origins) { } return hosts; } + +std::unique_ptr<quic::ProofVerifier> CreateProofVerifier( + const NetworkIsolationKey& isolation_key, + URLRequestContext* context, + const QuicTransportClient::Parameters& parameters) { + if (parameters.server_certificate_fingerprints.empty()) { + return std::make_unique<ProofVerifierChromium>( + context->cert_verifier(), context->ct_policy_enforcer(), + context->transport_security_state(), + context->cert_transparency_verifier(), + HostsFromOrigins( + context->quic_context()->params()->origins_to_force_quic_on), + isolation_key); + } + + auto verifier = std::make_unique<quic::WebTransportFingerprintProofVerifier>( + context->quic_context()->clock(), kCustomCertificateMaxValidityDays); + for (const quic::CertificateFingerprint& fingerprint : + parameters.server_certificate_fingerprints) { + bool success = verifier->AddFingerprint(fingerprint); + if (!success) { + DLOG(WARNING) << "Failed to add a certificate fingerprint: " + << fingerprint.fingerprint; + } + } + return verifier; +} } // namespace -constexpr quic::ParsedQuicVersion - QuicTransportClient::kQuicVersionForOriginTrial; +QuicTransportClient::Parameters::Parameters() = default; +QuicTransportClient::Parameters::~Parameters() = default; +QuicTransportClient::Parameters::Parameters(const Parameters&) = default; +QuicTransportClient::Parameters::Parameters(Parameters&&) = default; QuicTransportClient::QuicTransportClient( const GURL& url, const url::Origin& origin, Visitor* visitor, const NetworkIsolationKey& isolation_key, - URLRequestContext* context) + URLRequestContext* context, + const Parameters& parameters) : url_(url), origin_(origin), isolation_key_(isolation_key), @@ -53,15 +89,8 @@ QuicTransportClient::QuicTransportClient( // (currently, all certificate verification errors result in "TLS // handshake error" even when more detailed message is available). This // requires implementing ProofHandler::OnProofVerifyDetailsAvailable. - crypto_config_( - std::make_unique<ProofVerifierChromium>( - context->cert_verifier(), - context->ct_policy_enforcer(), - context->transport_security_state(), - context->cert_transparency_verifier(), - std::set<std::string>(HostsFromOrigins( - quic_context_->params()->origins_to_force_quic_on))), - /* session_cache */ nullptr) {} + crypto_config_(CreateProofVerifier(isolation_key_, context, parameters), + /* session_cache */ nullptr) {} QuicTransportClient::~QuicTransportClient() = default; @@ -139,13 +168,13 @@ int QuicTransportClient::DoInit() { // Ensure that for the duration of the origin trial, a fixed QUIC transport // version is available. - supported_versions_.push_back(kQuicVersionForOriginTrial); + supported_versions_ = QuicVersionsForWebTransportOriginTrial(); // Add other supported versions if available. for (quic::ParsedQuicVersion& version : quic_context_->params()->supported_versions) { if (!quic::IsVersionValidForQuicTransport(version)) continue; - if (version == kQuicVersionForOriginTrial) + if (base::Contains(supported_versions_, version)) continue; // Skip as we've already added it above. supported_versions_.push_back(version); } @@ -227,6 +256,20 @@ int QuicTransportClient::DoConnect() { if (rv != OK) return rv; + CreateConnection(); + next_connect_state_ = CONNECT_STATE_CONFIRM_CONNECTION; + return ERR_IO_PENDING; +} + +void QuicTransportClient::CreateConnection() { + // Delete the objects in the same order they would be normally deleted by the + // destructor. + packet_reader_ = nullptr; + session_ = nullptr; + connection_ = nullptr; + + IPEndPoint server_address = + *resolve_host_request_->GetAddressResults()->begin(); quic::QuicConnectionId connection_id = quic::QuicUtils::CreateRandomConnectionId( quic_context_->random_generator()); @@ -251,9 +294,6 @@ int QuicTransportClient::DoConnect() { session_->Initialize(); packet_reader_->StartReading(); session_->CryptoConnect(); - - next_connect_state_ = CONNECT_STATE_CONFIRM_CONNECTION; - return ERR_IO_PENDING; } int QuicTransportClient::DoConfirmConnection() { @@ -292,6 +332,18 @@ void QuicTransportClient::TransitionToState(State next_state) { error_.safe_to_report_details = session_->alpn_received(); } + base::UmaHistogramEnumeration("Net.QuicTransportClient.FailedAtState", + last_state, NUM_STATES); + base::UmaHistogramSparse("Net.QuicTransportClient.Error", + std::abs(error_.net_error)); + if (last_state == CONNECTING) { + base::UmaHistogramEnumeration( + "Net.QuicTransportClient.FailedAtConnectState", next_connect_state_, + CONNECT_STATE_NUM_STATES); + base::UmaHistogramSparse("Net.QuicTransportClient.ConnectionError", + std::abs(error_.net_error)); + } + DCHECK_NE(error_.net_error, OK); if (error_.details.empty()) { error_.details = ErrorToString(error_.net_error); @@ -372,7 +424,38 @@ void QuicTransportClient::OnConnectionClosed( quic::QuicConnectionId /*server_connection_id*/, quic::QuicErrorCode error, const std::string& error_details, - quic::ConnectionCloseSource /*source*/) { + quic::ConnectionCloseSource source) { + if (!retried_with_new_version_ && + session_->error() == quic::QUIC_INVALID_VERSION) { + retried_with_new_version_ = true; + base::EraseIf( + supported_versions_, [this](const quic::ParsedQuicVersion& version) { + return !base::Contains( + session_->connection()->server_supported_versions(), version); + }); + if (!supported_versions_.empty()) { + // Since this is a callback from QuicConnection, we can't replace the + // connection object in this method; do it from the top of the event loop + // instead. + task_runner_->PostTask( + FROM_HERE, base::BindOnce(&QuicTransportClient::CreateConnection, + weak_factory_.GetWeakPtr())); + return; + } + // If there are no supported versions, treat this as a regular error. + } + + std::string histogram_name; + switch (source) { + case quic::ConnectionCloseSource::FROM_SELF: + histogram_name = "Net.QuicTransportClient.ConnectionCloseCodeClient"; + break; + case quic::ConnectionCloseSource::FROM_PEER: + histogram_name = "Net.QuicTransportClient.ConnectionCloseCodeServer"; + break; + } + base::UmaHistogramSparse(histogram_name, error); + if (error == quic::QUIC_NO_ERROR) { TransitionToState(CLOSED); return; @@ -392,17 +475,4 @@ void QuicTransportClient::OnConnectionClosed( TransitionToState(FAILED); } -std::string QuicTransportErrorToString(const QuicTransportError& error) { - std::string message = - ExtendedErrorToString(error.net_error, error.quic_error); - if (error.details == message) - return message; - return quiche::QuicheStrCat(message, " (", error.details, ")"); -} - -std::ostream& operator<<(std::ostream& os, const QuicTransportError& error) { - os << QuicTransportErrorToString(error); - return os; -} - } // namespace net diff --git a/chromium/net/quic/quic_transport_client.h b/chromium/net/quic/quic_transport_client.h index 4f0f58ff8c8..de270225642 100644 --- a/chromium/net/quic/quic_transport_client.h +++ b/chromium/net/quic/quic_transport_client.h @@ -13,11 +13,13 @@ #include "net/quic/quic_chromium_packet_reader.h" #include "net/quic/quic_chromium_packet_writer.h" #include "net/quic/quic_context.h" +#include "net/quic/quic_transport_error.h" #include "net/socket/client_socket_factory.h" #include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.h" #include "net/third_party/quiche/src/quic/core/quic_config.h" #include "net/third_party/quiche/src/quic/core/quic_versions.h" #include "net/third_party/quiche/src/quic/quic_transport/quic_transport_client_session.h" +#include "net/third_party/quiche/src/quic/quic_transport/web_transport_fingerprint_proof_verifier.h" #include "url/gurl.h" #include "url/origin.h" @@ -27,29 +29,6 @@ class ProxyResolutionRequest; class QuicChromiumAlarmFactory; class URLRequestContext; -struct NET_EXPORT QuicTransportError { - // |net_error| is always set to a meaningful value. - int net_error = OK; - - // |quic_error| is set to a QUIC error, or to quic::QUIC_NO_ERROR if the error - // originates non-QUIC parts of the stack. - quic::QuicErrorCode quic_error = quic::QUIC_NO_ERROR; - - // Human-readable error summary. - std::string details; - - // QuicTransport requires that the connection errors have to be - // undistinguishable until the peer is confirmed to be a QuicTransport - // endpoint. See https://wicg.github.io/web-transport/#protocol-security - bool safe_to_report_details = false; -}; - -NET_EXPORT -std::string QuicTransportErrorToString(const QuicTransportError& error); - -NET_EXPORT -std::ostream& operator<<(std::ostream& os, const QuicTransportError& error); - // QuicTransportClient is the top-level API for QuicTransport in //net. class NET_EXPORT QuicTransportClient : public quic::QuicTransportClientSession::ClientVisitor, @@ -65,6 +44,9 @@ class NET_EXPORT QuicTransportClient // | | // +---> FAILED <---+ // + // These values are logged to UMA. Entries should not be renumbered and + // numeric values should never be reused. Please keep in sync with + // "QuicTransportClientState" in src/tools/metrics/histograms/enums.xml. enum State { // The client object has been created but Connect() has not been called. NEW, @@ -78,6 +60,9 @@ class NET_EXPORT QuicTransportClient CLOSED, // The connection has been closed abruptly. FAILED, + + // Total number of possible states. + NUM_STATES, }; class NET_EXPORT Visitor { @@ -97,17 +82,35 @@ class NET_EXPORT QuicTransportClient virtual void OnCanCreateNewOutgoingUnidirectionalStream() = 0; }; - // QUIC protocol version that is used in the origin trial. - static constexpr quic::ParsedQuicVersion kQuicVersionForOriginTrial = - quic::ParsedQuicVersion(quic::PROTOCOL_TLS1_3, - quic::QUIC_VERSION_IETF_DRAFT_27); + struct NET_EXPORT Parameters { + Parameters(); + ~Parameters(); + Parameters(const Parameters&); + Parameters(Parameters&&); + + // A vector of fingerprints for expected server certificates, as described + // in + // https://wicg.github.io/web-transport/#dom-quictransportconfiguration-server_certificate_fingerprints + // When empty, Web PKI is used. + std::vector<quic::CertificateFingerprint> server_certificate_fingerprints; + }; + + // QUIC protocol versions that are used in the origin trial. + static quic::ParsedQuicVersionVector + QuicVersionsForWebTransportOriginTrial() { + return quic::ParsedQuicVersionVector{ + quic::ParsedQuicVersion::Draft29(), // Enabled in M85. + quic::ParsedQuicVersion::Draft27() // Enabled in M84. + }; + } // |visitor| and |context| must outlive this object. QuicTransportClient(const GURL& url, const url::Origin& origin, Visitor* visitor, const NetworkIsolationKey& isolation_key, - URLRequestContext* context); + URLRequestContext* context, + const Parameters& parameters); ~QuicTransportClient() override; State state() const { return state_; } @@ -154,6 +157,11 @@ class NET_EXPORT QuicTransportClient private: // State of the connection establishment process. + // + // These values are logged to UMA. Entries should not be renumbered and + // numeric values should never be reused. Please keep in sync with + // "QuicTransportClientConnectState" in + // src/tools/metrics/histograms/enums.xml. enum ConnectState { CONNECT_STATE_NONE, CONNECT_STATE_INIT, @@ -163,6 +171,8 @@ class NET_EXPORT QuicTransportClient CONNECT_STATE_RESOLVE_HOST_COMPLETE, CONNECT_STATE_CONNECT, CONNECT_STATE_CONFIRM_CONNECTION, + + CONNECT_STATE_NUM_STATES, }; // DoLoop processing the Connect() call. @@ -177,6 +187,7 @@ class NET_EXPORT QuicTransportClient int DoResolveHostComplete(int rv); // Establishes the QUIC connection. int DoConnect(); + void CreateConnection(); // Verifies that the connection has succeeded. int DoConfirmConnection(); @@ -201,6 +212,7 @@ class NET_EXPORT QuicTransportClient State state_ = NEW; ConnectState next_connect_state_ = CONNECT_STATE_NONE; QuicTransportError error_; + bool retried_with_new_version_ = false; ProxyInfo proxy_info_; std::unique_ptr<ProxyResolutionRequest> proxy_resolution_request_; diff --git a/chromium/net/quic/quic_transport_end_to_end_test.cc b/chromium/net/quic/quic_transport_end_to_end_test.cc index 9783a05ac60..95ae1538fa6 100644 --- a/chromium/net/quic/quic_transport_end_to_end_test.cc +++ b/chromium/net/quic/quic_transport_end_to_end_test.cc @@ -10,6 +10,7 @@ #include "net/cert/mock_cert_verifier.h" #include "net/dns/mock_host_resolver.h" #include "net/proxy_resolution/configured_proxy_resolution_service.h" +#include "net/quic/crypto/proof_source_chromium.h" #include "net/test/test_data_directory.h" #include "net/test/test_with_task_environment.h" #include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h" @@ -37,10 +38,48 @@ class MockVisitor : public QuicTransportClient::Visitor { MOCK_METHOD0(OnCanCreateNewOutgoingUnidirectionalStream, void()); }; +// A clock that only mocks out WallNow(), but uses real Now() and +// ApproximateNow(). Useful for certificate verification. +class TestWallClock : public quic::QuicClock { + public: + quic::QuicTime Now() const override { + return quic::QuicChromiumClock::GetInstance()->Now(); + } + quic::QuicTime ApproximateNow() const override { + return quic::QuicChromiumClock::GetInstance()->ApproximateNow(); + } + quic::QuicWallTime WallNow() const override { return wall_now_; } + + void set_wall_now(quic::QuicWallTime now) { wall_now_ = now; } + + private: + quic::QuicWallTime wall_now_ = quic::QuicWallTime::Zero(); +}; + +class TestConnectionHelper : public quic::QuicConnectionHelperInterface { + public: + const quic::QuicClock* GetClock() const override { return &clock_; } + quic::QuicRandom* GetRandomGenerator() override { + return quic::QuicRandom::GetInstance(); + } + quic::QuicBufferAllocator* GetStreamSendBufferAllocator() override { + return &allocator_; + } + + TestWallClock& clock() { return clock_; } + + private: + TestWallClock clock_; + quic::SimpleBufferAllocator allocator_; +}; + class QuicTransportEndToEndTest : public TestWithTaskEnvironment { public: QuicTransportEndToEndTest() { - quic::QuicEnableVersion(QuicTransportClient::kQuicVersionForOriginTrial); + for (const quic::ParsedQuicVersion& version : + QuicTransportClient::QuicVersionsForWebTransportOriginTrial()) { + quic::QuicEnableVersion(version); + } origin_ = url::Origin::Create(GURL{"https://example.org"}); isolation_key_ = NetworkIsolationKey(origin_, origin_); @@ -56,7 +95,9 @@ class QuicTransportEndToEndTest : public TestWithTaskEnvironment { host_resolver->rules()->AddRule("test.example.com", "127.0.0.1"); builder.set_host_resolver(std::move(host_resolver)); - auto quic_context = std::make_unique<QuicContext>(); + auto helper = std::make_unique<TestConnectionHelper>(); + helper_ = helper.get(); + auto quic_context = std::make_unique<QuicContext>(std::move(helper)); quic_context->params()->supported_versions.clear(); // This is required to bypass the check that only allows known certificate // roots in QUIC. @@ -75,8 +116,6 @@ class QuicTransportEndToEndTest : public TestWithTaskEnvironment { LOG(INFO) << "Connection error: " << client_->error(); run_loop_->Quit(); }); - - StartServer(); } GURL GetURL(const std::string& suffix) { @@ -84,10 +123,13 @@ class QuicTransportEndToEndTest : public TestWithTaskEnvironment { "quic-transport://test.example.com:", port_, suffix)}; } - void StartServer() { + void StartServer(std::unique_ptr<quic::ProofSource> proof_source = nullptr) { + if (proof_source == nullptr) { + proof_source = quic::test::crypto_test_utils::ProofSourceForTesting(); + } server_ = std::make_unique<QuicTransportSimpleServer>( /* port */ 0, std::vector<url::Origin>({origin_}), - quic::test::crypto_test_utils::ProofSourceForTesting()); + std::move(proof_source)); ASSERT_EQ(EXIT_SUCCESS, server_->Start()); port_ = server_->server_address().port(); } @@ -105,6 +147,7 @@ class QuicTransportEndToEndTest : public TestWithTaskEnvironment { QuicFlagSaver flags_; // Save/restore all QUIC flag values. std::unique_ptr<URLRequestContext> context_; std::unique_ptr<QuicTransportClient> client_; + TestConnectionHelper* helper_; // Owned by |context_|. MockVisitor visitor_; std::unique_ptr<QuicTransportSimpleServer> server_; std::unique_ptr<base::RunLoop> run_loop_; @@ -115,8 +158,10 @@ class QuicTransportEndToEndTest : public TestWithTaskEnvironment { }; TEST_F(QuicTransportEndToEndTest, Connect) { + StartServer(); client_ = std::make_unique<QuicTransportClient>( - GetURL("/discard"), origin_, &visitor_, isolation_key_, context_.get()); + GetURL("/discard"), origin_, &visitor_, isolation_key_, context_.get(), + QuicTransportClient::Parameters()); client_->Connect(); EXPECT_CALL(visitor_, OnConnected()).WillOnce(StopRunning()); Run(); @@ -125,8 +170,10 @@ TEST_F(QuicTransportEndToEndTest, Connect) { } TEST_F(QuicTransportEndToEndTest, EchoUnidirectionalStream) { + StartServer(); client_ = std::make_unique<QuicTransportClient>( - GetURL("/echo"), origin_, &visitor_, isolation_key_, context_.get()); + GetURL("/echo"), origin_, &visitor_, isolation_key_, context_.get(), + QuicTransportClient::Parameters()); client_->Connect(); EXPECT_CALL(visitor_, OnConnected()).WillOnce(StopRunning()); Run(); @@ -151,6 +198,107 @@ TEST_F(QuicTransportEndToEndTest, EchoUnidirectionalStream) { EXPECT_EQ("test", data); } +TEST_F(QuicTransportEndToEndTest, CertificateFingerprint) { + auto proof_source = std::make_unique<net::ProofSourceChromium>(); + base::FilePath certs_dir = net::GetTestCertsDirectory(); + ASSERT_TRUE(proof_source->Initialize( + certs_dir.AppendASCII("quic-short-lived.pem"), + certs_dir.AppendASCII("quic-leaf-cert.key"), + certs_dir.AppendASCII("quic-leaf-cert.key.sct"))); + StartServer(std::move(proof_source)); + // Set clock to a time in which quic-short-lived.pem is valid + // (2020-06-05T20:35:00.000Z). + helper_->clock().set_wall_now( + quic::QuicWallTime::FromUNIXSeconds(1591389300)); + + QuicTransportClient::Parameters parameters; + parameters.server_certificate_fingerprints.push_back( + quic::CertificateFingerprint{ + .algorithm = quic::CertificateFingerprint::kSha256, + .fingerprint = "ED:3D:D7:C3:67:10:94:68:D1:DC:D1:26:5C:B2:74:D7:1C:" + "A2:63:3E:94:94:C0:84:39:D6:64:FA:08:B9:77:37"}); + client_ = std::make_unique<QuicTransportClient>(GetURL("/discard"), origin_, + &visitor_, isolation_key_, + context_.get(), parameters); + client_->Connect(); + EXPECT_CALL(visitor_, OnConnected()).WillOnce(StopRunning()); + Run(); + ASSERT_TRUE(client_->session() != nullptr); + EXPECT_TRUE(client_->session()->IsSessionReady()); +} + +TEST_F(QuicTransportEndToEndTest, CertificateFingerprintValidiyTooLong) { + StartServer(); + QuicTransportClient::Parameters parameters; + // The default QUIC test certificate is valid for ten years, which exceeds + // the two-week limit. + parameters.server_certificate_fingerprints.push_back( + quic::CertificateFingerprint{ + .algorithm = quic::CertificateFingerprint::kSha256, + .fingerprint = "25:17:B1:79:76:C8:94:BD:F0:B5:5C:0B:CC:70:C8:69:2B:" + "27:B8:84:F0:30:FE:A8:62:99:37:63:D2:A9:D6:EE"}); + client_ = std::make_unique<QuicTransportClient>(GetURL("/discard"), origin_, + &visitor_, isolation_key_, + context_.get(), parameters); + client_->Connect(); + EXPECT_CALL(visitor_, OnConnectionFailed()).WillOnce(StopRunning()); + Run(); + EXPECT_TRUE(client_->session() == nullptr); + EXPECT_EQ(client_->error().quic_error, quic::QUIC_HANDSHAKE_FAILED); +} + +TEST_F(QuicTransportEndToEndTest, CertificateFingerprintMismatch) { + StartServer(); + + QuicTransportClient::Parameters parameters; + parameters.server_certificate_fingerprints.push_back( + quic::CertificateFingerprint{ + .algorithm = quic::CertificateFingerprint::kSha256, + .fingerprint = "00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:" + "00:00:00:00:00:00:00:00:00:00:00:00:00:00:00"}); + client_ = std::make_unique<QuicTransportClient>(GetURL("/discard"), origin_, + &visitor_, isolation_key_, + context_.get(), parameters); + client_->Connect(); + EXPECT_CALL(visitor_, OnConnectionFailed()).WillOnce(StopRunning()); + Run(); + EXPECT_TRUE(client_->session() == nullptr); + EXPECT_EQ(client_->error().quic_error, quic::QUIC_HANDSHAKE_FAILED); +} + +TEST_F(QuicTransportEndToEndTest, OldVersion) { + // Ensure all WebTransport versions are enabled except the first one. + quic::QuicDisableVersion( + QuicTransportClient::QuicVersionsForWebTransportOriginTrial().front()); + + StartServer(); + client_ = std::make_unique<QuicTransportClient>( + GetURL("/discard"), origin_, &visitor_, isolation_key_, context_.get(), + QuicTransportClient::Parameters()); + client_->Connect(); + EXPECT_CALL(visitor_, OnConnected()).WillOnce(StopRunning()); + Run(); + ASSERT_TRUE(client_->session() != nullptr); + EXPECT_TRUE(client_->session()->IsSessionReady()); +} + +TEST_F(QuicTransportEndToEndTest, NoCommonVersion) { + // Disable all WebTransport versions. + for (const quic::ParsedQuicVersion& version : + QuicTransportClient::QuicVersionsForWebTransportOriginTrial()) { + quic::QuicDisableVersion(version); + } + + StartServer(); + client_ = std::make_unique<QuicTransportClient>( + GetURL("/discard"), origin_, &visitor_, isolation_key_, context_.get(), + QuicTransportClient::Parameters()); + client_->Connect(); + EXPECT_CALL(visitor_, OnConnectionFailed()).WillOnce(StopRunning()); + Run(); + EXPECT_TRUE(client_->session() == nullptr); + EXPECT_EQ(client_->error().quic_error, quic::QUIC_INVALID_VERSION); +} } // namespace } // namespace test } // namespace net diff --git a/chromium/net/quic/quic_transport_error.cc b/chromium/net/quic/quic_transport_error.cc new file mode 100644 index 00000000000..8c76d6705e9 --- /dev/null +++ b/chromium/net/quic/quic_transport_error.cc @@ -0,0 +1,24 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/quic/quic_transport_error.h" + +#include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h" + +namespace net { + +std::string QuicTransportErrorToString(const QuicTransportError& error) { + std::string message = + ExtendedErrorToString(error.net_error, error.quic_error); + if (error.details == message) + return message; + return quiche::QuicheStrCat(message, " (", error.details, ")"); +} + +std::ostream& operator<<(std::ostream& os, const QuicTransportError& error) { + os << QuicTransportErrorToString(error); + return os; +} + +} // namespace net diff --git a/chromium/net/quic/quic_transport_error.h b/chromium/net/quic/quic_transport_error.h new file mode 100644 index 00000000000..d970e094074 --- /dev/null +++ b/chromium/net/quic/quic_transport_error.h @@ -0,0 +1,53 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NET_QUIC_QUIC_TRANSPORT_ERROR_H_ +#define NET_QUIC_QUIC_TRANSPORT_ERROR_H_ + +#include <ostream> +#include <string> + +#include "base/strings/string_piece.h" +#include "net/base/net_errors.h" +#include "net/base/net_export.h" +#include "net/third_party/quiche/src/quic/core/quic_error_codes.h" + +namespace net { + +struct NET_EXPORT QuicTransportError { + QuicTransportError() = default; + QuicTransportError(int net_error, + quic::QuicErrorCode quic_error, + base::StringPiece details, + bool safe_to_report_details) + : net_error(net_error), + quic_error(quic_error), + details(details), + safe_to_report_details(safe_to_report_details) {} + + // |net_error| is always set to a meaningful value. + int net_error = OK; + + // |quic_error| is set to a QUIC error, or to quic::QUIC_NO_ERROR if the error + // originates non-QUIC parts of the stack. + quic::QuicErrorCode quic_error = quic::QUIC_NO_ERROR; + + // Human-readable error summary. + std::string details; + + // QuicTransport requires that the connection errors have to be + // undistinguishable until the peer is confirmed to be a QuicTransport + // endpoint. See https://wicg.github.io/web-transport/#protocol-security + bool safe_to_report_details = false; +}; + +NET_EXPORT +std::string QuicTransportErrorToString(const QuicTransportError& error); + +NET_EXPORT +std::ostream& operator<<(std::ostream& os, const QuicTransportError& error); + +} // namespace net + +#endif // NET_QUIC_QUIC_TRANSPORT_ERROR_H_ diff --git a/chromium/net/quic/quic_transport_parameters_fuzzer.cc b/chromium/net/quic/quic_transport_parameters_fuzzer.cc index 4225bc00b6b..e6b1b129f7a 100644 --- a/chromium/net/quic/quic_transport_parameters_fuzzer.cc +++ b/chromium/net/quic/quic_transport_parameters_fuzzer.cc @@ -19,14 +19,8 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { quic::TransportParameters transport_parameters; std::vector<uint8_t> remaining_bytes = data_provider.ConsumeRemainingBytes<uint8_t>(); - quic::ParsedQuicVersion version = quic::UnsupportedQuicVersion(); - for (const quic::ParsedQuicVersion& vers : quic::AllSupportedVersions()) { - if (vers.handshake_protocol == quic::PROTOCOL_TLS1_3) { - version = vers; - break; - } - } - CHECK_NE(version.transport_version, quic::QUIC_VERSION_UNSUPPORTED); + quic::ParsedQuicVersion version = quic::AllSupportedVersionsWithTls().front(); + CHECK(version.UsesTls()); std::string error_details; quic::ParseTransportParameters(version, perspective, remaining_bytes.data(), remaining_bytes.size(), &transport_parameters, diff --git a/chromium/net/quic/quic_utils_chromium.cc b/chromium/net/quic/quic_utils_chromium.cc deleted file mode 100644 index 90e08fcfa11..00000000000 --- a/chromium/net/quic/quic_utils_chromium.cc +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/quic/quic_utils_chromium.h" - -#include "base/containers/adapters.h" -#include "base/strings/string_split.h" -#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" - -namespace net { - -quic::QuicTagVector ParseQuicConnectionOptions( - const std::string& connection_options) { - quic::QuicTagVector options; - // Tokens are expected to be no more than 4 characters long, but - // handle overflow gracefully. - for (const quiche::QuicheStringPiece& token : - base::SplitStringPiece(connection_options, ",", base::TRIM_WHITESPACE, - base::SPLIT_WANT_ALL)) { - uint32_t option = 0; - for (char token_char : base::Reversed(token)) { - option <<= 8; - option |= static_cast<unsigned char>(token_char); - } - options.push_back(option); - } - return options; -} - -} // namespace net diff --git a/chromium/net/quic/quic_utils_chromium.h b/chromium/net/quic/quic_utils_chromium.h deleted file mode 100644 index 7f8a7de9064..00000000000 --- a/chromium/net/quic/quic_utils_chromium.h +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// -// Some helpers for quic that are for chromium codebase. - -#ifndef NET_QUIC_QUIC_UTILS_CHROMIUM_H_ -#define NET_QUIC_QUIC_UTILS_CHROMIUM_H_ - -#include <string> - -#include "base/logging.h" -#include "net/base/net_export.h" -#include "net/third_party/quiche/src/quic/core/quic_tag.h" -#include "net/third_party/quiche/src/quic/core/quic_versions.h" - -namespace net { - -// Returns the list of QUIC tags represented by the comma separated -// string in |connection_options|. -NET_EXPORT quic::QuicTagVector ParseQuicConnectionOptions( - const std::string& connection_options); - -} // namespace net - -#endif // NET_QUIC_QUIC_UTILS_CHROMIUM_H_ diff --git a/chromium/net/quic/quic_utils_chromium_test.cc b/chromium/net/quic/quic_utils_chromium_test.cc deleted file mode 100644 index 2af22a0d5e3..00000000000 --- a/chromium/net/quic/quic_utils_chromium_test.cc +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/quic/quic_utils_chromium.h" - -#include <map> - -#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -using ::testing::ElementsAre; -using ::testing::IsEmpty; - -namespace net { -namespace test { -namespace { - -TEST(QuicUtilsChromiumTest, ParseQuicConnectionOptions) { - quic::QuicTagVector empty_options = ParseQuicConnectionOptions(""); - EXPECT_TRUE(empty_options.empty()); - - quic::QuicTagVector parsed_options = - ParseQuicConnectionOptions("TIMER,TBBR,REJ"); - quic::QuicTagVector expected_options; - expected_options.push_back(quic::kTIME); - expected_options.push_back(quic::kTBBR); - expected_options.push_back(quic::kREJ); - EXPECT_EQ(expected_options, parsed_options); -} - -} // namespace -} // namespace test -} // namespace net diff --git a/chromium/net/quiche/common/platform/impl/quiche_logging_impl.h b/chromium/net/quiche/common/platform/impl/quiche_logging_impl.h index d3261b023f3..0d1d111be61 100644 --- a/chromium/net/quiche/common/platform/impl/quiche_logging_impl.h +++ b/chromium/net/quiche/common/platform/impl/quiche_logging_impl.h @@ -5,7 +5,9 @@ #ifndef NET_QUICHE_COMMON_PLATFORM_IMPL_QUICHE_LOGGING_IMPL_H_ #define NET_QUICHE_COMMON_PLATFORM_IMPL_QUICHE_LOGGING_IMPL_H_ +#include "base/check_op.h" #include "base/logging.h" +#include "base/notreached.h" #include "build/build_config.h" #include "net/base/net_export.h" diff --git a/chromium/net/quiche/common/platform/impl/quiche_optional_impl.h b/chromium/net/quiche/common/platform/impl/quiche_optional_impl.h index bbdb0a80308..9d1648695bc 100644 --- a/chromium/net/quiche/common/platform/impl/quiche_optional_impl.h +++ b/chromium/net/quiche/common/platform/impl/quiche_optional_impl.h @@ -12,7 +12,7 @@ namespace quiche { template <typename T> using QuicheOptionalImpl = base::Optional<T>; -#define QuicheNullOptImpl base::nullopt +#define QUICHE_NULLOPT_IMPL base::nullopt } // namespace quiche diff --git a/chromium/net/quiche/common/platform/impl/quiche_time_utils_impl.cc b/chromium/net/quiche/common/platform/impl/quiche_time_utils_impl.cc new file mode 100644 index 00000000000..7c78cbc5bcb --- /dev/null +++ b/chromium/net/quiche/common/platform/impl/quiche_time_utils_impl.cc @@ -0,0 +1,50 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/quiche/common/platform/impl/quiche_time_utils_impl.h" + +#include "base/time/time.h" + +#include <iostream> + +namespace quiche { +QuicheOptional<int64_t> QuicheUtcDateTimeToUnixSecondsInner(int year, + int month, + int day, + int hour, + int minute, + int second) { + base::Time::Exploded exploded{ + year, month, + 0, // day_of_week + day, hour, minute, second, + }; + base::Time time; + if (!base::Time::FromUTCExploded(exploded, &time)) { + return base::nullopt; + } + return (time - base::Time::UnixEpoch()).InSeconds(); +} + +QuicheOptional<int64_t> QuicheUtcDateTimeToUnixSecondsImpl(int year, + int month, + int day, + int hour, + int minute, + int second) { + // Handle leap seconds without letting any other irregularities happen. + if (second == 60) { + auto previous_second = QuicheUtcDateTimeToUnixSecondsInner( + year, month, day, hour, minute, second - 1); + if (!previous_second.has_value()) { + return base::nullopt; + } + return *previous_second + 1; + } + + return QuicheUtcDateTimeToUnixSecondsInner(year, month, day, hour, minute, + second); +} + +} // namespace quiche diff --git a/chromium/net/quiche/common/platform/impl/quiche_time_utils_impl.h b/chromium/net/quiche/common/platform/impl/quiche_time_utils_impl.h new file mode 100644 index 00000000000..60dda04eb65 --- /dev/null +++ b/chromium/net/quiche/common/platform/impl/quiche_time_utils_impl.h @@ -0,0 +1,25 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NET_QUICHE_COMMON_PLATFORM_IMPL_QUICHE_TIME_UTILS_IMPL_H_ +#define NET_QUICHE_COMMON_PLATFORM_IMPL_QUICHE_TIME_UTILS_IMPL_H_ + +#include <cstdint> + +#include "net/base/net_export.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_optional.h" + +namespace quiche { + +NET_EXPORT_PRIVATE QuicheOptional<int64_t> QuicheUtcDateTimeToUnixSecondsImpl( + int year, + int month, + int day, + int hour, + int minute, + int second); + +} // namespace quiche + +#endif // NET_QUICHE_COMMON_PLATFORM_IMPL_QUICHE_TIME_UTILS_IMPL_H_ diff --git a/chromium/net/reporting/reporting_browsing_data_remover.cc b/chromium/net/reporting/reporting_browsing_data_remover.cc index 310242aa14a..084b8d6c96f 100644 --- a/chromium/net/reporting/reporting_browsing_data_remover.cc +++ b/chromium/net/reporting/reporting_browsing_data_remover.cc @@ -15,7 +15,7 @@ namespace net { // static void ReportingBrowsingDataRemover::RemoveBrowsingData( ReportingCache* cache, - int data_type_mask, + uint64_t data_type_mask, const base::RepeatingCallback<bool(const GURL&)>& origin_filter) { if ((data_type_mask & DATA_TYPE_REPORTS) != 0) { std::vector<const ReportingReport*> all_reports; @@ -42,8 +42,9 @@ void ReportingBrowsingDataRemover::RemoveBrowsingData( } // static -void ReportingBrowsingDataRemover::RemoveAllBrowsingData(ReportingCache* cache, - int data_type_mask) { +void ReportingBrowsingDataRemover::RemoveAllBrowsingData( + ReportingCache* cache, + uint64_t data_type_mask) { if ((data_type_mask & DATA_TYPE_REPORTS) != 0) { cache->RemoveAllReports( ReportingReport::Outcome::ERASED_BROWSING_DATA_REMOVED); diff --git a/chromium/net/reporting/reporting_browsing_data_remover.h b/chromium/net/reporting/reporting_browsing_data_remover.h index ce3df31ffc0..f4a9e2b68b9 100644 --- a/chromium/net/reporting/reporting_browsing_data_remover.h +++ b/chromium/net/reporting/reporting_browsing_data_remover.h @@ -32,13 +32,14 @@ class NET_EXPORT ReportingBrowsingDataRemover { // persisted, it will need to be cleared as well. static void RemoveBrowsingData( ReportingCache* cache, - int data_type_mask, + uint64_t data_type_mask, const base::RepeatingCallback<bool(const GURL&)>& origin_filter); // Like RemoveBrowsingData except removes data for all origins without a // filter. Allows slight optimization over passing an always-true filter to // RemoveBrowsingData. - static void RemoveAllBrowsingData(ReportingCache* cache, int data_type_mask); + static void RemoveAllBrowsingData(ReportingCache* cache, + uint64_t data_type_mask); private: DISALLOW_IMPLICIT_CONSTRUCTORS(ReportingBrowsingDataRemover); diff --git a/chromium/net/reporting/reporting_browsing_data_remover_unittest.cc b/chromium/net/reporting/reporting_browsing_data_remover_unittest.cc index 1ddb5c266ad..687bf5a4e95 100644 --- a/chromium/net/reporting/reporting_browsing_data_remover_unittest.cc +++ b/chromium/net/reporting/reporting_browsing_data_remover_unittest.cc @@ -24,7 +24,7 @@ class ReportingBrowsingDataRemoverTest : public ReportingTestBase { void RemoveBrowsingData(bool remove_reports, bool remove_clients, std::string host) { - int data_type_mask = 0; + uint64_t data_type_mask = 0; if (remove_reports) data_type_mask |= ReportingBrowsingDataRemover::DATA_TYPE_REPORTS; if (remove_clients) @@ -43,15 +43,15 @@ class ReportingBrowsingDataRemoverTest : public ReportingTestBase { // TODO(chlily): Take NIK. void AddReport(const GURL& url) { - cache()->AddReport(NetworkIsolationKey::Todo(), url, kUserAgent_, kGroup_, - kType_, std::make_unique<base::DictionaryValue>(), 0, + cache()->AddReport(NetworkIsolationKey(), url, kUserAgent_, kGroup_, kType_, + std::make_unique<base::DictionaryValue>(), 0, tick_clock()->NowTicks(), 0); } // TODO(chlily): Take NIK. void SetEndpoint(const url::Origin& origin) { SetEndpointInCache( - ReportingEndpointGroupKey(NetworkIsolationKey::Todo(), origin, kGroup_), + ReportingEndpointGroupKey(NetworkIsolationKey(), origin, kGroup_), kEndpoint_, base::Time::Now() + base::TimeDelta::FromDays(7)); } @@ -154,14 +154,12 @@ TEST_F(ReportingBrowsingDataRemoverTest, RemoveSomeClients) { RemoveBrowsingData(/* remove_reports= */ false, /* remove_clients= */ true, /* host= */ kUrl1_.host()); EXPECT_EQ(2u, report_count()); - EXPECT_FALSE( - FindEndpointInCache(ReportingEndpointGroupKey(NetworkIsolationKey::Todo(), - kOrigin1_, kGroup_), - kEndpoint_)); - EXPECT_TRUE( - FindEndpointInCache(ReportingEndpointGroupKey(NetworkIsolationKey::Todo(), - kOrigin2_, kGroup_), - kEndpoint_)); + EXPECT_FALSE(FindEndpointInCache( + ReportingEndpointGroupKey(NetworkIsolationKey(), kOrigin1_, kGroup_), + kEndpoint_)); + EXPECT_TRUE(FindEndpointInCache( + ReportingEndpointGroupKey(NetworkIsolationKey(), kOrigin2_, kGroup_), + kEndpoint_)); } } // namespace diff --git a/chromium/net/reporting/reporting_cache_impl.cc b/chromium/net/reporting/reporting_cache_impl.cc index 14fc211c02d..7b4e0345b27 100644 --- a/chromium/net/reporting/reporting_cache_impl.cc +++ b/chromium/net/reporting/reporting_cache_impl.cc @@ -176,15 +176,11 @@ void ReportingCacheImpl::IncrementEndpointDeliveries( void ReportingCacheImpl::RemoveReports( const std::vector<const ReportingReport*>& reports, ReportingReport::Outcome outcome) { - base::Optional<base::TimeTicks> delivered = base::nullopt; - if (outcome == ReportingReport::Outcome::DELIVERED) - delivered = tick_clock().NowTicks(); for (const ReportingReport* report : reports) { auto it = reports_.find(report); DCHECK(it != reports_.end()); it->get()->outcome = outcome; - it->get()->delivered = delivered; if (it->get()->IsUploadPending()) { it->get()->status = ReportingReport::Status::DOOMED; diff --git a/chromium/net/reporting/reporting_delivery_agent.cc b/chromium/net/reporting/reporting_delivery_agent.cc index fca2421b239..80a7a8c9e75 100644 --- a/chromium/net/reporting/reporting_delivery_agent.cc +++ b/chromium/net/reporting/reporting_delivery_agent.cc @@ -4,9 +4,10 @@ #include "net/reporting/reporting_delivery_agent.h" +#include <algorithm> #include <map> +#include <set> #include <string> -#include <unordered_set> #include <utility> #include <vector> @@ -17,6 +18,7 @@ #include "base/timer/timer.h" #include "base/values.h" #include "net/base/network_isolation_key.h" +#include "net/base/url_util.h" #include "net/reporting/reporting_cache.h" #include "net/reporting/reporting_cache_observer.h" #include "net/reporting/reporting_context.h" @@ -31,9 +33,9 @@ namespace net { namespace { -void SerializeReports(const std::vector<const ReportingReport*>& reports, - base::TimeTicks now, - std::string* json_out) { +using ReportList = std::vector<const ReportingReport*>; + +std::string SerializeReports(const ReportList& reports, base::TimeTicks now) { base::ListValue reports_value; for (const ReportingReport* report : reports) { @@ -49,10 +51,112 @@ void SerializeReports(const std::vector<const ReportingReport*>& reports, reports_value.Append(std::move(report_value)); } - bool json_written = base::JSONWriter::Write(reports_value, json_out); + std::string json_out; + bool json_written = base::JSONWriter::Write(reports_value, &json_out); DCHECK(json_written); + return json_out; +} + +bool CompareReportGroupKeys(const ReportingReport* lhs, + const ReportingReport* rhs) { + return lhs->GetGroupKey() < rhs->GetGroupKey(); } +// Each Delivery corresponds to one upload URLRequest. +class Delivery { + public: + // The target of a delivery. All reports uploaded together must share the + // same values for these parameters. + // Note that |origin| here (which matches the report's |origin|) is not + // necessarily the same as the |origin| of the ReportingEndpoint's group key + // (if the endpoint is configured to include subdomains). Reports with + // different group keys can be in the same delivery, as long as the NIK and + // report origin are the same, and they all get assigned to the same endpoint + // URL. + struct Target { + Target(const NetworkIsolationKey& network_isolation_key, + const url::Origin& origin, + const GURL& endpoint_url) + : network_isolation_key(network_isolation_key), + origin(origin), + endpoint_url(endpoint_url) {} + + ~Target() = default; + + bool operator<(const Target& other) const { + return std::tie(network_isolation_key, origin, endpoint_url) < + std::tie(other.network_isolation_key, other.origin, + other.endpoint_url); + } + + NetworkIsolationKey network_isolation_key; + url::Origin origin; + GURL endpoint_url; + }; + + explicit Delivery(const Target& target) : target_(target) {} + + ~Delivery() = default; + + // Add the reports in [reports_begin, reports_end) into this delivery. + // Modify the report counter for the |endpoint| to which this delivery is + // destined. + void AddReports(const ReportingEndpoint& endpoint, + const ReportList::const_iterator reports_begin, + const ReportList::const_iterator reports_end) { + DCHECK(reports_begin != reports_end); + DCHECK_EQ(endpoint.group_key.network_isolation_key, + network_isolation_key()); + DCHECK(IsSubdomainOf(target_.origin.host() /* subdomain */, + endpoint.group_key.origin.host() /* superdomain */)); + for (auto it = reports_begin; it != reports_end; ++it) { + DCHECK_EQ((*reports_begin)->GetGroupKey(), (*it)->GetGroupKey()); + DCHECK_EQ((*it)->network_isolation_key, network_isolation_key()); + DCHECK_EQ(url::Origin::Create((*it)->url), target_.origin); + DCHECK_EQ((*it)->group, endpoint.group_key.group_name); + // Report origin is equal to, or a subdomain of, the endpoint + // configuration's origin. + DCHECK(IsSubdomainOf((*it)->url.host_piece() /* subdomain */, + endpoint.group_key.origin.host() /* superdomain */)); + } + + reports_per_group_[endpoint.group_key] += + std::distance(reports_begin, reports_end); + reports_.insert(reports_.end(), reports_begin, reports_end); + } + + // Records statistics for reports after an upload has completed. + // Either removes successfully delivered reports, or increments the failure + // counter if delivery was unsuccessful. + void ProcessOutcome(ReportingCache* cache, bool success) { + for (const auto& group_name_and_count : reports_per_group_) { + cache->IncrementEndpointDeliveries(group_name_and_count.first, + target_.endpoint_url, + group_name_and_count.second, success); + } + if (success) { + cache->RemoveReports(reports_, ReportingReport::Outcome::DELIVERED); + } else { + cache->IncrementReportsAttempts(reports_); + } + } + + const NetworkIsolationKey& network_isolation_key() const { + return target_.network_isolation_key; + } + const GURL& endpoint_url() const { return target_.endpoint_url; } + const ReportList& reports() const { return reports_; } + + private: + const Target target_; + ReportList reports_; + + // Used to track statistics for each ReportingEndpoint. + // The endpoint is uniquely identified by the key in conjunction with + // |target_.endpoint_url|. See ProcessOutcome(). + std::map<ReportingEndpointGroupKey, int> reports_per_group_; +}; + class ReportingDeliveryAgentImpl : public ReportingDeliveryAgent, public ReportingCacheObserver { public: @@ -89,33 +193,8 @@ class ReportingDeliveryAgentImpl : public ReportingDeliveryAgent, } private: - // TODO(chlily): Add NIK. - using OriginEndpoint = std::pair<url::Origin, GURL>; - using GroupEndpoint = std::pair<ReportingEndpointGroupKey, GURL>; - - class Delivery { - public: - explicit Delivery(const OriginEndpoint& report_origin_endpoint) - : report_origin(report_origin_endpoint.first), - endpoint(report_origin_endpoint.second) {} - - ~Delivery() = default; - - void AddReports(const ReportingEndpoint& endpoint, - const std::vector<const ReportingReport*>& to_add) { - GroupEndpoint key = std::make_pair(endpoint.group_key, endpoint.info.url); - reports_per_endpoint[key] += to_add.size(); - reports.insert(reports.end(), to_add.begin(), to_add.end()); - } - - const url::Origin report_origin; - const GURL endpoint; - std::vector<const ReportingReport*> reports; - std::map<GroupEndpoint, int> reports_per_endpoint; - }; - bool CacheHasReports() { - std::vector<const ReportingReport*> reports; + ReportList reports; context_->cache()->GetReports(&reports); return !reports.empty(); } @@ -134,8 +213,9 @@ class ReportingDeliveryAgentImpl : public ReportingDeliveryAgent, } void SendReports() { - std::vector<const ReportingReport*> reports = - cache()->GetReportsToDeliver(); + ReportList reports = cache()->GetReportsToDeliver(); + if (reports.empty()) + return; // First determine which origins we're allowed to upload reports about. std::set<url::Origin> report_origins; @@ -148,84 +228,79 @@ class ReportingDeliveryAgentImpl : public ReportingDeliveryAgent, weak_factory_.GetWeakPtr(), std::move(reports))); } - void OnSendPermissionsChecked(std::vector<const ReportingReport*> reports, + void OnSendPermissionsChecked(ReportList reports, std::set<url::Origin> allowed_report_origins) { - // Sort reports into buckets by endpoint group. - std::map<ReportingEndpointGroupKey, std::vector<const ReportingReport*>> - origin_group_reports; - for (const ReportingReport* report : reports) { - url::Origin report_origin = url::Origin::Create(report->url); - if (allowed_report_origins.find(report_origin) == - allowed_report_origins.end()) { + DCHECK(!reports.empty()); + std::map<Delivery::Target, std::unique_ptr<Delivery>> deliveries; + + // Sort by group key + std::sort(reports.begin(), reports.end(), &CompareReportGroupKeys); + + // Iterate over "buckets" of reports with the same group key. + for (auto bucket_it = reports.begin(); bucket_it != reports.end();) { + auto bucket_start = bucket_it; + // Set the iterator to the beginning of the next group bucket. + bucket_it = std::upper_bound(bucket_it, reports.end(), *bucket_it, + &CompareReportGroupKeys); + + // Skip this group if we don't have origin permissions for this origin. + const ReportingEndpointGroupKey& report_group_key = + (*bucket_start)->GetGroupKey(); + if (!base::Contains(allowed_report_origins, report_group_key.origin)) continue; - } - // TODO(chlily): Use proper NIK once reports are double-keyed. - ReportingEndpointGroupKey group_key(NetworkIsolationKey::Todo(), - report_origin, report->group); - origin_group_reports[group_key].push_back(report); - } - // Find an endpoint for each (origin, group) bucket and sort reports into - // endpoint buckets. Don't allow concurrent deliveries to the same (origin, - // group) bucket. - std::map<OriginEndpoint, std::unique_ptr<Delivery>> deliveries; - for (auto& it : origin_group_reports) { - const ReportingEndpointGroupKey& group_key = it.first; - - if (base::Contains(pending_groups_, group_key)) + // Skip this group if there is already a pending upload for it. + // We don't allow multiple concurrent uploads for the same group. + if (base::Contains(pending_groups_, report_group_key)) continue; + // Find an endpoint to deliver these reports to. const ReportingEndpoint endpoint = - endpoint_manager_->FindEndpointForDelivery(group_key); - - if (!endpoint) { - // TODO(chlily): Remove reports for which there are no valid - // delivery endpoints. + endpoint_manager_->FindEndpointForDelivery(report_group_key); + // TODO(chlily): Remove reports for which there are no valid delivery + // endpoints. + if (!endpoint) continue; - } - OriginEndpoint report_origin_endpoint(group_key.origin, - endpoint.info.url); - Delivery* delivery; - auto delivery_it = deliveries.find(report_origin_endpoint); + pending_groups_.insert(report_group_key); + + // Add the reports to the appropriate delivery. + Delivery::Target target(report_group_key.network_isolation_key, + report_group_key.origin, endpoint.info.url); + auto delivery_it = deliveries.find(target); if (delivery_it == deliveries.end()) { - auto new_delivery = std::make_unique<Delivery>(report_origin_endpoint); - delivery = new_delivery.get(); - deliveries[report_origin_endpoint] = std::move(new_delivery); - } else { - delivery = delivery_it->second.get(); + bool inserted; + auto new_delivery = std::make_unique<Delivery>(target); + std::tie(delivery_it, inserted) = deliveries.insert( + std::make_pair(std::move(target), std::move(new_delivery))); + DCHECK(inserted); } - - delivery->AddReports(endpoint, it.second); - pending_groups_.insert(group_key); + delivery_it->second->AddReports(endpoint, bucket_start, bucket_it); } // Keep track of which of these reports we don't queue for delivery; we'll // need to mark them as not-pending. - std::unordered_set<const ReportingReport*> undelivered_reports( - reports.begin(), reports.end()); + std::set<const ReportingReport*> undelivered_reports(reports.begin(), + reports.end()); // Start an upload for each delivery. - for (auto& it : deliveries) { - const OriginEndpoint& report_origin_endpoint = it.first; - const url::Origin& report_origin = report_origin_endpoint.first; - const GURL& endpoint = report_origin_endpoint.second; - std::unique_ptr<Delivery>& delivery = it.second; - - std::string json; - SerializeReports(delivery->reports, tick_clock().NowTicks(), &json); + for (auto& target_and_delivery : deliveries) { + const Delivery::Target& target = target_and_delivery.first; + std::unique_ptr<Delivery>& delivery = target_and_delivery.second; int max_depth = 0; - for (const ReportingReport* report : delivery->reports) { + for (const ReportingReport* report : delivery->reports()) { undelivered_reports.erase(report); - if (report->depth > max_depth) - max_depth = report->depth; + max_depth = std::max(report->depth, max_depth); } + std::string upload_data = + SerializeReports(delivery->reports(), tick_clock().NowTicks()); + // TODO: Calculate actual max depth. - // TODO(mmenke): Populate NetworkIsolationKey. uploader()->StartUpload( - report_origin, endpoint, NetworkIsolationKey::Todo(), json, max_depth, + target.origin, target.endpoint_url, target.network_isolation_key, + upload_data, max_depth, base::BindOnce(&ReportingDeliveryAgentImpl::OnUploadComplete, weak_factory_.GetWeakPtr(), std::move(delivery))); } @@ -236,39 +311,24 @@ class ReportingDeliveryAgentImpl : public ReportingDeliveryAgent, void OnUploadComplete(std::unique_ptr<Delivery> delivery, ReportingUploader::Outcome outcome) { - for (const auto& endpoint_and_count : delivery->reports_per_endpoint) { - const ReportingEndpointGroupKey& group_key = - endpoint_and_count.first.first; - const GURL& endpoint = endpoint_and_count.first.second; - int report_count = endpoint_and_count.second; - cache()->IncrementEndpointDeliveries( - group_key, endpoint, report_count, - outcome == ReportingUploader::Outcome::SUCCESS); - } + bool success = outcome == ReportingUploader::Outcome::SUCCESS; + delivery->ProcessOutcome(cache(), success); - if (outcome == ReportingUploader::Outcome::SUCCESS) { - cache()->RemoveReports(delivery->reports, - ReportingReport::Outcome::DELIVERED); - // TODO(mmenke): Populate NetworkIsolationKey argument. - endpoint_manager_->InformOfEndpointRequest(NetworkIsolationKey::Todo(), - delivery->endpoint, true); - } else { - cache()->IncrementReportsAttempts(delivery->reports); - // TODO(mmenke): Populate NetworkIsolationKey argument. - endpoint_manager_->InformOfEndpointRequest(NetworkIsolationKey::Todo(), - delivery->endpoint, false); - } + endpoint_manager_->InformOfEndpointRequest( + delivery->network_isolation_key(), delivery->endpoint_url(), success); + // TODO(chlily): This leaks information across NIKs. If the endpoint URL is + // configured for both NIK1 and NIK2, and it responds with a 410 on a NIK1 + // connection, then the change in configuration will be detectable on a NIK2 + // connection. if (outcome == ReportingUploader::Outcome::REMOVE_ENDPOINT) - cache()->RemoveEndpointsForUrl(delivery->endpoint); + cache()->RemoveEndpointsForUrl(delivery->endpoint_url()); - for (const ReportingReport* report : delivery->reports) { - ReportingEndpointGroupKey group_key( - NetworkIsolationKey::Todo(), delivery->report_origin, report->group); - pending_groups_.erase(group_key); + for (const ReportingReport* report : delivery->reports()) { + pending_groups_.erase(report->GetGroupKey()); } - cache()->ClearReportsPending(delivery->reports); + cache()->ClearReportsPending(delivery->reports()); } const ReportingPolicy& policy() const { return context_->policy(); } diff --git a/chromium/net/reporting/reporting_delivery_agent.h b/chromium/net/reporting/reporting_delivery_agent.h index b857fd16b98..08cb97f4c91 100644 --- a/chromium/net/reporting/reporting_delivery_agent.h +++ b/chromium/net/reporting/reporting_delivery_agent.h @@ -19,32 +19,27 @@ namespace net { class ReportingContext; -// Takes reports from the ReportingCache, assembles reports into deliveries to -// endpoints, and sends those deliveries using ReportingUploader. +// Batches reports fetched from the ReportingCache and uploads them using the +// ReportingUploader. // -// Since the Reporting spec is completely silent on issues of concurrency, the -// delivery agent handles it as so: +// Reports are only considered for delivery if all of the following are true: +// - The report is not already part of a pending upload request. +// - Uploads are allowed for the report's origin (i.e. the origin of the URL +// associated with the reported event). +// - There is not already a pending upload for any reports sharing the same +// (NIK, origin, group) key. // -// 1. An individual report can only be included in one delivery at once -- if -// SendReports is called again while a report is being delivered, it won't -// be included in another delivery during that call to SendReports. (This is, -// in fact, made redundant by rule 3, but it's included anyway in case rule 3 -// changes.) +// Reports are batched for upload to an endpoint URL such that: +// - The available reports with the same (NIK, origin, group) are always +// uploaded together. +// - All reports uploaded together must share a NIK and origin. +// - Reports for the same (NIK, origin) can be uploaded separately if they are +// for different groups. +// - Reports for different groups can be batched together, if they are assigned +// to ReportingEndpoints sharing a URL (that is, the upload URL). // -// 2. An endpoint can only be the target of one delivery at once -- if -// SendReports is called again with reports that could be delivered to that -// endpoint, they won't be delivered to that endpoint. -// -// 3. Reports for an (origin, group) tuple can only be included in one delivery -// at once -- if SendReports is called again with reports in that (origin, -// group), they won't be included in any delivery during that call to -// SendReports. (This prevents the agent from getting around rule 2 by using -// other endpoints in the same group.) -// -// 4. Reports for the same origin *can* be included in multiple parallel -// deliveries if they are in different groups within that origin. -// -// (Note that a single delivery can contain an infinite number of reports.) +// There is no limit to the number of reports that can be uploaded together. +// (Aside from the global cap on total reports.) // // TODO(juliatuttle): Consider capping the maximum number of reports per // delivery attempt. diff --git a/chromium/net/reporting/reporting_delivery_agent_unittest.cc b/chromium/net/reporting/reporting_delivery_agent_unittest.cc index 893cdd61eb2..7812de93c4d 100644 --- a/chromium/net/reporting/reporting_delivery_agent_unittest.cc +++ b/chromium/net/reporting/reporting_delivery_agent_unittest.cc @@ -37,12 +37,47 @@ class ReportingDeliveryAgentTest : public ReportingTestBase { policy.endpoint_backoff_policy.entry_lifetime_ms = 0; policy.endpoint_backoff_policy.always_use_initial_delay = false; UsePolicy(policy); + report_body_.SetStringKey("key", "value"); } - const NetworkIsolationKey kNik_ = NetworkIsolationKey::Todo(); + void AddReport(const NetworkIsolationKey& network_isolation_key, + const GURL& url, + const std::string& group) { + cache()->AddReport(network_isolation_key, url, kUserAgent_, group, kType_, + std::make_unique<base::Value>(report_body_.Clone()), + 0 /* depth */, tick_clock()->NowTicks() /* queued */, + 0 /* attempts */); + } + + // The first report added to the cache is uploaded immediately, and a timer is + // started for all subsequent reports (which may then be batched). To test + // behavior involving batching multiple reports, we need to add, upload, and + // immediately resolve a dummy report to prime the delivery timer. + void UploadFirstReportAndStartTimer() { + ReportingEndpointGroupKey dummy_group( + NetworkIsolationKey(), url::Origin::Create(GURL("https://dummy.test")), + "dummy"); + ASSERT_TRUE(SetEndpointInCache( + dummy_group, GURL("https://dummy.test/upload"), kExpires_)); + AddReport(dummy_group.network_isolation_key, dummy_group.origin.GetURL(), + dummy_group.group_name); + + ASSERT_EQ(1u, pending_uploads().size()); + pending_uploads()[0]->Complete(ReportingUploader::Outcome::SUCCESS); + EXPECT_EQ(0u, pending_uploads().size()); + EXPECT_TRUE(delivery_timer()->IsRunning()); + } + + base::Value report_body_{base::Value::Type::DICTIONARY}; const GURL kUrl_ = GURL("https://origin/path"); + const GURL kOtherUrl_ = GURL("https://other-origin/path"); const GURL kSubdomainUrl_ = GURL("https://sub.origin/path"); const url::Origin kOrigin_ = url::Origin::Create(GURL("https://origin/")); + const url::Origin kOtherOrigin_ = + url::Origin::Create(GURL("https://other-origin/")); + const NetworkIsolationKey kNik_; + const NetworkIsolationKey kOtherNik_ = + NetworkIsolationKey(kOrigin_, kOtherOrigin_); const GURL kEndpoint_ = GURL("https://endpoint/"); const std::string kUserAgent_ = "Mozilla/1.0"; const std::string kGroup_ = "group"; @@ -53,12 +88,8 @@ class ReportingDeliveryAgentTest : public ReportingTestBase { }; TEST_F(ReportingDeliveryAgentTest, SuccessfulImmediateUpload) { - base::DictionaryValue body; - body.SetString("key", "value"); - ASSERT_TRUE(SetEndpointInCache(kGroupKey_, kEndpoint_, kExpires_)); - cache()->AddReport(kNik_, kUrl_, kUserAgent_, kGroup_, kType_, - body.CreateDeepCopy(), 0, tick_clock()->NowTicks(), 0); + AddReport(kNik_, kUrl_, kGroup_); // Upload is automatically started when cache is modified. @@ -79,7 +110,8 @@ TEST_F(ReportingDeliveryAgentTest, SuccessfulImmediateUpload) { ExpectDictStringValue(kType_, *report, "type"); ExpectDictStringValue(kUrl_.spec(), *report, "url"); ExpectDictStringValue(kUserAgent_, *report, "user_agent"); - ExpectDictDictionaryValue(body, *report, "body"); + base::Value* body = report->FindDictKey("body"); + EXPECT_EQ("value", *body->FindStringKey("key")); } pending_uploads()[0]->Complete(ReportingUploader::Outcome::SUCCESS); @@ -89,7 +121,7 @@ TEST_F(ReportingDeliveryAgentTest, SuccessfulImmediateUpload) { EXPECT_TRUE(reports.empty()); { - const ReportingEndpoint::Statistics stats = + ReportingEndpoint::Statistics stats = GetEndpointStatistics(kGroupKey_, kEndpoint_); EXPECT_EQ(1, stats.attempted_uploads); EXPECT_EQ(1, stats.successful_uploads); @@ -101,13 +133,9 @@ TEST_F(ReportingDeliveryAgentTest, SuccessfulImmediateUpload) { } TEST_F(ReportingDeliveryAgentTest, SuccessfulImmediateSubdomainUpload) { - base::DictionaryValue body; - body.SetString("key", "value"); - ASSERT_TRUE(SetEndpointInCache(kGroupKey_, kEndpoint_, kExpires_, OriginSubdomains::INCLUDE)); - cache()->AddReport(kNik_, kSubdomainUrl_, kUserAgent_, kGroup_, kType_, - body.CreateDeepCopy(), 0, tick_clock()->NowTicks(), 0); + AddReport(kNik_, kSubdomainUrl_, kGroup_); // Upload is automatically started when cache is modified. @@ -128,7 +156,8 @@ TEST_F(ReportingDeliveryAgentTest, SuccessfulImmediateSubdomainUpload) { ExpectDictStringValue(kType_, *report, "type"); ExpectDictStringValue(kSubdomainUrl_.spec(), *report, "url"); ExpectDictStringValue(kUserAgent_, *report, "user_agent"); - ExpectDictDictionaryValue(body, *report, "body"); + base::Value* body = report->FindDictKey("body"); + EXPECT_EQ("value", *body->FindStringKey("key")); } pending_uploads()[0]->Complete(ReportingUploader::Outcome::SUCCESS); @@ -138,7 +167,7 @@ TEST_F(ReportingDeliveryAgentTest, SuccessfulImmediateSubdomainUpload) { EXPECT_TRUE(reports.empty()); { - const ReportingEndpoint::Statistics stats = + ReportingEndpoint::Statistics stats = GetEndpointStatistics(kGroupKey_, kEndpoint_); EXPECT_EQ(1, stats.attempted_uploads); EXPECT_EQ(1, stats.successful_uploads); @@ -151,13 +180,9 @@ TEST_F(ReportingDeliveryAgentTest, SuccessfulImmediateSubdomainUpload) { TEST_F(ReportingDeliveryAgentTest, SuccessfulImmediateSubdomainUploadWithOverwrittenEndpoint) { - base::DictionaryValue body; - body.SetString("key", "value"); - ASSERT_TRUE(SetEndpointInCache(kGroupKey_, kEndpoint_, kExpires_, OriginSubdomains::INCLUDE)); - cache()->AddReport(kNik_, kSubdomainUrl_, kUserAgent_, kGroup_, kType_, - body.CreateDeepCopy(), 0, tick_clock()->NowTicks(), 0); + AddReport(kNik_, kSubdomainUrl_, kGroup_); // Upload is automatically started when cache is modified. @@ -168,7 +193,7 @@ TEST_F(ReportingDeliveryAgentTest, pending_uploads()[0]->Complete(ReportingUploader::Outcome::SUCCESS); { - const ReportingEndpoint::Statistics stats = + ReportingEndpoint::Statistics stats = GetEndpointStatistics(kGroupKey_, kEndpoint_); EXPECT_EQ(1, stats.attempted_uploads); EXPECT_EQ(1, stats.successful_uploads); @@ -183,18 +208,13 @@ TEST_F(ReportingDeliveryAgentTest, } TEST_F(ReportingDeliveryAgentTest, SuccessfulDelayedUpload) { - base::DictionaryValue body; - body.SetString("key", "value"); - // Trigger and complete an upload to start the delivery timer. ASSERT_TRUE(SetEndpointInCache(kGroupKey_, kEndpoint_, kExpires_)); - cache()->AddReport(kNik_, kUrl_, kUserAgent_, kGroup_, kType_, - body.CreateDeepCopy(), 0, tick_clock()->NowTicks(), 0); + AddReport(kNik_, kUrl_, kGroup_); pending_uploads()[0]->Complete(ReportingUploader::Outcome::SUCCESS); // Add another report to upload after a delay. - cache()->AddReport(kNik_, kUrl_, kUserAgent_, kGroup_, kType_, - body.CreateDeepCopy(), 0, tick_clock()->NowTicks(), 0); + AddReport(kNik_, kUrl_, kGroup_); EXPECT_TRUE(delivery_timer()->IsRunning()); delivery_timer()->Fire(); @@ -216,12 +236,13 @@ TEST_F(ReportingDeliveryAgentTest, SuccessfulDelayedUpload) { ExpectDictStringValue(kType_, *report, "type"); ExpectDictStringValue(kUrl_.spec(), *report, "url"); ExpectDictStringValue(kUserAgent_, *report, "user_agent"); - ExpectDictDictionaryValue(body, *report, "body"); + base::Value* body = report->FindDictKey("body"); + EXPECT_EQ("value", *body->FindStringKey("key")); } pending_uploads()[0]->Complete(ReportingUploader::Outcome::SUCCESS); { - const ReportingEndpoint::Statistics stats = + ReportingEndpoint::Statistics stats = GetEndpointStatistics(kGroupKey_, kEndpoint_); EXPECT_EQ(2, stats.attempted_uploads); EXPECT_EQ(2, stats.successful_uploads); @@ -239,9 +260,7 @@ TEST_F(ReportingDeliveryAgentTest, SuccessfulDelayedUpload) { TEST_F(ReportingDeliveryAgentTest, FailedUpload) { ASSERT_TRUE(SetEndpointInCache(kGroupKey_, kEndpoint_, kExpires_)); - cache()->AddReport(kNik_, kUrl_, kUserAgent_, kGroup_, kType_, - std::make_unique<base::DictionaryValue>(), 0, - tick_clock()->NowTicks(), 0); + AddReport(kNik_, kUrl_, kGroup_); EXPECT_TRUE(delivery_timer()->IsRunning()); delivery_timer()->Fire(); @@ -250,7 +269,7 @@ TEST_F(ReportingDeliveryAgentTest, FailedUpload) { pending_uploads()[0]->Complete(ReportingUploader::Outcome::FAILURE); { - const ReportingEndpoint::Statistics stats = + ReportingEndpoint::Statistics stats = GetEndpointStatistics(kGroupKey_, kEndpoint_); EXPECT_EQ(1, stats.attempted_uploads); EXPECT_EQ(0, stats.successful_uploads); @@ -272,7 +291,7 @@ TEST_F(ReportingDeliveryAgentTest, FailedUpload) { EXPECT_TRUE(pending_uploads().empty()); { - const ReportingEndpoint::Statistics stats = + ReportingEndpoint::Statistics stats = GetEndpointStatistics(kGroupKey_, kEndpoint_); EXPECT_EQ(1, stats.attempted_uploads); EXPECT_EQ(0, stats.successful_uploads); @@ -292,8 +311,7 @@ TEST_F(ReportingDeliveryAgentTest, DisallowedUpload) { body.SetString("key", "value"); ASSERT_TRUE(SetEndpointInCache(kGroupKey_, kEndpoint_, kExpires_)); - cache()->AddReport(kNik_, kUrl_, kUserAgent_, kGroup_, kType_, - body.CreateDeepCopy(), 0, tick_clock()->NowTicks(), 0); + AddReport(kNik_, kUrl_, kGroup_); tick_clock()->Advance(base::TimeDelta::FromMilliseconds(kAgeMillis)); @@ -305,7 +323,7 @@ TEST_F(ReportingDeliveryAgentTest, DisallowedUpload) { EXPECT_TRUE(pending_uploads().empty()); { - const ReportingEndpoint::Statistics stats = + ReportingEndpoint::Statistics stats = GetEndpointStatistics(kGroupKey_, kEndpoint_); EXPECT_EQ(0, stats.attempted_uploads); EXPECT_EQ(0, stats.successful_uploads); @@ -320,17 +338,13 @@ TEST_F(ReportingDeliveryAgentTest, DisallowedUpload) { } TEST_F(ReportingDeliveryAgentTest, RemoveEndpointUpload) { - static const url::Origin kDifferentOrigin = - url::Origin::Create(GURL("https://origin2/")); - static const ReportingEndpointGroupKey kOtherGroupKey( - NetworkIsolationKey(), kDifferentOrigin, kGroup_); + static const ReportingEndpointGroupKey kOtherGroupKey(kNik_, kOtherOrigin_, + kGroup_); ASSERT_TRUE(SetEndpointInCache(kGroupKey_, kEndpoint_, kExpires_)); ASSERT_TRUE(SetEndpointInCache(kOtherGroupKey, kEndpoint_, kExpires_)); - cache()->AddReport(kNik_, kUrl_, kUserAgent_, kGroup_, kType_, - std::make_unique<base::DictionaryValue>(), 0, - tick_clock()->NowTicks(), 0); + AddReport(kNik_, kUrl_, kGroup_); EXPECT_TRUE(delivery_timer()->IsRunning()); delivery_timer()->Fire(); @@ -357,9 +371,7 @@ TEST_F(ReportingDeliveryAgentTest, RemoveEndpointUpload) { TEST_F(ReportingDeliveryAgentTest, ConcurrentRemove) { ASSERT_TRUE(SetEndpointInCache(kGroupKey_, kEndpoint_, kExpires_)); - cache()->AddReport(kNik_, kUrl_, kUserAgent_, kGroup_, kType_, - std::make_unique<base::DictionaryValue>(), 0, - tick_clock()->NowTicks(), 0); + AddReport(kNik_, kUrl_, kGroup_); EXPECT_TRUE(delivery_timer()->IsRunning()); delivery_timer()->Fire(); @@ -393,9 +405,7 @@ TEST_F(ReportingDeliveryAgentTest, ConcurrentRemoveDuringPermissionsCheck) { context()->test_delegate()->set_pause_permissions_check(true); ASSERT_TRUE(SetEndpointInCache(kGroupKey_, kEndpoint_, kExpires_)); - cache()->AddReport(kNik_, kUrl_, kUserAgent_, kGroup_, kType_, - std::make_unique<base::DictionaryValue>(), 0, - tick_clock()->NowTicks(), 0); + AddReport(kNik_, kUrl_, kGroup_); ASSERT_TRUE(context()->test_delegate()->PermissionsCheckPaused()); @@ -421,134 +431,126 @@ TEST_F(ReportingDeliveryAgentTest, ConcurrentRemoveDuringPermissionsCheck) { EXPECT_TRUE(reports.empty()); } -// Test that the agent will combine reports destined for the same endpoint, even -// if the reports are from different origins. -TEST_F(ReportingDeliveryAgentTest, - BatchReportsFromDifferentOriginsToSameEndpoint) { - static const GURL kDifferentUrl("https://origin2/path"); - static const url::Origin kDifferentOrigin = - url::Origin::Create(kDifferentUrl); - const ReportingEndpointGroupKey kDifferentGroupKey(NetworkIsolationKey(), - kDifferentOrigin, kGroup_); - - ASSERT_TRUE(SetEndpointInCache(kGroupKey_, kEndpoint_, kExpires_)); - ASSERT_TRUE(SetEndpointInCache(kDifferentGroupKey, kEndpoint_, kExpires_)); +// Reports uploaded together must share a NIK and origin. +// Test that the agent will not combine reports destined for the same endpoint +// if the reports are from different origins or NIKs, but does combine all +// reports for the same (NIK, origin). +TEST_F(ReportingDeliveryAgentTest, OnlyBatchSameNikAndOrigin) { + const ReportingEndpointGroupKey kGroupKeys[] = { + ReportingEndpointGroupKey(kNik_, kOrigin_, kGroup_), + ReportingEndpointGroupKey(kNik_, kOtherOrigin_, kGroup_), + ReportingEndpointGroupKey(kOtherNik_, kOrigin_, kGroup_), + ReportingEndpointGroupKey(kOtherNik_, kOtherOrigin_, kGroup_), + }; + for (const ReportingEndpointGroupKey& group_key : kGroupKeys) { + ASSERT_TRUE(SetEndpointInCache(group_key, kEndpoint_, kExpires_)); + } // Trigger and complete an upload to start the delivery timer. - cache()->AddReport(kNik_, kUrl_, kUserAgent_, kGroup_, kType_, - std::make_unique<base::DictionaryValue>(), 0, - tick_clock()->NowTicks(), 0); - pending_uploads()[0]->Complete(ReportingUploader::Outcome::SUCCESS); + UploadFirstReportAndStartTimer(); // Now that the delivery timer is running, these reports won't be immediately // uploaded. - cache()->AddReport(kNik_, kUrl_, kUserAgent_, kGroup_, kType_, - std::make_unique<base::DictionaryValue>(), 0, - tick_clock()->NowTicks(), 0); - cache()->AddReport(kNik_, kDifferentUrl, kUserAgent_, kGroup_, kType_, - std::make_unique<base::DictionaryValue>(), 0, - tick_clock()->NowTicks(), 0); + AddReport(kNik_, kUrl_, kGroup_); + AddReport(kNik_, kOtherUrl_, kGroup_); + AddReport(kNik_, kOtherUrl_, kGroup_); + AddReport(kOtherNik_, kUrl_, kGroup_); + AddReport(kOtherNik_, kUrl_, kGroup_); + AddReport(kOtherNik_, kUrl_, kGroup_); + AddReport(kOtherNik_, kOtherUrl_, kGroup_); + AddReport(kOtherNik_, kOtherUrl_, kGroup_); + AddReport(kOtherNik_, kOtherUrl_, kGroup_); + AddReport(kOtherNik_, kOtherUrl_, kGroup_); EXPECT_EQ(0u, pending_uploads().size()); - // When we fire the delivery timer, we should NOT batch these two reports into - // a single upload, since each upload must only contain reports about a single - // origin. + // There should be one upload per (NIK, origin). EXPECT_TRUE(delivery_timer()->IsRunning()); delivery_timer()->Fire(); - ASSERT_EQ(2u, pending_uploads().size()); + ASSERT_EQ(4u, pending_uploads().size()); pending_uploads()[0]->Complete(ReportingUploader::Outcome::SUCCESS); pending_uploads()[0]->Complete(ReportingUploader::Outcome::SUCCESS); - EXPECT_EQ(0u, pending_uploads().size()); -} - -// Test that the agent won't start a second upload to the same endpoint for a -// particular origin while one is pending, but will once it is no longer -// pending. -TEST_F(ReportingDeliveryAgentTest, SerializeUploadsToEndpoint) { - ASSERT_TRUE(SetEndpointInCache(kGroupKey_, kEndpoint_, kExpires_)); - - cache()->AddReport(kNik_, kUrl_, kUserAgent_, kGroup_, kType_, - std::make_unique<base::DictionaryValue>(), 0, - tick_clock()->NowTicks(), 0); - - EXPECT_TRUE(delivery_timer()->IsRunning()); - delivery_timer()->Fire(); - EXPECT_EQ(1u, pending_uploads().size()); - - cache()->AddReport(kNik_, kUrl_, kUserAgent_, kGroup_, kType_, - std::make_unique<base::DictionaryValue>(), 0, - tick_clock()->NowTicks(), 0); - - EXPECT_TRUE(delivery_timer()->IsRunning()); - delivery_timer()->Fire(); - ASSERT_EQ(1u, pending_uploads().size()); - pending_uploads()[0]->Complete(ReportingUploader::Outcome::SUCCESS); - EXPECT_EQ(0u, pending_uploads().size()); - - EXPECT_TRUE(delivery_timer()->IsRunning()); - delivery_timer()->Fire(); - ASSERT_EQ(1u, pending_uploads().size()); - pending_uploads()[0]->Complete(ReportingUploader::Outcome::SUCCESS); EXPECT_EQ(0u, pending_uploads().size()); + + for (int i = 0; i < 4; ++i) { + ReportingEndpoint::Statistics stats = + GetEndpointStatistics(kGroupKeys[i], kEndpoint_); + EXPECT_EQ(1, stats.attempted_uploads); + EXPECT_EQ(1, stats.successful_uploads); + EXPECT_EQ(i + 1, stats.attempted_reports); + EXPECT_EQ(i + 1, stats.successful_reports); + } } -// Test that the agent won't start a second upload for an (origin, group) while -// one is pending, even if a different endpoint is available, but will once the -// original delivery is complete and the (origin, group) is no longer pending. +// Test that the agent won't start a second upload for a (NIK, origin, group) +// while one is pending, even if a different endpoint is available, but will +// once the original delivery is complete and the (NIK, origin, group) is no +// longer pending. TEST_F(ReportingDeliveryAgentTest, SerializeUploadsToGroup) { static const GURL kDifferentEndpoint("https://endpoint2/"); ASSERT_TRUE(SetEndpointInCache(kGroupKey_, kEndpoint_, kExpires_)); ASSERT_TRUE(SetEndpointInCache(kGroupKey_, kDifferentEndpoint, kExpires_)); - cache()->AddReport(kNik_, kUrl_, kUserAgent_, kGroup_, kType_, - std::make_unique<base::DictionaryValue>(), 0, - tick_clock()->NowTicks(), 0); + // Trigger and complete an upload to start the delivery timer. + UploadFirstReportAndStartTimer(); + // First upload causes this group key to become pending. + AddReport(kNik_, kUrl_, kGroup_); + EXPECT_EQ(0u, pending_uploads().size()); EXPECT_TRUE(delivery_timer()->IsRunning()); delivery_timer()->Fire(); EXPECT_EQ(1u, pending_uploads().size()); - cache()->AddReport(kNik_, kUrl_, kUserAgent_, kGroup_, kType_, - std::make_unique<base::DictionaryValue>(), 0, - tick_clock()->NowTicks(), 0); - + // Second upload isn't started because the group is pending. + AddReport(kNik_, kUrl_, kGroup_); EXPECT_TRUE(delivery_timer()->IsRunning()); delivery_timer()->Fire(); ASSERT_EQ(1u, pending_uploads().size()); + // Resolve the first upload. pending_uploads()[0]->Complete(ReportingUploader::Outcome::SUCCESS); EXPECT_EQ(0u, pending_uploads().size()); + // Now the other upload can happen. EXPECT_TRUE(delivery_timer()->IsRunning()); delivery_timer()->Fire(); ASSERT_EQ(1u, pending_uploads().size()); - pending_uploads()[0]->Complete(ReportingUploader::Outcome::SUCCESS); EXPECT_EQ(0u, pending_uploads().size()); + + // A total of 2 reports were uploaded. + { + ReportingEndpoint::Statistics stats = + GetEndpointStatistics(kGroupKey_, kEndpoint_); + ReportingEndpoint::Statistics different_stats = + GetEndpointStatistics(kGroupKey_, kDifferentEndpoint); + EXPECT_EQ(2, stats.attempted_uploads + different_stats.attempted_uploads); + EXPECT_EQ(2, stats.successful_uploads + different_stats.successful_uploads); + EXPECT_EQ(2, stats.attempted_reports + different_stats.attempted_reports); + EXPECT_EQ(2, stats.successful_reports + different_stats.successful_reports); + } } // Tests that the agent will start parallel uploads to different groups within -// the same origin. +// the same (NIK, origin) to endpoints with different URLs. TEST_F(ReportingDeliveryAgentTest, ParallelizeUploadsAcrossGroups) { static const GURL kDifferentEndpoint("https://endpoint2/"); static const std::string kDifferentGroup("group2"); - const ReportingEndpointGroupKey kDifferentGroupKey(NetworkIsolationKey(), - kOrigin_, kDifferentGroup); + const ReportingEndpointGroupKey kDifferentGroupKey(kNik_, kOrigin_, + kDifferentGroup); ASSERT_TRUE(SetEndpointInCache(kGroupKey_, kEndpoint_, kExpires_)); ASSERT_TRUE( SetEndpointInCache(kDifferentGroupKey, kDifferentEndpoint, kExpires_)); - cache()->AddReport(kNik_, kUrl_, kUserAgent_, kGroup_, kType_, - std::make_unique<base::DictionaryValue>(), 0, - tick_clock()->NowTicks(), 0); - cache()->AddReport(kNik_, kUrl_, kUserAgent_, kDifferentGroup, kType_, - std::make_unique<base::DictionaryValue>(), 0, - tick_clock()->NowTicks(), 0); + // Trigger and complete an upload to start the delivery timer. + UploadFirstReportAndStartTimer(); + + AddReport(kNik_, kUrl_, kGroup_); + AddReport(kNik_, kUrl_, kDifferentGroup); EXPECT_TRUE(delivery_timer()->IsRunning()); delivery_timer()->Fire(); @@ -557,6 +559,63 @@ TEST_F(ReportingDeliveryAgentTest, ParallelizeUploadsAcrossGroups) { pending_uploads()[1]->Complete(ReportingUploader::Outcome::SUCCESS); pending_uploads()[0]->Complete(ReportingUploader::Outcome::SUCCESS); EXPECT_EQ(0u, pending_uploads().size()); + + { + ReportingEndpoint::Statistics stats = + GetEndpointStatistics(kGroupKey_, kEndpoint_); + EXPECT_EQ(1, stats.attempted_uploads); + EXPECT_EQ(1, stats.successful_uploads); + EXPECT_EQ(1, stats.attempted_reports); + EXPECT_EQ(1, stats.successful_reports); + } + { + ReportingEndpoint::Statistics stats = + GetEndpointStatistics(kDifferentGroupKey, kDifferentEndpoint); + EXPECT_EQ(1, stats.attempted_uploads); + EXPECT_EQ(1, stats.successful_uploads); + EXPECT_EQ(1, stats.attempted_reports); + EXPECT_EQ(1, stats.successful_reports); + } +} + +// Tests that the agent will include reports for different groups for the same +// (NIK, origin) in the same upload if they are destined for the same endpoint +// URL. +TEST_F(ReportingDeliveryAgentTest, BatchReportsAcrossGroups) { + static const std::string kDifferentGroup("group2"); + const ReportingEndpointGroupKey kDifferentGroupKey(kNik_, kOrigin_, + kDifferentGroup); + + ASSERT_TRUE(SetEndpointInCache(kGroupKey_, kEndpoint_, kExpires_)); + ASSERT_TRUE(SetEndpointInCache(kDifferentGroupKey, kEndpoint_, kExpires_)); + + UploadFirstReportAndStartTimer(); + + AddReport(kNik_, kUrl_, kGroup_); + AddReport(kNik_, kUrl_, kDifferentGroup); + + EXPECT_TRUE(delivery_timer()->IsRunning()); + delivery_timer()->Fire(); + ASSERT_EQ(1u, pending_uploads().size()); + pending_uploads()[0]->Complete(ReportingUploader::Outcome::SUCCESS); + EXPECT_EQ(0u, pending_uploads().size()); + + { + ReportingEndpoint::Statistics stats = + GetEndpointStatistics(kGroupKey_, kEndpoint_); + EXPECT_EQ(1, stats.attempted_uploads); + EXPECT_EQ(1, stats.successful_uploads); + EXPECT_EQ(1, stats.attempted_reports); + EXPECT_EQ(1, stats.successful_reports); + } + { + ReportingEndpoint::Statistics stats = + GetEndpointStatistics(kDifferentGroupKey, kEndpoint_); + EXPECT_EQ(1, stats.attempted_uploads); + EXPECT_EQ(1, stats.successful_uploads); + EXPECT_EQ(1, stats.attempted_reports); + EXPECT_EQ(1, stats.successful_reports); + } } } // namespace diff --git a/chromium/net/reporting/reporting_header_parser.cc b/chromium/net/reporting/reporting_header_parser.cc index 294f9039841..ec881490fdd 100644 --- a/chromium/net/reporting/reporting_header_parser.cc +++ b/chromium/net/reporting/reporting_header_parser.cc @@ -26,28 +26,6 @@ namespace net { namespace { -using HeaderEndpointGroupOutcome = - ReportingHeaderParser::HeaderEndpointGroupOutcome; -using HeaderEndpointOutcome = ReportingHeaderParser::HeaderEndpointOutcome; -using HeaderOutcome = ReportingHeaderParser::HeaderOutcome; - -void RecordHeaderOutcome(HeaderOutcome outcome) { - UMA_HISTOGRAM_ENUMERATION(ReportingHeaderParser::kHeaderOutcomeHistogram, - outcome, HeaderOutcome::MAX); -} - -void RecordHeaderEndpointGroupOutcome(HeaderEndpointGroupOutcome outcome) { - UMA_HISTOGRAM_ENUMERATION( - ReportingHeaderParser::kHeaderEndpointGroupOutcomeHistogram, outcome, - HeaderEndpointGroupOutcome::MAX); -} - -void RecordHeaderEndpointOutcome(HeaderEndpointOutcome outcome) { - UMA_HISTOGRAM_ENUMERATION( - ReportingHeaderParser::kHeaderEndpointOutcomeHistogram, outcome, - HeaderEndpointOutcome::MAX); -} - const char kUrlKey[] = "url"; const char kIncludeSubdomainsKey[] = "include_subdomains"; const char kEndpointsKey[] = "endpoints"; @@ -64,21 +42,21 @@ const char kWeightKey[] = "weight"; // |value| is the parsed JSON value of the endpoint tuple. // // |*endpoint_out| will contain the endpoint URL parsed out of the tuple. -HeaderEndpointOutcome ProcessEndpoint( - ReportingDelegate* delegate, - const ReportingEndpointGroupKey& group_key, - const base::Value& value, - ReportingEndpoint::EndpointInfo* endpoint_info_out) { +// Returns true on success or false if endpoint was discarded. +bool ProcessEndpoint(ReportingDelegate* delegate, + const ReportingEndpointGroupKey& group_key, + const base::Value& value, + ReportingEndpoint::EndpointInfo* endpoint_info_out) { const base::DictionaryValue* dict = nullptr; if (!value.GetAsDictionary(&dict)) - return HeaderEndpointOutcome::DISCARDED_NOT_DICTIONARY; + return false; DCHECK(dict); std::string endpoint_url_string; if (!dict->HasKey(kUrlKey)) - return HeaderEndpointOutcome::DISCARDED_URL_MISSING; + return false; if (!dict->GetString(kUrlKey, &endpoint_url_string)) - return HeaderEndpointOutcome::DISCARDED_URL_NOT_STRING; + return false; GURL endpoint_url; // Support path-absolute-URL string @@ -88,29 +66,26 @@ HeaderEndpointOutcome ProcessEndpoint( endpoint_url = GURL(endpoint_url_string); } if (!endpoint_url.is_valid()) - return HeaderEndpointOutcome::DISCARDED_URL_INVALID; + return false; if (!endpoint_url.SchemeIsCryptographic()) - return HeaderEndpointOutcome::DISCARDED_URL_INSECURE; + return false; endpoint_info_out->url = std::move(endpoint_url); int priority = ReportingEndpoint::EndpointInfo::kDefaultPriority; if (dict->HasKey(kPriorityKey) && !dict->GetInteger(kPriorityKey, &priority)) - return HeaderEndpointOutcome::DISCARDED_PRIORITY_NOT_INTEGER; + return false; if (priority < 0) - return HeaderEndpointOutcome::DISCARDED_PRIORITY_NEGATIVE; + return false; endpoint_info_out->priority = priority; int weight = ReportingEndpoint::EndpointInfo::kDefaultWeight; if (dict->HasKey(kWeightKey) && !dict->GetInteger(kWeightKey, &weight)) - return HeaderEndpointOutcome::DISCARDED_WEIGHT_NOT_INTEGER; + return false; if (weight < 0) - return HeaderEndpointOutcome::DISCARDED_WEIGHT_NEGATIVE; + return false; endpoint_info_out->weight = weight; - if (!delegate->CanSetClient(group_key.origin, endpoint_url)) - return HeaderEndpointOutcome::SET_REJECTED_BY_DELEGATE; - - return HeaderEndpointOutcome::SET; + return delegate->CanSetClient(group_key.origin, endpoint_url); } // Processes a single endpoint group tuple received in a Report-To header. @@ -118,36 +93,37 @@ HeaderEndpointOutcome ProcessEndpoint( // |origin| is the origin that sent the Report-To header. // // |value| is the parsed JSON value of the endpoint group tuple. -HeaderEndpointGroupOutcome ProcessEndpointGroup( - ReportingDelegate* delegate, - ReportingCache* cache, - const NetworkIsolationKey& network_isolation_key, - const url::Origin& origin, - const base::Value& value, - ReportingEndpointGroup* parsed_endpoint_group_out) { +// Returns true on successfully adding a non-empty group, or false if endpoint +// group was discarded or processed as a deletion. +bool ProcessEndpointGroup(ReportingDelegate* delegate, + ReportingCache* cache, + const NetworkIsolationKey& network_isolation_key, + const url::Origin& origin, + const base::Value& value, + ReportingEndpointGroup* parsed_endpoint_group_out) { const base::DictionaryValue* dict = nullptr; if (!value.GetAsDictionary(&dict)) - return HeaderEndpointGroupOutcome::DISCARDED_NOT_DICTIONARY; + return false; DCHECK(dict); std::string group_name = kDefaultGroupName; if (dict->HasKey(kGroupKey) && !dict->GetString(kGroupKey, &group_name)) - return HeaderEndpointGroupOutcome::DISCARDED_GROUP_NOT_STRING; + return false; ReportingEndpointGroupKey group_key(network_isolation_key, origin, group_name); parsed_endpoint_group_out->group_key = group_key; int ttl_sec = -1; if (!dict->HasKey(kMaxAgeKey)) - return HeaderEndpointGroupOutcome::DISCARDED_TTL_MISSING; + return false; if (!dict->GetInteger(kMaxAgeKey, &ttl_sec)) - return HeaderEndpointGroupOutcome::DISCARDED_TTL_NOT_INTEGER; + return false; if (ttl_sec < 0) - return HeaderEndpointGroupOutcome::DISCARDED_TTL_NEGATIVE; + return false; // max_age: 0 signifies removal of the endpoint group. if (ttl_sec == 0) { cache->RemoveEndpointGroup(group_key); - return HeaderEndpointGroupOutcome::REMOVED_TTL_ZERO; + return false; } parsed_endpoint_group_out->ttl = base::TimeDelta::FromSeconds(ttl_sec); @@ -160,8 +136,7 @@ HeaderEndpointGroupOutcome ProcessEndpointGroup( origin.GetURL(), registry_controlled_domains::INCLUDE_UNKNOWN_REGISTRIES, registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES) == 0) { - return HeaderEndpointGroupOutcome:: - DISCARDED_INCLUDE_SUBDOMAINS_NOT_ALLOWED; + return false; } parsed_endpoint_group_out->include_subdomains = OriginSubdomains::INCLUDE; @@ -169,9 +144,9 @@ HeaderEndpointGroupOutcome ProcessEndpointGroup( const base::ListValue* endpoint_list = nullptr; if (!dict->HasKey(kEndpointsKey)) - return HeaderEndpointGroupOutcome::DISCARDED_ENDPOINTS_MISSING; + return false; if (!dict->GetList(kEndpointsKey, &endpoint_list)) - return HeaderEndpointGroupOutcome::DISCARDED_ENDPOINTS_NOT_LIST; + return false; std::vector<ReportingEndpoint::EndpointInfo> endpoints; @@ -182,66 +157,24 @@ HeaderEndpointGroupOutcome ProcessEndpointGroup( ReportingEndpoint::EndpointInfo parsed_endpoint; - HeaderEndpointOutcome outcome = - ProcessEndpoint(delegate, group_key, *endpoint, &parsed_endpoint); - - if (outcome == HeaderEndpointOutcome::SET) + if (ProcessEndpoint(delegate, group_key, *endpoint, &parsed_endpoint)) endpoints.push_back(std::move(parsed_endpoint)); - - RecordHeaderEndpointOutcome(outcome); } // Remove the group if it is empty. if (endpoints.empty()) { cache->RemoveEndpointGroup(group_key); - return HeaderEndpointGroupOutcome::REMOVED_EMPTY; + return false; } parsed_endpoint_group_out->endpoints = std::move(endpoints); - return HeaderEndpointGroupOutcome::PARSED; + return true; } } // namespace // static -const char ReportingHeaderParser::kHeaderOutcomeHistogram[] = - "Net.Reporting.HeaderOutcome"; - -// static -const char ReportingHeaderParser::kHeaderEndpointGroupOutcomeHistogram[] = - "Net.Reporting.HeaderEndpointGroupOutcome"; - -// static -const char ReportingHeaderParser::kHeaderEndpointOutcomeHistogram[] = - "Net.Reporting.HeaderEndpointOutcome"; - -// static -void ReportingHeaderParser::RecordHeaderDiscardedForNoReportingService() { - RecordHeaderOutcome(HeaderOutcome::DISCARDED_NO_REPORTING_SERVICE); -} - -// static -void ReportingHeaderParser::RecordHeaderDiscardedForInvalidSSLInfo() { - RecordHeaderOutcome(HeaderOutcome::DISCARDED_INVALID_SSL_INFO); -} - -// static -void ReportingHeaderParser::RecordHeaderDiscardedForCertStatusError() { - RecordHeaderOutcome(HeaderOutcome::DISCARDED_CERT_STATUS_ERROR); -} - -// static -void ReportingHeaderParser::RecordHeaderDiscardedForJsonInvalid() { - RecordHeaderOutcome(HeaderOutcome::DISCARDED_JSON_INVALID); -} - -// static -void ReportingHeaderParser::RecordHeaderDiscardedForJsonTooBig() { - RecordHeaderOutcome(HeaderOutcome::DISCARDED_JSON_TOO_BIG); -} - -// static void ReportingHeaderParser::ParseHeader( ReportingContext* context, const NetworkIsolationKey& network_isolation_key, @@ -265,25 +198,21 @@ void ReportingHeaderParser::ParseHeader( bool got_group = group_list->Get(i, &group_value); DCHECK(got_group); ReportingEndpointGroup parsed_endpoint_group; - HeaderEndpointGroupOutcome outcome = - ProcessEndpointGroup(delegate, cache, network_isolation_key, origin, - *group_value, &parsed_endpoint_group); - RecordHeaderEndpointGroupOutcome(outcome); - if (outcome == HeaderEndpointGroupOutcome::PARSED) + if (ProcessEndpointGroup(delegate, cache, network_isolation_key, origin, + *group_value, &parsed_endpoint_group)) { parsed_header.push_back(std::move(parsed_endpoint_group)); + } } // Remove the client if it has no valid endpoint groups. if (parsed_header.empty()) { // TODO(chlily): Pass NIK to cache. cache->RemoveClient(NetworkIsolationKey::Todo(), origin); - RecordHeaderOutcome(HeaderOutcome::REMOVED_EMPTY); return; } cache->OnParsedHeader(network_isolation_key, origin, std::move(parsed_header)); - RecordHeaderOutcome(HeaderOutcome::PARSED); } } // namespace net diff --git a/chromium/net/reporting/reporting_header_parser.h b/chromium/net/reporting/reporting_header_parser.h index adba204742a..2e167f2ccde 100644 --- a/chromium/net/reporting/reporting_header_parser.h +++ b/chromium/net/reporting/reporting_header_parser.h @@ -22,64 +22,6 @@ class ReportingContext; class NET_EXPORT ReportingHeaderParser { public: - // Histograms. These are mainly used in test cases to verify that interesting - // events occurred. - - static const char kHeaderOutcomeHistogram[]; - static const char kHeaderEndpointGroupOutcomeHistogram[]; - static const char kHeaderEndpointOutcomeHistogram[]; - - enum class HeaderOutcome { - DISCARDED_NO_REPORTING_SERVICE = 0, - DISCARDED_INVALID_SSL_INFO = 1, - DISCARDED_CERT_STATUS_ERROR = 2, - DISCARDED_JSON_TOO_BIG = 3, - DISCARDED_JSON_INVALID = 4, - PARSED = 5, - REMOVED_EMPTY = 6, - MAX - }; - - enum class HeaderEndpointGroupOutcome { - DISCARDED_NOT_DICTIONARY = 0, - DISCARDED_GROUP_NOT_STRING = 1, - DISCARDED_TTL_MISSING = 2, - DISCARDED_TTL_NOT_INTEGER = 3, - DISCARDED_TTL_NEGATIVE = 4, - DISCARDED_ENDPOINTS_MISSING = 5, - DISCARDED_ENDPOINTS_NOT_LIST = 6, - - PARSED = 7, - REMOVED_TTL_ZERO = 8, - REMOVED_EMPTY = 9, - DISCARDED_INCLUDE_SUBDOMAINS_NOT_ALLOWED = 10, - MAX - }; - - enum class HeaderEndpointOutcome { - DISCARDED_NOT_DICTIONARY = 0, - DISCARDED_URL_MISSING = 1, - DISCARDED_URL_NOT_STRING = 2, - DISCARDED_URL_INVALID = 3, - DISCARDED_URL_INSECURE = 4, - DISCARDED_PRIORITY_NOT_INTEGER = 5, - DISCARDED_WEIGHT_NOT_INTEGER = 6, - DISCARDED_WEIGHT_NEGATIVE = 7, - - REMOVED = 8, // Obsolete: removing for max_age: 0 is done on a group basis. - SET_REJECTED_BY_DELEGATE = 9, - SET = 10, - DISCARDED_PRIORITY_NEGATIVE = 11, - - MAX - }; - - static void RecordHeaderDiscardedForNoReportingService(); - static void RecordHeaderDiscardedForInvalidSSLInfo(); - static void RecordHeaderDiscardedForCertStatusError(); - static void RecordHeaderDiscardedForJsonInvalid(); - static void RecordHeaderDiscardedForJsonTooBig(); - static void ParseHeader(ReportingContext* context, const NetworkIsolationKey& network_isolation_key, const GURL& url, diff --git a/chromium/net/reporting/reporting_report.cc b/chromium/net/reporting/reporting_report.cc index 63648cff1b9..3bc047dfcb6 100644 --- a/chromium/net/reporting/reporting_report.cc +++ b/chromium/net/reporting/reporting_report.cc @@ -45,16 +45,14 @@ ReportingReport::ReportingReport( attempts(attempts) {} ReportingReport::~ReportingReport() { - if (outcome == Outcome::DELIVERED) { - // |delivered| should always have a value here, since the ReportingCache - // records the delivery time for any successful delivery. - UMA_HISTOGRAM_LONG_TIMES_100("Net.Reporting.ReportDeliveredLatency", - delivered.value() - queued); - UMA_HISTOGRAM_COUNTS_100("Net.Reporting.ReportDeliveredAttempts", attempts); - } RecordReportOutcome(outcome); } +ReportingEndpointGroupKey ReportingReport::GetGroupKey() const { + return ReportingEndpointGroupKey(network_isolation_key, + url::Origin::Create(url), group); +} + // static void ReportingReport::RecordReportDiscardedForNoURLRequestContext() { RecordReportOutcome(Outcome::DISCARDED_NO_URL_REQUEST_CONTEXT); diff --git a/chromium/net/reporting/reporting_report.h b/chromium/net/reporting/reporting_report.h index 02018ad25df..dee358878cc 100644 --- a/chromium/net/reporting/reporting_report.h +++ b/chromium/net/reporting/reporting_report.h @@ -12,6 +12,7 @@ #include "base/time/time.h" #include "net/base/net_export.h" #include "net/base/network_isolation_key.h" +#include "net/reporting/reporting_endpoint.h" #include "url/gurl.h" namespace base { @@ -65,6 +66,13 @@ struct NET_EXPORT ReportingReport { // Records metrics about report outcome. ~ReportingReport(); + // Bundles together the NIK, origin of the report URL, and group name. + // This is not exactly the same as the group key of the endpoint that the + // report will be delivered to. The origin may differ if the endpoint is + // configured for a superdomain of the report's origin. The NIK and group name + // will be the same. + ReportingEndpointGroupKey GetGroupKey() const; + static void RecordReportDiscardedForNoURLRequestContext(); static void RecordReportDiscardedForNoReportingService(); @@ -101,10 +109,6 @@ struct NET_EXPORT ReportingReport { // relative to the time of the delivery attempt.) base::TimeTicks queued; - // Time when report was delivered, if it was delivered successfully. - // The destructor assumes that this has a value if the outcome is DELIVERED. - base::Optional<base::TimeTicks> delivered = base::nullopt; - // The number of delivery attempts made so far, not including an active // attempt. (Not included in the delivered report.) int attempts = 0; diff --git a/chromium/net/reporting/reporting_service.cc b/chromium/net/reporting/reporting_service.cc index 2a410343302..ca44492f9e2 100644 --- a/chromium/net/reporting/reporting_service.cc +++ b/chromium/net/reporting/reporting_service.cc @@ -8,6 +8,7 @@ #include "base/bind.h" #include "base/json/json_reader.h" +#include "base/logging.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/time/tick_clock.h" @@ -81,18 +82,14 @@ class ReportingServiceImpl : public ReportingService { void ProcessHeader(const GURL& url, const std::string& header_string) override { - if (header_string.size() > kMaxJsonSize) { - ReportingHeaderParser::RecordHeaderDiscardedForJsonTooBig(); + if (header_string.size() > kMaxJsonSize) return; - } std::unique_ptr<base::Value> header_value = base::JSONReader::ReadDeprecated("[" + header_string + "]", base::JSON_PARSE_RFC, kMaxJsonDepth); - if (!header_value) { - ReportingHeaderParser::RecordHeaderDiscardedForJsonInvalid(); + if (!header_value) return; - } DVLOG(1) << "Received Reporting policy for " << url.GetOrigin(); // TODO(chlily): Get the proper NetworkIsolationKey from the caller. @@ -101,7 +98,7 @@ class ReportingServiceImpl : public ReportingService { NetworkIsolationKey::Todo(), url, std::move(header_value))); } - void RemoveBrowsingData(int data_type_mask, + void RemoveBrowsingData(uint64_t data_type_mask, const base::RepeatingCallback<bool(const GURL&)>& origin_filter) override { DoOrBacklogTask(base::BindOnce(&ReportingServiceImpl::DoRemoveBrowsingData, @@ -109,7 +106,7 @@ class ReportingServiceImpl : public ReportingService { origin_filter)); } - void RemoveAllBrowsingData(int data_type_mask) override { + void RemoveAllBrowsingData(uint64_t data_type_mask) override { DoOrBacklogTask( base::BindOnce(&ReportingServiceImpl::DoRemoveAllBrowsingData, base::Unretained(this), data_type_mask)); @@ -174,14 +171,14 @@ class ReportingServiceImpl : public ReportingService { } void DoRemoveBrowsingData( - int data_type_mask, + uint64_t data_type_mask, const base::RepeatingCallback<bool(const GURL&)>& origin_filter) { DCHECK(initialized_); ReportingBrowsingDataRemover::RemoveBrowsingData( context_->cache(), data_type_mask, origin_filter); } - void DoRemoveAllBrowsingData(int data_type_mask) { + void DoRemoveAllBrowsingData(uint64_t data_type_mask) { DCHECK(initialized_); ReportingBrowsingDataRemover::RemoveAllBrowsingData(context_->cache(), data_type_mask); diff --git a/chromium/net/reporting/reporting_service.h b/chromium/net/reporting/reporting_service.h index 233608c0b2a..e2152361002 100644 --- a/chromium/net/reporting/reporting_service.h +++ b/chromium/net/reporting/reporting_service.h @@ -68,12 +68,12 @@ class NET_EXPORT ReportingService { // Removes browsing data from the Reporting system. See // ReportingBrowsingDataRemover for more details. virtual void RemoveBrowsingData( - int data_type_mask, + uint64_t data_type_mask, const base::RepeatingCallback<bool(const GURL&)>& origin_filter) = 0; // Like RemoveBrowsingData except removes data for all origins without a // filter. - virtual void RemoveAllBrowsingData(int data_type_mask) = 0; + virtual void RemoveAllBrowsingData(uint64_t data_type_mask) = 0; // Shuts down the Reporting service so that no new headers or reports are // processed, and pending uploads are cancelled. diff --git a/chromium/net/reporting/reporting_service_unittest.cc b/chromium/net/reporting/reporting_service_unittest.cc index 96365b1adf0..0ac00ac44d7 100644 --- a/chromium/net/reporting/reporting_service_unittest.cc +++ b/chromium/net/reporting/reporting_service_unittest.cc @@ -44,11 +44,9 @@ class ReportingServiceTest : public ::testing::TestWithParam<bool>, const std::string kGroup_ = "group"; const std::string kType_ = "type"; const ReportingEndpointGroupKey kGroupKey_ = - ReportingEndpointGroupKey(NetworkIsolationKey::Todo(), kOrigin_, kGroup_); + ReportingEndpointGroupKey(NetworkIsolationKey(), kOrigin_, kGroup_); const ReportingEndpointGroupKey kGroupKey2_ = - ReportingEndpointGroupKey(NetworkIsolationKey::Todo(), - kOrigin2_, - kGroup_); + ReportingEndpointGroupKey(NetworkIsolationKey(), kOrigin2_, kGroup_); ReportingServiceTest() { if (GetParam()) diff --git a/chromium/net/reporting/reporting_test_util.cc b/chromium/net/reporting/reporting_test_util.cc index 47ebd724330..fc3b0150182 100644 --- a/chromium/net/reporting/reporting_test_util.cc +++ b/chromium/net/reporting/reporting_test_util.cc @@ -334,12 +334,12 @@ void TestReportingService::ProcessHeader(const GURL& url, } void TestReportingService::RemoveBrowsingData( - int data_type_mask, + uint64_t data_type_mask, const base::RepeatingCallback<bool(const GURL&)>& origin_filter) { NOTREACHED(); } -void TestReportingService::RemoveAllBrowsingData(int data_type_mask) { +void TestReportingService::RemoveAllBrowsingData(uint64_t data_type_mask) { NOTREACHED(); } diff --git a/chromium/net/reporting/reporting_test_util.h b/chromium/net/reporting/reporting_test_util.h index 5f7c990e5f6..e58f449154a 100644 --- a/chromium/net/reporting/reporting_test_util.h +++ b/chromium/net/reporting/reporting_test_util.h @@ -320,10 +320,10 @@ class TestReportingService : public ReportingService { void ProcessHeader(const GURL& url, const std::string& header_value) override; void RemoveBrowsingData( - int data_type_mask, + uint64_t data_type_mask, const base::RepeatingCallback<bool(const GURL&)>& origin_filter) override; - void RemoveAllBrowsingData(int data_type_mask) override; + void RemoveAllBrowsingData(uint64_t data_type_mask) override; void OnShutdown() override; diff --git a/chromium/net/reporting/reporting_uploader.cc b/chromium/net/reporting/reporting_uploader.cc index aacec913e1f..a54bfc4fcbe 100644 --- a/chromium/net/reporting/reporting_uploader.cc +++ b/chromium/net/reporting/reporting_uploader.cc @@ -9,8 +9,6 @@ #include <vector> #include "base/callback_helpers.h" -#include "base/metrics/histogram_functions.h" -#include "base/metrics/histogram_macros.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" #include "net/base/elements_upload_data_stream.h" @@ -78,27 +76,6 @@ ReportingUploader::Outcome ResponseCodeToOutcome(int response_code) { return ReportingUploader::Outcome::FAILURE; } -enum class UploadOutcome { - CANCELED_REDIRECT_TO_INSECURE_URL = 0, - CANCELED_AUTH_REQUIRED = 1, - CANCELED_CERTIFICATE_REQUESTED = 2, - CANCELED_SSL_CERTIFICATE_ERROR = 3, - CANCELED_REPORTING_SHUTDOWN = 4, - FAILED = 5, // See Net.Reporting.UploadError for breakdown. - SUCCEEDED_SUCCESS = 6, - SUCCEEDED_REMOVE_ENDPOINT = 7, - CORS_PREFLIGHT_ERROR = 8, - - MAX -}; - -void RecordUploadOutcome(UploadOutcome outcome) { - UMA_HISTOGRAM_ENUMERATION("Net.Reporting.UploadOutcome", outcome, - UploadOutcome::MAX); -} - -// TODO: Record net and HTTP error. - struct PendingUpload { enum State { CREATED, SENDING_PREFLIGHT, SENDING_PAYLOAD }; @@ -269,8 +246,6 @@ class ReportingUploaderImpl : public ReportingUploader, URLRequest::Delegate { uploads_.erase(it); if (net_error != OK) { - RecordUploadOutcome(UploadOutcome::FAILED); - base::UmaHistogramSparse("Net.Reporting.UploadError", net_error); upload->RunCallback(ReportingUploader::Outcome::FAILURE); return; } @@ -310,7 +285,6 @@ class ReportingUploaderImpl : public ReportingUploader, URLRequest::Delegate { HasHeaderValues(request, "Access-Control-Allow-Headers", {"content-type"}); if (!preflight_succeeded) { - RecordUploadOutcome(UploadOutcome::CORS_PREFLIGHT_ERROR); upload->RunCallback(ReportingUploader::Outcome::FAILURE); return; } @@ -320,14 +294,6 @@ class ReportingUploaderImpl : public ReportingUploader, URLRequest::Delegate { void HandlePayloadResponse(std::unique_ptr<PendingUpload> upload, int response_code) { - if (response_code >= 200 && response_code <= 299) { - RecordUploadOutcome(UploadOutcome::SUCCEEDED_SUCCESS); - } else if (response_code == 410) { - RecordUploadOutcome(UploadOutcome::SUCCEEDED_REMOVE_ENDPOINT); - } else { - RecordUploadOutcome(UploadOutcome::FAILED); - base::UmaHistogramSparse("Net.Reporting.UploadError", response_code); - } upload->RunCallback(ResponseCodeToOutcome(response_code)); } diff --git a/chromium/net/reporting/reporting_uploader_unittest.cc b/chromium/net/reporting/reporting_uploader_unittest.cc index 66b61e7e4ef..364585b3cfd 100644 --- a/chromium/net/reporting/reporting_uploader_unittest.cc +++ b/chromium/net/reporting/reporting_uploader_unittest.cc @@ -14,6 +14,7 @@ #include "base/test/scoped_feature_list.h" #include "net/base/features.h" #include "net/base/network_isolation_key.h" +#include "net/cookies/cookie_inclusion_status.h" #include "net/cookies/cookie_store.h" #include "net/cookies/cookie_store_test_callbacks.h" #include "net/http/http_status_code.h" @@ -446,8 +447,7 @@ TEST_F(ReportingUploaderTest, DontSendCookies) { server_.RegisterRequestHandler(base::BindRepeating(&ReturnResponse, HTTP_OK)); ASSERT_TRUE(server_.Start()); - ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus> - cookie_callback; + ResultSavingCookieCallback<CookieInclusionStatus> cookie_callback; GURL url = server_.GetURL("/"); auto cookie = CanonicalCookie::Create(url, "foo=bar", base::Time::Now(), base::nullopt /* server_time */); diff --git a/chromium/net/socket/client_socket_handle.h b/chromium/net/socket/client_socket_handle.h index 727972d7de4..9282dae7dd8 100644 --- a/chromium/net/socket/client_socket_handle.h +++ b/chromium/net/socket/client_socket_handle.h @@ -10,7 +10,7 @@ #include <utility> #include "base/bind.h" -#include "base/logging.h" +#include "base/check.h" #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/optional.h" diff --git a/chromium/net/socket/client_socket_pool_base_unittest.cc b/chromium/net/socket/client_socket_pool_base_unittest.cc index be3196e53bc..29e27ab3e7d 100644 --- a/chromium/net/socket/client_socket_pool_base_unittest.cc +++ b/chromium/net/socket/client_socket_pool_base_unittest.cc @@ -4224,11 +4224,11 @@ TEST_F(ClientSocketPoolBaseTest, PreconnectWithoutBackupJob) { // Verify the backup timer doesn't create a backup job, by making // the backup job a pending job instead of a waiting job, so it // *would* complete if it were created. + base::RunLoop loop; connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob); base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( - FROM_HERE, base::RunLoop::QuitCurrentWhenIdleClosureDeprecated(), - base::TimeDelta::FromSeconds(1)); - base::RunLoop().Run(); + FROM_HERE, loop.QuitClosure(), base::TimeDelta::FromSeconds(1)); + loop.Run(); EXPECT_FALSE(pool_->HasGroupForTesting(TestGroupId("a"))); } diff --git a/chromium/net/socket/socket_posix.cc b/chromium/net/socket/socket_posix.cc index 61cc75851ca..807ef26f78b 100644 --- a/chromium/net/socket/socket_posix.cc +++ b/chromium/net/socket/socket_posix.cc @@ -384,7 +384,7 @@ int SocketPosix::GetPeerAddress(SockaddrStorage* address) const { void SocketPosix::SetPeerAddress(const SockaddrStorage& address) { DCHECK(thread_checker_.CalledOnValidThread()); - // |peer_address_| will be non-NULL if Connect() has been called. Unless + // |peer_address_| will be non-nullptr if Connect() has been called. Unless // Close() is called to reset the internal state, a second call to Connect() // is not allowed. // Please note that we don't allow a second Connect() even if the previous @@ -397,7 +397,7 @@ void SocketPosix::SetPeerAddress(const SockaddrStorage& address) { bool SocketPosix::HasPeerAddress() const { DCHECK(thread_checker_.CalledOnValidThread()); - return peer_address_ != NULL; + return peer_address_ != nullptr; } void SocketPosix::Close() { @@ -455,7 +455,7 @@ void SocketPosix::AcceptCompleted() { bool ok = accept_socket_watcher_.StopWatchingFileDescriptor(); DCHECK(ok); - accept_socket_ = NULL; + accept_socket_ = nullptr; std::move(accept_callback_).Run(rv); } @@ -560,7 +560,7 @@ void SocketPosix::StopWatchingAndCleanUp(bool close_socket) { } if (!accept_callback_.is_null()) { - accept_socket_ = NULL; + accept_socket_ = nullptr; accept_callback_.Reset(); } diff --git a/chromium/net/socket/socket_test_util.h b/chromium/net/socket/socket_test_util.h index fee1b1f7aa2..8cc3aeedef4 100644 --- a/chromium/net/socket/socket_test_util.h +++ b/chromium/net/socket/socket_test_util.h @@ -16,8 +16,8 @@ #include "base/bind.h" #include "base/callback.h" +#include "base/check_op.h" #include "base/containers/span.h" -#include "base/logging.h" #include "base/macros.h" #include "base/memory/ptr_util.h" #include "base/memory/ref_counted.h" diff --git a/chromium/net/socket/ssl_client_socket_impl.cc b/chromium/net/socket/ssl_client_socket_impl.cc index 12fb37570a5..fcada6e3420 100644 --- a/chromium/net/socket/ssl_client_socket_impl.cc +++ b/chromium/net/socket/ssl_client_socket_impl.cc @@ -900,8 +900,12 @@ int SSLClientSocketImpl::Init() { // TODO(https://crbug.com/775438), if |ssl_config_.privacy_mode| is enabled, // this should always continue with no client certificate. - send_client_cert_ = context_->GetClientCertificate( - host_and_port_, &client_cert_, &client_private_key_); + if (ssl_config_.privacy_mode == PRIVACY_MODE_ENABLED_WITHOUT_CLIENT_CERTS) { + send_client_cert_ = true; + } else { + send_client_cert_ = context_->GetClientCertificate( + host_and_port_, &client_cert_, &client_private_key_); + } return OK; } @@ -1012,13 +1016,10 @@ int SSLClientSocketImpl::DoHandshakeComplete(int result) { // See how feasible enforcing RSA key usage would be. See // https://crbug.com/795089. - RSAKeyUsage rsa_key_usage = - CheckRSAKeyUsage(server_cert_.get(), SSL_get_current_cipher(ssl_.get())); - if (rsa_key_usage != RSAKeyUsage::kNotRSA) { - if (server_cert_verify_result_.is_issued_by_known_root) { - UMA_HISTOGRAM_ENUMERATION("Net.SSLRSAKeyUsage.KnownRoot", rsa_key_usage, - static_cast<int>(RSAKeyUsage::kLastValue) + 1); - } else { + if (!server_cert_verify_result_.is_issued_by_known_root) { + RSAKeyUsage rsa_key_usage = CheckRSAKeyUsage( + server_cert_.get(), SSL_get_current_cipher(ssl_.get())); + if (rsa_key_usage != RSAKeyUsage::kNotRSA) { UMA_HISTOGRAM_ENUMERATION("Net.SSLRSAKeyUsage.UnknownRoot", rsa_key_usage, static_cast<int>(RSAKeyUsage::kLastValue) + 1); } @@ -1648,7 +1649,8 @@ int SSLClientSocketImpl::VerifyCT() { server_cert_verify_result_.verified_cert.get(), server_cert_.get(), ct_verify_result_.scts, TransportSecurityState::ENABLE_EXPECT_CT_REPORTS, - ct_verify_result_.policy_compliance); + ct_verify_result_.policy_compliance, + ssl_config_.network_isolation_key); if (ct_requirement_status != TransportSecurityState::CT_NOT_REQUIRED) { ct_verify_result_.policy_compliance_required = true; if (server_cert_verify_result_.is_issued_by_known_root) { diff --git a/chromium/net/socket/ssl_client_socket_unittest.cc b/chromium/net/socket/ssl_client_socket_unittest.cc index 41aea1c8951..31e4179058c 100644 --- a/chromium/net/socket/ssl_client_socket_unittest.cc +++ b/chromium/net/socket/ssl_client_socket_unittest.cc @@ -563,34 +563,40 @@ class MockExpectCTReporter : public TransportSecurityState::ExpectCTReporter { MockExpectCTReporter() : num_failures_(0) {} ~MockExpectCTReporter() override = default; - void OnExpectCTFailed(const HostPortPair& host_port_pair, - const GURL& report_uri, - base::Time expiration, - const X509Certificate* validated_certificate_chain, - const X509Certificate* served_certificate_chain, - const SignedCertificateTimestampAndStatusList& - signed_certificate_timestamps) override { + void OnExpectCTFailed( + const HostPortPair& host_port_pair, + const GURL& report_uri, + base::Time expiration, + const X509Certificate* validated_certificate_chain, + const X509Certificate* served_certificate_chain, + const SignedCertificateTimestampAndStatusList& + signed_certificate_timestamps, + const NetworkIsolationKey& network_isolation_key) override { num_failures_++; host_port_pair_ = host_port_pair; report_uri_ = report_uri; served_certificate_chain_ = served_certificate_chain; validated_certificate_chain_ = validated_certificate_chain; signed_certificate_timestamps_ = signed_certificate_timestamps; + network_isolation_key_ = network_isolation_key; } - const HostPortPair& host_port_pair() { return host_port_pair_; } - const GURL& report_uri() { return report_uri_; } - uint32_t num_failures() { return num_failures_; } - const X509Certificate* served_certificate_chain() { + const HostPortPair& host_port_pair() const { return host_port_pair_; } + const GURL& report_uri() const { return report_uri_; } + uint32_t num_failures() const { return num_failures_; } + const X509Certificate* served_certificate_chain() const { return served_certificate_chain_; } - const X509Certificate* validated_certificate_chain() { + const X509Certificate* validated_certificate_chain() const { return validated_certificate_chain_; } - const SignedCertificateTimestampAndStatusList& - signed_certificate_timestamps() { + const SignedCertificateTimestampAndStatusList& signed_certificate_timestamps() + const { return signed_certificate_timestamps_; } + const NetworkIsolationKey network_isolation_key() const { + return network_isolation_key_; + } private: HostPortPair host_port_pair_; @@ -599,6 +605,7 @@ class MockExpectCTReporter : public TransportSecurityState::ExpectCTReporter { const X509Certificate* served_certificate_chain_; const X509Certificate* validated_certificate_chain_; SignedCertificateTimestampAndStatusList signed_certificate_timestamps_; + NetworkIsolationKey network_isolation_key_; }; // A mock CTVerifier that records every call to Verify but doesn't verify @@ -4172,9 +4179,9 @@ TEST_P(SSLClientSocketVersionTest, CTRequiredHistogramCompliant) { // Set up the Expect-CT opt-in. const base::Time current_time(base::Time::Now()); const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000); - transport_security_state_->AddExpectCT(host_port_pair().host(), expiry, - true /* enforce */, - GURL("https://example-report.test")); + transport_security_state_->AddExpectCT( + host_port_pair().host(), expiry, true /* enforce */, + GURL("https://example-report.test"), NetworkIsolationKey()); MockExpectCTReporter reporter; transport_security_state_->SetExpectCTReporter(&reporter); @@ -4257,9 +4264,9 @@ TEST_P(SSLClientSocketVersionTest, CTRequiredHistogramNonCompliant) { // Set up the Expect-CT opt-in. const base::Time current_time(base::Time::Now()); const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000); - transport_security_state_->AddExpectCT(host_port_pair().host(), expiry, - true /* enforce */, - GURL("https://example-report.test")); + transport_security_state_->AddExpectCT( + host_port_pair().host(), expiry, true /* enforce */, + GURL("https://example-report.test"), NetworkIsolationKey()); MockExpectCTReporter reporter; transport_security_state_->SetExpectCTReporter(&reporter); @@ -4301,7 +4308,8 @@ TEST_P(SSLClientSocketVersionTest, CTRequirementsFlagNotMet) { const base::Time current_time(base::Time::Now()); const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000); transport_security_state_->AddExpectCT(host_port_pair().host(), expiry, - true /* enforce */, GURL()); + true /* enforce */, GURL(), + NetworkIsolationKey()); EXPECT_CALL(*ct_policy_enforcer_, CheckCompliance(server_cert.get(), _, _)) .WillRepeatedly( @@ -4335,7 +4343,8 @@ TEST_P(SSLClientSocketVersionTest, CTRequirementsFlagMet) { const base::Time current_time(base::Time::Now()); const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000); transport_security_state_->AddExpectCT(host_port_pair().host(), expiry, - true /* enforce */, GURL()); + true /* enforce */, GURL(), + NetworkIsolationKey()); EXPECT_CALL(*ct_policy_enforcer_, CheckCompliance(server_cert.get(), _, _)) .WillRepeatedly( @@ -4417,11 +4426,13 @@ TEST_P(SSLClientSocketVersionTest, CTIsRequiredByExpectCT) { cert_verifier_->AddResultForCert(server_cert.get(), verify_result, OK); // Set up the Expect-CT opt-in. + NetworkIsolationKey network_isolation_key = + NetworkIsolationKey::CreateTransient(); const base::Time current_time(base::Time::Now()); const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000); - transport_security_state_->AddExpectCT(host_port_pair().host(), expiry, - true /* enforce */, - GURL("https://example-report.test")); + transport_security_state_->AddExpectCT( + host_port_pair().host(), expiry, true /* enforce */, + GURL("https://example-report.test"), NetworkIsolationKey()); MockExpectCTReporter reporter; transport_security_state_->SetExpectCTReporter(&reporter); @@ -4430,6 +4441,7 @@ TEST_P(SSLClientSocketVersionTest, CTIsRequiredByExpectCT) { Return(ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS)); SSLConfig ssl_config; + ssl_config.network_isolation_key = network_isolation_key; int rv; ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv)); SSLInfo ssl_info; @@ -4446,6 +4458,7 @@ TEST_P(SSLClientSocketVersionTest, CTIsRequiredByExpectCT) { reporter.served_certificate_chain()); EXPECT_EQ(ssl_info.cert.get(), reporter.validated_certificate_chain()); EXPECT_EQ(0u, reporter.signed_certificate_timestamps().size()); + EXPECT_EQ(network_isolation_key, reporter.network_isolation_key()); transport_security_state_->ClearReportCachesForTesting(); EXPECT_CALL(*ct_policy_enforcer_, CheckCompliance(server_cert.get(), _, _)) @@ -4465,6 +4478,7 @@ TEST_P(SSLClientSocketVersionTest, CTIsRequiredByExpectCT) { reporter.served_certificate_chain()); EXPECT_EQ(ssl_info.cert.get(), reporter.validated_certificate_chain()); EXPECT_EQ(0u, reporter.signed_certificate_timestamps().size()); + EXPECT_EQ(network_isolation_key, reporter.network_isolation_key()); // If the connection is CT compliant, then there should be no socket error nor // a report. @@ -5586,6 +5600,7 @@ TEST_P(TLS13DowngradeMetricsTest, Metrics) { SSLContextConfig config; config.version_max = SSL_PROTOCOL_VERSION_TLS1_3; + config.tls13_hardening_for_local_anchors_enabled = false; ssl_config_service_->UpdateSSLConfigAndNotify(config); std::unique_ptr<SSLClientSocket> ssl_socket = diff --git a/chromium/net/socket/transport_client_socket_pool.cc b/chromium/net/socket/transport_client_socket_pool.cc index 3d5aff54368..6e01e7c0be5 100644 --- a/chromium/net/socket/transport_client_socket_pool.cc +++ b/chromium/net/socket/transport_client_socket_pool.cc @@ -1201,13 +1201,6 @@ void TransportClientSocketPool::HandOutSocket( static_cast<int>(idle_time.InMilliseconds())); } - if (reuse_type != ClientSocketHandle::UNUSED) { - // The socket being handed out is no longer considered idle, but was - // considered idle until just before this method was called. - UMA_HISTOGRAM_CUSTOM_COUNTS("Net.Socket.NumIdleSockets", - idle_socket_count_ + 1, 1, 256, 50); - } - net_log.AddEventReferencingSource( NetLogEventType::SOCKET_POOL_BOUND_TO_SOCKET, handle->socket()->NetLog().source()); diff --git a/chromium/net/socket/udp_socket_posix.cc b/chromium/net/socket/udp_socket_posix.cc index 0b61ca9bac2..32f0f199824 100644 --- a/chromium/net/socket/udp_socket_posix.cc +++ b/chromium/net/socket/udp_socket_posix.cc @@ -197,7 +197,7 @@ UDPSocketPosix::UDPSocketPosix(DatagramSocket::BindType bind_type, write_async_timer_running_(false), write_async_outstanding_(0), read_buf_len_(0), - recv_from_address_(NULL), + recv_from_address_(nullptr), write_buf_len_(0), net_log_(NetLogWithSource::Make(net_log, NetLogSourceType::UDP_SOCKET)), bound_network_(NetworkChangeNotifier::kInvalidNetworkHandle), @@ -220,8 +220,8 @@ int UDPSocketPosix::Open(AddressFamily address_family) { if (socket_ == kInvalidSocket) return MapSystemError(errno); #if defined(OS_MACOSX) && !defined(OS_IOS) - PCHECK(change_fdguard_np(socket_, NULL, 0, &kSocketFdGuard, - GUARD_CLOSE | GUARD_DUP, NULL) == 0); + PCHECK(change_fdguard_np(socket_, nullptr, 0, &kSocketFdGuard, + GUARD_CLOSE | GUARD_DUP, nullptr) == 0); #endif // defined(OS_MACOSX) && !defined(OS_IOS) socket_hash_ = GetSocketFDHash(socket_); if (!base::SetNonBlocking(socket_)) { @@ -299,7 +299,7 @@ void UDPSocketPosix::Close() { read_buf_.reset(); read_buf_len_ = 0; read_callback_.Reset(); - recv_from_address_ = NULL; + recv_from_address_ = nullptr; write_buf_.reset(); write_buf_len_ = 0; write_callback_.Reset(); @@ -375,7 +375,7 @@ int UDPSocketPosix::GetLocalAddress(IPEndPoint* address) const { int UDPSocketPosix::Read(IOBuffer* buf, int buf_len, CompletionOnceCallback callback) { - return RecvFrom(buf, buf_len, NULL, std::move(callback)); + return RecvFrom(buf, buf_len, nullptr, std::move(callback)); } int UDPSocketPosix::RecvFrom(IOBuffer* buf, @@ -398,7 +398,7 @@ int UDPSocketPosix::RecvFrom(IOBuffer* buf, &read_socket_watcher_, &read_watcher_)) { PLOG(ERROR) << "WatchFileDescriptor failed on read"; int result = MapSystemError(errno); - LogRead(result, NULL, 0, NULL); + LogRead(result, nullptr, 0, nullptr); return result; } @@ -414,7 +414,7 @@ int UDPSocketPosix::Write( int buf_len, CompletionOnceCallback callback, const NetworkTrafficAnnotationTag& traffic_annotation) { - return SendToOrWrite(buf, buf_len, NULL, std::move(callback)); + return SendToOrWrite(buf, buf_len, nullptr, std::move(callback)); } int UDPSocketPosix::SendTo(IOBuffer* buf, @@ -443,7 +443,7 @@ int UDPSocketPosix::SendToOrWrite(IOBuffer* buf, &write_socket_watcher_, &write_watcher_)) { DVPLOG(1) << "WatchFileDescriptor failed on write"; int result = MapSystemError(errno); - LogWrite(result, NULL, NULL); + LogWrite(result, nullptr, nullptr); return result; } @@ -742,7 +742,7 @@ void UDPSocketPosix::DidCompleteRead() { if (result != ERR_IO_PENDING) { read_buf_.reset(); read_buf_len_ = 0; - recv_from_address_ = NULL; + recv_from_address_ = nullptr; bool ok = read_socket_watcher_.StopWatchingFileDescriptor(); DCHECK(ok); DoReadCallback(result); @@ -884,12 +884,12 @@ int UDPSocketPosix::InternalSendTo(IOBuffer* buf, SockaddrStorage storage; struct sockaddr* addr = storage.addr; if (!address) { - addr = NULL; + addr = nullptr; storage.addr_len = 0; } else { if (!address->ToSockAddr(storage.addr, &storage.addr_len)) { int result = ERR_ADDRESS_INVALID; - LogWrite(result, NULL, NULL); + LogWrite(result, nullptr, nullptr); return result; } } @@ -1382,7 +1382,7 @@ void UDPSocketPosix::DidSendBuffers(SendResult send_result) { it = buffers.cbegin(); for (int i = 0; i < write_count; i++, it++) { auto& buffer = *it; - LogWrite(buffer->length(), buffer->data(), NULL); + LogWrite(buffer->length(), buffer->data(), nullptr); written_bytes_ += buffer->length(); } // Return written buffers to pool @@ -1413,7 +1413,7 @@ void UDPSocketPosix::DidSendBuffers(SendResult send_result) { if (!WatchFileDescriptor()) { DVPLOG(1) << "WatchFileDescriptor failed on write"; last_async_result_ = MapSystemError(errno); - LogWrite(last_async_result_, NULL, NULL); + LogWrite(last_async_result_, nullptr, nullptr); } else { last_async_result_ = 0; } diff --git a/chromium/net/socket/udp_socket_posix.h b/chromium/net/socket/udp_socket_posix.h index ce96046e720..df3bf9735ba 100644 --- a/chromium/net/socket/udp_socket_posix.h +++ b/chromium/net/socket/udp_socket_posix.h @@ -11,6 +11,7 @@ #include <memory> +#include "base/logging.h" #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/message_loop/message_pump_for_io.h" @@ -493,7 +494,7 @@ class NET_EXPORT UDPSocketPosix { // Same as SendTo(), except that address is passed by pointer // instead of by reference. It is called from Write() with |address| - // set to NULL. + // set to nullptr. int SendToOrWrite(IOBuffer* buf, int buf_len, const IPEndPoint* address, diff --git a/chromium/net/socket/websocket_endpoint_lock_manager.h b/chromium/net/socket/websocket_endpoint_lock_manager.h index 4e96c736a10..cdd8e033b9d 100644 --- a/chromium/net/socket/websocket_endpoint_lock_manager.h +++ b/chromium/net/socket/websocket_endpoint_lock_manager.h @@ -11,7 +11,6 @@ #include <memory> #include "base/containers/linked_list.h" -#include "base/logging.h" #include "base/macros.h" #include "base/time/time.h" #include "net/base/ip_endpoint.h" diff --git a/chromium/net/spdy/OWNERS b/chromium/net/spdy/OWNERS index b608e73eafc..e041764c5b6 100644 --- a/chromium/net/spdy/OWNERS +++ b/chromium/net/spdy/OWNERS @@ -2,7 +2,6 @@ birenroy@chromium.org bnc@chromium.org dahollings@chromium.org diannahu@chromium.org -rch@chromium.org yasong@chromium.org # COMPONENT: Internals>Network>HTTP2 diff --git a/chromium/net/spdy/platform/impl/spdy_logging_impl.h b/chromium/net/spdy/platform/impl/spdy_logging_impl.h index cc79854df01..a9ba72bbb76 100644 --- a/chromium/net/spdy/platform/impl/spdy_logging_impl.h +++ b/chromium/net/spdy/platform/impl/spdy_logging_impl.h @@ -5,7 +5,9 @@ #ifndef NET_SPDY_PLATFORM_IMPL_SPDY_LOGGING_IMPL_H_ #define NET_SPDY_PLATFORM_IMPL_SPDY_LOGGING_IMPL_H_ +#include "base/check_op.h" #include "base/logging.h" +#include "base/notreached.h" #include "build/build_config.h" #include "net/base/net_export.h" diff --git a/chromium/net/spdy/platform/impl/spdy_macros_impl.h b/chromium/net/spdy/platform/impl/spdy_macros_impl.h index fb286bc9ab0..3c1da5102c3 100644 --- a/chromium/net/spdy/platform/impl/spdy_macros_impl.h +++ b/chromium/net/spdy/platform/impl/spdy_macros_impl.h @@ -6,7 +6,6 @@ #define NET_SPDY_PLATFORM_IMPL_SPDY_MACROS_IMPL_H_ #include "base/compiler_specific.h" -#include "base/logging.h" #define SPDY_MUST_USE_RESULT_IMPL WARN_UNUSED_RESULT #define SPDY_UNUSED_IMPL ALLOW_UNUSED_TYPE diff --git a/chromium/net/spdy/spdy_network_transaction_unittest.cc b/chromium/net/spdy/spdy_network_transaction_unittest.cc index 1da839038e0..0caead021a1 100644 --- a/chromium/net/spdy/spdy_network_transaction_unittest.cc +++ b/chromium/net/spdy/spdy_network_transaction_unittest.cc @@ -41,6 +41,8 @@ #include "net/http/http_response_info.h" #include "net/http/http_server_properties.h" #include "net/http/http_transaction_test_util.h" +#include "net/http/test_upload_data_stream_not_allow_http1.h" +#include "net/http/transport_security_state.h" #include "net/log/net_log_event_type.h" #include "net/log/net_log_with_source.h" #include "net/log/test_net_log.h" @@ -411,7 +413,8 @@ class SpdyNetworkTransactionTest : public TestWithTaskEnvironment { SpdySessionKey key(HostPortPair::FromURL(request_.url), ProxyServer::Direct(), PRIVACY_MODE_DISABLED, SpdySessionKey::IsProxySession::kFalse, SocketTag(), - NetworkIsolationKey(), false /* disable_secure_dns */); + request_.network_isolation_key, + false /* disable_secure_dns */); HttpNetworkSession* session = helper.session(); base::WeakPtr<SpdySession> spdy_session = session->spdy_session_pool()->FindAvailableSession( @@ -5177,7 +5180,7 @@ TEST_F(SpdyNetworkTransactionTest, FailOnGoAway) { NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr); helper.RunToCompletion(&data); TransactionHelperResult out = helper.output(); - EXPECT_THAT(out.rv, IsError(ERR_ABORTED)); + EXPECT_THAT(out.rv, IsError(ERR_HTTP2_PROTOCOL_ERROR)); } // Request should be retried on a new connection upon receiving a GOAWAY frame @@ -6414,28 +6417,53 @@ struct PushUrlTestParams { const char* url_to_fetch; const char* url_to_push; bool client_cert_sent; + bool expect_ct_error; SpdyPushedStreamFate expected_fate; } push_url_test_cases[] = { // http scheme cannot be pushed (except by trusted proxy). - {"https://www.example.org/foo.html", "http://www.example.org/foo.js", false, + {"https://www.example.org/foo.html", "http://www.example.org/foo.js", + false /* client_cert_sent */, false /* expect_ct_error */, SpdyPushedStreamFate::kNonHttpsPushedScheme}, // ftp scheme cannot be pushed. - {"https://www.example.org/foo.html", "ftp://www.example.org/foo.js", false, + {"https://www.example.org/foo.html", "ftp://www.example.org/foo.js", + false /* client_cert_sent */, false /* expect_ct_error */, SpdyPushedStreamFate::kInvalidUrl}, // Cross subdomain, certificate not valid. {"https://www.example.org/foo.html", "https://blat.www.example.org/foo.js", - false, SpdyPushedStreamFate::kCertificateMismatch}, + false /* client_cert_sent */, false /* expect_ct_error */, + SpdyPushedStreamFate::kCertificateMismatch}, // Cross domain, certificate not valid. - {"https://www.example.org/foo.html", "https://www.foo.com/foo.js", false, + {"https://www.example.org/foo.html", "https://www.foo.com/foo.js", + false /* client_cert_sent */, false /* expect_ct_error */, SpdyPushedStreamFate::kCertificateMismatch}, // Cross domain, certificate valid, but cross-origin push is rejected on a // connection with client certificate. {"https://www.example.org/foo.html", "https://mail.example.org/foo.js", - true, SpdyPushedStreamFate::kCertificateMismatch}}; + true /* client_cert_sent */, false /* expect_ct_error */, + SpdyPushedStreamFate::kCertificateMismatch}, + // Cross domain, certificate valid, but cross-origin push is rejected on a + // connection with an Expect-CT error. + {"https://www.example.org/foo.html", "https://mail.example.org/foo.js", + false /* client_cert_sent */, true /* expect_ct_error */, + SpdyPushedStreamFate::kCertificateMismatch}}; class SpdyNetworkTransactionPushUrlTest : public SpdyNetworkTransactionTest, public ::testing::WithParamInterface<PushUrlTestParams> { + public: + SpdyNetworkTransactionPushUrlTest() { + // Set features needed for the |expect_ct_error| case, where it's important + // to check that NetworkIsolationKeys are respected. + feature_list_.InitWithFeatures( + /* enabled_features */ + {TransportSecurityState::kDynamicExpectCTFeature, + features::kPartitionExpectCTStateByNetworkIsolationKey, + features::kPartitionConnectionsByNetworkIsolationKey, + features::kPartitionSSLSessionsByNetworkIsolationKey}, + /* disabled_features */ + {}); + } + protected: // In this test we want to verify that we can't accidentally push content // which can't be pushed by this content server. @@ -6478,6 +6506,9 @@ class SpdyNetworkTransactionPushUrlTest SequencedSocketData data(reads, writes); request_.url = GURL(GetParam().url_to_fetch); + // Set a NetworkIsolationKey for the |expect_ct_error| case, to make sure + // NetworkIsolationKeys are respected. + request_.network_isolation_key = NetworkIsolationKey::CreateTransient(); // Enable cross-origin push. Since we are not using a proxy, this should // not actually enable cross-origin SPDY push. @@ -6487,15 +6518,33 @@ class SpdyNetworkTransactionPushUrlTest "https://123.45.67.89:443", net::ProxyServer::SCHEME_HTTP)); session_deps->proxy_resolution_service->SetProxyDelegate( proxy_delegate.get()); - NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, - std::move(session_deps)); - - helper.RunPreTestSetup(); auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK); ssl_provider->ssl_info.client_cert_sent = GetParam().client_cert_sent; ssl_provider->ssl_info.cert = ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem"); + if (GetParam().expect_ct_error) { + ssl_provider->ssl_info.ct_policy_compliance = + ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS; + ssl_provider->ssl_info.is_issued_by_known_root = true; + + session_deps->transport_security_state->AddExpectCT( + "mail.example.org", + base::Time::Now() + base::TimeDelta::FromDays(1) /* expiry */, true, + GURL(), request_.network_isolation_key); + } + + NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, + std::move(session_deps)); + + helper.RunPreTestSetup(); + + if (GetParam().expect_ct_error) { + ssl_provider->ssl_info.ct_policy_compliance = + ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS; + ssl_provider->ssl_info.is_issued_by_known_root = true; + } + helper.AddDataWithSSLSocketDataProvider(&data, std::move(ssl_provider)); HttpNetworkTransaction* trans = helper.trans(); @@ -6533,6 +6582,8 @@ class SpdyNetworkTransactionPushUrlTest 1); histogram_tester.ExpectTotalCount("Net.SpdyPushedStreamFate", 1); } + + base::test::ScopedFeatureList feature_list_; }; INSTANTIATE_TEST_SUITE_P(All, @@ -10438,4 +10489,30 @@ TEST_F(SpdyNetworkTransactionTest, OnDataSentDoesNotCrashWithGreasedFrameType) { helper.VerifyDataConsumed(); } +TEST_F(SpdyNetworkTransactionTest, NotAllowHTTP1NotBlockH2Post) { + spdy::SpdySerializedFrame req( + spdy_util_.ConstructChunkedSpdyPost(nullptr, 0)); + spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true)); + MockWrite writes[] = { + CreateMockWrite(req, 0), CreateMockWrite(body, 1), // POST upload frame + }; + spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0)); + MockRead reads[] = { + CreateMockRead(resp, 2), CreateMockRead(body, 3), + MockRead(ASYNC, 0, 4) // EOF + }; + SequencedSocketData data(reads, writes); + + request_.method = "POST"; + UploadDataStreamNotAllowHTTP1 upload_data(kUploadData); + request_.upload_data_stream = &upload_data; + + NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr); + helper.RunToCompletion(&data); + TransactionHelperResult out = helper.output(); + EXPECT_THAT(out.rv, IsOk()); + EXPECT_EQ("HTTP/1.1 200", out.status_line); + EXPECT_EQ("hello!", out.response_data); +} + } // namespace net diff --git a/chromium/net/spdy/spdy_session.cc b/chromium/net/spdy/spdy_session.cc index b61963f6716..eef09df91ed 100644 --- a/chromium/net/spdy/spdy_session.cc +++ b/chromium/net/spdy/spdy_session.cc @@ -27,6 +27,7 @@ #include "base/trace_event/memory_usage_estimator.h" #include "base/trace_event/trace_event.h" #include "base/values.h" +#include "net/base/features.h" #include "net/base/url_util.h" #include "net/cert/asn1_util.h" #include "net/cert/cert_verify_result.h" @@ -836,11 +837,13 @@ void SpdyStreamRequest::OnConfirmHandshakeComplete(int rv) { } // static -bool SpdySession::CanPool(TransportSecurityState* transport_security_state, - const SSLInfo& ssl_info, - const SSLConfigService& ssl_config_service, - const std::string& old_hostname, - const std::string& new_hostname) { +bool SpdySession::CanPool( + TransportSecurityState* transport_security_state, + const SSLInfo& ssl_info, + const SSLConfigService& ssl_config_service, + const std::string& old_hostname, + const std::string& new_hostname, + const net::NetworkIsolationKey& network_isolation_key) { // Pooling is prohibited if the server cert is not valid for the new domain, // and for connections on which client certs were sent. It is also prohibited // when channel ID was sent if the hosts are from different eTLDs+1. @@ -875,7 +878,7 @@ bool SpdySession::CanPool(TransportSecurityState* transport_security_state, ssl_info.public_key_hashes, ssl_info.cert.get(), ssl_info.unverified_cert.get(), ssl_info.signed_certificate_timestamps, TransportSecurityState::DISABLE_EXPECT_CT_REPORTS, - ssl_info.ct_policy_compliance)) { + ssl_info.ct_policy_compliance, network_isolation_key)) { case TransportSecurityState::CT_REQUIREMENTS_NOT_MET: return false; case TransportSecurityState::CT_REQUIREMENTS_MET: @@ -1098,7 +1101,8 @@ bool SpdySession::VerifyDomainAuthentication(const std::string& domain) const { return true; // This is not a secure session, so all domains are okay. return CanPool(transport_security_state_, ssl_info, *ssl_config_service_, - host_port_pair().host(), domain); + host_port_pair().host(), domain, + spdy_session_key_.network_isolation_key()); } void SpdySession::EnqueueStreamWrite( @@ -1165,15 +1169,13 @@ std::unique_ptr<spdy::SpdySerializedFrame> SpdySession::CreateHeaders( priority_dependency_state_.OnStreamCreation( stream_id, spdy_priority, &parent_stream_id, &weight, &exclusive); - if (net_log().IsCapturing()) { - net_log().AddEvent(NetLogEventType::HTTP2_SESSION_SEND_HEADERS, - [&](NetLogCaptureMode capture_mode) { - return NetLogSpdyHeadersSentParams( - &block, (flags & spdy::CONTROL_FLAG_FIN) != 0, - stream_id, has_priority, weight, parent_stream_id, - exclusive, source_dependency, capture_mode); - }); - } + net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_SEND_HEADERS, + [&](NetLogCaptureMode capture_mode) { + return NetLogSpdyHeadersSentParams( + &block, (flags & spdy::CONTROL_FLAG_FIN) != 0, + stream_id, has_priority, weight, parent_stream_id, + exclusive, source_dependency, capture_mode); + }); spdy::SpdyHeadersIR headers(stream_id, std::move(block)); headers.set_has_priority(has_priority); @@ -1241,7 +1243,7 @@ std::unique_ptr<SpdyBuffer> SpdySession::CreateDataBuffer( // Even though we're currently stalled only by the stream, we // might end up being stalled by the session also. QueueSendStalledStream(*stream); - net_log().AddEventWithIntParams( + net_log_.AddEventWithIntParams( NetLogEventType::HTTP2_SESSION_STREAM_STALLED_BY_STREAM_SEND_WINDOW, "stream_id", stream_id); return std::unique_ptr<SpdyBuffer>(); @@ -1253,7 +1255,7 @@ std::unique_ptr<SpdyBuffer> SpdySession::CreateDataBuffer( if (send_stalled_by_session) { stream->set_send_stalled_by_flow_control(true); QueueSendStalledStream(*stream); - net_log().AddEventWithIntParams( + net_log_.AddEventWithIntParams( NetLogEventType::HTTP2_SESSION_STREAM_STALLED_BY_SESSION_SEND_WINDOW, "stream_id", stream_id); return std::unique_ptr<SpdyBuffer>(); @@ -1268,12 +1270,10 @@ std::unique_ptr<SpdyBuffer> SpdySession::CreateDataBuffer( if (effective_len < len) flags = static_cast<spdy::SpdyDataFlags>(flags & ~spdy::DATA_FLAG_FIN); - if (net_log().IsCapturing()) { - net_log().AddEvent(NetLogEventType::HTTP2_SESSION_SEND_DATA, [&] { - return NetLogSpdyDataParams(stream_id, effective_len, - (flags & spdy::DATA_FLAG_FIN) != 0); - }); - } + net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_SEND_DATA, [&] { + return NetLogSpdyDataParams(stream_id, effective_len, + (flags & spdy::DATA_FLAG_FIN) != 0); + }); // Send PrefacePing for DATA_FRAMEs with nonzero payload size. if (effective_len > 0) @@ -1316,6 +1316,9 @@ void SpdySession::UpdateStreamPriority(SpdyStream* stream, DCHECK(IsStreamActive(stream_id)); + if (base::FeatureList::IsEnabled(features::kAvoidH2Reprioritization)) + return; + auto updates = priority_dependency_state_.OnStreamUpdate( stream_id, ConvertRequestPriorityToSpdyPriority(new_priority)); for (auto u : updates) { @@ -1745,13 +1748,12 @@ int SpdySession::TryCreateStream( return CreateStream(*request, stream); } - if (net_log().IsCapturing()) { - net_log().AddEvent(NetLogEventType::HTTP2_SESSION_STALLED_MAX_STREAMS, [&] { - return NetLogSpdySessionStalledParams( - active_streams_.size(), created_streams_.size(), num_pushed_streams_, - max_concurrent_streams_, request->url().spec()); - }); - } + net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_STALLED_MAX_STREAMS, [&] { + return NetLogSpdySessionStalledParams( + active_streams_.size(), created_streams_.size(), num_pushed_streams_, + max_concurrent_streams_, request->url().spec()); + }); + RequestPriority priority = request->priority(); CHECK_GE(priority, MINIMUM_PRIORITY); CHECK_LE(priority, MAXIMUM_PRIORITY); @@ -1999,7 +2001,8 @@ void SpdySession::TryCreatePushStream(spdy::SpdyStreamId stream_id, SSLInfo ssl_info; CHECK(GetSSLInfo(&ssl_info)); if (!CanPool(transport_security_state_, ssl_info, *ssl_config_service_, - associated_url.host(), gurl.host())) { + associated_url.host(), gurl.host(), + spdy_session_key_.network_isolation_key())) { RecordSpdyPushedStreamFateHistogram( SpdyPushedStreamFate::kCertificateMismatch); EnqueueResetStreamFrame(stream_id, request_priority, @@ -2167,7 +2170,7 @@ void SpdySession::EnqueueResetStreamFrame(spdy::SpdyStreamId stream_id, const std::string& description) { DCHECK_NE(stream_id, 0u); - net_log().AddEvent(NetLogEventType::HTTP2_SESSION_SEND_RST_STREAM, [&] { + net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_SEND_RST_STREAM, [&] { return NetLogSpdySendRstStreamParams(stream_id, error_code, description); }); @@ -2184,7 +2187,7 @@ void SpdySession::EnqueuePriorityFrame(spdy::SpdyStreamId stream_id, spdy::SpdyStreamId dependency_id, int weight, bool exclusive) { - net_log().AddEvent(NetLogEventType::HTTP2_STREAM_SEND_PRIORITY, [&] { + net_log_.AddEvent(NetLogEventType::HTTP2_STREAM_SEND_PRIORITY, [&] { return NetLogSpdyPriorityParams(stream_id, dependency_id, weight, exclusive); }); @@ -2600,7 +2603,7 @@ void SpdySession::HandleSetting(uint32_t id, uint32_t value) { break; case spdy::SETTINGS_INITIAL_WINDOW_SIZE: { if (value > static_cast<uint32_t>(std::numeric_limits<int32_t>::max())) { - net_log().AddEventWithIntParams( + net_log_.AddEventWithIntParams( NetLogEventType::HTTP2_SESSION_INITIAL_WINDOW_SIZE_OUT_OF_RANGE, "initial_window_size", value); return; @@ -2612,7 +2615,7 @@ void SpdySession::HandleSetting(uint32_t id, uint32_t value) { static_cast<int32_t>(value) - stream_initial_send_window_size_; stream_initial_send_window_size_ = static_cast<int32_t>(value); UpdateStreamsSendWindowSize(delta_window_size); - net_log().AddEventWithIntParams( + net_log_.AddEventWithIntParams( NetLogEventType::HTTP2_SESSION_UPDATE_STREAMS_SEND_WINDOW_SIZE, "delta_window_size", delta_window_size); break; @@ -2697,11 +2700,10 @@ void SpdySession::WritePingFrame(spdy::SpdyPingId unique_id, bool is_ack) { EnqueueSessionWrite(HIGHEST, spdy::SpdyFrameType::PING, std::move(ping_frame)); - if (net_log().IsCapturing()) { - net_log().AddEvent(NetLogEventType::HTTP2_SESSION_PING, [&] { - return NetLogSpdyPingParams(unique_id, is_ack, "sent"); - }); - } + net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_PING, [&] { + return NetLogSpdyPingParams(unique_id, is_ack, "sent"); + }); + if (!is_ack) { DCHECK(!ping_in_flight_); @@ -3078,7 +3080,7 @@ void SpdySession::OnRstStream(spdy::SpdyStreamId stream_id, spdy::SpdyErrorCode error_code) { CHECK(in_io_loop_); - net_log().AddEvent(NetLogEventType::HTTP2_SESSION_RECV_RST_STREAM, [&] { + net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_RECV_RST_STREAM, [&] { return NetLogSpdyRecvRstStreamParams(stream_id, error_code); }); @@ -3101,19 +3103,15 @@ void SpdySession::OnRstStream(spdy::SpdyStreamId stream_id, CloseActiveStreamIterator(it, ERR_HTTP2_SERVER_REFUSED_STREAM); } else if (error_code == spdy::ERROR_CODE_HTTP_1_1_REQUIRED) { // TODO(bnc): Record histogram with number of open streams capped at 50. - if (net_log().IsCapturing()) { - it->second->LogStreamError(ERR_HTTP_1_1_REQUIRED, - "Closing session because server reset stream " - "with ERR_HTTP_1_1_REQUIRED."); - } + it->second->LogStreamError(ERR_HTTP_1_1_REQUIRED, + "Closing session because server reset stream " + "with ERR_HTTP_1_1_REQUIRED."); DoDrainSession(ERR_HTTP_1_1_REQUIRED, "HTTP_1_1_REQUIRED for stream."); } else { RecordProtocolErrorHistogram( PROTOCOL_ERROR_RST_STREAM_FOR_NON_ACTIVE_STREAM); - if (net_log().IsCapturing()) { - it->second->LogStreamError(ERR_HTTP2_PROTOCOL_ERROR, - "Server reset stream."); - } + it->second->LogStreamError(ERR_HTTP2_PROTOCOL_ERROR, + "Server reset stream."); // TODO(mbelshe): Map from Spdy-protocol errors to something sensical. // For now, it doesn't matter much - it is a protocol error. CloseActiveStreamIterator(it, ERR_HTTP2_PROTOCOL_ERROR); @@ -3142,7 +3140,7 @@ void SpdySession::OnGoAway(spdy::SpdyStreamId last_accepted_stream_id, } else if (error_code == spdy::ERROR_CODE_NO_ERROR) { StartGoingAway(last_accepted_stream_id, ERR_HTTP2_SERVER_REFUSED_STREAM); } else { - StartGoingAway(last_accepted_stream_id, ERR_ABORTED); + StartGoingAway(last_accepted_stream_id, ERR_HTTP2_PROTOCOL_ERROR); } // This is to handle the case when we already don't have any active // streams (i.e., StartGoingAway() did nothing). Otherwise, we have @@ -3174,11 +3172,10 @@ void SpdySession::OnStreamFrameData(spdy::SpdyStreamId stream_id, size_t len) { CHECK(in_io_loop_); DCHECK_LT(len, 1u << 24); - if (net_log().IsCapturing()) { - net_log().AddEvent(NetLogEventType::HTTP2_SESSION_RECV_DATA, [&] { - return NetLogSpdyDataParams(stream_id, len, false); - }); - } + + net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_RECV_DATA, [&] { + return NetLogSpdyDataParams(stream_id, len, false); + }); // Build the buffer as early as possible so that we go through the // session flow control checks and update @@ -3213,11 +3210,8 @@ void SpdySession::OnStreamFrameData(spdy::SpdyStreamId stream_id, void SpdySession::OnStreamEnd(spdy::SpdyStreamId stream_id) { CHECK(in_io_loop_); - if (net_log().IsCapturing()) { - net_log().AddEvent(NetLogEventType::HTTP2_SESSION_RECV_DATA, [&] { - return NetLogSpdyDataParams(stream_id, 0, true); - }); - } + net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_RECV_DATA, + [&] { return NetLogSpdyDataParams(stream_id, 0, true); }); auto it = active_streams_.find(stream_id); // By the time data comes in, the stream may already be inactive. @@ -3249,10 +3243,8 @@ void SpdySession::OnStreamPadding(spdy::SpdyStreamId stream_id, size_t len) { void SpdySession::OnSettings() { CHECK(in_io_loop_); - if (net_log_.IsCapturing()) { - net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_RECV_SETTINGS); - net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_SEND_SETTINGS_ACK); - } + net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_RECV_SETTINGS); + net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_SEND_SETTINGS_ACK); // Send an acknowledgment of the setting. spdy::SpdySettingsIR settings_ir; @@ -3265,8 +3257,7 @@ void SpdySession::OnSettings() { void SpdySession::OnSettingsAck() { CHECK(in_io_loop_); - if (net_log_.IsCapturing()) - net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_RECV_SETTINGS_ACK); + net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_RECV_SETTINGS_ACK); } void SpdySession::OnSetting(spdy::SpdySettingsId id, uint32_t value) { @@ -3329,14 +3320,12 @@ void SpdySession::OnPushPromise(spdy::SpdyStreamId stream_id, spdy::SpdyHeaderBlock headers) { CHECK(in_io_loop_); - if (net_log_.IsCapturing()) { - net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_RECV_PUSH_PROMISE, - [&](NetLogCaptureMode capture_mode) { - return NetLogSpdyPushPromiseReceivedParams( - &headers, stream_id, promised_stream_id, - capture_mode); - }); - } + net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_RECV_PUSH_PROMISE, + [&](NetLogCaptureMode capture_mode) { + return NetLogSpdyPushPromiseReceivedParams( + &headers, stream_id, promised_stream_id, + capture_mode); + }); TryCreatePushStream(promised_stream_id, stream_id, std::move(headers)); } @@ -3351,13 +3340,11 @@ void SpdySession::OnHeaders(spdy::SpdyStreamId stream_id, base::TimeTicks recv_first_byte_time) { CHECK(in_io_loop_); - if (net_log().IsCapturing()) { - net_log().AddEvent(NetLogEventType::HTTP2_SESSION_RECV_HEADERS, - [&](NetLogCaptureMode capture_mode) { - return NetLogSpdyHeadersReceivedParams( - &headers, fin, stream_id, capture_mode); - }); - } + net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_RECV_HEADERS, + [&](NetLogCaptureMode capture_mode) { + return NetLogSpdyHeadersReceivedParams( + &headers, fin, stream_id, capture_mode); + }); auto it = active_streams_.find(stream_id); if (it == active_streams_.end()) { @@ -3412,7 +3399,8 @@ void SpdySession::OnAltSvc( if (!GetSSLInfo(&ssl_info)) return; if (!CanPool(transport_security_state_, ssl_info, *ssl_config_service_, - host_port_pair().host(), gurl.host())) { + host_port_pair().host(), gurl.host(), + spdy_session_key_.network_isolation_key())) { return; } scheme_host_port = url::SchemeHostPort(gurl); diff --git a/chromium/net/spdy/spdy_session.h b/chromium/net/spdy/spdy_session.h index 9c1c504859f..35bb0836e02 100644 --- a/chromium/net/spdy/spdy_session.h +++ b/chromium/net/spdy/spdy_session.h @@ -329,7 +329,8 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface, const SSLInfo& ssl_info, const SSLConfigService& ssl_config_service, const std::string& old_hostname, - const std::string& new_hostname); + const std::string& new_hostname, + const net::NetworkIsolationKey& network_isolation_key); // Create a new SpdySession. // |spdy_session_key| is the host/port that this session connects to, privacy @@ -1106,8 +1107,8 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface, // and maximum HPACK dynamic table size. const spdy::SettingsMap initial_settings_; - // If set, an HTTP/2 frame with a reserved frame type will be sent after every - // valid HTTP/2 frame. See + // If set, an HTTP/2 frame with a reserved frame type will be sent after + // every HTTP/2 SETTINGS frame and before every HTTP/2 DATA frame. See // https://tools.ietf.org/html/draft-bishop-httpbis-grease-00. const base::Optional<SpdySessionPool::GreasedHttp2Frame> greased_http2_frame_; diff --git a/chromium/net/spdy/spdy_session_unittest.cc b/chromium/net/spdy/spdy_session_unittest.cc index bffd8d2f7d3..65c23fa9999 100644 --- a/chromium/net/spdy/spdy_session_unittest.cc +++ b/chromium/net/spdy/spdy_session_unittest.cc @@ -22,6 +22,7 @@ #include "net/base/host_port_pair.h" #include "net/base/io_buffer.h" #include "net/base/ip_endpoint.h" +#include "net/base/network_isolation_key.h" #include "net/base/privacy_mode.h" #include "net/base/proxy_delegate.h" #include "net/base/proxy_server.h" @@ -2778,6 +2779,63 @@ TEST_F(SpdySessionTest, VerifyDomainAuthentication) { EXPECT_FALSE(session_->VerifyDomainAuthentication("mail.google.com")); } +// Check that VerifyDomainAuthentication respects Expect-CT failures, and uses +// the correct NetworkIsolationKey. +TEST_F(SpdySessionTest, VerifyDomainAuthenticationExpectCT) { + base::test::ScopedFeatureList feature_list; + feature_list.InitWithFeatures( + /* enabled_features */ + {TransportSecurityState::kDynamicExpectCTFeature, + features::kPartitionExpectCTStateByNetworkIsolationKey, + features::kPartitionConnectionsByNetworkIsolationKey, + features::kPartitionSSLSessionsByNetworkIsolationKey}, + /* disabled_features */ + {}); + + key_ = SpdySessionKey(HostPortPair::FromURL(test_url_), ProxyServer::Direct(), + PRIVACY_MODE_DISABLED, + SpdySessionKey::IsProxySession::kFalse, SocketTag(), + NetworkIsolationKey::CreateTransient(), + false /* disable_secure_dns */); + ssl_.ssl_info.ct_policy_compliance = + ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS; + ssl_.ssl_info.is_issued_by_known_root = true; + + // Need to create this after enabling features. + session_deps_.transport_security_state = + std::make_unique<TransportSecurityState>(); + + SequencedSocketData data; + session_deps_.socket_factory->AddSocketDataProvider(&data); + + AddSSLSocketData(); + + CreateNetworkSession(); + CreateSpdySession(); + + EXPECT_TRUE(session_->VerifyDomainAuthentication("www.example.org")); + EXPECT_TRUE(session_->VerifyDomainAuthentication("mail.example.org")); + EXPECT_TRUE(session_->VerifyDomainAuthentication("mail.example.com")); + EXPECT_FALSE(session_->VerifyDomainAuthentication("mail.google.com")); + + // Add Expect-CT data for all three hosts that passed the above checks, using + // different NetworkIsolationKeys. + const base::Time expiry = base::Time::Now() + base::TimeDelta::FromDays(1); + session_deps_.transport_security_state->AddExpectCT( + "www.example.org", expiry, true, GURL(), NetworkIsolationKey()); + session_deps_.transport_security_state->AddExpectCT( + "mail.example.org", expiry, true, GURL(), key_.network_isolation_key()); + session_deps_.transport_security_state->AddExpectCT( + "mail.example.com", expiry, true, GURL(), + NetworkIsolationKey::CreateTransient()); + + // The host with the Expect-CT data that matches the SpdySession's should fail + // the check now. + EXPECT_TRUE(session_->VerifyDomainAuthentication("www.example.org")); + EXPECT_FALSE(session_->VerifyDomainAuthentication("mail.example.org")); + EXPECT_TRUE(session_->VerifyDomainAuthentication("mail.example.com")); +} + TEST_F(SpdySessionTest, CloseTwoStalledCreateStream) { // TODO(rtenneti): Define a helper class/methods and move the common code in // this file. @@ -6232,7 +6290,11 @@ class AltSvcFrameTest : public SpdySessionTest { "alternative.example.org", 443, 86400, - spdy::SpdyAltSvcWireFormat::VersionVector()) {} + spdy::SpdyAltSvcWireFormat::VersionVector()) { + // Since the default |alternative_service_| is QUIC, need to enable QUIC for + // the not added tests to be meaningful. + session_deps_.enable_quic = true; + } void AddSocketData(const spdy::SpdyAltSvcIR& altsvc_ir) { altsvc_frame_ = spdy_util_.SerializeFrame(altsvc_ir); @@ -6258,8 +6320,6 @@ class AltSvcFrameTest : public SpdySessionTest { }; TEST_F(AltSvcFrameTest, ProcessAltSvcFrame) { - session_deps_.enable_quic = true; - const char origin[] = "https://mail.example.org"; spdy::SpdyAltSvcIR altsvc_ir(/* stream_id = */ 0); altsvc_ir.add_altsvc(alternative_service_); @@ -6290,15 +6350,14 @@ TEST_F(AltSvcFrameTest, ProcessAltSvcFrame) { // Regression test for https://crbug.com/736063. TEST_F(AltSvcFrameTest, IgnoreQuicAltSvcWithUnsupportedVersion) { + session_deps_.enable_quic = true; + + // Note that this test only uses the legacy Google-specific Alt-Svc format. const char origin[] = "https://mail.example.org"; spdy::SpdyAltSvcIR altsvc_ir(/* stream_id = */ 0); spdy::SpdyAltSvcWireFormat::AlternativeService quic_alternative_service( "quic", "alternative.example.org", 443, 86400, spdy::SpdyAltSvcWireFormat::VersionVector()); - // TODO(zhongyi): spdy::SpdyAltSvcWireFormat::ParseHeaderFieldValue expects - // positve versions while VersionVector allows nonnegative verisons. Fix the - // parse function and change the hardcoded invalid version to - // quic::QUIC_VERSION_UNSUPPORTED. quic_alternative_service.version.push_back(/* invalid QUIC version */ 1); altsvc_ir.add_altsvc(quic_alternative_service); altsvc_ir.set_origin(origin); @@ -6323,7 +6382,64 @@ TEST_F(AltSvcFrameTest, IgnoreQuicAltSvcWithUnsupportedVersion) { ASSERT_EQ(0u, altsvc_info_vector.size()); } +TEST_F(AltSvcFrameTest, DoNotProcessAltSvcFrameWithExpectCTError) { + const char origin[] = "https://mail.example.org"; + + base::test::ScopedFeatureList feature_list; + feature_list.InitWithFeatures( + /* enabled_features */ + {TransportSecurityState::kDynamicExpectCTFeature, + features::kPartitionExpectCTStateByNetworkIsolationKey, + features::kPartitionConnectionsByNetworkIsolationKey, + features::kPartitionSSLSessionsByNetworkIsolationKey}, + /* disabled_features */ + {}); + + key_ = SpdySessionKey(HostPortPair::FromURL(test_url_), ProxyServer::Direct(), + PRIVACY_MODE_DISABLED, + SpdySessionKey::IsProxySession::kFalse, SocketTag(), + NetworkIsolationKey::CreateTransient(), + false /* disable_secure_dns */); + ssl_.ssl_info.ct_policy_compliance = + ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS; + ssl_.ssl_info.is_issued_by_known_root = true; + + // Need to create this after enabling features. + session_deps_.transport_security_state = + std::make_unique<TransportSecurityState>(); + session_deps_.transport_security_state->AddExpectCT( + GURL(origin).host(), + base::Time::Now() + base::TimeDelta::FromDays(1) /* expiry */, true, + GURL(), key_.network_isolation_key()); + + spdy::SpdyAltSvcIR altsvc_ir(/* stream_id = */ 0); + altsvc_ir.add_altsvc(alternative_service_); + altsvc_ir.set_origin(origin); + AddSocketData(altsvc_ir); + AddSSLSocketData(); + + CreateNetworkSession(); + CreateSpdySession(); + + base::RunLoop().RunUntilIdle(); + + const url::SchemeHostPort session_origin("https", test_url_.host(), + test_url_.EffectiveIntPort()); + ASSERT_TRUE(spdy_session_pool_->http_server_properties() + ->GetAlternativeServiceInfos(session_origin, + key_.network_isolation_key()) + .empty()); + + ASSERT_TRUE( + spdy_session_pool_->http_server_properties() + ->GetAlternativeServiceInfos(url::SchemeHostPort(GURL(origin)), + key_.network_isolation_key()) + .empty()); +} + TEST_F(AltSvcFrameTest, DoNotProcessAltSvcFrameForOriginNotCoveredByCert) { + session_deps_.enable_quic = true; + const char origin[] = "https://invalid.example.org"; spdy::SpdyAltSvcIR altsvc_ir(/* stream_id = */ 0); altsvc_ir.add_altsvc(alternative_service_); @@ -6394,8 +6510,6 @@ TEST_F(AltSvcFrameTest, } TEST_F(AltSvcFrameTest, ProcessAltSvcFrameOnActiveStream) { - session_deps_.enable_quic = true; - spdy::SpdyAltSvcIR altsvc_ir(/* stream_id = */ 1); altsvc_ir.add_altsvc(alternative_service_); @@ -6453,8 +6567,6 @@ TEST_F(AltSvcFrameTest, ProcessAltSvcFrameOnActiveStream) { TEST_F(AltSvcFrameTest, ProcessAltSvcFrameOnActiveStreamWithNetworkIsolationKey) { - session_deps_.enable_quic = true; - base::test::ScopedFeatureList feature_list; feature_list.InitWithFeatures( // enabled_features @@ -6761,19 +6873,27 @@ TEST(CanPoolTest, CanPool) { "spdy_pooling.pem"); EXPECT_TRUE(SpdySession::CanPool(&tss, ssl_info, ssl_config_service, - "www.example.org", "www.example.org")); + "www.example.org", "www.example.org", + NetworkIsolationKey())); EXPECT_TRUE(SpdySession::CanPool(&tss, ssl_info, ssl_config_service, - "www.example.org", "mail.example.org")); + "www.example.org", "mail.example.org", + NetworkIsolationKey())); EXPECT_TRUE(SpdySession::CanPool(&tss, ssl_info, ssl_config_service, - "www.example.org", "mail.example.com")); + "www.example.org", "mail.example.com", + NetworkIsolationKey())); EXPECT_FALSE(SpdySession::CanPool(&tss, ssl_info, ssl_config_service, - "www.example.org", "mail.google.com")); + "www.example.org", "mail.google.com", + NetworkIsolationKey())); } TEST(CanPoolTest, CanPoolExpectCT) { base::test::ScopedFeatureList feature_list; - feature_list.InitAndEnableFeature( - TransportSecurityState::kDynamicExpectCTFeature); + feature_list.InitWithFeatures( + /* enabled_features */ + {TransportSecurityState::kDynamicExpectCTFeature, + features::kPartitionExpectCTStateByNetworkIsolationKey}, + /* disabled_features */ + {}); // Load a cert that is valid for: // www.example.org // mail.example.org @@ -6789,8 +6909,11 @@ TEST(CanPoolTest, CanPoolExpectCT) { ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS; ssl_info.is_issued_by_known_root = true; + net::NetworkIsolationKey network_isolation_key = + NetworkIsolationKey::CreateTransient(); EXPECT_TRUE(SpdySession::CanPool(&tss, ssl_info, ssl_config_service, - "www.example.org", "www.example.org")); + "www.example.org", "www.example.org", + network_isolation_key)); const base::Time current_time(base::Time::Now()); const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000); @@ -6798,20 +6921,31 @@ TEST(CanPoolTest, CanPoolExpectCT) { ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS; // A different Expect-CT enabled host should not be allowed to pool. - tss.AddExpectCT("mail.example.org", expiry, true, GURL()); + tss.AddExpectCT("mail.example.org", expiry, true, GURL(), + network_isolation_key); EXPECT_FALSE(SpdySession::CanPool(&tss, ssl_info, ssl_config_service, - "www.example.org", "mail.example.org")); + "www.example.org", "mail.example.org", + network_isolation_key)); // A report-only Expect-CT configuration should not prevent pooling. tss.AddExpectCT("mail.example.org", expiry, false, - GURL("https://report.test")); + GURL("https://report.test"), network_isolation_key); EXPECT_TRUE(SpdySession::CanPool(&tss, ssl_info, ssl_config_service, - "www.example.org", "mail.example.org")); + "www.example.org", "mail.example.org", + network_isolation_key)); // If Expect-CT becomes enabled for the same host for which the connection was // already made, subsequent connections to that host should not be allowed to // pool. - tss.AddExpectCT("www.example.org", expiry, true, GURL()); + tss.AddExpectCT("www.example.org", expiry, true, GURL(), + network_isolation_key); EXPECT_FALSE(SpdySession::CanPool(&tss, ssl_info, ssl_config_service, - "www.example.org", "www.example.org")); + "www.example.org", "www.example.org", + network_isolation_key)); + + // With a different NetworkIsolationKey, CanPool() should still return true, + // as CT information is scoped to a single NetworkIsolationKey. + EXPECT_TRUE(SpdySession::CanPool(&tss, ssl_info, ssl_config_service, + "www.example.org", "www.example.org", + NetworkIsolationKey::CreateTransient())); } TEST(CanPoolTest, CanNotPoolWithCertErrors) { @@ -6828,7 +6962,8 @@ TEST(CanPoolTest, CanNotPoolWithCertErrors) { ssl_info.cert_status = CERT_STATUS_REVOKED; EXPECT_FALSE(SpdySession::CanPool(&tss, ssl_info, ssl_config_service, - "www.example.org", "mail.example.org")); + "www.example.org", "mail.example.org", + NetworkIsolationKey())); } TEST(CanPoolTest, CanNotPoolWithClientCerts) { @@ -6845,7 +6980,8 @@ TEST(CanPoolTest, CanNotPoolWithClientCerts) { ssl_info.client_cert_sent = true; EXPECT_FALSE(SpdySession::CanPool(&tss, ssl_info, ssl_config_service, - "www.example.org", "mail.example.org")); + "www.example.org", "mail.example.org", + NetworkIsolationKey())); } TEST(CanPoolTest, CanNotPoolWithBadPins) { @@ -6862,7 +6998,8 @@ TEST(CanPoolTest, CanNotPoolWithBadPins) { ssl_info.public_key_hashes.push_back(test::GetTestHashValue(bad_pin)); EXPECT_FALSE(SpdySession::CanPool(&tss, ssl_info, ssl_config_service, - "www.example.org", "example.test")); + "www.example.org", "example.test", + NetworkIsolationKey())); } TEST(CanPoolTest, CanNotPoolWithBadCTWhenCTRequired) { @@ -6890,7 +7027,8 @@ TEST(CanPoolTest, CanNotPoolWithBadCTWhenCTRequired) { tss.SetRequireCTDelegate(&require_ct_delegate); EXPECT_FALSE(SpdySession::CanPool(&tss, ssl_info, ssl_config_service, - "www.example.org", "mail.example.org")); + "www.example.org", "mail.example.org", + NetworkIsolationKey())); } TEST(CanPoolTest, CanPoolWithBadCTWhenCTNotRequired) { @@ -6918,7 +7056,8 @@ TEST(CanPoolTest, CanPoolWithBadCTWhenCTNotRequired) { tss.SetRequireCTDelegate(&require_ct_delegate); EXPECT_TRUE(SpdySession::CanPool(&tss, ssl_info, ssl_config_service, - "www.example.org", "mail.example.org")); + "www.example.org", "mail.example.org", + NetworkIsolationKey())); } TEST(CanPoolTest, CanPoolWithGoodCTWhenCTRequired) { @@ -6946,7 +7085,8 @@ TEST(CanPoolTest, CanPoolWithGoodCTWhenCTRequired) { tss.SetRequireCTDelegate(&require_ct_delegate); EXPECT_TRUE(SpdySession::CanPool(&tss, ssl_info, ssl_config_service, - "www.example.org", "mail.example.org")); + "www.example.org", "mail.example.org", + NetworkIsolationKey())); } TEST(CanPoolTest, CanPoolWithAcceptablePins) { @@ -6966,7 +7106,8 @@ TEST(CanPoolTest, CanPoolWithAcceptablePins) { ssl_info.public_key_hashes.push_back(hash); EXPECT_TRUE(SpdySession::CanPool(&tss, ssl_info, ssl_config_service, - "www.example.org", "mail.example.org")); + "www.example.org", "mail.example.org", + NetworkIsolationKey())); } TEST(CanPoolTest, CanPoolWithClientCertsAndPolicy) { @@ -6986,11 +7127,14 @@ TEST(CanPoolTest, CanPoolWithClientCertsAndPolicy) { // CanShareConnectionWithClientCerts returns true for both hostnames, but not // just one hostname. EXPECT_TRUE(SpdySession::CanPool(&tss, ssl_info, ssl_config_service, - "www.example.org", "mail.example.org")); + "www.example.org", "mail.example.org", + NetworkIsolationKey())); EXPECT_FALSE(SpdySession::CanPool(&tss, ssl_info, ssl_config_service, - "www.example.org", "mail.example.com")); + "www.example.org", "mail.example.com", + NetworkIsolationKey())); EXPECT_FALSE(SpdySession::CanPool(&tss, ssl_info, ssl_config_service, - "mail.example.com", "www.example.org")); + "mail.example.com", "www.example.org", + NetworkIsolationKey())); } TEST(RecordPushedStreamHistogramTest, VaryResponseHeader) { diff --git a/chromium/net/spdy/spdy_stream.cc b/chromium/net/spdy/spdy_stream.cc index ba8ffe66aff..0c28112f6e5 100644 --- a/chromium/net/spdy/spdy_stream.cc +++ b/chromium/net/spdy/spdy_stream.cc @@ -35,11 +35,11 @@ namespace { base::Value NetLogSpdyStreamErrorParams(spdy::SpdyStreamId stream_id, int net_error, - const std::string* description) { + base::StringPiece description) { base::Value dict(base::Value::Type::DICTIONARY); dict.SetIntKey("stream_id", static_cast<int>(stream_id)); dict.SetStringKey("net_error", ErrorToShortString(net_error)); - dict.SetStringKey("description", *description); + dict.SetStringKey("description", description); return dict; } @@ -412,6 +412,10 @@ void SpdyStream::OnHeadersReceived( // in which case it needs to pass through so that the WebSocket layer // can signal an error. if (status / 100 == 1 && status != 101) { + // Record the timing of the 103 Early Hints response for the experiment + // (https://crbug.com/1093693). + if (status == 103 && first_early_hints_time_.is_null()) + first_early_hints_time_ = recv_first_byte_time; return; } @@ -660,9 +664,9 @@ int SpdyStream::OnDataSent(size_t frame_size) { } } -void SpdyStream::LogStreamError(int error, const std::string& description) { +void SpdyStream::LogStreamError(int error, base::StringPiece description) { net_log_.AddEvent(NetLogEventType::HTTP2_STREAM_ERROR, [&] { - return NetLogSpdyStreamErrorParams(stream_id_, error, &description); + return NetLogSpdyStreamErrorParams(stream_id_, error, description); }); } @@ -816,6 +820,7 @@ bool SpdyStream::GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const { // first bytes of the HEADERS frame were received to BufferedSpdyFramer // (https://crbug.com/568024). load_timing_info->receive_headers_start = recv_first_byte_time_; + load_timing_info->first_early_hints_time = first_early_hints_time_; return result; } diff --git a/chromium/net/spdy/spdy_stream.h b/chromium/net/spdy/spdy_stream.h index e9245b01b6f..922c43fefc1 100644 --- a/chromium/net/spdy/spdy_stream.h +++ b/chromium/net/spdy/spdy_stream.h @@ -301,7 +301,7 @@ class NET_EXPORT_PRIVATE SpdyStream { void OnClose(int status); // Called by the SpdySession to log stream related errors. - void LogStreamError(int error, const std::string& description); + void LogStreamError(int error, base::StringPiece description); // If this stream is active, reset it, and close it otherwise. In // either case the stream is deleted. @@ -515,6 +515,8 @@ class NET_EXPORT_PRIVATE SpdyStream { base::TimeTicks send_time_; base::TimeTicks recv_first_byte_time_; base::TimeTicks recv_last_byte_time_; + // The time at which the first 103 Early Hints response is received. + base::TimeTicks first_early_hints_time_; // Number of bytes that have been received on this stream, including frame // overhead and headers. diff --git a/chromium/net/spdy/spdy_stream_test_util.cc b/chromium/net/spdy/spdy_stream_test_util.cc index 8307e999c69..b8309626edb 100644 --- a/chromium/net/spdy/spdy_stream_test_util.cc +++ b/chromium/net/spdy/spdy_stream_test_util.cc @@ -83,6 +83,7 @@ void StreamDelegateBase::OnClose(int status) { if (!stream_.get()) return; stream_id_ = stream_->stream_id(); + stream_->GetLoadTimingInfo(&load_timing_info_); stream_.reset(); callback_.callback().Run(status); } @@ -118,6 +119,11 @@ std::string StreamDelegateBase::GetResponseHeaderValue( : it->second.as_string(); } +const LoadTimingInfo& StreamDelegateBase::GetLoadTimingInfo() { + DCHECK(StreamIsClosed()); + return load_timing_info_; +} + StreamDelegateDoNothing::StreamDelegateDoNothing( const base::WeakPtr<SpdyStream>& stream) : StreamDelegateBase(stream) {} diff --git a/chromium/net/spdy/spdy_stream_test_util.h b/chromium/net/spdy/spdy_stream_test_util.h index cb1dd50875d..2453c78bd41 100644 --- a/chromium/net/spdy/spdy_stream_test_util.h +++ b/chromium/net/spdy/spdy_stream_test_util.h @@ -12,6 +12,7 @@ #include "base/memory/ref_counted.h" #include "base/strings/string_piece.h" #include "net/base/io_buffer.h" +#include "net/base/load_timing_info.h" #include "net/base/test_completion_callback.h" #include "net/log/net_log_source.h" #include "net/spdy/spdy_read_queue.h" @@ -83,6 +84,10 @@ class StreamDelegateBase : public SpdyStream::Delegate { std::string GetResponseHeaderValue(const std::string& name) const; bool send_headers_completed() const { return send_headers_completed_; } + // Returns the load timing info on the stream. This must be called after the + // stream is closed in order to get the up-to-date information. + const LoadTimingInfo& GetLoadTimingInfo(); + protected: const base::WeakPtr<SpdyStream>& stream() { return stream_; } @@ -93,6 +98,7 @@ class StreamDelegateBase : public SpdyStream::Delegate { bool send_headers_completed_; spdy::SpdyHeaderBlock response_headers_; SpdyReadQueue received_data_queue_; + LoadTimingInfo load_timing_info_; }; // Test delegate that does nothing. Used to capture data about the diff --git a/chromium/net/spdy/spdy_stream_unittest.cc b/chromium/net/spdy/spdy_stream_unittest.cc index 0f56bcdb5a8..c3fad7a4173 100644 --- a/chromium/net/spdy/spdy_stream_unittest.cc +++ b/chromium/net/spdy/spdy_stream_unittest.cc @@ -1084,6 +1084,69 @@ TEST_F(SpdyStreamTest, InformationalHeaders) { EXPECT_TRUE(data.AllReadDataConsumed()); } +// 103 Early Hints hasn't been implemented yet, but we collect timing +// information for the experiment (https://crbug.com/1093693). This tests it. +TEST_F(SpdyStreamTest, EarlyHints) { + spdy::SpdySerializedFrame req( + spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST)); + AddWrite(req); + + // Serve the early hints. + spdy::SpdyHeaderBlock informational_headers; + informational_headers[":status"] = "103"; + spdy::SpdySerializedFrame informational_response( + spdy_util_.ConstructSpdyResponseHeaders( + 1, std::move(informational_headers), false)); + AddRead(informational_response); + + spdy::SpdySerializedFrame reply( + spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); + AddRead(reply); + + spdy::SpdySerializedFrame body( + spdy_util_.ConstructSpdyDataFrame(1, kPostBodyStringPiece, true)); + AddRead(body); + + AddReadEOF(); + + SequencedSocketData data(GetReads(), GetWrites()); + MockConnect connect_data(SYNCHRONOUS, OK); + data.set_connect_data(connect_data); + session_deps_.socket_factory->AddSocketDataProvider(&data); + + AddSSLSocketData(); + + base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); + + base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously( + SPDY_REQUEST_RESPONSE_STREAM, session, url_, LOWEST, NetLogWithSource()); + ASSERT_TRUE(stream); + EXPECT_EQ(kDefaultUrl, stream->url().spec()); + + StreamDelegateDoNothing delegate(stream); + stream->SetDelegate(&delegate); + + spdy::SpdyHeaderBlock headers( + spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); + EXPECT_EQ(ERR_IO_PENDING, stream->SendRequestHeaders(std::move(headers), + NO_MORE_DATA_TO_SEND)); + + EXPECT_THAT(delegate.WaitForClose(), IsOk()); + EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy::kHttp2StatusHeader)); + EXPECT_EQ(std::string(kPostBody, kPostBodyLength), + delegate.TakeReceivedData()); + + // Check if the timing of the early hints response is captured. + const LoadTimingInfo& load_timing_info = delegate.GetLoadTimingInfo(); + EXPECT_FALSE(load_timing_info.first_early_hints_time.is_null()); + + // Finish async network reads and writes. + base::RunLoop().RunUntilIdle(); + + EXPECT_TRUE(data.AllWriteDataConsumed()); + EXPECT_TRUE(data.AllReadDataConsumed()); +} + TEST_F(SpdyStreamTest, StatusMustBeNumber) { spdy::SpdySerializedFrame req( spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST)); diff --git a/chromium/net/ssl/openssl_ssl_util.cc b/chromium/net/ssl/openssl_ssl_util.cc index 77fa36a277d..b03c9b32ed0 100644 --- a/chromium/net/ssl/openssl_ssl_util.cc +++ b/chromium/net/ssl/openssl_ssl_util.cc @@ -11,6 +11,7 @@ #include "base/lazy_instance.h" #include "base/location.h" #include "base/logging.h" +#include "base/notreached.h" #include "base/values.h" #include "build/build_config.h" #include "crypto/openssl_util.h" diff --git a/chromium/net/ssl/ssl_client_session_cache.cc b/chromium/net/ssl/ssl_client_session_cache.cc index 00bd91764cc..1869eba9669 100644 --- a/chromium/net/ssl/ssl_client_session_cache.cc +++ b/chromium/net/ssl/ssl_client_session_cache.cc @@ -48,9 +48,9 @@ SSLClientSessionCache::SSLClientSessionCache(const Config& config) config_(config), cache_(config.max_entries), lookups_since_flush_(0) { - memory_pressure_listener_.reset( - new base::MemoryPressureListener(base::BindRepeating( - &SSLClientSessionCache::OnMemoryPressure, base::Unretained(this)))); + memory_pressure_listener_ = std::make_unique<base::MemoryPressureListener>( + FROM_HERE, base::BindRepeating(&SSLClientSessionCache::OnMemoryPressure, + base::Unretained(this))); } SSLClientSessionCache::~SSLClientSessionCache() { diff --git a/chromium/net/ssl/ssl_config_service.h b/chromium/net/ssl/ssl_config_service.h index 6a553c64df7..0b2b947d58e 100644 --- a/chromium/net/ssl/ssl_config_service.h +++ b/chromium/net/ssl/ssl_config_service.h @@ -46,10 +46,7 @@ struct NET_EXPORT SSLContextConfig { // If true, enables TLS 1.3 downgrade hardening for connections using // local trust anchors. (Hardening for known roots is always enabled.) - // - // TODO(https://crbug.com/1033598): Enable this it has successfully been - // enabled in Chrome. - bool tls13_hardening_for_local_anchors_enabled = false; + bool tls13_hardening_for_local_anchors_enabled = true; }; // The interface for retrieving global SSL configuration. This interface diff --git a/chromium/net/ssl/ssl_connection_status_flags.h b/chromium/net/ssl/ssl_connection_status_flags.h index cd3ad50cb87..a2f2b0e146c 100644 --- a/chromium/net/ssl/ssl_connection_status_flags.h +++ b/chromium/net/ssl/ssl_connection_status_flags.h @@ -7,7 +7,7 @@ #include <stdint.h> -#include "base/logging.h" +#include "base/check_op.h" #include "base/macros.h" namespace net { diff --git a/chromium/net/test/cert_test_util_nss.cc b/chromium/net/test/cert_test_util_nss.cc index 2b55ebc979c..096285d0963 100644 --- a/chromium/net/test/cert_test_util_nss.cc +++ b/chromium/net/test/cert_test_util_nss.cc @@ -12,6 +12,7 @@ #include "base/files/file_path.h" #include "base/files/file_util.h" +#include "base/logging.h" #include "crypto/ec_private_key.h" #include "crypto/nss_key_util.h" #include "crypto/nss_util.h" diff --git a/chromium/net/test/embedded_test_server/embedded_test_server.cc b/chromium/net/test/embedded_test_server/embedded_test_server.cc index 36873f21b8a..d143a79ff94 100644 --- a/chromium/net/test/embedded_test_server/embedded_test_server.cc +++ b/chromium/net/test/embedded_test_server/embedded_test_server.cc @@ -219,6 +219,28 @@ bool MaybeCreateOCSPResponse(CertBuilder* target, } // namespace +EmbeddedTestServerHandle::EmbeddedTestServerHandle( + EmbeddedTestServerHandle&& other) { + operator=(std::move(other)); +} + +EmbeddedTestServerHandle& EmbeddedTestServerHandle::operator=( + EmbeddedTestServerHandle&& other) { + EmbeddedTestServerHandle temporary; + std::swap(other.test_server_, temporary.test_server_); + std::swap(temporary.test_server_, test_server_); + return *this; +} + +EmbeddedTestServerHandle::EmbeddedTestServerHandle( + EmbeddedTestServer* test_server) + : test_server_(test_server) {} + +EmbeddedTestServerHandle::~EmbeddedTestServerHandle() { + if (test_server_) + CHECK(test_server_->ShutdownAndWaitUntilComplete()); +} + EmbeddedTestServer::OCSPConfig::OCSPConfig() = default; EmbeddedTestServer::OCSPConfig::OCSPConfig(ResponseType response_type) : response_type(response_type) {} @@ -268,9 +290,8 @@ EmbeddedTestServer::EmbeddedTestServer(Type type) EmbeddedTestServer::~EmbeddedTestServer() { DCHECK(thread_checker_.CalledOnValidThread()); - if (Started() && !ShutdownAndWaitUntilComplete()) { - LOG(ERROR) << "EmbeddedTestServer failed to shut down."; - } + if (Started()) + CHECK(ShutdownAndWaitUntilComplete()); { base::ScopedAllowBaseSyncPrimitivesForTesting allow_wait_for_thread_join; @@ -288,23 +309,21 @@ void EmbeddedTestServer::RegisterTestCerts() { void EmbeddedTestServer::SetConnectionListener( EmbeddedTestServerConnectionListener* listener) { - DCHECK(!io_thread_.get()) + DCHECK(!io_thread_) << "ConnectionListener must be set before starting the server."; connection_listener_ = listener; } EmbeddedTestServerHandle EmbeddedTestServer::StartAndReturnHandle(int port) { - if (!Start(port)) - return EmbeddedTestServerHandle(); - return EmbeddedTestServerHandle(this); + bool result = Start(port); + return result ? EmbeddedTestServerHandle(this) : EmbeddedTestServerHandle(); } bool EmbeddedTestServer::Start(int port) { bool success = InitializeAndListen(port); - if (!success) - return false; - StartAcceptingConnections(); - return true; + if (success) + StartAcceptingConnections(); + return success; } bool EmbeddedTestServer::InitializeAndListen(int port) { @@ -543,7 +562,7 @@ bool EmbeddedTestServer::GenerateCertAndKey() { // StartAcceptingConnections so that this server and the AIA server start at // the same time. (If the test only called InitializeAndListen they expect no // threads to be created yet.) - if (io_thread_.get()) + if (io_thread_) aia_http_server_->StartAcceptingConnections(); return true; @@ -562,10 +581,14 @@ bool EmbeddedTestServer::InitializeSSLServerContext() { return true; } +EmbeddedTestServerHandle +EmbeddedTestServer::StartAcceptingConnectionsAndReturnHandle() { + return EmbeddedTestServerHandle(this); +} + void EmbeddedTestServer::StartAcceptingConnections() { DCHECK(Started()); - DCHECK(!io_thread_.get()) - << "Server must not be started while server is running"; + DCHECK(!io_thread_) << "Server must not be started while server is running"; if (aia_http_server_) aia_http_server_->StartAcceptingConnections(); @@ -584,8 +607,18 @@ void EmbeddedTestServer::StartAcceptingConnections() { bool EmbeddedTestServer::ShutdownAndWaitUntilComplete() { DCHECK(thread_checker_.CalledOnValidThread()); - return PostTaskToIOThreadAndWait(base::BindOnce( - &EmbeddedTestServer::ShutdownOnIOThread, base::Unretained(this))); + // Ensure that the AIA HTTP server is no longer Started(). + bool aia_http_server_not_started = true; + if (aia_http_server_ && aia_http_server_->Started()) { + aia_http_server_not_started = + aia_http_server_->ShutdownAndWaitUntilComplete(); + } + + // Return false if either this or the AIA HTTP server are still Started(). + return PostTaskToIOThreadAndWait( + base::BindOnce(&EmbeddedTestServer::ShutdownOnIOThread, + base::Unretained(this))) && + aia_http_server_not_started; } // static @@ -793,21 +826,21 @@ void EmbeddedTestServer::AddDefaultHandlers(const base::FilePath& directory) { void EmbeddedTestServer::RegisterRequestHandler( const HandleRequestCallback& callback) { - DCHECK(!io_thread_.get()) + DCHECK(!io_thread_) << "Handlers must be registered before starting the server."; request_handlers_.push_back(callback); } void EmbeddedTestServer::RegisterRequestMonitor( const MonitorRequestCallback& callback) { - DCHECK(!io_thread_.get()) + DCHECK(!io_thread_) << "Monitors must be registered before starting the server."; request_monitors_.push_back(callback); } void EmbeddedTestServer::RegisterDefaultHandler( const HandleRequestCallback& callback) { - DCHECK(!io_thread_.get()) + DCHECK(!io_thread_) << "Handlers must be registered before starting the server."; default_request_handlers_.push_back(callback); } @@ -1008,27 +1041,5 @@ bool EmbeddedTestServer::PostTaskToIOThreadAndWaitWithResult( return task_result; } -EmbeddedTestServerHandle::EmbeddedTestServerHandle( - EmbeddedTestServerHandle&& other) { - operator=(std::move(other)); -} - -EmbeddedTestServerHandle& EmbeddedTestServerHandle::operator=( - EmbeddedTestServerHandle&& other) { - EmbeddedTestServerHandle temporary; - std::swap(other.test_server_, temporary.test_server_); - std::swap(temporary.test_server_, test_server_); - return *this; -} - -EmbeddedTestServerHandle::EmbeddedTestServerHandle( - EmbeddedTestServer* test_server) - : test_server_(test_server) {} - -EmbeddedTestServerHandle::~EmbeddedTestServerHandle() { - if (test_server_) - EXPECT_TRUE(test_server_->ShutdownAndWaitUntilComplete()); -} - } // namespace test_server } // namespace net diff --git a/chromium/net/test/embedded_test_server/embedded_test_server.h b/chromium/net/test/embedded_test_server/embedded_test_server.h index 699e64f6a4c..b296db0223f 100644 --- a/chromium/net/test/embedded_test_server/embedded_test_server.h +++ b/chromium/net/test/embedded_test_server/embedded_test_server.h @@ -39,11 +39,33 @@ class TCPServerSocket; namespace test_server { class EmbeddedTestServerConnectionListener; -class EmbeddedTestServerHandle; class HttpConnection; class HttpResponse; struct HttpRequest; +class EmbeddedTestServer; + +// Returned by the Start[AcceptingConnections]WithHandle() APIs, to simplify +// correct shutdown ordering of the EmbeddedTestServer. Shutdown() is invoked +// on the associated test server when the handle goes out of scope. The handle +// must therefore be destroyed before the test server. +class EmbeddedTestServerHandle { + public: + EmbeddedTestServerHandle() = default; + EmbeddedTestServerHandle(EmbeddedTestServerHandle&& other); + EmbeddedTestServerHandle& operator=(EmbeddedTestServerHandle&& other); + ~EmbeddedTestServerHandle(); + + bool is_valid() const { return test_server_; } + explicit operator bool() const { return test_server_; } + + private: + friend class EmbeddedTestServer; + + explicit EmbeddedTestServerHandle(EmbeddedTestServer* test_server); + EmbeddedTestServer* test_server_ = nullptr; +}; + // Class providing an HTTP server for testing purpose. This is a basic server // providing only an essential subset of HTTP/1.1 protocol. Especially, // it assumes that the request syntax is correct. It *does not* support @@ -61,7 +83,7 @@ struct HttpRequest; // std::unique_ptr<HttpResponse> HandleRequest(const HttpRequest& request) { // GURL absolute_url = test_server_->GetURL(request.relative_url); // if (absolute_url.path() != "/test") -// return std::unique_ptr<HttpResponse>(); +// return nullptr; // // auto http_response = std::make_unique<BasicHttpResponse>(); // http_response->set_code(net::HTTP_OK); @@ -274,7 +296,8 @@ class EmbeddedTestServer { typedef base::RepeatingCallback<void(const HttpRequest& request)> MonitorRequestCallback; - // Creates a http test server. Start() must be called to start the server. + // Creates a http test server. StartAndReturnHandle() must be called to start + // the server. // |type| indicates the protocol type of the server (HTTP/HTTPS). // // When a TYPE_HTTPS server is created, EmbeddedTestServer will call @@ -299,13 +322,14 @@ class EmbeddedTestServer { // Initializes and waits until the server is ready to accept requests. // This is the equivalent of calling InitializeAndListen() followed by - // StartAcceptingConnections(). + // StartAcceptingConnectionsAndReturnHandle(). // Returns a "handle" which will ShutdownAndWaitUntilComplete() when // destroyed, or null if the listening socket could not be created. EmbeddedTestServerHandle StartAndReturnHandle(int port = 0) WARN_UNUSED_RESULT; - // Deprecated equivalent of StartAndReturnHandle(). + // Equivalent of StartAndReturnHandle(), but requires manual Shutdown() by + // the caller. bool Start(int port = 0) WARN_UNUSED_RESULT; // Starts listening for incoming connections but will not yet accept them. @@ -313,9 +337,16 @@ class EmbeddedTestServer { bool InitializeAndListen(int port = 0) WARN_UNUSED_RESULT; // Starts the Accept IO Thread and begins accepting connections. + EmbeddedTestServerHandle StartAcceptingConnectionsAndReturnHandle() + WARN_UNUSED_RESULT; + + // Equivalent of StartAcceptingConnectionsAndReturnHandle(), but requires + // manual Shutdown() by the caller. void StartAcceptingConnections(); // Shuts down the http server and waits until the shutdown is complete. + // Prefer to use the Start*AndReturnHandle() APIs to manage shutdown, if + // possible. bool ShutdownAndWaitUntilComplete() WARN_UNUSED_RESULT; // Checks if the server has started listening for incoming connections. @@ -386,23 +417,22 @@ class EmbeddedTestServer { // |directory| directory, relative to DIR_SOURCE_ROOT. void AddDefaultHandlers(const base::FilePath& directory); - // The most general purpose method. Any request processing can be added using - // this method. Takes ownership of the object. The |callback| is called - // on the server's IO thread so all handlers must be registered before the - // server is started. + // Adds a request handler that can perform any general-purpose processing. + // |callback| will be invoked on the server's IO thread. Note that: + // 1. All handlers must be registered before the server is Start()ed. + // 2. The server should be Shutdown() before any variables referred to by + // |callback| (e.g. via base::Unretained(&local)) are deleted. Using the + // Start*WithHandle() API variants is recommended for this reason. void RegisterRequestHandler(const HandleRequestCallback& callback); - // Adds request monitors. The |callback| is called before any handlers are - // called, but can not respond it. This is useful to monitor requests that - // will be handled by other request handlers. The |callback| is called - // on the server's IO thread so all monitors must be registered before the - // server is started. + // Adds a request monitor that will be called before any handlers. Monitors + // can be used to observe requests, but not to respond to them. + // See RegisterRequestHandler() for notes on usage. void RegisterRequestMonitor(const MonitorRequestCallback& callback); - // Adds default handlers, including those added by AddDefaultHandlers, to be - // tried after all other user-specified handlers have been tried. The - // |callback| is called on the server's IO thread so all handlers must be - // registered before the server is started. + // Adds a default request handler, to be called if no user-specified handler + // handles the request. + // See RegisterRequestHandler() for notes on usage. void RegisterDefaultHandler(const HandleRequestCallback& callback); bool FlushAllSocketsAndConnectionsOnUIThread(); @@ -525,23 +555,6 @@ class EmbeddedTestServer { DISALLOW_COPY_AND_ASSIGN(EmbeddedTestServer); }; -class EmbeddedTestServerHandle { - public: - EmbeddedTestServerHandle() = default; - EmbeddedTestServerHandle(EmbeddedTestServerHandle&& other); - EmbeddedTestServerHandle& operator=(EmbeddedTestServerHandle&& other); - - ~EmbeddedTestServerHandle(); - - explicit operator bool() const { return test_server_; } - - private: - friend class EmbeddedTestServer; - - explicit EmbeddedTestServerHandle(EmbeddedTestServer* test_server); - EmbeddedTestServer* test_server_ = nullptr; -}; - } // namespace test_server // TODO(svaldez): Refactor EmbeddedTestServer to be in the net namespace. diff --git a/chromium/net/test/embedded_test_server/request_handler_util.cc b/chromium/net/test/embedded_test_server/request_handler_util.cc index 91d4275f94b..f08d3c34a0b 100644 --- a/chromium/net/test/embedded_test_server/request_handler_util.cc +++ b/chromium/net/test/embedded_test_server/request_handler_util.cc @@ -60,6 +60,10 @@ std::string GetContentType(const base::FilePath& path) { return "audio/wav"; if (path.MatchesExtension(FILE_PATH_LITERAL(".webp"))) return "image/webp"; + if (path.MatchesExtension(FILE_PATH_LITERAL(".mp4"))) + return "video/mp4"; + if (path.MatchesExtension(FILE_PATH_LITERAL(".webm"))) + return "video/webm"; if (path.MatchesExtension(FILE_PATH_LITERAL(".xml"))) return "text/xml"; if (path.MatchesExtension(FILE_PATH_LITERAL(".mhtml"))) diff --git a/chromium/net/test/spawned_test_server/base_test_server.cc b/chromium/net/test/spawned_test_server/base_test_server.cc index 22fd960a7f3..8330ccda5d2 100644 --- a/chromium/net/test/spawned_test_server/base_test_server.cc +++ b/chromium/net/test/spawned_test_server/base_test_server.cc @@ -19,6 +19,7 @@ #include "net/base/address_list.h" #include "net/base/host_port_pair.h" #include "net/base/net_errors.h" +#include "net/base/network_isolation_key.h" #include "net/base/port_util.h" #include "net/base/test_completion_callback.h" #include "net/cert/test_root_certs.h" @@ -221,7 +222,8 @@ bool BaseTestServer::GetAddressList(AddressList* address_list) const { parameters.dns_query_type = DnsQueryType::A; std::unique_ptr<HostResolver::ResolveHostRequest> request = - resolver->CreateRequest(host_port_pair_, NetLogWithSource(), parameters); + resolver->CreateRequest(host_port_pair_, NetworkIsolationKey(), + NetLogWithSource(), parameters); TestCompletionCallback callback; int rv = request->Start(callback.callback()); @@ -361,15 +363,14 @@ void BaseTestServer::SetResourcePath(const base::FilePath& document_root, bool BaseTestServer::SetAndParseServerData(const std::string& server_data, int* port) { VLOG(1) << "Server data: " << server_data; - base::JSONReader json_reader; - base::Optional<base::Value> value(json_reader.ReadToValue(server_data)); - if (!value || !value->is_dict()) { - LOG(ERROR) << "Could not parse server data: " - << json_reader.GetErrorMessage(); + base::JSONReader::ValueWithError parsed_json = + base::JSONReader::ReadAndReturnValueWithError(server_data); + if (!parsed_json.value || !parsed_json.value->is_dict()) { + LOG(ERROR) << "Could not parse server data: " << parsed_json.error_message; return false; } - server_data_ = std::move(value); + server_data_ = std::move(parsed_json.value); base::Optional<int> port_value = server_data_->FindIntKey("port"); if (!port_value) { diff --git a/chromium/net/test/spawned_test_server/local_test_server.cc b/chromium/net/test/spawned_test_server/local_test_server.cc index 3f46015d4fc..eb5016bd805 100644 --- a/chromium/net/test/spawned_test_server/local_test_server.cc +++ b/chromium/net/test/spawned_test_server/local_test_server.cc @@ -7,6 +7,7 @@ #include "base/command_line.h" #include "base/json/json_reader.h" #include "base/logging.h" +#include "base/notreached.h" #include "base/path_service.h" #include "base/strings/string_number_conversions.h" #include "base/threading/thread_restrictions.h" diff --git a/chromium/net/test/spawned_test_server/local_test_server_win.cc b/chromium/net/test/spawned_test_server/local_test_server_win.cc index 085a3f8cd59..319eee0789e 100644 --- a/chromium/net/test/spawned_test_server/local_test_server_win.cc +++ b/chromium/net/test/spawned_test_server/local_test_server_win.cc @@ -11,6 +11,7 @@ #include "base/command_line.h" #include "base/environment.h" #include "base/files/file_path.h" +#include "base/logging.h" #include "base/path_service.h" #include "base/process/launch.h" #include "base/strings/string_number_conversions.h" diff --git a/chromium/net/test/url_request/url_request_slow_download_job.cc b/chromium/net/test/url_request/url_request_slow_download_job.cc deleted file mode 100644 index 2195db86e6f..00000000000 --- a/chromium/net/test/url_request/url_request_slow_download_job.cc +++ /dev/null @@ -1,283 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/test/url_request/url_request_slow_download_job.h" - -#include "base/bind.h" -#include "base/compiler_specific.h" -#include "base/location.h" -#include "base/logging.h" -#include "base/macros.h" -#include "base/single_thread_task_runner.h" -#include "base/strings/string_util.h" -#include "base/strings/stringprintf.h" -#include "base/threading/thread_task_runner_handle.h" -#include "net/base/io_buffer.h" -#include "net/base/net_errors.h" -#include "net/http/http_response_headers.h" -#include "net/url_request/url_request.h" -#include "net/url_request/url_request_filter.h" -#include "net/url_request/url_request_interceptor.h" -#include "url/gurl.h" - -namespace net { - -const char URLRequestSlowDownloadJob::kUnknownSizeUrl[] = - "http://url.handled.by.slow.download/download-unknown-size"; -const char URLRequestSlowDownloadJob::kKnownSizeUrl[] = - "http://url.handled.by.slow.download/download-known-size"; -const char URLRequestSlowDownloadJob::kFinishDownloadUrl[] = - "http://url.handled.by.slow.download/download-finish"; -const char URLRequestSlowDownloadJob::kErrorDownloadUrl[] = - "http://url.handled.by.slow.download/download-error"; - -const int URLRequestSlowDownloadJob::kFirstDownloadSize = 1024 * 35; -const int URLRequestSlowDownloadJob::kSecondDownloadSize = 1024 * 10; - -class URLRequestSlowDownloadJob::Interceptor : public URLRequestInterceptor { - public: - Interceptor() = default; - ~Interceptor() override = default; - - // URLRequestInterceptor implementation: - URLRequestJob* MaybeInterceptRequest( - URLRequest* request, - NetworkDelegate* network_delegate) const override { - URLRequestSlowDownloadJob* job = - new URLRequestSlowDownloadJob(request, network_delegate); - if (request->url().spec() != kFinishDownloadUrl && - request->url().spec() != kErrorDownloadUrl) { - pending_requests_.Get().insert(job); - } - return job; - } - - private: - DISALLOW_COPY_AND_ASSIGN(Interceptor); -}; - -// static -base::LazyInstance<URLRequestSlowDownloadJob::SlowJobsSet>::Leaky - URLRequestSlowDownloadJob::pending_requests_ = LAZY_INSTANCE_INITIALIZER; - -void URLRequestSlowDownloadJob::Start() { - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(&URLRequestSlowDownloadJob::StartAsync, - weak_factory_.GetWeakPtr())); -} - -int64_t URLRequestSlowDownloadJob::GetTotalReceivedBytes() const { - return bytes_already_sent_; -} - -// static -void URLRequestSlowDownloadJob::AddUrlHandler() { - URLRequestFilter* filter = URLRequestFilter::GetInstance(); - filter->AddUrlInterceptor( - GURL(kUnknownSizeUrl), - std::unique_ptr<URLRequestInterceptor>(new Interceptor())); - filter->AddUrlInterceptor( - GURL(kKnownSizeUrl), - std::unique_ptr<URLRequestInterceptor>(new Interceptor())); - filter->AddUrlInterceptor( - GURL(kFinishDownloadUrl), - std::unique_ptr<URLRequestInterceptor>(new Interceptor())); - filter->AddUrlInterceptor( - GURL(kErrorDownloadUrl), - std::unique_ptr<URLRequestInterceptor>(new Interceptor())); -} - -// static -size_t URLRequestSlowDownloadJob::NumberOutstandingRequests() { - return pending_requests_.Get().size(); -} - -// static -void URLRequestSlowDownloadJob::FinishPendingRequests() { - for (auto it = pending_requests_.Get().begin(); - it != pending_requests_.Get().end(); ++it) { - (*it)->set_should_finish_download(); - } -} - -void URLRequestSlowDownloadJob::ErrorPendingRequests() { - for (auto it = pending_requests_.Get().begin(); - it != pending_requests_.Get().end(); ++it) { - (*it)->set_should_error_download(); - } -} - -URLRequestSlowDownloadJob::URLRequestSlowDownloadJob( - URLRequest* request, - NetworkDelegate* network_delegate) - : URLRequestJob(request, network_delegate), - bytes_already_sent_(0), - should_error_download_(false), - should_finish_download_(false), - buffer_size_(0) {} - -void URLRequestSlowDownloadJob::StartAsync() { - if (base::LowerCaseEqualsASCII(kFinishDownloadUrl, - request_->url().spec().c_str())) - URLRequestSlowDownloadJob::FinishPendingRequests(); - if (base::LowerCaseEqualsASCII(kErrorDownloadUrl, - request_->url().spec().c_str())) - URLRequestSlowDownloadJob::ErrorPendingRequests(); - - NotifyHeadersComplete(); -} - -// ReadRawData and CheckDoneStatus together implement a state -// machine. ReadRawData may be called arbitrarily by the network stack. -// It responds by: -// * If there are bytes remaining in the first chunk, they are -// returned. -// [No bytes remaining in first chunk. ] -// * If should_finish_download_ is not set, it returns IO_PENDING, -// and starts calling CheckDoneStatus on a regular timer. -// [should_finish_download_ set.] -// * If there are bytes remaining in the second chunk, they are filled. -// * Otherwise, return *bytes_read = 0 to indicate end of request. -// CheckDoneStatus is called on a regular basis, in the specific -// case where we have transmitted all of the first chunk and none of the -// second. If should_finish_download_ becomes set, it will "complete" -// the ReadRawData call that spawned off the CheckDoneStatus() repeated call. -// -// FillBufferHelper is a helper function that does the actual work of figuring -// out where in the state machine we are and how we should fill the buffer. -// It returns an enum indicating the state of the read. -URLRequestSlowDownloadJob::ReadStatus -URLRequestSlowDownloadJob::FillBufferHelper(IOBuffer* buf, - int buf_size, - int* bytes_written) { - if (bytes_already_sent_ < kFirstDownloadSize) { - int bytes_to_write = - std::min(kFirstDownloadSize - bytes_already_sent_, buf_size); - for (int i = 0; i < bytes_to_write; ++i) { - buf->data()[i] = '*'; - } - *bytes_written = bytes_to_write; - bytes_already_sent_ += bytes_to_write; - return BUFFER_FILLED; - } - - if (!should_finish_download_) - return REQUEST_BLOCKED; - - if (bytes_already_sent_ < kFirstDownloadSize + kSecondDownloadSize) { - int bytes_to_write = - std::min(kFirstDownloadSize + kSecondDownloadSize - bytes_already_sent_, - buf_size); - for (int i = 0; i < bytes_to_write; ++i) { - buf->data()[i] = '*'; - } - *bytes_written = bytes_to_write; - bytes_already_sent_ += bytes_to_write; - return BUFFER_FILLED; - } - - return REQUEST_COMPLETE; -} - -int URLRequestSlowDownloadJob::ReadRawData(IOBuffer* buf, int buf_size) { - if (base::LowerCaseEqualsASCII(kFinishDownloadUrl, - request_->url().spec().c_str()) || - base::LowerCaseEqualsASCII(kErrorDownloadUrl, - request_->url().spec().c_str())) { - VLOG(10) << __FUNCTION__ << " called w/ kFinish/ErrorDownloadUrl."; - return 0; - } - - VLOG(10) << __FUNCTION__ << " called at position " << bytes_already_sent_ - << " in the stream."; - int bytes_read = 0; - ReadStatus status = FillBufferHelper(buf, buf_size, &bytes_read); - switch (status) { - case BUFFER_FILLED: - case REQUEST_COMPLETE: - return bytes_read; - case REQUEST_BLOCKED: - buffer_ = buf; - buffer_size_ = buf_size; - base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( - FROM_HERE, - base::BindOnce(&URLRequestSlowDownloadJob::CheckDoneStatus, - weak_factory_.GetWeakPtr()), - base::TimeDelta::FromMilliseconds(100)); - return ERR_IO_PENDING; - } - NOTREACHED(); - return OK; -} - -void URLRequestSlowDownloadJob::CheckDoneStatus() { - if (should_finish_download_) { - VLOG(10) << __FUNCTION__ << " called w/ should_finish_download_ set."; - DCHECK(nullptr != buffer_.get()); - int bytes_written = 0; - ReadStatus status = - FillBufferHelper(buffer_.get(), buffer_size_, &bytes_written); - DCHECK_EQ(BUFFER_FILLED, status); - buffer_ = nullptr; // Release the reference. - ReadRawDataComplete(bytes_written); - } else if (should_error_download_) { - VLOG(10) << __FUNCTION__ << " called w/ should_finish_ownload_ set."; - ReadRawDataComplete(ERR_CONNECTION_RESET); - } else { - base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( - FROM_HERE, - base::BindOnce(&URLRequestSlowDownloadJob::CheckDoneStatus, - weak_factory_.GetWeakPtr()), - base::TimeDelta::FromMilliseconds(100)); - } -} - -// Public virtual version. -void URLRequestSlowDownloadJob::GetResponseInfo(HttpResponseInfo* info) { - // Forward to private const version. - GetResponseInfoConst(info); -} - -URLRequestSlowDownloadJob::~URLRequestSlowDownloadJob() { - pending_requests_.Get().erase(this); -} - -// Private const version. -void URLRequestSlowDownloadJob::GetResponseInfoConst( - HttpResponseInfo* info) const { - // Send back mock headers. - std::string raw_headers; - if (base::LowerCaseEqualsASCII(kFinishDownloadUrl, - request_->url().spec().c_str()) || - base::LowerCaseEqualsASCII(kErrorDownloadUrl, - request_->url().spec().c_str())) { - raw_headers.append( - "HTTP/1.1 200 OK\n" - "Content-type: text/plain\n"); - } else { - raw_headers.append( - "HTTP/1.1 200 OK\n" - "Content-type: application/octet-stream\n" - "Cache-Control: max-age=0\n"); - - if (base::LowerCaseEqualsASCII(kKnownSizeUrl, - request_->url().spec().c_str())) { - raw_headers.append(base::StringPrintf( - "Content-Length: %d\n", kFirstDownloadSize + kSecondDownloadSize)); - } - } - - // ParseRawHeaders expects \0 to end each header line. - base::ReplaceSubstringsAfterOffset( - &raw_headers, 0, "\n", base::StringPiece("\0", 1)); - info->headers = new HttpResponseHeaders(raw_headers); -} - -bool URLRequestSlowDownloadJob::GetMimeType(std::string* mime_type) const { - HttpResponseInfo info; - GetResponseInfoConst(&info); - return info.headers.get() && info.headers->GetMimeType(mime_type); -} - -} // namespace net diff --git a/chromium/net/test/url_request/url_request_slow_download_job.h b/chromium/net/test/url_request/url_request_slow_download_job.h deleted file mode 100644 index c7302c9074c..00000000000 --- a/chromium/net/test/url_request/url_request_slow_download_job.h +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// This class simulates a slow download. Requests to |kUnknownSizeUrl| and -// |kKnownSizeUrl| start downloads that pause after the first N bytes, to be -// completed by sending a request to |kFinishDownloadUrl|. - -#ifndef NET_TEST_URL_REQUEST_URL_REQUEST_SLOW_DOWNLOAD_JOB_H_ -#define NET_TEST_URL_REQUEST_URL_REQUEST_SLOW_DOWNLOAD_JOB_H_ - -#include <stddef.h> -#include <stdint.h> - -#include <set> -#include <string> - -#include "base/lazy_instance.h" -#include "base/memory/weak_ptr.h" -#include "net/url_request/url_request_job.h" - -namespace net { - -class URLRequestSlowDownloadJob : public URLRequestJob { - public: - // Test URLs. - static const char kUnknownSizeUrl[]; - static const char kKnownSizeUrl[]; - static const char kFinishDownloadUrl[]; - static const char kErrorDownloadUrl[]; - - // Download sizes. - static const int kFirstDownloadSize; - static const int kSecondDownloadSize; - - // Timer callback, used to check to see if we should finish our download and - // send the second chunk. - void CheckDoneStatus(); - - // URLRequestJob methods - void Start() override; - int64_t GetTotalReceivedBytes() const override; - bool GetMimeType(std::string* mime_type) const override; - void GetResponseInfo(HttpResponseInfo* info) override; - int ReadRawData(IOBuffer* buf, int buf_size) override; - - // Returns the current number of URLRequestSlowDownloadJobs that have - // not yet completed. - static size_t NumberOutstandingRequests(); - - // Adds the testing URLs to the URLRequestFilter. - static void AddUrlHandler(); - - private: - class Interceptor; - - // Enum indicating where we are in the read after a call to - // FillBufferHelper. - enum ReadStatus { - // The buffer was filled with data and may be returned. - BUFFER_FILLED, - - // No data was added to the buffer because kFinishDownloadUrl has - // not yet been seen and we've already returned the first chunk. - REQUEST_BLOCKED, - - // No data was added to the buffer because we've already returned - // all the data. - REQUEST_COMPLETE - }; - - URLRequestSlowDownloadJob(URLRequest* request, - NetworkDelegate* network_delegate); - ~URLRequestSlowDownloadJob() override; - - ReadStatus FillBufferHelper(IOBuffer* buf, int buf_size, int* bytes_written); - - void GetResponseInfoConst(HttpResponseInfo* info) const; - - // Mark all pending requests to be finished. We keep track of pending - // requests in |pending_requests_|. - static void FinishPendingRequests(); - static void ErrorPendingRequests(); - typedef std::set<URLRequestSlowDownloadJob*> SlowJobsSet; - static base::LazyInstance<SlowJobsSet>::Leaky pending_requests_; - - void StartAsync(); - - void set_should_finish_download() { should_finish_download_ = true; } - void set_should_error_download() { should_error_download_ = true; } - - int bytes_already_sent_; - bool should_error_download_; - bool should_finish_download_; - scoped_refptr<IOBuffer> buffer_; - int buffer_size_; - - base::WeakPtrFactory<URLRequestSlowDownloadJob> weak_factory_{this}; -}; - -} // namespace net - -#endif // NET_TEST_URL_REQUEST_URL_REQUEST_SLOW_DOWNLOAD_JOB_H_ diff --git a/chromium/net/third_party/mozilla_security_manager/nsNSSCertificateDB.cpp b/chromium/net/third_party/mozilla_security_manager/nsNSSCertificateDB.cpp index 7174f9947b7..39e9a6267d3 100644 --- a/chromium/net/third_party/mozilla_security_manager/nsNSSCertificateDB.cpp +++ b/chromium/net/third_party/mozilla_security_manager/nsNSSCertificateDB.cpp @@ -44,6 +44,7 @@ #include <secerr.h> #include "base/logging.h" +#include "base/notreached.h" #include "crypto/scoped_nss_types.h" #include "net/base/net_errors.h" #include "net/cert/x509_certificate.h" diff --git a/chromium/net/third_party/quiche/BUILD.gn b/chromium/net/third_party/quiche/BUILD.gn index 59a75e2132a..a715ea8e2cc 100644 --- a/chromium/net/third_party/quiche/BUILD.gn +++ b/chromium/net/third_party/quiche/BUILD.gn @@ -23,6 +23,7 @@ source_set("quiche") { "src/common/platform/api/quiche_str_cat.h", "src/common/platform/api/quiche_string_piece.h", "src/common/platform/api/quiche_text_utils.h", + "src/common/platform/api/quiche_time_utils.h", "src/common/platform/api/quiche_unordered_containers.h", "src/common/quiche_data_reader.cc", "src/common/quiche_data_reader.h", @@ -253,6 +254,8 @@ source_set("quiche") { "src/quic/core/crypto/transport_parameters.h", "src/quic/core/frames/quic_ack_frame.cc", "src/quic/core/frames/quic_ack_frame.h", + "src/quic/core/frames/quic_ack_frequency_frame.cc", + "src/quic/core/frames/quic_ack_frequency_frame.h", "src/quic/core/frames/quic_blocked_frame.cc", "src/quic/core/frames/quic_blocked_frame.h", "src/quic/core/frames/quic_connection_close_frame.cc", @@ -431,6 +434,8 @@ source_set("quiche") { "src/quic/core/quic_interval.h", "src/quic/core/quic_interval_deque.h", "src/quic/core/quic_interval_set.h", + "src/quic/core/quic_legacy_version_encapsulator.cc", + "src/quic/core/quic_legacy_version_encapsulator.h", "src/quic/core/quic_lru_cache.h", "src/quic/core/quic_mtu_discovery.cc", "src/quic/core/quic_mtu_discovery.h", @@ -548,6 +553,8 @@ source_set("quiche") { "src/quic/quic_transport/quic_transport_session_interface.h", "src/quic/quic_transport/quic_transport_stream.cc", "src/quic/quic_transport/quic_transport_stream.h", + "src/quic/quic_transport/web_transport_fingerprint_proof_verifier.cc", + "src/quic/quic_transport/web_transport_fingerprint_proof_verifier.h", "src/spdy/core/fifo_write_scheduler.h", "src/spdy/core/hpack/hpack_constants.cc", "src/spdy/core/hpack/hpack_constants.h", @@ -1230,6 +1237,7 @@ source_set("quiche_tests") { "src/common/platform/api/quiche_endian_test.cc", "src/common/platform/api/quiche_str_cat_test.cc", "src/common/platform/api/quiche_text_utils_test.cc", + "src/common/platform/api/quiche_time_utils_test.cc", "src/quic/core/congestion_control/bbr_sender_test.cc", "src/quic/core/congestion_control/cubic_bytes_test.cc", "src/quic/core/congestion_control/general_loss_algorithm_test.cc", @@ -1329,6 +1337,7 @@ source_set("quiche_tests") { "src/quic/core/quic_interval_deque_test.cc", "src/quic/core/quic_interval_set_test.cc", "src/quic/core/quic_interval_test.cc", + "src/quic/core/quic_legacy_version_encapsulator_test.cc", "src/quic/core/quic_lru_cache_test.cc", "src/quic/core/quic_network_blackhole_detector_test.cc", "src/quic/core/quic_one_block_arena_test.cc", @@ -1374,6 +1383,7 @@ source_set("quiche_tests") { "src/quic/quic_transport/quic_transport_integration_test.cc", "src/quic/quic_transport/quic_transport_server_session_test.cc", "src/quic/quic_transport/quic_transport_stream_test.cc", + "src/quic/quic_transport/web_transport_fingerprint_proof_verifier_test.cc", "src/quic/test_tools/crypto_test_utils_test.cc", "src/quic/test_tools/mock_quic_time_wait_list_manager.cc", "src/quic/test_tools/mock_quic_time_wait_list_manager.h", @@ -1426,58 +1436,6 @@ source_set("quiche_tests") { "src/spdy/platform/api/spdy_test_helpers.h", ] - # Disable building Quartc tests on iOS as they appear to be flaky there. - if (!is_ios) { - sources += [ - "src/quic/quartc/counting_packet_filter.h", - "src/quic/quartc/quartc_connection_helper.cc", - "src/quic/quartc/quartc_connection_helper.h", - "src/quic/quartc/quartc_crypto_helpers.cc", - "src/quic/quartc/quartc_crypto_helpers.h", - "src/quic/quartc/quartc_dispatcher.cc", - "src/quic/quartc/quartc_dispatcher.h", - "src/quic/quartc/quartc_endpoint.cc", - "src/quic/quartc/quartc_endpoint.h", - "src/quic/quartc/quartc_endpoint_test.cc", - "src/quic/quartc/quartc_factory.cc", - "src/quic/quartc/quartc_factory.h", - "src/quic/quartc/quartc_fakes.h", - "src/quic/quartc/quartc_interval_counter.h", - "src/quic/quartc/quartc_interval_counter_test.cc", - "src/quic/quartc/quartc_multiplexer.cc", - "src/quic/quartc/quartc_multiplexer.h", - "src/quic/quartc/quartc_multiplexer_test.cc", - "src/quic/quartc/quartc_packet_writer.cc", - "src/quic/quartc/quartc_packet_writer.h", - "src/quic/quartc/quartc_session.cc", - "src/quic/quartc/quartc_session.h", - "src/quic/quartc/quartc_session_test.cc", - "src/quic/quartc/quartc_stream.cc", - "src/quic/quartc/quartc_stream.h", - "src/quic/quartc/quartc_stream_test.cc", - "src/quic/quartc/simulated_packet_transport.cc", - "src/quic/quartc/simulated_packet_transport.h", - "src/quic/quartc/simulated_packet_transport_test.cc", - "src/quic/quartc/test/bidi_test_runner.cc", - "src/quic/quartc/test/bidi_test_runner.h", - "src/quic/quartc/test/quartc_bidi_test.cc", - "src/quic/quartc/test/quartc_competing_endpoint.cc", - "src/quic/quartc/test/quartc_competing_endpoint.h", - "src/quic/quartc/test/quartc_data_source.cc", - "src/quic/quartc/test/quartc_data_source.h", - "src/quic/quartc/test/quartc_data_source_test.cc", - "src/quic/quartc/test/quartc_peer.cc", - "src/quic/quartc/test/quartc_peer.h", - "src/quic/quartc/test/quartc_peer_test.cc", - "src/quic/quartc/test/quic_trace_interceptor.cc", - "src/quic/quartc/test/quic_trace_interceptor.h", - "src/quic/quartc/test/random_delay_link.cc", - "src/quic/quartc/test/random_delay_link.h", - "src/quic/quartc/test/random_packet_filter.cc", - "src/quic/quartc/test/random_packet_filter.h", - ] - } - deps = [ "//net", "//net:quic_test_tools", diff --git a/chromium/net/third_party/quiche/src/common/platform/api/quiche_optional.h b/chromium/net/third_party/quiche/src/common/platform/api/quiche_optional.h index 141c0e49cd8..d5d3dac3538 100644 --- a/chromium/net/third_party/quiche/src/common/platform/api/quiche_optional.h +++ b/chromium/net/third_party/quiche/src/common/platform/api/quiche_optional.h @@ -13,7 +13,8 @@ namespace quiche { template <typename T> using QuicheOptional = QuicheOptionalImpl<T>; -#define QuicheNullOpt QuicheNullOptImpl + +#define QUICHE_NULLOPT QUICHE_NULLOPT_IMPL } // namespace quiche diff --git a/chromium/net/third_party/quiche/src/common/platform/api/quiche_time_utils.h b/chromium/net/third_party/quiche/src/common/platform/api/quiche_time_utils.h new file mode 100644 index 00000000000..7319568172b --- /dev/null +++ b/chromium/net/third_party/quiche/src/common/platform/api/quiche_time_utils.h @@ -0,0 +1,31 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_COMMON_PLATFORM_API_QUICHE_TIME_UTILS_H_ +#define QUICHE_COMMON_PLATFORM_API_QUICHE_TIME_UTILS_H_ + +#include <cstdint> + +#include "net/quiche/common/platform/impl/quiche_time_utils_impl.h" + +namespace quiche { + +// Converts a civil time specified in UTC into a number of seconds since the +// Unix epoch. This function is strict about validity of accepted dates. For +// instance, it will reject February 29 on non-leap years, or 25 hours in a day. +// As a notable exception, 60 seconds is accepted to deal with potential leap +// seconds. If the date predates Unix epoch, nullopt will be returned. +inline QuicheOptional<int64_t> QuicheUtcDateTimeToUnixSeconds(int year, + int month, + int day, + int hour, + int minute, + int second) { + return QuicheUtcDateTimeToUnixSecondsImpl(year, month, day, hour, minute, + second); +} + +} // namespace quiche + +#endif // QUICHE_COMMON_PLATFORM_API_QUICHE_TIME_UTILS_H_ diff --git a/chromium/net/third_party/quiche/src/common/platform/api/quiche_time_utils_test.cc b/chromium/net/third_party/quiche/src/common/platform/api/quiche_time_utils_test.cc new file mode 100644 index 00000000000..3ae296dbd81 --- /dev/null +++ b/chromium/net/third_party/quiche/src/common/platform/api/quiche_time_utils_test.cc @@ -0,0 +1,53 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/third_party/quiche/src/common/platform/api/quiche_time_utils.h" + +#include "net/third_party/quiche/src/common/platform/api/quiche_optional.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_test.h" + +namespace quiche { +namespace { + +TEST(QuicheTimeUtilsTest, Basic) { + EXPECT_EQ(1, QuicheUtcDateTimeToUnixSeconds(1970, 1, 1, 0, 0, 1)); + EXPECT_EQ(365 * 86400, QuicheUtcDateTimeToUnixSeconds(1971, 1, 1, 0, 0, 0)); + // Some arbitrary timestamps closer to the present, compared to the output of + // "Date(...).getTime()" from the JavaScript console. + EXPECT_EQ(1152966896, + QuicheUtcDateTimeToUnixSeconds(2006, 7, 15, 12, 34, 56)); + EXPECT_EQ(1591130001, QuicheUtcDateTimeToUnixSeconds(2020, 6, 2, 20, 33, 21)); + + EXPECT_EQ(QUICHE_NULLOPT, + QuicheUtcDateTimeToUnixSeconds(1970, 2, 29, 0, 0, 1)); + EXPECT_NE(QUICHE_NULLOPT, + QuicheUtcDateTimeToUnixSeconds(1972, 2, 29, 0, 0, 1)); +} + +TEST(QuicheTimeUtilsTest, Bounds) { + EXPECT_EQ(QUICHE_NULLOPT, + QuicheUtcDateTimeToUnixSeconds(1970, 1, 32, 0, 0, 1)); + EXPECT_EQ(QUICHE_NULLOPT, + QuicheUtcDateTimeToUnixSeconds(1970, 4, 31, 0, 0, 1)); + EXPECT_EQ(QUICHE_NULLOPT, + QuicheUtcDateTimeToUnixSeconds(1970, 1, 0, 0, 0, 1)); + EXPECT_EQ(QUICHE_NULLOPT, + QuicheUtcDateTimeToUnixSeconds(1970, 13, 1, 0, 0, 1)); + EXPECT_EQ(QUICHE_NULLOPT, + QuicheUtcDateTimeToUnixSeconds(1970, 0, 1, 0, 0, 1)); + EXPECT_EQ(QUICHE_NULLOPT, + QuicheUtcDateTimeToUnixSeconds(1970, 1, 1, 24, 0, 0)); + EXPECT_EQ(QUICHE_NULLOPT, + QuicheUtcDateTimeToUnixSeconds(1970, 1, 1, 0, 60, 0)); +} + +TEST(QuicheTimeUtilsTest, LeapSecond) { + EXPECT_EQ(QuicheUtcDateTimeToUnixSeconds(2015, 6, 30, 23, 59, 60), + QuicheUtcDateTimeToUnixSeconds(2015, 7, 1, 0, 0, 0)); + EXPECT_EQ(QuicheUtcDateTimeToUnixSeconds(2015, 6, 30, 25, 59, 60), + QUICHE_NULLOPT); +} + +} // namespace +} // namespace quiche diff --git a/chromium/net/third_party/quiche/src/common/quiche_data_reader.cc b/chromium/net/third_party/quiche/src/common/quiche_data_reader.cc index 344501378b5..2242fea6437 100644 --- a/chromium/net/third_party/quiche/src/common/quiche_data_reader.cc +++ b/chromium/net/third_party/quiche/src/common/quiche_data_reader.cc @@ -10,6 +10,7 @@ #include "net/third_party/quiche/src/common/platform/api/quiche_logging.h" #include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h" #include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_text_utils.h" namespace quiche { @@ -119,6 +120,15 @@ bool QuicheDataReader::ReadTag(uint32_t* tag) { return ReadBytes(tag, sizeof(*tag)); } +bool QuicheDataReader::ReadDecimal64(size_t num_digits, uint64_t* result) { + quiche::QuicheStringPiece digits; + if (!ReadStringPiece(&digits, num_digits)) { + return false; + } + + return QuicheTextUtils::StringToUint64(digits, result); +} + quiche::QuicheStringPiece QuicheDataReader::ReadRemainingPayload() { quiche::QuicheStringPiece payload = PeekRemainingPayload(); pos_ = len_; diff --git a/chromium/net/third_party/quiche/src/common/quiche_data_reader.h b/chromium/net/third_party/quiche/src/common/quiche_data_reader.h index cf62a164708..f74f90d19e2 100644 --- a/chromium/net/third_party/quiche/src/common/quiche_data_reader.h +++ b/chromium/net/third_party/quiche/src/common/quiche_data_reader.h @@ -87,6 +87,11 @@ class QUICHE_EXPORT_PRIVATE QuicheDataReader { // endian. bool ReadTag(uint32_t* tag); + // Reads a sequence of a fixed number of decimal digits, parses them as an + // unsigned integer and returns them as a uint64_t. Forwards internal + // iterator on success, may forward it even in case of failure. + bool ReadDecimal64(size_t num_digits, uint64_t* result); + // Returns the remaining payload as a quiche::QuicheStringPiece. // // NOTE: Does not copy but rather references strings in the underlying buffer. diff --git a/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_base.cc b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_base.cc new file mode 100644 index 00000000000..919f76b3b80 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_base.cc @@ -0,0 +1,177 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_base.h" +#include <cstdint> + +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" + +namespace quic { + +QuicBatchWriterBase::QuicBatchWriterBase( + std::unique_ptr<QuicBatchWriterBuffer> batch_buffer) + : write_blocked_(false), batch_buffer_(std::move(batch_buffer)) {} + +WriteResult QuicBatchWriterBase::WritePacket( + const char* buffer, + size_t buf_len, + const QuicIpAddress& self_address, + const QuicSocketAddress& peer_address, + PerPacketOptions* options) { + const WriteResult result = + InternalWritePacket(buffer, buf_len, self_address, peer_address, options); + if (result.status == WRITE_STATUS_BLOCKED) { + write_blocked_ = true; + } + return result; +} + +uint64_t QuicBatchWriterBase::GetReleaseTime( + const PerPacketOptions* options) const { + DCHECK(SupportsReleaseTime()); + + if (options == nullptr) { + return 0; + } + + if ((options->release_time_delay.IsZero() || options->allow_burst) && + !buffered_writes().empty()) { + // Send as soon as possible, but no sooner than the last buffered packet. + return buffered_writes().back().release_time; + } + + // Send according to the release time delay. + return NowInNanosForReleaseTime() + + options->release_time_delay.ToMicroseconds() * 1000; +} + +WriteResult QuicBatchWriterBase::InternalWritePacket( + const char* buffer, + size_t buf_len, + const QuicIpAddress& self_address, + const QuicSocketAddress& peer_address, + PerPacketOptions* options) { + if (buf_len > kMaxOutgoingPacketSize) { + return WriteResult(WRITE_STATUS_MSG_TOO_BIG, EMSGSIZE); + } + + uint64_t release_time = SupportsReleaseTime() ? GetReleaseTime(options) : 0; + + const CanBatchResult can_batch_result = CanBatch( + buffer, buf_len, self_address, peer_address, options, release_time); + + bool buffered = false; + bool flush = can_batch_result.must_flush; + + if (can_batch_result.can_batch) { + QuicBatchWriterBuffer::PushResult push_result = + batch_buffer_->PushBufferedWrite(buffer, buf_len, self_address, + peer_address, options, release_time); + if (push_result.succeeded) { + buffered = true; + // If there's no space left after the packet is buffered, force a flush. + flush = flush || (batch_buffer_->GetNextWriteLocation() == nullptr); + } else { + // If there's no space without this packet, force a flush. + flush = true; + } + } + + if (!flush) { + return WriteResult(WRITE_STATUS_OK, 0); + } + + size_t num_buffered_packets = buffered_writes().size(); + const FlushImplResult flush_result = CheckedFlush(); + const WriteResult& result = flush_result.write_result; + QUIC_DVLOG(1) << "Internally flushed " << flush_result.num_packets_sent + << " out of " << num_buffered_packets + << " packets. WriteResult=" << result; + + if (result.status != WRITE_STATUS_OK) { + if (IsWriteBlockedStatus(result.status)) { + return WriteResult( + buffered ? WRITE_STATUS_BLOCKED_DATA_BUFFERED : WRITE_STATUS_BLOCKED, + result.error_code); + } + + // Drop all packets, including the one being written. + size_t dropped_packets = + buffered ? buffered_writes().size() : buffered_writes().size() + 1; + + batch_buffer().Clear(); + WriteResult result_with_dropped = result; + result_with_dropped.dropped_packets = + dropped_packets > std::numeric_limits<uint16_t>::max() + ? std::numeric_limits<uint16_t>::max() + : static_cast<uint16_t>(dropped_packets); + return result_with_dropped; + } + + if (!buffered) { + QuicBatchWriterBuffer::PushResult push_result = + batch_buffer_->PushBufferedWrite(buffer, buf_len, self_address, + peer_address, options, release_time); + buffered = push_result.succeeded; + + // Since buffered_writes has been emptied, this write must have been + // buffered successfully. + QUIC_BUG_IF(!buffered) << "Failed to push to an empty batch buffer." + << " self_addr:" << self_address.ToString() + << ", peer_addr:" << peer_address.ToString() + << ", buf_len:" << buf_len; + } + + return result; +} + +QuicBatchWriterBase::FlushImplResult QuicBatchWriterBase::CheckedFlush() { + if (buffered_writes().empty()) { + return FlushImplResult{WriteResult(WRITE_STATUS_OK, 0), + /*num_packets_sent=*/0, /*bytes_written=*/0}; + } + + const FlushImplResult flush_result = FlushImpl(); + + // Either flush_result.write_result.status is not WRITE_STATUS_OK, or it is + // WRITE_STATUS_OK and batch_buffer is empty. + DCHECK(flush_result.write_result.status != WRITE_STATUS_OK || + buffered_writes().empty()); + + // Flush should never return WRITE_STATUS_BLOCKED_DATA_BUFFERED. + DCHECK(flush_result.write_result.status != + WRITE_STATUS_BLOCKED_DATA_BUFFERED); + + return flush_result; +} + +WriteResult QuicBatchWriterBase::Flush() { + size_t num_buffered_packets = buffered_writes().size(); + FlushImplResult flush_result = CheckedFlush(); + QUIC_DVLOG(1) << "Externally flushed " << flush_result.num_packets_sent + << " out of " << num_buffered_packets + << " packets. WriteResult=" << flush_result.write_result; + + if (IsWriteError(flush_result.write_result.status)) { + if (buffered_writes().size() > std::numeric_limits<uint16_t>::max()) { + flush_result.write_result.dropped_packets = + std::numeric_limits<uint16_t>::max(); + } else { + flush_result.write_result.dropped_packets = + static_cast<uint16_t>(buffered_writes().size()); + } + // Treat all errors as non-retryable fatal errors. Drop all buffered packets + // to avoid sending them and getting the same error again. + batch_buffer().Clear(); + } + + if (flush_result.write_result.status == WRITE_STATUS_BLOCKED) { + write_blocked_ = true; + } + return flush_result.write_result; +} + +} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_base.h b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_base.h new file mode 100644 index 00000000000..0213894f227 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_base.h @@ -0,0 +1,149 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_PLATFORM_IMPL_BATCH_WRITER_QUIC_BATCH_WRITER_BASE_H_ +#define QUICHE_QUIC_PLATFORM_IMPL_BATCH_WRITER_QUIC_BATCH_WRITER_BASE_H_ + +#include <cstdint> +#include "net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_buffer.h" +#include "net/third_party/quiche/src/quic/core/quic_packet_writer.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_ip_address.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h" + +namespace quic { + +// QuicBatchWriterBase implements logic common to all derived batch writers, +// including maintaining write blockage state and a skeleton implemention of +// WritePacket(). +// A derived batch writer must override the FlushImpl() function to send all +// buffered writes in a batch. It must also override the CanBatch() function +// to control whether/when a WritePacket() call should flush. +class QUIC_EXPORT_PRIVATE QuicBatchWriterBase : public QuicPacketWriter { + public: + explicit QuicBatchWriterBase( + std::unique_ptr<QuicBatchWriterBuffer> batch_buffer); + + // ATTENTION: If this write triggered a flush, and the flush failed, all + // buffered packets will be dropped to allow the next write to work. The + // number of dropped packets can be found in WriteResult.dropped_packets. + WriteResult WritePacket(const char* buffer, + size_t buf_len, + const QuicIpAddress& self_address, + const QuicSocketAddress& peer_address, + PerPacketOptions* options) override; + + bool IsWriteBlocked() const final { return write_blocked_; } + + void SetWritable() final { write_blocked_ = false; } + + QuicByteCount GetMaxPacketSize( + const QuicSocketAddress& peer_address) const final { + return kMaxOutgoingPacketSize; + } + + bool SupportsReleaseTime() const { return false; } + + bool IsBatchMode() const final { return true; } + + QuicPacketBuffer GetNextWriteLocation( + const QuicIpAddress& self_address, + const QuicSocketAddress& peer_address) final { + // No need to explicitly delete QuicBatchWriterBuffer. + return {batch_buffer_->GetNextWriteLocation(), nullptr}; + } + + WriteResult Flush() final; + + protected: + const QuicBatchWriterBuffer& batch_buffer() const { return *batch_buffer_; } + QuicBatchWriterBuffer& batch_buffer() { return *batch_buffer_; } + + const QuicCircularDeque<BufferedWrite>& buffered_writes() const { + return batch_buffer_->buffered_writes(); + } + + // Get the current time in nanos which is understood by the sending api for + // releasing packets in the future. + virtual uint64_t NowInNanosForReleaseTime() const { + DCHECK(false) << "Should not be called since release time is unsupported."; + return 0; + } + + // Given the release delay in |options| and the state of |batch_buffer_|, get + // the absolute release time. + uint64_t GetReleaseTime(const PerPacketOptions* options) const; + + struct QUIC_EXPORT_PRIVATE CanBatchResult { + CanBatchResult(bool can_batch, bool must_flush) + : can_batch(can_batch), must_flush(must_flush) {} + // Whether this write can be batched with existing buffered writes. + bool can_batch; + // If |can_batch|, whether the caller must flush after this packet is + // buffered. + // Always true if not |can_batch|. + bool must_flush; + }; + + // Given the existing buffered writes(in buffered_writes()), whether a new + // write(in the arguments) can be batched. + virtual CanBatchResult CanBatch(const char* buffer, + size_t buf_len, + const QuicIpAddress& self_address, + const QuicSocketAddress& peer_address, + const PerPacketOptions* options, + uint64_t release_time) const = 0; + + struct QUIC_EXPORT_PRIVATE FlushImplResult { + // The return value of the Flush() interface, which is: + // - WriteResult(WRITE_STATUS_OK, <bytes_flushed>) if all buffered writes + // were sent successfully. + // - WRITE_STATUS_BLOCKED or WRITE_STATUS_ERROR, if the batch write is + // blocked or returned an error while sending. If a portion of buffered + // writes were sent successfully, |FlushImplResult.num_packets_sent| and + // |FlushImplResult.bytes_written| contain the number of successfully sent + // packets and their total bytes. + WriteResult write_result; + int num_packets_sent; + // If write_result.status == WRITE_STATUS_OK, |bytes_written| will be equal + // to write_result.bytes_written. Otherwise |bytes_written| will be the + // number of bytes written before WRITE_BLOCK or WRITE_ERROR happened. + int bytes_written; + }; + + // Send all buffered writes(in buffered_writes()) in a batch. + // buffered_writes() is guaranteed to be non-empty when this function is + // called. + virtual FlushImplResult FlushImpl() = 0; + + private: + WriteResult InternalWritePacket(const char* buffer, + size_t buf_len, + const QuicIpAddress& self_address, + const QuicSocketAddress& peer_address, + PerPacketOptions* options); + + // Calls FlushImpl() and check its post condition. + FlushImplResult CheckedFlush(); + + bool write_blocked_; + std::unique_ptr<QuicBatchWriterBuffer> batch_buffer_; +}; + +// QuicUdpBatchWriter is a batch writer backed by a UDP socket. +class QUIC_EXPORT_PRIVATE QuicUdpBatchWriter : public QuicBatchWriterBase { + public: + QuicUdpBatchWriter(std::unique_ptr<QuicBatchWriterBuffer> batch_buffer, + int fd) + : QuicBatchWriterBase(std::move(batch_buffer)), fd_(fd) {} + + int fd() const { return fd_; } + + private: + const int fd_; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_PLATFORM_IMPL_BATCH_WRITER_QUIC_BATCH_WRITER_BASE_H_ diff --git a/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_buffer.cc b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_buffer.cc new file mode 100644 index 00000000000..62261393256 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_buffer.cc @@ -0,0 +1,154 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_buffer.h" + +#include <sstream> + +namespace quic { + +QuicBatchWriterBuffer::QuicBatchWriterBuffer() { + memset(buffer_, 0, sizeof(buffer_)); +} + +void QuicBatchWriterBuffer::Clear() { + buffered_writes_.clear(); +} + +std::string QuicBatchWriterBuffer::DebugString() const { + std::ostringstream os; + os << "{ buffer: " << static_cast<const void*>(buffer_) + << " buffer_end: " << static_cast<const void*>(buffer_end()) + << " buffered_writes_.size(): " << buffered_writes_.size() + << " next_write_loc: " << static_cast<const void*>(GetNextWriteLocation()) + << " SizeInUse: " << SizeInUse() << " }"; + return os.str(); +} + +bool QuicBatchWriterBuffer::Invariants() const { + // Buffers in buffered_writes_ should not overlap, and collectively they + // should cover a continuous prefix of buffer_. + const char* next_buffer = buffer_; + for (auto iter = buffered_writes_.begin(); iter != buffered_writes_.end(); + ++iter) { + if ((iter->buffer != next_buffer) || + (iter->buffer + iter->buf_len > buffer_end())) { + return false; + } + next_buffer += iter->buf_len; + } + + return (next_buffer - buffer_) == SizeInUse(); +} + +char* QuicBatchWriterBuffer::GetNextWriteLocation() const { + const char* next_loc = + buffered_writes_.empty() + ? buffer_ + : buffered_writes_.back().buffer + buffered_writes_.back().buf_len; + if (buffer_end() - next_loc < kMaxOutgoingPacketSize) { + return nullptr; + } + return const_cast<char*>(next_loc); +} + +QuicBatchWriterBuffer::PushResult QuicBatchWriterBuffer::PushBufferedWrite( + const char* buffer, + size_t buf_len, + const QuicIpAddress& self_address, + const QuicSocketAddress& peer_address, + const PerPacketOptions* options, + uint64_t release_time) { + DCHECK(Invariants()); + DCHECK_LE(buf_len, kMaxOutgoingPacketSize); + + PushResult result = {/*succeeded=*/false, /*buffer_copied=*/false}; + char* next_write_location = GetNextWriteLocation(); + if (next_write_location == nullptr) { + return result; + } + + if (buffer != next_write_location) { + if (IsExternalBuffer(buffer, buf_len)) { + memcpy(next_write_location, buffer, buf_len); + } else if (IsInternalBuffer(buffer, buf_len)) { + memmove(next_write_location, buffer, buf_len); + } else { + QUIC_BUG << "Buffer[" << static_cast<const void*>(buffer) << ", " + << static_cast<const void*>(buffer + buf_len) + << ") overlaps with internal buffer[" + << static_cast<const void*>(buffer_) << ", " + << static_cast<const void*>(buffer_end()) << ")"; + return result; + } + result.buffer_copied = true; + } else { + // In place push, do nothing. + } + buffered_writes_.emplace_back( + next_write_location, buf_len, self_address, peer_address, + options ? options->Clone() : std::unique_ptr<PerPacketOptions>(), + release_time); + + DCHECK(Invariants()); + + result.succeeded = true; + return result; +} + +void QuicBatchWriterBuffer::UndoLastPush() { + if (!buffered_writes_.empty()) { + buffered_writes_.pop_back(); + } +} + +QuicBatchWriterBuffer::PopResult QuicBatchWriterBuffer::PopBufferedWrite( + int32_t num_buffered_writes) { + DCHECK(Invariants()); + DCHECK_GE(num_buffered_writes, 0); + DCHECK_LE(num_buffered_writes, buffered_writes_.size()); + + PopResult result = {/*num_buffers_popped=*/0, + /*moved_remaining_buffers=*/false}; + + result.num_buffers_popped = std::max<int32_t>(num_buffered_writes, 0); + result.num_buffers_popped = + std::min<int32_t>(result.num_buffers_popped, buffered_writes_.size()); + buffered_writes_.pop_front_n(result.num_buffers_popped); + + if (!buffered_writes_.empty()) { + // If not all buffered writes are erased, the remaining ones will not cover + // a continuous prefix of buffer_. We'll fix it by moving the remaining + // buffers to the beginning of buffer_ and adjust the buffer pointers in all + // remaining buffered writes. + // This should happen very rarely, about once per write block. + result.moved_remaining_buffers = true; + const char* buffer_before_move = buffered_writes_.front().buffer; + size_t buffer_len_to_move = buffered_writes_.back().buffer + + buffered_writes_.back().buf_len - + buffer_before_move; + memmove(buffer_, buffer_before_move, buffer_len_to_move); + + size_t distance_to_move = buffer_before_move - buffer_; + for (BufferedWrite& buffered_write : buffered_writes_) { + buffered_write.buffer -= distance_to_move; + } + + DCHECK_EQ(buffer_, buffered_writes_.front().buffer); + } + DCHECK(Invariants()); + + return result; +} + +size_t QuicBatchWriterBuffer::SizeInUse() const { + if (buffered_writes_.empty()) { + return 0; + } + + return buffered_writes_.back().buffer + buffered_writes_.back().buf_len - + buffer_; +} + +} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_buffer.h b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_buffer.h new file mode 100644 index 00000000000..a441ec3c9d6 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_buffer.h @@ -0,0 +1,95 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_PLATFORM_IMPL_BATCH_WRITER_QUIC_BATCH_WRITER_BUFFER_H_ +#define QUICHE_QUIC_PLATFORM_IMPL_BATCH_WRITER_QUIC_BATCH_WRITER_BUFFER_H_ + +#include "net/third_party/quiche/src/quic/core/quic_circular_deque.h" +#include "net/third_party/quiche/src/quic/core/quic_linux_socket_utils.h" +#include "net/third_party/quiche/src/quic/core/quic_packet_writer.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_aligned.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_ip_address.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h" + +namespace quic { + +// QuicBatchWriterBuffer manages an internal buffer to hold data from multiple +// packets. Packet data are placed continuously within the internal buffer such +// that they can be sent by a QuicGsoBatchWriter. +// This class can also be used by a QuicBatchWriter which uses sendmmsg, +// although it is not optimized for that use case. +class QUIC_EXPORT_PRIVATE QuicBatchWriterBuffer { + public: + QuicBatchWriterBuffer(); + + // Clear all buffered writes, but leave the internal buffer intact. + void Clear(); + + char* GetNextWriteLocation() const; + + // Push a buffered write to the back. + struct QUIC_EXPORT_PRIVATE PushResult { + bool succeeded; + // True in one of the following cases: + // 1) The packet buffer is external and copied to the internal buffer, or + // 2) The packet buffer is from the internal buffer and moved within it. + // This only happens if PopBufferedWrite is called in the middle of a + // in-place push. + // Only valid if |succeeded| is true. + bool buffer_copied; + }; + + PushResult PushBufferedWrite(const char* buffer, + size_t buf_len, + const QuicIpAddress& self_address, + const QuicSocketAddress& peer_address, + const PerPacketOptions* options, + uint64_t release_time); + + void UndoLastPush(); + + // Pop |num_buffered_writes| buffered writes from the front. + // |num_buffered_writes| will be capped to [0, buffered_writes().size()] + // before it is used. + struct QUIC_EXPORT_PRIVATE PopResult { + int32_t num_buffers_popped; + // True if after |num_buffers_popped| buffers are popped from front, the + // remaining buffers are moved to the beginning of the internal buffer. + // This should normally be false. + bool moved_remaining_buffers; + }; + PopResult PopBufferedWrite(int32_t num_buffered_writes); + + const QuicCircularDeque<BufferedWrite>& buffered_writes() const { + return buffered_writes_; + } + + bool IsExternalBuffer(const char* buffer, size_t buf_len) const { + return (buffer + buf_len) <= buffer_ || buffer >= buffer_end(); + } + bool IsInternalBuffer(const char* buffer, size_t buf_len) const { + return buffer >= buffer_ && (buffer + buf_len) <= buffer_end(); + } + + // Number of bytes used in |buffer_|. + // PushBufferedWrite() increases this; PopBufferedWrite decreases this. + size_t SizeInUse() const; + + // Rounded up from |kMaxGsoPacketSize|, which is the maximum allowed + // size of a GSO packet. + static const size_t kBufferSize = 64 * 1024; + + std::string DebugString() const; + + protected: + // Whether the invariants of the buffer are upheld. For debug & test only. + bool Invariants() const; + const char* const buffer_end() const { return buffer_ + sizeof(buffer_); } + QUIC_CACHELINE_ALIGNED char buffer_[kBufferSize]; + QuicCircularDeque<BufferedWrite> buffered_writes_; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_PLATFORM_IMPL_BATCH_WRITER_QUIC_BATCH_WRITER_BUFFER_H_ diff --git a/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_buffer_test.cc b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_buffer_test.cc new file mode 100644 index 00000000000..4cdb747ab7c --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_buffer_test.cc @@ -0,0 +1,281 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_buffer.h" +#include <memory> +#include <string> + +#include "net/third_party/quiche/src/quic/core/quic_constants.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_ip_address.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" + +namespace quic { +namespace test { +namespace { + +class QUIC_EXPORT_PRIVATE TestQuicBatchWriterBuffer + : public QuicBatchWriterBuffer { + public: + using QuicBatchWriterBuffer::buffer_; + using QuicBatchWriterBuffer::buffered_writes_; +}; + +static const size_t kBatchBufferSize = QuicBatchWriterBuffer::kBufferSize; + +class QuicBatchWriterBufferTest : public QuicTest { + public: + QuicBatchWriterBufferTest() { SwitchToNewBuffer(); } + + void SwitchToNewBuffer() { + batch_buffer_ = std::make_unique<TestQuicBatchWriterBuffer>(); + } + + // Fill packet_buffer_ with kMaxOutgoingPacketSize bytes of |c|s. + char* FillPacketBuffer(char c) { + return FillPacketBuffer(c, packet_buffer_, kMaxOutgoingPacketSize); + } + + // Fill |packet_buffer| with kMaxOutgoingPacketSize bytes of |c|s. + char* FillPacketBuffer(char c, char* packet_buffer) { + return FillPacketBuffer(c, packet_buffer, kMaxOutgoingPacketSize); + } + + // Fill |packet_buffer| with |buf_len| bytes of |c|s. + char* FillPacketBuffer(char c, char* packet_buffer, size_t buf_len) { + memset(packet_buffer, c, buf_len); + return packet_buffer; + } + + void CheckBufferedWriteContent(int buffered_write_index, + char buffer_content, + size_t buf_len, + const QuicIpAddress& self_addr, + const QuicSocketAddress& peer_addr, + const PerPacketOptions* options) { + const BufferedWrite& buffered_write = + batch_buffer_->buffered_writes()[buffered_write_index]; + EXPECT_EQ(buf_len, buffered_write.buf_len); + for (size_t i = 0; i < buf_len; ++i) { + EXPECT_EQ(buffer_content, buffered_write.buffer[i]); + if (buffer_content != buffered_write.buffer[i]) { + break; + } + } + EXPECT_EQ(self_addr, buffered_write.self_address); + EXPECT_EQ(peer_addr, buffered_write.peer_address); + if (options == nullptr) { + EXPECT_EQ(nullptr, buffered_write.options); + } else { + EXPECT_EQ(options->release_time_delay, + buffered_write.options->release_time_delay); + } + } + + protected: + std::unique_ptr<TestQuicBatchWriterBuffer> batch_buffer_; + QuicIpAddress self_addr_; + QuicSocketAddress peer_addr_; + uint64_t release_time_ = 0; + char packet_buffer_[kMaxOutgoingPacketSize]; +}; + +class BufferSizeSequence { + public: + explicit BufferSizeSequence( + std::vector<std::pair<std::vector<size_t>, size_t>> stages) + : stages_(std::move(stages)), + total_buf_len_(0), + stage_index_(0), + sequence_index_(0) {} + + size_t Next() { + const std::vector<size_t>& seq = stages_[stage_index_].first; + size_t buf_len = seq[sequence_index_++ % seq.size()]; + total_buf_len_ += buf_len; + if (stages_[stage_index_].second <= total_buf_len_) { + stage_index_ = std::min(stage_index_ + 1, stages_.size() - 1); + } + return buf_len; + } + + private: + const std::vector<std::pair<std::vector<size_t>, size_t>> stages_; + size_t total_buf_len_; + size_t stage_index_; + size_t sequence_index_; +}; + +// Test in-place pushes. A in-place push is a push with a buffer address that is +// equal to the result of GetNextWriteLocation(). +TEST_F(QuicBatchWriterBufferTest, InPlacePushes) { + std::vector<BufferSizeSequence> buffer_size_sequences = { + // Push large writes until the buffer is near full, then switch to 1-byte + // writes. This covers the edge cases when detecting insufficient buffer. + BufferSizeSequence({{{1350}, kBatchBufferSize - 3000}, {{1}, 1e6}}), + // A sequence that looks real. + BufferSizeSequence({{{1, 39, 97, 150, 1350, 1350, 1350, 1350}, 1e6}}), + }; + + for (auto& buffer_size_sequence : buffer_size_sequences) { + SwitchToNewBuffer(); + int64_t num_push_failures = 0; + + while (batch_buffer_->SizeInUse() < kBatchBufferSize) { + size_t buf_len = buffer_size_sequence.Next(); + const bool has_enough_space = + (kBatchBufferSize - batch_buffer_->SizeInUse() >= + kMaxOutgoingPacketSize); + + char* buffer = batch_buffer_->GetNextWriteLocation(); + + if (has_enough_space) { + EXPECT_EQ(batch_buffer_->buffer_ + batch_buffer_->SizeInUse(), buffer); + } else { + EXPECT_EQ(nullptr, buffer); + } + + SCOPED_TRACE(testing::Message() + << "Before Push: buf_len=" << buf_len + << ", has_enough_space=" << has_enough_space + << ", batch_buffer=" << batch_buffer_->DebugString()); + + auto push_result = batch_buffer_->PushBufferedWrite( + buffer, buf_len, self_addr_, peer_addr_, nullptr, release_time_); + if (!push_result.succeeded) { + ++num_push_failures; + } + EXPECT_EQ(has_enough_space, push_result.succeeded); + EXPECT_FALSE(push_result.buffer_copied); + if (!has_enough_space) { + break; + } + } + // Expect one and only one failure from the final push operation. + EXPECT_EQ(1, num_push_failures); + } +} + +// Test some in-place pushes mixed with pushes with external buffers. +TEST_F(QuicBatchWriterBufferTest, MixedPushes) { + // First, a in-place push. + char* buffer = batch_buffer_->GetNextWriteLocation(); + auto push_result = batch_buffer_->PushBufferedWrite( + FillPacketBuffer('A', buffer), kDefaultMaxPacketSize, self_addr_, + peer_addr_, nullptr, release_time_); + EXPECT_TRUE(push_result.succeeded); + EXPECT_FALSE(push_result.buffer_copied); + CheckBufferedWriteContent(0, 'A', kDefaultMaxPacketSize, self_addr_, + peer_addr_, nullptr); + + // Then a push with external buffer. + push_result = batch_buffer_->PushBufferedWrite( + FillPacketBuffer('B'), kDefaultMaxPacketSize, self_addr_, peer_addr_, + nullptr, release_time_); + EXPECT_TRUE(push_result.succeeded); + EXPECT_TRUE(push_result.buffer_copied); + CheckBufferedWriteContent(1, 'B', kDefaultMaxPacketSize, self_addr_, + peer_addr_, nullptr); + + // Then another in-place push. + buffer = batch_buffer_->GetNextWriteLocation(); + push_result = batch_buffer_->PushBufferedWrite( + FillPacketBuffer('C', buffer), kDefaultMaxPacketSize, self_addr_, + peer_addr_, nullptr, release_time_); + EXPECT_TRUE(push_result.succeeded); + EXPECT_FALSE(push_result.buffer_copied); + CheckBufferedWriteContent(2, 'C', kDefaultMaxPacketSize, self_addr_, + peer_addr_, nullptr); + + // Then another push with external buffer. + push_result = batch_buffer_->PushBufferedWrite( + FillPacketBuffer('D'), kDefaultMaxPacketSize, self_addr_, peer_addr_, + nullptr, release_time_); + EXPECT_TRUE(push_result.succeeded); + EXPECT_TRUE(push_result.buffer_copied); + CheckBufferedWriteContent(3, 'D', kDefaultMaxPacketSize, self_addr_, + peer_addr_, nullptr); +} + +TEST_F(QuicBatchWriterBufferTest, PopAll) { + const int kNumBufferedWrites = 10; + for (int i = 0; i < kNumBufferedWrites; ++i) { + EXPECT_TRUE(batch_buffer_ + ->PushBufferedWrite(packet_buffer_, kDefaultMaxPacketSize, + self_addr_, peer_addr_, nullptr, + release_time_) + .succeeded); + } + EXPECT_EQ(kNumBufferedWrites, batch_buffer_->buffered_writes().size()); + + auto pop_result = batch_buffer_->PopBufferedWrite(kNumBufferedWrites); + EXPECT_EQ(0, batch_buffer_->buffered_writes().size()); + EXPECT_EQ(kNumBufferedWrites, pop_result.num_buffers_popped); + EXPECT_FALSE(pop_result.moved_remaining_buffers); +} + +TEST_F(QuicBatchWriterBufferTest, PopPartial) { + const int kNumBufferedWrites = 10; + for (int i = 0; i < kNumBufferedWrites; ++i) { + EXPECT_TRUE(batch_buffer_ + ->PushBufferedWrite(FillPacketBuffer('A' + i), + kDefaultMaxPacketSize - i, self_addr_, + peer_addr_, nullptr, release_time_) + .succeeded); + } + + for (int i = 0; + i < kNumBufferedWrites && !batch_buffer_->buffered_writes().empty(); + ++i) { + const size_t size_before_pop = batch_buffer_->buffered_writes().size(); + const size_t expect_size_after_pop = + size_before_pop < i ? 0 : size_before_pop - i; + batch_buffer_->PopBufferedWrite(i); + ASSERT_EQ(expect_size_after_pop, batch_buffer_->buffered_writes().size()); + const char first_write_content = + 'A' + kNumBufferedWrites - expect_size_after_pop; + const size_t first_write_len = + kDefaultMaxPacketSize - kNumBufferedWrites + expect_size_after_pop; + for (int j = 0; j < expect_size_after_pop; ++j) { + CheckBufferedWriteContent(j, first_write_content + j, first_write_len - j, + self_addr_, peer_addr_, nullptr); + } + } +} + +TEST_F(QuicBatchWriterBufferTest, InPlacePushWithPops) { + // First, a in-place push. + char* buffer = batch_buffer_->GetNextWriteLocation(); + const size_t first_packet_len = 2; + auto push_result = batch_buffer_->PushBufferedWrite( + FillPacketBuffer('A', buffer, first_packet_len), first_packet_len, + self_addr_, peer_addr_, nullptr, release_time_); + EXPECT_TRUE(push_result.succeeded); + EXPECT_FALSE(push_result.buffer_copied); + CheckBufferedWriteContent(0, 'A', first_packet_len, self_addr_, peer_addr_, + nullptr); + + // Simulate the case where the writer wants to do another in-place push, but + // can't do so because it can't be batched with the first buffer. + buffer = batch_buffer_->GetNextWriteLocation(); + const size_t second_packet_len = 1350; + + // Flush the first buffer. + auto pop_result = batch_buffer_->PopBufferedWrite(1); + EXPECT_EQ(1, pop_result.num_buffers_popped); + EXPECT_FALSE(pop_result.moved_remaining_buffers); + + // Now the second push. + push_result = batch_buffer_->PushBufferedWrite( + FillPacketBuffer('B', buffer, second_packet_len), second_packet_len, + self_addr_, peer_addr_, nullptr, release_time_); + EXPECT_TRUE(push_result.succeeded); + EXPECT_TRUE(push_result.buffer_copied); + CheckBufferedWriteContent(0, 'B', second_packet_len, self_addr_, peer_addr_, + nullptr); +} + +} // namespace +} // namespace test +} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_test.cc b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_test.cc new file mode 100644 index 00000000000..583b2485c4c --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_test.cc @@ -0,0 +1,78 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_test.h" +#include "net/third_party/quiche/src/quic/core/batch_writer/quic_gso_batch_writer.h" +#include "net/third_party/quiche/src/quic/core/batch_writer/quic_sendmmsg_batch_writer.h" + +namespace quic { +namespace test { +namespace { + +class QuicGsoBatchWriterIOTestDelegate + : public QuicUdpBatchWriterIOTestDelegate { + public: + bool ShouldSkip(const QuicUdpBatchWriterIOTestParams& params) override { + QuicUdpSocketApi socket_api; + int fd = + socket_api.Create(params.address_family, + /*receive_buffer_size=*/kDefaultSocketReceiveBuffer, + /*send_buffer_size=*/kDefaultSocketReceiveBuffer); + if (fd < 0) { + QUIC_LOG(ERROR) << "CreateSocket() failed: " << strerror(errno); + return false; // Let the test fail rather than skip it. + } + const bool gso_not_supported = + QuicLinuxSocketUtils::GetUDPSegmentSize(fd) < 0; + socket_api.Destroy(fd); + + if (gso_not_supported) { + QUIC_LOG(WARNING) << "Test skipped since GSO is not supported."; + return true; + } + + QUIC_LOG(WARNING) << "OK: GSO is supported."; + return false; + } + + void ResetWriter(int fd) override { + writer_ = std::make_unique<QuicGsoBatchWriter>( + std::make_unique<QuicBatchWriterBuffer>(), fd); + } + + QuicUdpBatchWriter* GetWriter() override { return writer_.get(); } + + private: + std::unique_ptr<QuicGsoBatchWriter> writer_; +}; + +INSTANTIATE_TEST_SUITE_P( + QuicGsoBatchWriterTest, + QuicUdpBatchWriterIOTest, + testing::ValuesIn( + MakeQuicBatchWriterTestParams<QuicGsoBatchWriterIOTestDelegate>())); + +class QuicSendmmsgBatchWriterIOTestDelegate + : public QuicUdpBatchWriterIOTestDelegate { + public: + void ResetWriter(int fd) override { + writer_ = std::make_unique<QuicSendmmsgBatchWriter>( + std::make_unique<QuicBatchWriterBuffer>(), fd); + } + + QuicUdpBatchWriter* GetWriter() override { return writer_.get(); } + + private: + std::unique_ptr<QuicSendmmsgBatchWriter> writer_; +}; + +INSTANTIATE_TEST_SUITE_P( + QuicSendmmsgBatchWriterTest, + QuicUdpBatchWriterIOTest, + testing::ValuesIn(MakeQuicBatchWriterTestParams< + QuicSendmmsgBatchWriterIOTestDelegate>())); + +} // namespace +} // namespace test +} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_test.h b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_test.h new file mode 100644 index 00000000000..b4f36b9f3ca --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_test.h @@ -0,0 +1,284 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_PLATFORM_IMPL_BATCH_WRITER_QUIC_BATCH_WRITER_TEST_H_ +#define QUICHE_QUIC_PLATFORM_IMPL_BATCH_WRITER_QUIC_BATCH_WRITER_TEST_H_ + +#include <sys/socket.h> +#include <sys/types.h> + +#include <iostream> +#include <utility> + +#include "net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_base.h" +#include "net/third_party/quiche/src/quic/core/quic_udp_socket.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" + +namespace quic { +namespace test { + +static bool IsAddressFamilySupported(int address_family) { + static auto check_function = [](int address_family) { + int fd = socket(address_family, SOCK_STREAM, 0); + if (fd < 0) { + QUIC_LOG(ERROR) << "address_family not supported: " << address_family + << ", error: " << strerror(errno); + EXPECT_EQ(EAFNOSUPPORT, errno); + return false; + } + close(fd); + return true; + }; + + if (address_family == AF_INET) { + static const bool ipv4_supported = check_function(AF_INET); + return ipv4_supported; + } + + static const bool ipv6_supported = check_function(AF_INET6); + return ipv6_supported; +} + +static bool CreateSocket(int family, QuicSocketAddress* address, int* fd) { + if (family == AF_INET) { + *address = QuicSocketAddress(QuicIpAddress::Loopback4(), 0); + } else { + DCHECK_EQ(family, AF_INET6); + *address = QuicSocketAddress(QuicIpAddress::Loopback6(), 0); + } + + QuicUdpSocketApi socket_api; + *fd = socket_api.Create(family, + /*receive_buffer_size=*/kDefaultSocketReceiveBuffer, + /*send_buffer_size=*/kDefaultSocketReceiveBuffer); + if (*fd < 0) { + QUIC_LOG(ERROR) << "CreateSocket() failed: " << strerror(errno); + return false; + } + socket_api.EnableDroppedPacketCount(*fd); + + if (!socket_api.Bind(*fd, *address)) { + QUIC_LOG(ERROR) << "Bind failed: " << strerror(errno); + return false; + } + + if (address->FromSocket(*fd) != 0) { + QUIC_LOG(ERROR) << "Unable to get self address. Error: " + << strerror(errno); + return false; + } + return true; +} + +struct QuicUdpBatchWriterIOTestParams; +class QUIC_EXPORT_PRIVATE QuicUdpBatchWriterIOTestDelegate { + public: + virtual ~QuicUdpBatchWriterIOTestDelegate() {} + + virtual bool ShouldSkip(const QuicUdpBatchWriterIOTestParams& params) { + return false; + } + + virtual void ResetWriter(int fd) = 0; + + virtual QuicUdpBatchWriter* GetWriter() = 0; +}; + +struct QUIC_EXPORT_PRIVATE QuicUdpBatchWriterIOTestParams { + // Use shared_ptr because gtest makes copies of test params. + std::shared_ptr<QuicUdpBatchWriterIOTestDelegate> delegate; + int address_family; + int data_size; + int packet_size; + + QUIC_EXPORT_PRIVATE friend std::ostream& operator<<( + std::ostream& os, + const QuicUdpBatchWriterIOTestParams& p) { + os << "{ address_family: " << p.address_family + << " data_size: " << p.data_size << " packet_size: " << p.packet_size + << " }"; + return os; + } +}; + +template <class QuicUdpBatchWriterIOTestDelegateT> +static std::vector<QuicUdpBatchWriterIOTestParams> +MakeQuicBatchWriterTestParams() { + static_assert(std::is_base_of<QuicUdpBatchWriterIOTestDelegate, + QuicUdpBatchWriterIOTestDelegateT>::value, + "<QuicUdpBatchWriterIOTestDelegateT> needs to derive from " + "QuicUdpBatchWriterIOTestDelegate"); + + std::vector<QuicUdpBatchWriterIOTestParams> params; + for (int address_family : {AF_INET, AF_INET6}) { + for (int data_size : {1, 150, 1500, 15000, 64000, 512 * 1024}) { + for (int packet_size : {1, 50, 1350, 1452}) { + if (packet_size <= data_size && (data_size / packet_size < 2000)) { + params.push_back( + {std::make_unique<QuicUdpBatchWriterIOTestDelegateT>(), + address_family, data_size, packet_size}); + } + } + } + } + return params; +} + +// QuicUdpBatchWriterIOTest is a value parameterized test fixture that can be +// used by tests of derived classes of QuicUdpBatchWriter, to verify basic +// packet IO capabilities. +class QUIC_EXPORT_PRIVATE QuicUdpBatchWriterIOTest + : public QuicTestWithParam<QuicUdpBatchWriterIOTestParams> { + protected: + QuicUdpBatchWriterIOTest() + : address_family_(GetParam().address_family), + data_size_(GetParam().data_size), + packet_size_(GetParam().packet_size), + self_socket_(-1), + peer_socket_(-1) { + QUIC_LOG(INFO) << "QuicUdpBatchWriterIOTestParams: " << GetParam(); + EXPECT_TRUE(address_family_ == AF_INET || address_family_ == AF_INET6); + EXPECT_LE(packet_size_, data_size_); + EXPECT_LE(packet_size_, sizeof(packet_buffer_)); + } + + ~QuicUdpBatchWriterIOTest() override { + if (self_socket_ > 0) { + close(self_socket_); + } + if (peer_socket_ > 0) { + close(peer_socket_); + } + } + + // Whether this test should be skipped. A test is passed if skipped. + // A test can be skipped when e.g. it exercises a kernel feature that is not + // available on the system. + bool ShouldSkip() { + if (!IsAddressFamilySupported(address_family_)) { + QUIC_LOG(WARNING) + << "Test skipped since address_family is not supported."; + return true; + } + + return GetParam().delegate->ShouldSkip(GetParam()); + } + + // Initialize a test. + // To fail the test in Initialize, use ASSERT_xx macros. + void Initialize() { + ASSERT_TRUE(CreateSocket(address_family_, &self_address_, &self_socket_)); + ASSERT_TRUE(CreateSocket(address_family_, &peer_address_, &peer_socket_)); + + QUIC_DLOG(INFO) << "Self address: " << self_address_.ToString() << ", fd " + << self_socket_; + QUIC_DLOG(INFO) << "Peer address: " << peer_address_.ToString() << ", fd " + << peer_socket_; + GetParam().delegate->ResetWriter(self_socket_); + } + + QuicUdpBatchWriter* GetWriter() { return GetParam().delegate->GetWriter(); } + + void ValidateWrite() { + char this_packet_content = '\0'; + int this_packet_size; + int num_writes = 0; + int bytes_flushed = 0; + WriteResult result; + + for (int bytes_sent = 0; bytes_sent < data_size_; + bytes_sent += this_packet_size, ++this_packet_content) { + this_packet_size = std::min(packet_size_, data_size_ - bytes_sent); + memset(&packet_buffer_[0], this_packet_content, this_packet_size); + + result = GetWriter()->WritePacket(&packet_buffer_[0], this_packet_size, + self_address_.host(), peer_address_, + nullptr); + + ASSERT_EQ(WRITE_STATUS_OK, result.status) << strerror(result.error_code); + bytes_flushed += result.bytes_written; + ++num_writes; + + QUIC_DVLOG(1) << "[write #" << num_writes + << "] this_packet_size: " << this_packet_size + << ", total_bytes_sent: " << bytes_sent + this_packet_size + << ", bytes_flushed: " << bytes_flushed + << ", pkt content:" << std::hex << int(this_packet_content); + } + + result = GetWriter()->Flush(); + ASSERT_EQ(WRITE_STATUS_OK, result.status) << strerror(result.error_code); + bytes_flushed += result.bytes_written; + ASSERT_EQ(data_size_, bytes_flushed); + + QUIC_LOG(INFO) << "Sent " << data_size_ << " bytes in " << num_writes + << " writes."; + } + + void ValidateRead() { + char this_packet_content = '\0'; + int this_packet_size; + int packets_received = 0; + for (int bytes_received = 0; bytes_received < data_size_; + bytes_received += this_packet_size, ++this_packet_content) { + this_packet_size = std::min(packet_size_, data_size_ - bytes_received); + SCOPED_TRACE(testing::Message() + << "Before ReadPacket: bytes_received=" << bytes_received + << ", this_packet_size=" << this_packet_size); + + QuicUdpSocketApi::ReadPacketResult result; + result.packet_buffer = {&packet_buffer_[0], sizeof(packet_buffer_)}; + result.control_buffer = {&control_buffer_[0], sizeof(control_buffer_)}; + QuicUdpSocketApi().ReadPacket( + peer_socket_, + quic::BitMask64(QuicUdpPacketInfoBit::V4_SELF_IP, + QuicUdpPacketInfoBit::V6_SELF_IP, + QuicUdpPacketInfoBit::PEER_ADDRESS), + &result); + ASSERT_TRUE(result.ok); + ASSERT_TRUE( + result.packet_info.HasValue(QuicUdpPacketInfoBit::PEER_ADDRESS)); + QuicSocketAddress read_peer_address = result.packet_info.peer_address(); + QuicIpAddress read_self_address = read_peer_address.host().IsIPv6() + ? result.packet_info.self_v6_ip() + : result.packet_info.self_v4_ip(); + + EXPECT_EQ(read_self_address, peer_address_.host()); + EXPECT_EQ(read_peer_address, self_address_); + for (int i = 0; i < this_packet_size; ++i) { + EXPECT_EQ(this_packet_content, packet_buffer_[i]); + } + packets_received += this_packet_size; + } + + QUIC_LOG(INFO) << "Received " << data_size_ << " bytes in " + << packets_received << " packets."; + } + + QuicSocketAddress self_address_; + QuicSocketAddress peer_address_; + char packet_buffer_[1500]; + char control_buffer_[kDefaultUdpPacketControlBufferSize]; + int address_family_; + const int data_size_; + const int packet_size_; + int self_socket_; + int peer_socket_; +}; + +TEST_P(QuicUdpBatchWriterIOTest, WriteAndRead) { + if (ShouldSkip()) { + return; + } + + Initialize(); + + ValidateWrite(); + ValidateRead(); +} + +} // namespace test +} // namespace quic + +#endif // QUICHE_QUIC_PLATFORM_IMPL_BATCH_WRITER_QUIC_BATCH_WRITER_TEST_H_ diff --git a/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_gso_batch_writer.cc b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_gso_batch_writer.cc new file mode 100644 index 00000000000..56c0e10171f --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_gso_batch_writer.cc @@ -0,0 +1,122 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/third_party/quiche/src/quic/core/batch_writer/quic_gso_batch_writer.h" + +#include <time.h> +#include <ctime> + +#include "net/third_party/quiche/src/quic/core/quic_linux_socket_utils.h" + +namespace quic { + +QuicGsoBatchWriter::QuicGsoBatchWriter( + std::unique_ptr<QuicBatchWriterBuffer> batch_buffer, + int fd) + : QuicGsoBatchWriter(std::move(batch_buffer), fd, CLOCK_MONOTONIC) {} + +QuicGsoBatchWriter::QuicGsoBatchWriter( + std::unique_ptr<QuicBatchWriterBuffer> batch_buffer, + int fd, + clockid_t clockid_for_release_time) + : QuicUdpBatchWriter(std::move(batch_buffer), fd), + clockid_for_release_time_(clockid_for_release_time), + supports_release_time_( + GetQuicRestartFlag(quic_support_release_time_for_gso) && + QuicLinuxSocketUtils::EnableReleaseTime(fd, + clockid_for_release_time)) { + if (supports_release_time_) { + QUIC_RESTART_FLAG_COUNT(quic_support_release_time_for_gso); + QUIC_LOG_FIRST_N(INFO, 5) << "Release time is enabled."; + } else { + QUIC_LOG_FIRST_N(INFO, 5) << "Release time is not enabled."; + } +} + +QuicGsoBatchWriter::QuicGsoBatchWriter( + std::unique_ptr<QuicBatchWriterBuffer> batch_buffer, + int fd, + clockid_t clockid_for_release_time, + ReleaseTimeForceEnabler enabler) + : QuicUdpBatchWriter(std::move(batch_buffer), fd), + clockid_for_release_time_(clockid_for_release_time), + supports_release_time_(true) { + QUIC_DLOG(INFO) << "Release time forcefully enabled."; +} + +QuicGsoBatchWriter::CanBatchResult QuicGsoBatchWriter::CanBatch( + const char* buffer, + size_t buf_len, + const QuicIpAddress& self_address, + const QuicSocketAddress& peer_address, + const PerPacketOptions* options, + uint64_t release_time) const { + // If there is nothing buffered already, this write will be included in this + // batch. + if (buffered_writes().empty()) { + return CanBatchResult(/*can_batch=*/true, /*must_flush=*/false); + } + + // The new write can be batched if all of the following are true: + // [0] The total number of the GSO segments(one write=one segment, including + // the new write) must not exceed |max_segments|. + // [1] It has the same source and destination addresses as already buffered + // writes. + // [2] It won't cause this batch to exceed kMaxGsoPacketSize. + // [3] Already buffered writes all have the same length. + // [4] Length of already buffered writes must >= length of the new write. + // [5] The new packet has the same release time as buffered writes. + const BufferedWrite& first = buffered_writes().front(); + const BufferedWrite& last = buffered_writes().back(); + size_t max_segments = MaxSegments(first.buf_len); + bool can_batch = + buffered_writes().size() < max_segments && // [0] + last.self_address == self_address && // [1] + last.peer_address == peer_address && // [1] + batch_buffer().SizeInUse() + buf_len <= kMaxGsoPacketSize && // [2] + first.buf_len == last.buf_len && // [3] + first.buf_len >= buf_len && // [4] + (!SupportsReleaseTime() || first.release_time == release_time); // [5] + + // A flush is required if any of the following is true: + // [a] The new write can't be batched. + // [b] Length of the new write is different from the length of already + // buffered writes. + // [c] The total number of the GSO segments, including the new write, reaches + // |max_segments|. + bool must_flush = (!can_batch) || // [a] + (last.buf_len != buf_len) || // [b] + (buffered_writes().size() + 1 == max_segments); // [c] + return CanBatchResult(can_batch, must_flush); +} + +uint64_t QuicGsoBatchWriter::NowInNanosForReleaseTime() const { + struct timespec ts; + + if (clock_gettime(clockid_for_release_time_, &ts) != 0) { + return 0; + } + + return ts.tv_sec * (1000ULL * 1000 * 1000) + ts.tv_nsec; +} + +// static +void QuicGsoBatchWriter::BuildCmsg(QuicMsgHdr* hdr, + const QuicIpAddress& self_address, + uint16_t gso_size, + uint64_t release_time) { + hdr->SetIpInNextCmsg(self_address); + if (gso_size > 0) { + *hdr->GetNextCmsgData<uint16_t>(SOL_UDP, UDP_SEGMENT) = gso_size; + } + if (release_time != 0) { + *hdr->GetNextCmsgData<uint64_t>(SOL_SOCKET, SO_TXTIME) = release_time; + } +} + +QuicGsoBatchWriter::FlushImplResult QuicGsoBatchWriter::FlushImpl() { + return InternalFlushImpl<kCmsgSpace>(BuildCmsg); +} + +} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_gso_batch_writer.h b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_gso_batch_writer.h new file mode 100644 index 00000000000..64c7e02fdd4 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_gso_batch_writer.h @@ -0,0 +1,114 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_PLATFORM_IMPL_BATCH_WRITER_QUIC_GSO_BATCH_WRITER_H_ +#define QUICHE_QUIC_PLATFORM_IMPL_BATCH_WRITER_QUIC_GSO_BATCH_WRITER_H_ + +#include "net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_base.h" + +namespace quic { + +// QuicGsoBatchWriter sends QUIC packets in batches, using UDP socket's generic +// segmentation offload(GSO) capability. +class QUIC_EXPORT_PRIVATE QuicGsoBatchWriter : public QuicUdpBatchWriter { + public: + QuicGsoBatchWriter(std::unique_ptr<QuicBatchWriterBuffer> batch_buffer, + int fd); + + // |clockid_for_release_time|: FQ qdisc requires CLOCK_MONOTONIC, EDF requires + // CLOCK_TAI. + QuicGsoBatchWriter(std::unique_ptr<QuicBatchWriterBuffer> batch_buffer, + int fd, + clockid_t clockid_for_release_time); + + bool SupportsReleaseTime() const final { return supports_release_time_; } + + CanBatchResult CanBatch(const char* buffer, + size_t buf_len, + const QuicIpAddress& self_address, + const QuicSocketAddress& peer_address, + const PerPacketOptions* options, + uint64_t release_time) const override; + + FlushImplResult FlushImpl() override; + + protected: + // Test only constructor to forcefully enable release time. + struct QUIC_EXPORT_PRIVATE ReleaseTimeForceEnabler {}; + QuicGsoBatchWriter(std::unique_ptr<QuicBatchWriterBuffer> batch_buffer, + int fd, + clockid_t clockid_for_release_time, + ReleaseTimeForceEnabler enabler); + + uint64_t NowInNanosForReleaseTime() const override; + + static size_t MaxSegments(size_t gso_size) { + // Max segments should be the min of UDP_MAX_SEGMENTS(64) and + // (((64KB - sizeof(ip hdr) - sizeof(udp hdr)) / MSS) + 1), in the typical + // case of IPv6 packets with 1500-byte MTU, the result is + // ((64KB - 40 - 8) / (1500 - 48)) + 1 = 46 + // However, due a kernel bug, the limit is much lower for tiny gso_sizes. + return gso_size <= 2 ? 16 : 45; + } + + static const int kCmsgSpace = + kCmsgSpaceForIp + kCmsgSpaceForSegmentSize + kCmsgSpaceForTxTime; + static void BuildCmsg(QuicMsgHdr* hdr, + const QuicIpAddress& self_address, + uint16_t gso_size, + uint64_t release_time); + + template <size_t CmsgSpace, typename CmsgBuilderT> + FlushImplResult InternalFlushImpl(CmsgBuilderT cmsg_builder) { + DCHECK(!IsWriteBlocked()); + DCHECK(!buffered_writes().empty()); + + FlushImplResult result = {WriteResult(WRITE_STATUS_OK, 0), + /*num_packets_sent=*/0, /*bytes_written=*/0}; + WriteResult& write_result = result.write_result; + + int total_bytes = batch_buffer().SizeInUse(); + const BufferedWrite& first = buffered_writes().front(); + char cbuf[CmsgSpace]; + QuicMsgHdr hdr(first.buffer, total_bytes, first.peer_address, cbuf, + sizeof(cbuf)); + + uint16_t gso_size = buffered_writes().size() > 1 ? first.buf_len : 0; + cmsg_builder(&hdr, first.self_address, gso_size, first.release_time); + + write_result = QuicLinuxSocketUtils::WritePacket(fd(), hdr); + QUIC_DVLOG(1) << "Write GSO packet result: " << write_result + << ", fd: " << fd() + << ", self_address: " << first.self_address.ToString() + << ", peer_address: " << first.peer_address.ToString() + << ", num_segments: " << buffered_writes().size() + << ", total_bytes: " << total_bytes + << ", gso_size: " << gso_size; + + // All segments in a GSO packet share the same fate - if the write failed, + // none of them are sent, and it's not needed to call PopBufferedWrite(). + if (write_result.status != WRITE_STATUS_OK) { + return result; + } + + result.num_packets_sent = buffered_writes().size(); + + write_result.bytes_written = total_bytes; + result.bytes_written = total_bytes; + + batch_buffer().PopBufferedWrite(buffered_writes().size()); + + QUIC_BUG_IF(!buffered_writes().empty()) + << "All packets should have been written on a successful return"; + return result; + } + + private: + const clockid_t clockid_for_release_time_; + const bool supports_release_time_; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_PLATFORM_IMPL_BATCH_WRITER_QUIC_GSO_BATCH_WRITER_H_ diff --git a/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_gso_batch_writer_test.cc b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_gso_batch_writer_test.cc new file mode 100644 index 00000000000..c7d695ab4f5 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_gso_batch_writer_test.cc @@ -0,0 +1,461 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/third_party/quiche/src/quic/core/batch_writer/quic_gso_batch_writer.h" + +#include <cstdint> +#include <limits> +#include <memory> +#include <utility> + +#include "net/third_party/quiche/src/quic/platform/api/quic_ip_address.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_mock_syscall_wrapper.h" + +using testing::_; +using testing::Invoke; +using testing::StrictMock; + +namespace quic { +namespace test { +namespace { + +size_t PacketLength(const msghdr* msg) { + size_t length = 0; + for (size_t i = 0; i < msg->msg_iovlen; ++i) { + length += msg->msg_iov[i].iov_len; + } + return length; +} + +uint64_t MillisToNanos(uint64_t milliseconds) { + return milliseconds * 1000000; +} + +class QUIC_EXPORT_PRIVATE TestQuicGsoBatchWriter : public QuicGsoBatchWriter { + public: + using QuicGsoBatchWriter::batch_buffer; + using QuicGsoBatchWriter::buffered_writes; + using QuicGsoBatchWriter::CanBatch; + using QuicGsoBatchWriter::CanBatchResult; + using QuicGsoBatchWriter::GetReleaseTime; + using QuicGsoBatchWriter::MaxSegments; + using QuicGsoBatchWriter::QuicGsoBatchWriter; + + static std::unique_ptr<TestQuicGsoBatchWriter> + NewInstanceWithReleaseTimeSupport() { + return std::unique_ptr<TestQuicGsoBatchWriter>(new TestQuicGsoBatchWriter( + std::make_unique<QuicBatchWriterBuffer>(), + /*fd=*/-1, CLOCK_MONOTONIC, ReleaseTimeForceEnabler())); + } + + uint64_t NowInNanosForReleaseTime() const override { + return MillisToNanos(forced_release_time_ms_); + } + + void ForceReleaseTimeMs(uint64_t forced_release_time_ms) { + forced_release_time_ms_ = forced_release_time_ms; + } + + private: + uint64_t forced_release_time_ms_ = 1; +}; + +struct QUIC_EXPORT_PRIVATE TestPerPacketOptions : public PerPacketOptions { + std::unique_ptr<quic::PerPacketOptions> Clone() const override { + return std::make_unique<TestPerPacketOptions>(*this); + } +}; + +// TestBufferedWrite is a copy-constructible BufferedWrite. +struct QUIC_EXPORT_PRIVATE TestBufferedWrite : public BufferedWrite { + using BufferedWrite::BufferedWrite; + TestBufferedWrite(const TestBufferedWrite& other) + : BufferedWrite(other.buffer, + other.buf_len, + other.self_address, + other.peer_address, + other.options ? other.options->Clone() + : std::unique_ptr<PerPacketOptions>(), + other.release_time) {} +}; + +// Pointed to by all instances of |BatchCriteriaTestData|. Content not used. +static char unused_packet_buffer[kMaxOutgoingPacketSize]; + +struct QUIC_EXPORT_PRIVATE BatchCriteriaTestData { + BatchCriteriaTestData(size_t buf_len, + const QuicIpAddress& self_address, + const QuicSocketAddress& peer_address, + uint64_t release_time, + bool can_batch, + bool must_flush) + : buffered_write(unused_packet_buffer, + buf_len, + self_address, + peer_address, + std::unique_ptr<PerPacketOptions>(), + release_time), + can_batch(can_batch), + must_flush(must_flush) {} + + TestBufferedWrite buffered_write; + // Expected value of CanBatchResult.can_batch when batching |buffered_write|. + bool can_batch; + // Expected value of CanBatchResult.must_flush when batching |buffered_write|. + bool must_flush; +}; + +std::vector<BatchCriteriaTestData> BatchCriteriaTestData_SizeDecrease() { + const QuicIpAddress self_addr; + const QuicSocketAddress peer_addr; + std::vector<BatchCriteriaTestData> test_data_table = { + // clang-format off + // buf_len self_addr peer_addr t_rel can_batch must_flush + {1350, self_addr, peer_addr, 0, true, false}, + {1350, self_addr, peer_addr, 0, true, false}, + {1350, self_addr, peer_addr, 0, true, false}, + {39, self_addr, peer_addr, 0, true, true}, + {39, self_addr, peer_addr, 0, false, true}, + {1350, self_addr, peer_addr, 0, false, true}, + // clang-format on + }; + return test_data_table; +} + +std::vector<BatchCriteriaTestData> BatchCriteriaTestData_SizeIncrease() { + const QuicIpAddress self_addr; + const QuicSocketAddress peer_addr; + std::vector<BatchCriteriaTestData> test_data_table = { + // clang-format off + // buf_len self_addr peer_addr t_rel can_batch must_flush + {1350, self_addr, peer_addr, 0, true, false}, + {1350, self_addr, peer_addr, 0, true, false}, + {1350, self_addr, peer_addr, 0, true, false}, + {1351, self_addr, peer_addr, 0, false, true}, + // clang-format on + }; + return test_data_table; +} + +std::vector<BatchCriteriaTestData> BatchCriteriaTestData_AddressChange() { + const QuicIpAddress self_addr1 = QuicIpAddress::Loopback4(); + const QuicIpAddress self_addr2 = QuicIpAddress::Loopback6(); + const QuicSocketAddress peer_addr1(self_addr1, 666); + const QuicSocketAddress peer_addr2(self_addr1, 777); + const QuicSocketAddress peer_addr3(self_addr2, 666); + const QuicSocketAddress peer_addr4(self_addr2, 777); + std::vector<BatchCriteriaTestData> test_data_table = { + // clang-format off + // buf_len self_addr peer_addr t_rel can_batch must_flush + {1350, self_addr1, peer_addr1, 0, true, false}, + {1350, self_addr1, peer_addr1, 0, true, false}, + {1350, self_addr1, peer_addr1, 0, true, false}, + {1350, self_addr2, peer_addr1, 0, false, true}, + {1350, self_addr1, peer_addr2, 0, false, true}, + {1350, self_addr1, peer_addr3, 0, false, true}, + {1350, self_addr1, peer_addr4, 0, false, true}, + {1350, self_addr1, peer_addr4, 0, false, true}, + // clang-format on + }; + return test_data_table; +} + +std::vector<BatchCriteriaTestData> BatchCriteriaTestData_ReleaseTime1() { + const QuicIpAddress self_addr; + const QuicSocketAddress peer_addr; + std::vector<BatchCriteriaTestData> test_data_table = { + // clang-format off + // buf_len self_addr peer_addr t_rel can_batch must_flush + {1350, self_addr, peer_addr, 5, true, false}, + {1350, self_addr, peer_addr, 5, true, false}, + {1350, self_addr, peer_addr, 5, true, false}, + {1350, self_addr, peer_addr, 9, false, true}, + // clang-format on + }; + return test_data_table; +} + +std::vector<BatchCriteriaTestData> BatchCriteriaTestData_ReleaseTime2() { + const QuicIpAddress self_addr; + const QuicSocketAddress peer_addr; + std::vector<BatchCriteriaTestData> test_data_table = { + // clang-format off + // buf_len self_addr peer_addr t_rel can_batch must_flush + {1350, self_addr, peer_addr, 0, true, false}, + {1350, self_addr, peer_addr, 0, true, false}, + {1350, self_addr, peer_addr, 0, true, false}, + {1350, self_addr, peer_addr, 9, false, true}, + // clang-format on + }; + return test_data_table; +} + +std::vector<BatchCriteriaTestData> BatchCriteriaTestData_MaxSegments( + size_t gso_size) { + const QuicIpAddress self_addr; + const QuicSocketAddress peer_addr; + std::vector<BatchCriteriaTestData> test_data_table; + size_t max_segments = TestQuicGsoBatchWriter::MaxSegments(gso_size); + for (int i = 0; i < max_segments; ++i) { + bool is_last_in_batch = (i + 1 == max_segments); + test_data_table.push_back({gso_size, self_addr, peer_addr, + /*release_time=*/0, true, is_last_in_batch}); + } + test_data_table.push_back( + {gso_size, self_addr, peer_addr, /*release_time=*/0, false, true}); + return test_data_table; +} + +class QuicGsoBatchWriterTest : public QuicTest { + protected: + WriteResult WritePacket(QuicGsoBatchWriter* writer, size_t packet_size) { + return writer->WritePacket(&packet_buffer_[0], packet_size, self_address_, + peer_address_, nullptr); + } + + WriteResult WritePacketWithOptions(QuicGsoBatchWriter* writer, + PerPacketOptions* options) { + return writer->WritePacket(&packet_buffer_[0], 1350, self_address_, + peer_address_, options); + } + + QuicIpAddress self_address_ = QuicIpAddress::Any4(); + QuicSocketAddress peer_address_{QuicIpAddress::Any4(), 443}; + char packet_buffer_[1500]; + StrictMock<MockQuicSyscallWrapper> mock_syscalls_; + ScopedGlobalSyscallWrapperOverride syscall_override_{&mock_syscalls_}; +}; + +TEST_F(QuicGsoBatchWriterTest, BatchCriteria) { + std::unique_ptr<TestQuicGsoBatchWriter> writer; + + std::vector<std::vector<BatchCriteriaTestData>> test_data_tables; + test_data_tables.emplace_back(BatchCriteriaTestData_SizeDecrease()); + test_data_tables.emplace_back(BatchCriteriaTestData_SizeIncrease()); + test_data_tables.emplace_back(BatchCriteriaTestData_AddressChange()); + test_data_tables.emplace_back(BatchCriteriaTestData_ReleaseTime1()); + test_data_tables.emplace_back(BatchCriteriaTestData_ReleaseTime2()); + test_data_tables.emplace_back(BatchCriteriaTestData_MaxSegments(1)); + test_data_tables.emplace_back(BatchCriteriaTestData_MaxSegments(2)); + test_data_tables.emplace_back(BatchCriteriaTestData_MaxSegments(1350)); + + for (size_t i = 0; i < test_data_tables.size(); ++i) { + writer = TestQuicGsoBatchWriter::NewInstanceWithReleaseTimeSupport(); + + const auto& test_data_table = test_data_tables[i]; + for (size_t j = 0; j < test_data_table.size(); ++j) { + const BatchCriteriaTestData& test_data = test_data_table[j]; + SCOPED_TRACE(testing::Message() << "i=" << i << ", j=" << j); + TestQuicGsoBatchWriter::CanBatchResult result = writer->CanBatch( + test_data.buffered_write.buffer, test_data.buffered_write.buf_len, + test_data.buffered_write.self_address, + test_data.buffered_write.peer_address, + /*options=*/nullptr, test_data.buffered_write.release_time); + + ASSERT_EQ(test_data.can_batch, result.can_batch); + ASSERT_EQ(test_data.must_flush, result.must_flush); + + if (result.can_batch) { + ASSERT_TRUE( + writer->batch_buffer() + .PushBufferedWrite(test_data.buffered_write.buffer, + test_data.buffered_write.buf_len, + test_data.buffered_write.self_address, + test_data.buffered_write.peer_address, + /*options=*/nullptr, + test_data.buffered_write.release_time) + .succeeded); + } + } + } +} + +TEST_F(QuicGsoBatchWriterTest, WriteSuccess) { + TestQuicGsoBatchWriter writer(std::make_unique<QuicBatchWriterBuffer>(), + /*fd=*/-1); + + ASSERT_EQ(WriteResult(WRITE_STATUS_OK, 0), WritePacket(&writer, 1000)); + + EXPECT_CALL(mock_syscalls_, Sendmsg(_, _, _)) + .WillOnce(Invoke([](int sockfd, const msghdr* msg, int flags) { + EXPECT_EQ(1100u, PacketLength(msg)); + return 1100; + })); + ASSERT_EQ(WriteResult(WRITE_STATUS_OK, 1100), WritePacket(&writer, 100)); + ASSERT_EQ(0u, writer.batch_buffer().SizeInUse()); + ASSERT_EQ(0u, writer.buffered_writes().size()); +} + +TEST_F(QuicGsoBatchWriterTest, WriteBlockDataNotBuffered) { + TestQuicGsoBatchWriter writer(std::make_unique<QuicBatchWriterBuffer>(), + /*fd=*/-1); + + ASSERT_EQ(WriteResult(WRITE_STATUS_OK, 0), WritePacket(&writer, 100)); + ASSERT_EQ(WriteResult(WRITE_STATUS_OK, 0), WritePacket(&writer, 100)); + + EXPECT_CALL(mock_syscalls_, Sendmsg(_, _, _)) + .WillOnce(Invoke([](int sockfd, const msghdr* msg, int flags) { + EXPECT_EQ(200u, PacketLength(msg)); + errno = EWOULDBLOCK; + return -1; + })); + ASSERT_EQ(WriteResult(WRITE_STATUS_BLOCKED, EWOULDBLOCK), + WritePacket(&writer, 150)); + ASSERT_EQ(200u, writer.batch_buffer().SizeInUse()); + ASSERT_EQ(2u, writer.buffered_writes().size()); +} + +TEST_F(QuicGsoBatchWriterTest, WriteBlockDataBuffered) { + TestQuicGsoBatchWriter writer(std::make_unique<QuicBatchWriterBuffer>(), + /*fd=*/-1); + + ASSERT_EQ(WriteResult(WRITE_STATUS_OK, 0), WritePacket(&writer, 100)); + ASSERT_EQ(WriteResult(WRITE_STATUS_OK, 0), WritePacket(&writer, 100)); + + EXPECT_CALL(mock_syscalls_, Sendmsg(_, _, _)) + .WillOnce(Invoke([](int sockfd, const msghdr* msg, int flags) { + EXPECT_EQ(250u, PacketLength(msg)); + errno = EWOULDBLOCK; + return -1; + })); + ASSERT_EQ(WriteResult(WRITE_STATUS_BLOCKED_DATA_BUFFERED, EWOULDBLOCK), + WritePacket(&writer, 50)); + ASSERT_EQ(250u, writer.batch_buffer().SizeInUse()); + ASSERT_EQ(3u, writer.buffered_writes().size()); +} + +TEST_F(QuicGsoBatchWriterTest, WriteErrorWithoutDataBuffered) { + TestQuicGsoBatchWriter writer(std::make_unique<QuicBatchWriterBuffer>(), + /*fd=*/-1); + + ASSERT_EQ(WriteResult(WRITE_STATUS_OK, 0), WritePacket(&writer, 100)); + ASSERT_EQ(WriteResult(WRITE_STATUS_OK, 0), WritePacket(&writer, 100)); + + EXPECT_CALL(mock_syscalls_, Sendmsg(_, _, _)) + .WillOnce(Invoke([](int sockfd, const msghdr* msg, int flags) { + EXPECT_EQ(200u, PacketLength(msg)); + errno = EPERM; + return -1; + })); + WriteResult error_result = WritePacket(&writer, 150); + ASSERT_EQ(WriteResult(WRITE_STATUS_ERROR, EPERM), error_result); + + ASSERT_EQ(3u, error_result.dropped_packets); + ASSERT_EQ(0u, writer.batch_buffer().SizeInUse()); + ASSERT_EQ(0u, writer.buffered_writes().size()); +} + +TEST_F(QuicGsoBatchWriterTest, WriteErrorAfterDataBuffered) { + TestQuicGsoBatchWriter writer(std::make_unique<QuicBatchWriterBuffer>(), + /*fd=*/-1); + + ASSERT_EQ(WriteResult(WRITE_STATUS_OK, 0), WritePacket(&writer, 100)); + ASSERT_EQ(WriteResult(WRITE_STATUS_OK, 0), WritePacket(&writer, 100)); + + EXPECT_CALL(mock_syscalls_, Sendmsg(_, _, _)) + .WillOnce(Invoke([](int sockfd, const msghdr* msg, int flags) { + EXPECT_EQ(250u, PacketLength(msg)); + errno = EPERM; + return -1; + })); + WriteResult error_result = WritePacket(&writer, 50); + ASSERT_EQ(WriteResult(WRITE_STATUS_ERROR, EPERM), error_result); + + ASSERT_EQ(3u, error_result.dropped_packets); + ASSERT_EQ(0u, writer.batch_buffer().SizeInUse()); + ASSERT_EQ(0u, writer.buffered_writes().size()); +} + +TEST_F(QuicGsoBatchWriterTest, FlushError) { + TestQuicGsoBatchWriter writer(std::make_unique<QuicBatchWriterBuffer>(), + /*fd=*/-1); + + ASSERT_EQ(WriteResult(WRITE_STATUS_OK, 0), WritePacket(&writer, 100)); + ASSERT_EQ(WriteResult(WRITE_STATUS_OK, 0), WritePacket(&writer, 100)); + + EXPECT_CALL(mock_syscalls_, Sendmsg(_, _, _)) + .WillOnce(Invoke([](int sockfd, const msghdr* msg, int flags) { + EXPECT_EQ(200u, PacketLength(msg)); + errno = EINVAL; + return -1; + })); + WriteResult error_result = writer.Flush(); + ASSERT_EQ(WriteResult(WRITE_STATUS_ERROR, EINVAL), error_result); + + ASSERT_EQ(2u, error_result.dropped_packets); + ASSERT_EQ(0u, writer.batch_buffer().SizeInUse()); + ASSERT_EQ(0u, writer.buffered_writes().size()); +} + +TEST_F(QuicGsoBatchWriterTest, ReleaseTimeNullOptions) { + auto writer = TestQuicGsoBatchWriter::NewInstanceWithReleaseTimeSupport(); + EXPECT_EQ(0, writer->GetReleaseTime(nullptr)); +} + +TEST_F(QuicGsoBatchWriterTest, ReleaseTime) { + const WriteResult write_buffered(WRITE_STATUS_OK, 0); + + auto writer = TestQuicGsoBatchWriter::NewInstanceWithReleaseTimeSupport(); + + TestPerPacketOptions options; + EXPECT_TRUE(options.release_time_delay.IsZero()); + EXPECT_FALSE(options.allow_burst); + EXPECT_EQ(MillisToNanos(1), writer->GetReleaseTime(&options)); + + // The 1st packet has no delay. + ASSERT_EQ(write_buffered, WritePacketWithOptions(writer.get(), &options)); + EXPECT_EQ(MillisToNanos(1), writer->buffered_writes().back().release_time); + + // The 2nd packet has some delay, but allows burst. + options.release_time_delay = QuicTime::Delta::FromMilliseconds(3); + options.allow_burst = true; + ASSERT_EQ(write_buffered, WritePacketWithOptions(writer.get(), &options)); + EXPECT_EQ(MillisToNanos(1), writer->buffered_writes().back().release_time); + + // The 3rd packet has more delay and does not allow burst. + // The first 2 packets are flushed due to different release time. + EXPECT_CALL(mock_syscalls_, Sendmsg(_, _, _)) + .WillOnce(Invoke([](int sockfd, const msghdr* msg, int flags) { + EXPECT_EQ(2700u, PacketLength(msg)); + errno = 0; + return 0; + })); + options.release_time_delay = QuicTime::Delta::FromMilliseconds(5); + options.allow_burst = false; + ASSERT_EQ(WriteResult(WRITE_STATUS_OK, 2700), + WritePacketWithOptions(writer.get(), &options)); + EXPECT_EQ(MillisToNanos(6), writer->buffered_writes().back().release_time); + + // The 4th packet has same delay, but allows burst. + options.allow_burst = true; + ASSERT_EQ(write_buffered, WritePacketWithOptions(writer.get(), &options)); + EXPECT_EQ(MillisToNanos(6), writer->buffered_writes().back().release_time); + + // The 5th packet has same delay, allows burst, but is shorter. + // Packets 3,4 and 5 are flushed. + EXPECT_CALL(mock_syscalls_, Sendmsg(_, _, _)) + .WillOnce(Invoke([](int sockfd, const msghdr* msg, int flags) { + EXPECT_EQ(3000u, PacketLength(msg)); + errno = 0; + return 0; + })); + options.allow_burst = true; + EXPECT_EQ(MillisToNanos(6), writer->GetReleaseTime(&options)); + ASSERT_EQ(WriteResult(WRITE_STATUS_OK, 3000), + writer->WritePacket(&packet_buffer_[0], 300, self_address_, + peer_address_, &options)); + EXPECT_TRUE(writer->buffered_writes().empty()); + + // Pretend 1ms has elapsed and the 6th packet has 1ms less delay. In other + // words, the release time should still be the same as packets 3-5. + writer->ForceReleaseTimeMs(2); + options.release_time_delay = QuicTime::Delta::FromMilliseconds(4); + ASSERT_EQ(write_buffered, WritePacketWithOptions(writer.get(), &options)); + EXPECT_EQ(MillisToNanos(6), writer->buffered_writes().back().release_time); +} + +} // namespace +} // namespace test +} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_sendmmsg_batch_writer.cc b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_sendmmsg_batch_writer.cc new file mode 100644 index 00000000000..efd21791c4d --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_sendmmsg_batch_writer.cc @@ -0,0 +1,83 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/third_party/quiche/src/quic/core/batch_writer/quic_sendmmsg_batch_writer.h" + +namespace quic { + +QuicSendmmsgBatchWriter::QuicSendmmsgBatchWriter( + std::unique_ptr<QuicBatchWriterBuffer> batch_buffer, + int fd) + : QuicUdpBatchWriter(std::move(batch_buffer), fd) {} + +QuicSendmmsgBatchWriter::CanBatchResult QuicSendmmsgBatchWriter::CanBatch( + const char* buffer, + size_t buf_len, + const QuicIpAddress& self_address, + const QuicSocketAddress& peer_address, + const PerPacketOptions* options, + uint64_t release_time) const { + return CanBatchResult(/*can_batch=*/true, /*must_flush=*/false); +} + +QuicSendmmsgBatchWriter::FlushImplResult QuicSendmmsgBatchWriter::FlushImpl() { + return InternalFlushImpl( + kCmsgSpaceForIp, + [](QuicMMsgHdr* mhdr, int i, const BufferedWrite& buffered_write) { + mhdr->SetIpInNextCmsg(i, buffered_write.self_address); + }); +} + +QuicSendmmsgBatchWriter::FlushImplResult +QuicSendmmsgBatchWriter::InternalFlushImpl(size_t cmsg_space, + const CmsgBuilder& cmsg_builder) { + DCHECK(!IsWriteBlocked()); + DCHECK(!buffered_writes().empty()); + + FlushImplResult result = {WriteResult(WRITE_STATUS_OK, 0), + /*num_packets_sent=*/0, /*bytes_written=*/0}; + WriteResult& write_result = result.write_result; + + auto first = buffered_writes().cbegin(); + const auto last = buffered_writes().cend(); + while (first != last) { + QuicMMsgHdr mhdr(first, last, cmsg_space, cmsg_builder); + + int num_packets_sent; + write_result = QuicLinuxSocketUtils::WriteMultiplePackets( + fd(), &mhdr, &num_packets_sent); + QUIC_DVLOG(1) << "WriteMultiplePackets sent " << num_packets_sent + << " out of " << mhdr.num_msgs() + << " packets. WriteResult=" << write_result; + + if (write_result.status != WRITE_STATUS_OK) { + DCHECK_EQ(0, num_packets_sent); + break; + } else if (num_packets_sent == 0) { + QUIC_BUG << "WriteMultiplePackets returned OK, but no packets were sent."; + write_result = WriteResult(WRITE_STATUS_ERROR, EIO); + break; + } + + first += num_packets_sent; + + result.num_packets_sent += num_packets_sent; + result.bytes_written += write_result.bytes_written; + } + + // Call PopBufferedWrite() even if write_result.status is not WRITE_STATUS_OK, + // to deal with partial writes. + batch_buffer().PopBufferedWrite(result.num_packets_sent); + + if (write_result.status != WRITE_STATUS_OK) { + return result; + } + + QUIC_BUG_IF(!buffered_writes().empty()) + << "All packets should have been written on a successful return"; + write_result.bytes_written = result.bytes_written; + return result; +} + +} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_sendmmsg_batch_writer.h b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_sendmmsg_batch_writer.h new file mode 100644 index 00000000000..26a728e676a --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_sendmmsg_batch_writer.h @@ -0,0 +1,35 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_PLATFORM_IMPL_QUIC_SENDMMSG_BATCH_WRITER_H_ +#define QUICHE_QUIC_PLATFORM_IMPL_QUIC_SENDMMSG_BATCH_WRITER_H_ + +#include "net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_base.h" +#include "net/third_party/quiche/src/quic/core/quic_linux_socket_utils.h" + +namespace quic { + +class QUIC_EXPORT_PRIVATE QuicSendmmsgBatchWriter : public QuicUdpBatchWriter { + public: + QuicSendmmsgBatchWriter(std::unique_ptr<QuicBatchWriterBuffer> batch_buffer, + int fd); + + CanBatchResult CanBatch(const char* buffer, + size_t buf_len, + const QuicIpAddress& self_address, + const QuicSocketAddress& peer_address, + const PerPacketOptions* options, + uint64_t release_time) const override; + + FlushImplResult FlushImpl() override; + + protected: + typedef QuicMMsgHdr::ControlBufferInitializer CmsgBuilder; + FlushImplResult InternalFlushImpl(size_t cmsg_space, + const CmsgBuilder& cmsg_builder); +}; + +} // namespace quic + +#endif // QUICHE_QUIC_PLATFORM_IMPL_QUIC_SENDMMSG_BATCH_WRITER_H_ diff --git a/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_sendmmsg_batch_writer_test.cc b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_sendmmsg_batch_writer_test.cc new file mode 100644 index 00000000000..4dcc33c91d3 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_sendmmsg_batch_writer_test.cc @@ -0,0 +1,15 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/third_party/quiche/src/quic/core/batch_writer/quic_sendmmsg_batch_writer.h" + +namespace quic { +namespace test { +namespace { + +// Add tests here. + +} // namespace +} // namespace test +} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/chlo_extractor.cc b/chromium/net/third_party/quiche/src/quic/core/chlo_extractor.cc index b4907d4a020..1605b264c63 100644 --- a/chromium/net/third_party/quiche/src/quic/core/chlo_extractor.cc +++ b/chromium/net/third_party/quiche/src/quic/core/chlo_extractor.cc @@ -11,6 +11,7 @@ #include "net/third_party/quiche/src/quic/core/crypto/crypto_utils.h" #include "net/third_party/quiche/src/quic/core/crypto/quic_decrypter.h" #include "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h" +#include "net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.h" #include "net/third_party/quiche/src/quic/core/quic_framer.h" #include "net/third_party/quiche/src/quic/core/quic_utils.h" #include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" @@ -77,6 +78,7 @@ class ChloFramerVisitor : public QuicFramerVisitorInterface, bool OnPaddingFrame(const QuicPaddingFrame& frame) override; bool OnMessageFrame(const QuicMessageFrame& frame) override; bool OnHandshakeDoneFrame(const QuicHandshakeDoneFrame& frame) override; + bool OnAckFrequencyFrame(const QuicAckFrequencyFrame& farme) override; void OnPacketComplete() override {} bool IsValidStatelessResetToken(QuicUint128 token) const override; void OnAuthenticatedIetfStatelessResetPacket( @@ -289,6 +291,11 @@ bool ChloFramerVisitor::OnHandshakeDoneFrame( return true; } +bool ChloFramerVisitor::OnAckFrequencyFrame( + const QuicAckFrequencyFrame& /*frame*/) { + return true; +} + bool ChloFramerVisitor::IsValidStatelessResetToken( QuicUint128 /*token*/) const { return false; diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler.cc index f885c94794c..6eacef38e2e 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler.cc +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler.cc @@ -87,7 +87,7 @@ BandwidthSampler::BandwidthSampler( total_bytes_sent_at_last_acked_packet_(0), last_acked_packet_sent_time_(QuicTime::Zero()), last_acked_packet_ack_time_(QuicTime::Zero()), - is_app_limited_(started_as_app_limited_), + is_app_limited_(true), connection_state_map_(), max_tracked_packets_(GetQuicFlag(FLAGS_quic_max_tracked_packet_count)), unacked_packet_map_(unacked_packet_map), @@ -105,7 +105,6 @@ BandwidthSampler::BandwidthSampler(const BandwidthSampler& other) last_acked_packet_sent_time_(other.last_acked_packet_sent_time_), last_acked_packet_ack_time_(other.last_acked_packet_ack_time_), last_sent_packet_(other.last_sent_packet_), - started_as_app_limited_(other.started_as_app_limited_), is_app_limited_(other.is_app_limited_), end_of_app_limited_phase_(other.end_of_app_limited_phase_), connection_state_map_(other.connection_state_map_), @@ -321,23 +320,13 @@ BandwidthSample BandwidthSampler::OnPacketAcknowledgedInner( recent_ack_points_.Update(ack_time, total_bytes_acked_); } - if (started_as_app_limited_) { - if (is_app_limited_) { - // Exit app-limited phase in two cases: - // (1) end_of_app_limited_phase_ is not initialized, i.e., so far all - // packets are sent while there are buffered packets or pending data. - // (2) The current acked packet is after the sent packet marked as the end - // of the app limit phase. - if (!end_of_app_limited_phase_.IsInitialized() || - packet_number > end_of_app_limited_phase_) { - QUIC_RELOADABLE_FLAG_COUNT(quic_bw_sampler_app_limited_starting_value); - is_app_limited_ = false; - } - } - } else { - // Exit app-limited phase once a packet that was sent while the connection - // is not app-limited is acknowledged. - if (is_app_limited_ && end_of_app_limited_phase_.IsInitialized() && + if (is_app_limited_) { + // Exit app-limited phase in two cases: + // (1) end_of_app_limited_phase_ is not initialized, i.e., so far all + // packets are sent while there are buffered packets or pending data. + // (2) The current acked packet is after the sent packet marked as the end + // of the app limit phase. + if (!end_of_app_limited_phase_.IsInitialized() || packet_number > end_of_app_limited_phase_) { is_app_limited_ = false; } diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler.h b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler.h index b3c07364705..f32eabf0694 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler.h +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler.h @@ -528,10 +528,6 @@ class QUIC_EXPORT_PRIVATE BandwidthSampler : public BandwidthSamplerInterface { // The most recently sent packet. QuicPacketNumber last_sent_packet_; - // Indicates whether the bandwidth sampler is started in app-limited phase. - const bool started_as_app_limited_ = - GetQuicReloadableFlag(quic_bw_sampler_app_limited_starting_value); - // Indicates whether the bandwidth sampler is currently in an app-limited // phase. bool is_app_limited_; @@ -565,8 +561,7 @@ class QUIC_EXPORT_PRIVATE BandwidthSampler : public BandwidthSamplerInterface { MaxAckHeightTracker max_ack_height_tracker_; QuicByteCount total_bytes_acked_after_last_ack_event_; - // True if --quic_avoid_overestimate_bandwidth_with_aggregation=true and - // connection option 'BSAO' is set. + // True if connection option 'BSAO' is set. bool overestimate_avoidance_; }; diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler_test.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler_test.cc index 5dda9986965..f689553bc5b 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler_test.cc @@ -34,8 +34,18 @@ const QuicByteCount kRegularPacketSize = 1280; static_assert((kRegularPacketSize & 31) == 0, "kRegularPacketSize has to be five times divisible by 2"); +struct TestParameters { + bool overestimate_avoidance; +}; + +// Used by ::testing::PrintToStringParamName(). +std::string PrintToString(const TestParameters& p) { + return p.overestimate_avoidance ? "enable_overestimate_avoidance" + : "no_enable_overestimate_avoidance"; +} + // A test fixture with utility methods for BandwidthSampler tests. -class BandwidthSamplerTest : public QuicTest { +class BandwidthSamplerTest : public QuicTestWithParam<TestParameters> { protected: BandwidthSamplerTest() : sampler_(nullptr, /*max_height_tracker_window_length=*/0), @@ -46,8 +56,7 @@ class BandwidthSamplerTest : public QuicTest { round_trip_count_(0) { // Ensure that the clock does not start at zero. clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1)); - if (GetQuicReloadableFlag( - quic_avoid_overestimate_bandwidth_with_aggregation)) { + if (GetParam().overestimate_avoidance) { sampler_.EnableOverestimateAvoidance(); } } @@ -170,8 +179,15 @@ class BandwidthSamplerTest : public QuicTest { } }; +INSTANTIATE_TEST_SUITE_P( + BandwidthSamplerTests, + BandwidthSamplerTest, + testing::Values(TestParameters{/*overestimate_avoidance=*/false}, + TestParameters{/*overestimate_avoidance=*/true}), + testing::PrintToStringParamName()); + // Test the sampler in a simple stop-and-wait sender setting. -TEST_F(BandwidthSamplerTest, SendAndWait) { +TEST_P(BandwidthSamplerTest, SendAndWait) { QuicTime::Delta time_between_packets = QuicTime::Delta::FromMilliseconds(10); QuicBandwidth expected_bandwidth = QuicBandwidth::FromBytesPerSecond(kRegularPacketSize * 100); @@ -200,7 +216,7 @@ TEST_F(BandwidthSamplerTest, SendAndWait) { EXPECT_EQ(0u, bytes_in_flight_); } -TEST_F(BandwidthSamplerTest, SendTimeState) { +TEST_P(BandwidthSamplerTest, SendTimeState) { QuicTime::Delta time_between_packets = QuicTime::Delta::FromMilliseconds(10); // Send packets 1-5. @@ -266,7 +282,7 @@ TEST_F(BandwidthSamplerTest, SendTimeState) { // Test the sampler during regular windowed sender scenario with fixed // CWND of 20. -TEST_F(BandwidthSamplerTest, SendPaced) { +TEST_P(BandwidthSamplerTest, SendPaced) { const QuicTime::Delta time_between_packets = QuicTime::Delta::FromMilliseconds(1); QuicBandwidth expected_bandwidth = @@ -288,7 +304,7 @@ TEST_F(BandwidthSamplerTest, SendPaced) { } // Test the sampler in a scenario where 50% of packets is consistently lost. -TEST_F(BandwidthSamplerTest, SendWithLosses) { +TEST_P(BandwidthSamplerTest, SendWithLosses) { const QuicTime::Delta time_between_packets = QuicTime::Delta::FromMilliseconds(1); QuicBandwidth expected_bandwidth = @@ -333,7 +349,7 @@ TEST_F(BandwidthSamplerTest, SendWithLosses) { // congestion controlled (specifically, non-retransmittable data is not // congestion controlled). Should be functionally consistent in behavior with // the SendWithLosses test. -TEST_F(BandwidthSamplerTest, NotCongestionControlled) { +TEST_P(BandwidthSamplerTest, NotCongestionControlled) { const QuicTime::Delta time_between_packets = QuicTime::Delta::FromMilliseconds(1); QuicBandwidth expected_bandwidth = @@ -382,7 +398,7 @@ TEST_F(BandwidthSamplerTest, NotCongestionControlled) { // Simulate a situation where ACKs arrive in burst and earlier than usual, thus // producing an ACK rate which is higher than the original send rate. -TEST_F(BandwidthSamplerTest, CompressedAck) { +TEST_P(BandwidthSamplerTest, CompressedAck) { const QuicTime::Delta time_between_packets = QuicTime::Delta::FromMilliseconds(1); QuicBandwidth expected_bandwidth = @@ -410,7 +426,7 @@ TEST_F(BandwidthSamplerTest, CompressedAck) { } // Tests receiving ACK packets in the reverse order. -TEST_F(BandwidthSamplerTest, ReorderedAck) { +TEST_P(BandwidthSamplerTest, ReorderedAck) { const QuicTime::Delta time_between_packets = QuicTime::Delta::FromMilliseconds(1); QuicBandwidth expected_bandwidth = @@ -441,7 +457,7 @@ TEST_F(BandwidthSamplerTest, ReorderedAck) { } // Test the app-limited logic. -TEST_F(BandwidthSamplerTest, AppLimited) { +TEST_P(BandwidthSamplerTest, AppLimited) { const QuicTime::Delta time_between_packets = QuicTime::Delta::FromMilliseconds(1); QuicBandwidth expected_bandwidth = @@ -508,7 +524,7 @@ TEST_F(BandwidthSamplerTest, AppLimited) { } // Test the samples taken at the first flight of packets sent. -TEST_F(BandwidthSamplerTest, FirstRoundTrip) { +TEST_P(BandwidthSamplerTest, FirstRoundTrip) { const QuicTime::Delta time_between_packets = QuicTime::Delta::FromMilliseconds(1); const QuicTime::Delta rtt = QuicTime::Delta::FromMilliseconds(800); @@ -543,7 +559,7 @@ TEST_F(BandwidthSamplerTest, FirstRoundTrip) { } // Test sampler's ability to remove obsolete packets. -TEST_F(BandwidthSamplerTest, RemoveObsoletePackets) { +TEST_P(BandwidthSamplerTest, RemoveObsoletePackets) { SendPacket(1); SendPacket(2); SendPacket(3); @@ -566,7 +582,7 @@ TEST_F(BandwidthSamplerTest, RemoveObsoletePackets) { EXPECT_EQ(0u, BandwidthSamplerPeer::GetNumberOfTrackedPackets(sampler_)); } -TEST_F(BandwidthSamplerTest, NeuterPacket) { +TEST_P(BandwidthSamplerTest, NeuterPacket) { SendPacket(1); EXPECT_EQ(0u, sampler_.total_bytes_neutered()); @@ -589,7 +605,7 @@ TEST_F(BandwidthSamplerTest, NeuterPacket) { EXPECT_EQ(0u, sample.extra_acked); } -TEST_F(BandwidthSamplerTest, CongestionEventSampleDefaultValues) { +TEST_P(BandwidthSamplerTest, CongestionEventSampleDefaultValues) { // Make sure a default constructed CongestionEventSample has the correct // initial values for BandwidthSampler::OnCongestionEvent() to work. BandwidthSampler::CongestionEventSample sample; @@ -602,7 +618,7 @@ TEST_F(BandwidthSamplerTest, CongestionEventSampleDefaultValues) { } // 1) Send 2 packets, 2) Ack both in 1 event, 3) Repeat. -TEST_F(BandwidthSamplerTest, TwoAckedPacketsPerEvent) { +TEST_P(BandwidthSamplerTest, TwoAckedPacketsPerEvent) { QuicTime::Delta time_between_packets = QuicTime::Delta::FromMilliseconds(10); QuicBandwidth sending_rate = QuicBandwidth::FromBytesAndTimeDelta( kRegularPacketSize, time_between_packets); @@ -631,7 +647,7 @@ TEST_F(BandwidthSamplerTest, TwoAckedPacketsPerEvent) { } } -TEST_F(BandwidthSamplerTest, LoseEveryOtherPacket) { +TEST_P(BandwidthSamplerTest, LoseEveryOtherPacket) { QuicTime::Delta time_between_packets = QuicTime::Delta::FromMilliseconds(10); QuicBandwidth sending_rate = QuicBandwidth::FromBytesAndTimeDelta( kRegularPacketSize, time_between_packets); @@ -663,7 +679,7 @@ TEST_F(BandwidthSamplerTest, LoseEveryOtherPacket) { } } -TEST_F(BandwidthSamplerTest, AckHeightRespectBandwidthEstimateUpperBound) { +TEST_P(BandwidthSamplerTest, AckHeightRespectBandwidthEstimateUpperBound) { QuicTime::Delta time_between_packets = QuicTime::Delta::FromMilliseconds(10); QuicBandwidth first_packet_sending_rate = QuicBandwidth::FromBytesAndTimeDelta(kRegularPacketSize, @@ -693,10 +709,7 @@ TEST_F(BandwidthSamplerTest, AckHeightRespectBandwidthEstimateUpperBound) { class MaxAckHeightTrackerTest : public QuicTest { protected: MaxAckHeightTrackerTest() : tracker_(/*initial_filter_window=*/10) { - if (GetQuicReloadableFlag( - quic_avoid_overestimate_bandwidth_with_aggregation)) { - tracker_.SetAckAggregationBandwidthThreshold(1.8); - } + tracker_.SetAckAggregationBandwidthThreshold(1.8); } // Run a full aggregation episode, which is one or more aggregated acks, diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.cc index 90df9a0c0da..cdd0cb54c16 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.cc +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.cc @@ -110,7 +110,7 @@ void Bbr2NetworkModel::OnCongestionEventStart( // b) all packets in |acked_packets| did not generate valid samples. (e.g. ack // of ack-only packets). In both cases, total_bytes_acked() will not change. if (prior_bytes_acked != total_bytes_acked()) { - QUIC_BUG_IF(sample.sample_max_bandwidth.IsZero()) + QUIC_LOG_IF(WARNING, sample.sample_max_bandwidth.IsZero()) << total_bytes_acked() - prior_bytes_acked << " bytes from " << acked_packets.size() << " packets have been acked, but sample_max_bandwidth is zero."; diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.h b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.h index e110a4c3297..ddef7722939 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.h +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.h @@ -184,6 +184,9 @@ struct QUIC_EXPORT_PRIVATE Bbr2Params { // Can be enabled by connection option 'B2LO'. bool ignore_inflight_lo = false; + + // Can be enabled by connection optoin 'B2HI'. + bool limit_inflight_hi_by_cwnd = false; }; class QUIC_EXPORT_PRIVATE RoundTripCounter { diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_probe_bw.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_probe_bw.cc index 6fb7eee8059..f6a09388604 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_probe_bw.cc +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_probe_bw.cc @@ -198,9 +198,9 @@ Bbr2ProbeBwMode::AdaptUpperBoundsResult Bbr2ProbeBwMode::MaybeAdaptUpperBounds( cycle_.is_sample_from_probing = false; if (!send_state.is_app_limited) { - QuicByteCount inflight_at_send = BytesInFlight(send_state); + const QuicByteCount inflight_at_send = BytesInFlight(send_state); - QuicByteCount inflight_target = + const QuicByteCount inflight_target = sender_->GetTargetBytesInflight() * (1.0 - Params().beta); if (inflight_at_send >= inflight_target) { // The new code does not change behavior. @@ -209,7 +209,20 @@ Bbr2ProbeBwMode::AdaptUpperBoundsResult Bbr2ProbeBwMode::MaybeAdaptUpperBounds( // The new code actually cuts inflight_hi slower than before. QUIC_CODE_COUNT(quic_bbr2_cut_inflight_hi_gradually_in_effect); } - model_->set_inflight_hi(std::max(inflight_at_send, inflight_target)); + if (Params().limit_inflight_hi_by_cwnd) { + const QuicByteCount cwnd_target = + sender_->GetCongestionWindow() * (1.0 - Params().beta); + if (inflight_at_send >= cwnd_target) { + // The new code does not change behavior. + QUIC_CODE_COUNT(quic_bbr2_cut_inflight_hi_cwnd_noop); + } else { + // The new code actually cuts inflight_hi slower than before. + QUIC_CODE_COUNT(quic_bbr2_cut_inflight_hi_cwnd_in_effect); + } + model_->set_inflight_hi(std::max(inflight_at_send, cwnd_target)); + } else { + model_->set_inflight_hi(std::max(inflight_at_send, inflight_target)); + } } QUIC_DVLOG(3) << sender_ << " " << cycle_.phase diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_sender.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_sender.cc index 8c0171bc9bf..d1b3159f271 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_sender.cc +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_sender.cc @@ -95,11 +95,7 @@ void Bbr2Sender::SetFromConfig(const QuicConfig& config, if (config.HasClientRequestedIndependentOption(kBBR9, perspective)) { params_.flexible_app_limited = true; } - if (GetQuicReloadableFlag( - quic_avoid_overestimate_bandwidth_with_aggregation) && - config.HasClientRequestedIndependentOption(kBSAO, perspective)) { - QUIC_RELOADABLE_FLAG_COUNT_N( - quic_avoid_overestimate_bandwidth_with_aggregation, 4, 4); + if (config.HasClientRequestedIndependentOption(kBSAO, perspective)) { model_.EnableOverestimateAvoidance(); } if (config.HasClientRequestedIndependentOption(kB2NA, perspective)) { @@ -127,14 +123,18 @@ void Bbr2Sender::SetFromConfig(const QuicConfig& config, QUIC_RELOADABLE_FLAG_COUNT(quic_bbr2_ignore_inflight_lo); params_.ignore_inflight_lo = true; } + if (GetQuicReloadableFlag(quic_bbr2_limit_inflight_hi) && + config.HasClientRequestedIndependentOption(kB2HI, perspective)) { + QUIC_RELOADABLE_FLAG_COUNT(quic_bbr2_limit_inflight_hi); + params_.limit_inflight_hi_by_cwnd = true; + } ApplyConnectionOptions(config.ClientRequestedIndependentOptions(perspective)); } void Bbr2Sender::ApplyConnectionOptions( const QuicTagVector& connection_options) { - if (GetQuicReloadableFlag(quic_bbr2_lower_startup_cwnd_gain) && - ContainsQuicTag(connection_options, kBBQ2)) { + if (ContainsQuicTag(connection_options, kBBQ2)) { // 2 is the lower, derived gain for CWND. params_.startup_cwnd_gain = 2; params_.drain_cwnd_gain = 2; diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_simulator_test.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_simulator_test.cc index f803ab68cdf..205d3563f90 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_simulator_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_simulator_test.cc @@ -427,10 +427,7 @@ TEST_F(Bbr2DefaultTopologyTest, SimpleTransferSmallBuffer) { } TEST_F(Bbr2DefaultTopologyTest, SimpleTransfer2RTTAggregationBytes) { - if (GetQuicReloadableFlag( - quic_avoid_overestimate_bandwidth_with_aggregation)) { - SetConnectionOption(kBSAO); - } + SetConnectionOption(kBSAO); DefaultTopologyParams params; CreateNetwork(params); // 2 RTTs of aggregation, with a max of 10kb. @@ -440,17 +437,9 @@ TEST_F(Bbr2DefaultTopologyTest, SimpleTransfer2RTTAggregationBytes) { DoSimpleTransfer(12 * 1024 * 1024, QuicTime::Delta::FromSeconds(35)); EXPECT_TRUE(Bbr2ModeIsOneOf({Bbr2Mode::PROBE_BW, Bbr2Mode::PROBE_RTT})); - if (GetQuicReloadableFlag( - quic_avoid_overestimate_bandwidth_with_aggregation)) { - EXPECT_APPROX_EQ(params.BottleneckBandwidth(), - sender_->ExportDebugState().bandwidth_hi, 0.01f); - } else { - EXPECT_LE(params.BottleneckBandwidth() * 0.99f, - sender_->ExportDebugState().bandwidth_hi); - // TODO(b/36022633): Bandwidth sampler overestimates with aggregation. - EXPECT_GE(params.BottleneckBandwidth() * 1.5f, - sender_->ExportDebugState().bandwidth_hi); - } + EXPECT_APPROX_EQ(params.BottleneckBandwidth(), + sender_->ExportDebugState().bandwidth_hi, 0.01f); + EXPECT_LE(sender_loss_rate_in_packets(), 0.05); // The margin here is high, because the aggregation greatly increases // smoothed rtt. @@ -459,10 +448,7 @@ TEST_F(Bbr2DefaultTopologyTest, SimpleTransfer2RTTAggregationBytes) { } TEST_F(Bbr2DefaultTopologyTest, SimpleTransferAckDecimation) { - if (GetQuicReloadableFlag( - quic_avoid_overestimate_bandwidth_with_aggregation)) { - SetConnectionOption(kBSAO); - } + SetConnectionOption(kBSAO); // Enable Ack Decimation on the receiver. QuicConnectionPeer::SetAckMode(receiver_endpoint_.connection(), AckMode::ACK_DECIMATION); @@ -473,17 +459,9 @@ TEST_F(Bbr2DefaultTopologyTest, SimpleTransferAckDecimation) { DoSimpleTransfer(12 * 1024 * 1024, QuicTime::Delta::FromSeconds(35)); EXPECT_TRUE(Bbr2ModeIsOneOf({Bbr2Mode::PROBE_BW, Bbr2Mode::PROBE_RTT})); - if (GetQuicReloadableFlag( - quic_avoid_overestimate_bandwidth_with_aggregation)) { - EXPECT_APPROX_EQ(params.BottleneckBandwidth(), - sender_->ExportDebugState().bandwidth_hi, 0.01f); - } else { - EXPECT_LE(params.BottleneckBandwidth() * 0.99f, - sender_->ExportDebugState().bandwidth_hi); - // TODO(b/36022633): Bandwidth sampler overestimates with aggregation. - EXPECT_GE(params.BottleneckBandwidth() * 1.1f, - sender_->ExportDebugState().bandwidth_hi); - } + EXPECT_APPROX_EQ(params.BottleneckBandwidth(), + sender_->ExportDebugState().bandwidth_hi, 0.01f); + EXPECT_LE(sender_loss_rate_in_packets(), 0.001); EXPECT_FALSE(sender_->ExportDebugState().last_sample_is_app_limited); // The margin here is high, because the aggregation greatly increases diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.cc index f150ec14787..6c6f3efd2ad 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.cc +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.cc @@ -32,10 +32,6 @@ const float kDefaultHighGain = 2.885f; const float kDerivedHighGain = 2.773f; // The newly derived CWND gain for STARTUP, 2. const float kDerivedHighCWNDGain = 2.0f; -// The gain used in STARTUP after loss has been detected. -// 1.5 is enough to allow for 25% exogenous loss and still observe a 25% growth -// in measured bandwidth. -const float kStartupAfterLossGain = 1.5f; // The cycle of gains used during the PROBE_BW stage. const float kPacingGain[] = {1.25, 0.75, 1, 1, 1, 1, 1, 1}; @@ -106,8 +102,6 @@ BbrSender::BbrSender(QuicTime now, congestion_window_gain_constant_( static_cast<float>(GetQuicFlag(FLAGS_quic_bbr_cwnd_gain))), num_startup_rtts_(kRoundTripsWithoutGrowthBeforeExitingStartup), - exit_startup_on_loss_( - GetQuicReloadableFlag(quic_bbr_default_exit_startup_on_loss)), cycle_current_offset_(0), last_cycle_start_(QuicTime::Zero()), is_at_full_bandwidth_(false), @@ -138,10 +132,7 @@ BbrSender::BbrSender(QuicTime now, stats_->slowstart_duration = QuicTimeAccumulator(); } EnterStartupMode(now); - if (exit_startup_on_loss_) { - QUIC_RELOADABLE_FLAG_COUNT(quic_bbr_default_exit_startup_on_loss); - set_high_cwnd_gain(kDerivedHighCWNDGain); - } + set_high_cwnd_gain(kDerivedHighCWNDGain); } BbrSender::~BbrSender() {} @@ -203,14 +194,8 @@ QuicByteCount BbrSender::GetCongestionWindow() const { return ProbeRttCongestionWindow(); } - if (exit_startup_on_loss_) { - if (InRecovery()) { - return std::min(congestion_window_, recovery_window_); - } - } else { - if (InRecovery() && !(rate_based_startup_ && mode_ == STARTUP)) { - return std::min(congestion_window_, recovery_window_); - } + if (InRecovery()) { + return std::min(congestion_window_, recovery_window_); } return congestion_window_; @@ -265,17 +250,9 @@ void BbrSender::SetFromConfig(const QuicConfig& config, if (config.HasClientRequestedIndependentOption(k2RTT, perspective)) { num_startup_rtts_ = 2; } - if (!exit_startup_on_loss_ && - config.HasClientRequestedIndependentOption(kBBRS, perspective)) { - slower_startup_ = true; - } if (config.HasClientRequestedIndependentOption(kBBR3, perspective)) { drain_to_target_ = true; } - if (!exit_startup_on_loss_ && - config.HasClientRequestedIndependentOption(kBBS1, perspective)) { - rate_based_startup_ = true; - } if (GetQuicReloadableFlag(quic_bbr_mitigate_overly_large_bandwidth_sample)) { if (config.HasClientRequestedIndependentOption(kBWM3, perspective)) { bytes_lost_multiplier_with_network_parameters_adjusted_ = 3; @@ -313,11 +290,7 @@ void BbrSender::SetFromConfig(const QuicConfig& config, max_congestion_window_with_network_parameters_adjusted_ = 100 * kDefaultTCPMSS; } - if (GetQuicReloadableFlag( - quic_avoid_overestimate_bandwidth_with_aggregation) && - config.HasClientRequestedIndependentOption(kBSAO, perspective)) { - QUIC_RELOADABLE_FLAG_COUNT_N( - quic_avoid_overestimate_bandwidth_with_aggregation, 3, 4); + if (config.HasClientRequestedIndependentOption(kBSAO, perspective)) { sampler_.EnableOverestimateAvoidance(); } @@ -325,14 +298,7 @@ void BbrSender::SetFromConfig(const QuicConfig& config, } void BbrSender::ApplyConnectionOptions( - const QuicTagVector& connection_options) { - if (ContainsQuicTag(connection_options, kLRTT)) { - exit_startup_on_loss_ = true; - } - if (ContainsQuicTag(connection_options, kBBQ2)) { - set_high_cwnd_gain(kDerivedHighCWNDGain); - } -} + const QuicTagVector& /*connection_options*/) {} void BbrSender::AdjustNetworkParameters(const NetworkParams& params) { const QuicBandwidth& bandwidth = params.bandwidth; @@ -352,12 +318,16 @@ void BbrSender::AdjustNetworkParameters(const NetworkParams& params) { // Ignore bad bandwidth samples. return; } + + auto cwnd_bootstrapping_rtt = params.quic_bbr_donot_inject_bandwidth + ? GetMinRtt() + : rtt_stats_->SmoothedOrInitialRtt(); const QuicByteCount new_cwnd = std::max( kMinInitialCongestionWindow * kDefaultTCPMSS, std::min(max_congestion_window_with_network_parameters_adjusted_, - bandwidth * (params.quic_bbr_donot_inject_bandwidth - ? GetMinRtt() - : rtt_stats_->SmoothedOrInitialRtt()))); + bandwidth * cwnd_bootstrapping_rtt)); + + stats_->cwnd_bootstrapping_rtt_us = cwnd_bootstrapping_rtt.ToMicroseconds(); if (!rtt_stats_->smoothed_rtt().IsZero()) { QUIC_CODE_COUNT(quic_smoothed_rtt_available); } else if (rtt_stats_->initial_rtt() != @@ -434,7 +404,7 @@ void BbrSender::OnCongestionEvent(bool /*rtt_updated*/, // ack-only packets). In both cases, sampler_.total_bytes_acked() will not // change. if (total_bytes_acked_before != sampler_.total_bytes_acked()) { - QUIC_BUG_IF(sample.sample_max_bandwidth.IsZero()) + QUIC_LOG_IF(WARNING, sample.sample_max_bandwidth.IsZero()) << sampler_.total_bytes_acked() - total_bytes_acked_before << " bytes from " << acked_packets.size() << " packets have been acked, but sample_max_bandwidth is zero."; @@ -502,13 +472,10 @@ QuicTime::Delta BbrSender::GetMinRtt() const { if (!min_rtt_.IsZero()) { return min_rtt_; } - if (GetQuicReloadableFlag(quic_bbr_use_available_min_rtt)) { - // min_rtt could be available if the handshake packet gets neutered then - // gets acknowledged. This could only happen for QUIC crypto where we do not - // drop keys. - return rtt_stats_->MinOrInitialRtt(); - } - return rtt_stats_->initial_rtt(); + // min_rtt could be available if the handshake packet gets neutered then + // gets acknowledged. This could only happen for QUIC crypto where we do not + // drop keys. + return rtt_stats_->MinOrInitialRtt(); } QuicByteCount BbrSender::GetTargetCongestionWindow(float gain) const { @@ -675,10 +642,6 @@ void BbrSender::OnExitStartup(QuicTime now) { bool BbrSender::ShouldExitStartupDueToLoss( const SendTimeState& last_packet_send_state) const { - if (!exit_startup_on_loss_) { - return false; - } - if (num_loss_events_in_round_ < GetQuicFlag(FLAGS_quic_bbr2_default_startup_full_loss_count) || !last_packet_send_state.is_valid) { @@ -749,7 +712,7 @@ void BbrSender::UpdateRecoveryState(QuicPacketNumber last_acked_packet, bool has_losses, bool is_round_start) { // Disable recovery in startup, if loss-based exit is enabled. - if (exit_startup_on_loss_ && !is_at_full_bandwidth_) { + if (!is_at_full_bandwidth_) { return; } @@ -843,16 +806,6 @@ void BbrSender::CalculatePacingRate(QuicByteCount bytes_lost) { } } - if (!exit_startup_on_loss_) { - // Slow the pacing rate in STARTUP once loss has ever been detected. - const bool has_ever_detected_loss = end_recovery_at_.IsInitialized(); - if (slower_startup_ && has_ever_detected_loss && - has_non_app_limited_sample_) { - pacing_rate_ = kStartupAfterLossGain * BandwidthEstimate(); - return; - } - } - // Do not decrease the pacing rate during startup. pacing_rate_ = std::max(pacing_rate_, target_rate); } @@ -898,10 +851,6 @@ void BbrSender::CalculateCongestionWindow(QuicByteCount bytes_acked, void BbrSender::CalculateRecoveryWindow(QuicByteCount bytes_acked, QuicByteCount bytes_lost) { - if (!exit_startup_on_loss_ && rate_based_startup_ && mode_ == STARTUP) { - return; - } - if (recovery_state_ == NOT_IN_RECOVERY) { return; } diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.h b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.h index c7285d76f24..446f0ddff8d 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.h +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.h @@ -326,13 +326,6 @@ class QUIC_EXPORT_PRIVATE BbrSender : public SendAlgorithmInterface { // The number of RTTs to stay in STARTUP mode. Defaults to 3. QuicRoundTripCount num_startup_rtts_; - // Latched value of --quic_bbr_default_exit_startup_on_loss. - // If true, exit startup if all of the following conditions are met: - // - 1RTT has passed with no bandwidth increase, - // - Some number of congestion events happened with loss, in the last round. - // - Some amount of inflight bytes (at the start of the last round) are lost. - bool exit_startup_on_loss_; - // Number of round-trips in PROBE_BW mode, used for determining the current // pacing gain cycle. int cycle_current_offset_; diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender_test.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender_test.cc index e50a7c04c61..88559185087 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender_test.cc @@ -115,6 +115,9 @@ class BbrSenderTest : public QuicTest { } void SetUp() override { + SetQuicReloadableFlag(quic_fix_bbr_cwnd_in_bandwidth_resumption, true); + SetQuicReloadableFlag(quic_bbr_fix_pacing_rate, true); + SetQuicReloadableFlag(quic_bbr_donot_inject_bandwidth, true); if (GetQuicFlag(FLAGS_quic_bbr_test_regression_mode) == "regress") { SendAlgorithmTestResult expected; ASSERT_TRUE(LoadSendAlgorithmTestResult(&expected)); @@ -389,10 +392,7 @@ TEST_F(BbrSenderTest, RemoveBytesLostInRecovery) { // Test a simple long data transfer with 2 rtts of aggregation. TEST_F(BbrSenderTest, SimpleTransfer2RTTAggregationBytes) { - if (GetQuicReloadableFlag( - quic_avoid_overestimate_bandwidth_with_aggregation)) { - SetConnectionOption(kBSAO); - } + SetConnectionOption(kBSAO); CreateDefaultSetup(); // 2 RTTs of aggregation, with a max of 10kb. EnableAggregation(10 * 1024, 2 * kTestRtt); @@ -401,20 +401,10 @@ TEST_F(BbrSenderTest, SimpleTransfer2RTTAggregationBytes) { DoSimpleTransfer(12 * 1024 * 1024, QuicTime::Delta::FromSeconds(35)); EXPECT_TRUE(sender_->ExportDebugState().mode == BbrSender::PROBE_BW || sender_->ExportDebugState().mode == BbrSender::PROBE_RTT); - if (GetQuicReloadableFlag( - quic_avoid_overestimate_bandwidth_with_aggregation)) { - EXPECT_APPROX_EQ(kTestLinkBandwidth, - sender_->ExportDebugState().max_bandwidth, 0.01f); - } else { - // It's possible to read a bandwidth as much as 50% too high with - // aggregation. - EXPECT_LE(kTestLinkBandwidth * 0.93f, - sender_->ExportDebugState().max_bandwidth); - // TODO(ianswett): Tighten this bound once we understand why BBR is - // overestimating bandwidth with aggregation. b/36022633 - EXPECT_GE(kTestLinkBandwidth * 1.5f, - sender_->ExportDebugState().max_bandwidth); - } + + EXPECT_APPROX_EQ(kTestLinkBandwidth, + sender_->ExportDebugState().max_bandwidth, 0.01f); + // The margin here is high, because the aggregation greatly increases // smoothed rtt. EXPECT_GE(kTestRtt * 4, rtt_stats_->smoothed_rtt()); @@ -423,10 +413,7 @@ TEST_F(BbrSenderTest, SimpleTransfer2RTTAggregationBytes) { // Test a simple long data transfer with 2 rtts of aggregation. TEST_F(BbrSenderTest, SimpleTransferAckDecimation) { - if (GetQuicReloadableFlag( - quic_avoid_overestimate_bandwidth_with_aggregation)) { - SetConnectionOption(kBSAO); - } + SetConnectionOption(kBSAO); // Decrease the CWND gain so extra CWND is required with stretch acks. SetQuicFlag(FLAGS_quic_bbr_cwnd_gain, 1.0); sender_ = new BbrSender( @@ -446,20 +433,9 @@ TEST_F(BbrSenderTest, SimpleTransferAckDecimation) { DoSimpleTransfer(12 * 1024 * 1024, QuicTime::Delta::FromSeconds(35)); EXPECT_EQ(BbrSender::PROBE_BW, sender_->ExportDebugState().mode); - if (GetQuicReloadableFlag( - quic_avoid_overestimate_bandwidth_with_aggregation)) { - EXPECT_APPROX_EQ(kTestLinkBandwidth, - sender_->ExportDebugState().max_bandwidth, 0.01f); - } else { - // It's possible to read a bandwidth as much as 50% too high with - // aggregation. - EXPECT_LE(kTestLinkBandwidth * 0.93f, - sender_->ExportDebugState().max_bandwidth); - // TODO(ianswett): Tighten this bound once we understand why BBR is - // overestimating bandwidth with aggregation. b/36022633 - EXPECT_GE(kTestLinkBandwidth * 1.5f, - sender_->ExportDebugState().max_bandwidth); - } + EXPECT_APPROX_EQ(kTestLinkBandwidth, + sender_->ExportDebugState().max_bandwidth, 0.01f); + // TODO(ianswett): Expect 0 packets are lost once BBR no longer measures // bandwidth higher than the link rate. EXPECT_FALSE(sender_->ExportDebugState().last_sample_is_app_limited); @@ -471,10 +447,7 @@ TEST_F(BbrSenderTest, SimpleTransferAckDecimation) { // Test a simple long data transfer with 2 rtts of aggregation. TEST_F(BbrSenderTest, SimpleTransfer2RTTAggregationBytes20RTTWindow) { - if (GetQuicReloadableFlag( - quic_avoid_overestimate_bandwidth_with_aggregation)) { - SetConnectionOption(kBSAO); - } + SetConnectionOption(kBSAO); // Disable Ack Decimation on the receiver, because it can increase srtt. QuicConnectionPeer::SetAckMode(receiver_.connection(), AckMode::TCP_ACKING); CreateDefaultSetup(); @@ -486,20 +459,10 @@ TEST_F(BbrSenderTest, SimpleTransfer2RTTAggregationBytes20RTTWindow) { DoSimpleTransfer(12 * 1024 * 1024, QuicTime::Delta::FromSeconds(35)); EXPECT_TRUE(sender_->ExportDebugState().mode == BbrSender::PROBE_BW || sender_->ExportDebugState().mode == BbrSender::PROBE_RTT); - if (GetQuicReloadableFlag( - quic_avoid_overestimate_bandwidth_with_aggregation)) { - EXPECT_APPROX_EQ(kTestLinkBandwidth, - sender_->ExportDebugState().max_bandwidth, 0.01f); - } else { - // It's possible to read a bandwidth as much as 50% too high with - // aggregation. - EXPECT_LE(kTestLinkBandwidth * 0.93f, - sender_->ExportDebugState().max_bandwidth); - // TODO(ianswett): Tighten this bound once we understand why BBR is - // overestimating bandwidth with aggregation. b/36022633 - EXPECT_GE(kTestLinkBandwidth * 1.5f, - sender_->ExportDebugState().max_bandwidth); - } + + EXPECT_APPROX_EQ(kTestLinkBandwidth, + sender_->ExportDebugState().max_bandwidth, 0.01f); + // TODO(ianswett): Expect 0 packets are lost once BBR no longer measures // bandwidth higher than the link rate. // The margin here is high, because the aggregation greatly increases @@ -510,10 +473,7 @@ TEST_F(BbrSenderTest, SimpleTransfer2RTTAggregationBytes20RTTWindow) { // Test a simple long data transfer with 2 rtts of aggregation. TEST_F(BbrSenderTest, SimpleTransfer2RTTAggregationBytes40RTTWindow) { - if (GetQuicReloadableFlag( - quic_avoid_overestimate_bandwidth_with_aggregation)) { - SetConnectionOption(kBSAO); - } + SetConnectionOption(kBSAO); // Disable Ack Decimation on the receiver, because it can increase srtt. QuicConnectionPeer::SetAckMode(receiver_.connection(), AckMode::TCP_ACKING); CreateDefaultSetup(); @@ -525,20 +485,10 @@ TEST_F(BbrSenderTest, SimpleTransfer2RTTAggregationBytes40RTTWindow) { DoSimpleTransfer(12 * 1024 * 1024, QuicTime::Delta::FromSeconds(35)); EXPECT_TRUE(sender_->ExportDebugState().mode == BbrSender::PROBE_BW || sender_->ExportDebugState().mode == BbrSender::PROBE_RTT); - if (GetQuicReloadableFlag( - quic_avoid_overestimate_bandwidth_with_aggregation)) { - EXPECT_APPROX_EQ(kTestLinkBandwidth, - sender_->ExportDebugState().max_bandwidth, 0.01f); - } else { - // It's possible to read a bandwidth as much as 50% too high with - // aggregation. - EXPECT_LE(kTestLinkBandwidth * 0.93f, - sender_->ExportDebugState().max_bandwidth); - // TODO(ianswett): Tighten this bound once we understand why BBR is - // overestimating bandwidth with aggregation. b/36022633 - EXPECT_GE(kTestLinkBandwidth * 1.5f, - sender_->ExportDebugState().max_bandwidth); - } + + EXPECT_APPROX_EQ(kTestLinkBandwidth, + sender_->ExportDebugState().max_bandwidth, 0.01f); + // TODO(ianswett): Expect 0 packets are lost once BBR no longer measures // bandwidth higher than the link rate. // The margin here is high, because the aggregation greatly increases @@ -667,17 +617,10 @@ TEST_F(BbrSenderTest, Drain) { EXPECT_APPROX_EQ(sender_->BandwidthEstimate() * (1 / 2.885f), sender_->PacingRate(0), 0.01f); - if (!GetQuicReloadableFlag(quic_bbr_default_exit_startup_on_loss)) { - // BBR uses CWND gain of 2.88 during STARTUP, hence it will fill the buffer - // with approximately 1.88 BDPs. Here, we use 1.5 to give some margin for - // error. - EXPECT_GE(queue->bytes_queued(), 1.5 * kTestBdp); - } else { - // BBR uses CWND gain of 2 during STARTUP, hence it will fill the buffer - // with approximately 1 BDP. Here, we use 0.8 to give some margin for - // error. - EXPECT_GE(queue->bytes_queued(), 0.8 * kTestBdp); - } + // BBR uses CWND gain of 2 during STARTUP, hence it will fill the buffer + // with approximately 1 BDP. Here, we use 0.8 to give some margin for + // error. + EXPECT_GE(queue->bytes_queued(), 0.8 * kTestBdp); // Observe increased RTT due to bufferbloat. const QuicTime::Delta queueing_delay = @@ -935,9 +878,6 @@ TEST_F(BbrSenderTest, SimpleTransfer2RTTStartup) { TEST_F(BbrSenderTest, SimpleTransferExitStartupOnLoss) { CreateDefaultSetup(); - if (!GetQuicReloadableFlag(quic_bbr_default_exit_startup_on_loss)) { - SetConnectionOption(kLRTT); - } EXPECT_EQ(3u, sender_->num_startup_rtts()); // Run until the full bandwidth is reached and check how many rounds it was. @@ -965,9 +905,6 @@ TEST_F(BbrSenderTest, SimpleTransferExitStartupOnLoss) { TEST_F(BbrSenderTest, SimpleTransferExitStartupOnLossSmallBuffer) { CreateSmallBufferSetup(); - if (!GetQuicReloadableFlag(quic_bbr_default_exit_startup_on_loss)) { - SetConnectionOption(kLRTT); - } EXPECT_EQ(3u, sender_->num_startup_rtts()); // Run until the full bandwidth is reached and check how many rounds it was. @@ -1021,9 +958,6 @@ TEST_F(BbrSenderTest, DerivedPacingGainStartup) { TEST_F(BbrSenderTest, DerivedCWNDGainStartup) { CreateSmallBufferSetup(); - if (!GetQuicReloadableFlag(quic_bbr_default_exit_startup_on_loss)) { - SetConnectionOption(kBBQ2); - } EXPECT_EQ(3u, sender_->num_startup_rtts()); // Verify that Sender is in slow start. EXPECT_TRUE(sender_->InSlowStart()); diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm.cc index f00045e7b8e..666e7ea7c5a 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm.cc +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm.cc @@ -12,6 +12,20 @@ namespace quic { +namespace { +float DetectionResponseTime(QuicTime::Delta rtt, + QuicTime send_time, + QuicTime detection_time) { + if (detection_time <= send_time || rtt.IsZero()) { + // Time skewed, assume a very fast detection where |detection_time| is + // |send_time| + |rtt|. + return 1.0; + } + float send_to_detection_us = (detection_time - send_time).ToMicroseconds(); + return send_to_detection_us / rtt.ToMicroseconds(); +} +} // namespace + GeneralLossAlgorithm::GeneralLossAlgorithm() : loss_detection_timeout_(QuicTime::Zero()), reordering_shift_(kDefaultLossDelayShift), @@ -56,7 +70,7 @@ LossDetectionInterface::DetectionStats GeneralLossAlgorithm::DetectLosses( QuicTime::Delta max_rtt = std::max(rtt_stats.previous_srtt(), rtt_stats.latest_rtt()); max_rtt = std::max(kAlarmGranularity, max_rtt); - QuicTime::Delta loss_delay = max_rtt + (max_rtt >> reordering_shift_); + const QuicTime::Delta loss_delay = max_rtt + (max_rtt >> reordering_shift_); QuicPacketNumber packet_number = unacked_packets.GetLeastUnacked(); auto it = unacked_packets.begin(); if (least_in_flight_.IsInitialized() && least_in_flight_ >= packet_number) { @@ -100,12 +114,18 @@ LossDetectionInterface::DetectionStats GeneralLossAlgorithm::DetectLosses( if (!skip_packet_threshold_detection && largest_newly_acked - packet_number >= reordering_threshold_) { packets_lost->push_back(LostPacket(packet_number, it->bytes_sent)); + detection_stats.total_loss_detection_response_time += + DetectionResponseTime(max_rtt, it->sent_time, time); continue; } // Time threshold loss detection. QuicTime when_lost = it->sent_time + loss_delay; if (time < when_lost) { + if (time >= + it->sent_time + max_rtt + (max_rtt >> (reordering_shift_ + 1))) { + ++detection_stats.sent_packets_num_borderline_time_reorderings; + } loss_detection_timeout_ = when_lost; if (!least_in_flight_.IsInitialized()) { // At this point, packet_number is in flight and not detected as lost. @@ -114,6 +134,8 @@ LossDetectionInterface::DetectionStats GeneralLossAlgorithm::DetectLosses( break; } packets_lost->push_back(LostPacket(packet_number, it->bytes_sent)); + detection_stats.total_loss_detection_response_time += + DetectionResponseTime(max_rtt, it->sent_time, time); } if (!least_in_flight_.IsInitialized()) { // There is no in flight packet. diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm.h b/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm.h index ee8ba64c2d7..950831e4594 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm.h +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm.h @@ -58,6 +58,11 @@ class QUIC_EXPORT_PRIVATE GeneralLossAlgorithm : public LossDetectionInterface { << "Unexpected call to GeneralLossAlgorithm::OnMinRttAvailable"; } + void OnUserAgentIdKnown() override { + DCHECK(false) + << "Unexpected call to GeneralLossAlgorithm::OnUserAgentIdKnown"; + } + void OnConnectionClosed() override { DCHECK(false) << "Unexpected call to GeneralLossAlgorithm::OnConnectionClosed"; diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm_test.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm_test.cc index 1a58ade2695..be33c25857c 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm_test.cc @@ -62,14 +62,17 @@ class GeneralLossAlgorithmTest : public QuicTest { const AckedPacketVector& packets_acked, const std::vector<uint64_t>& losses_expected) { return VerifyLosses(largest_newly_acked, packets_acked, losses_expected, + quiche::QuicheOptional<QuicPacketCount>(), quiche::QuicheOptional<QuicPacketCount>()); } - void VerifyLosses(uint64_t largest_newly_acked, - const AckedPacketVector& packets_acked, - const std::vector<uint64_t>& losses_expected, - quiche::QuicheOptional<QuicPacketCount> - max_sequence_reordering_expected) { + void VerifyLosses( + uint64_t largest_newly_acked, + const AckedPacketVector& packets_acked, + const std::vector<uint64_t>& losses_expected, + quiche::QuicheOptional<QuicPacketCount> max_sequence_reordering_expected, + quiche::QuicheOptional<QuicPacketCount> + num_borderline_time_reorderings_expected) { unacked_packets_.MaybeUpdateLargestAckedOfPacketNumberSpace( APPLICATION_DATA, QuicPacketNumber(largest_newly_acked)); LostPacketVector lost_packets; @@ -80,6 +83,10 @@ class GeneralLossAlgorithmTest : public QuicTest { EXPECT_EQ(stats.sent_packets_max_sequence_reordering, max_sequence_reordering_expected.value()); } + if (num_borderline_time_reorderings_expected.has_value()) { + EXPECT_EQ(stats.sent_packets_num_borderline_time_reorderings, + num_borderline_time_reorderings_expected.value()); + } ASSERT_EQ(losses_expected.size(), lost_packets.size()); for (size_t i = 0; i < losses_expected.size(); ++i) { EXPECT_EQ(lost_packets[i].packet_number, @@ -104,19 +111,19 @@ TEST_F(GeneralLossAlgorithmTest, NackRetransmit1Packet) { unacked_packets_.RemoveFromInFlight(QuicPacketNumber(2)); packets_acked.push_back(AckedPacket( QuicPacketNumber(2), kMaxOutgoingPacketSize, QuicTime::Zero())); - VerifyLosses(2, packets_acked, std::vector<uint64_t>{}, 1); + VerifyLosses(2, packets_acked, std::vector<uint64_t>{}, 1, 0); packets_acked.clear(); // No loss on two acks. unacked_packets_.RemoveFromInFlight(QuicPacketNumber(3)); packets_acked.push_back(AckedPacket( QuicPacketNumber(3), kMaxOutgoingPacketSize, QuicTime::Zero())); - VerifyLosses(3, packets_acked, std::vector<uint64_t>{}, 2); + VerifyLosses(3, packets_acked, std::vector<uint64_t>{}, 2, 0); packets_acked.clear(); // Loss on three acks. unacked_packets_.RemoveFromInFlight(QuicPacketNumber(4)); packets_acked.push_back(AckedPacket( QuicPacketNumber(4), kMaxOutgoingPacketSize, QuicTime::Zero())); - VerifyLosses(4, packets_acked, {1}, 3); + VerifyLosses(4, packets_acked, {1}, 3, 0); EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); } @@ -176,7 +183,12 @@ TEST_F(GeneralLossAlgorithmTest, EarlyRetransmit1Packet) { EXPECT_EQ(clock_.Now() + 1.25 * rtt_stats_.smoothed_rtt(), loss_algorithm_.GetLossTimeout()); - clock_.AdvanceTime(1.25 * rtt_stats_.latest_rtt()); + clock_.AdvanceTime(1.13 * rtt_stats_.latest_rtt()); + // If reordering_shift increases by one we should have detected a loss. + VerifyLosses(2, packets_acked, {}, /*max_sequence_reordering_expected=*/1, + /*num_borderline_time_reorderings_expected=*/1); + + clock_.AdvanceTime(0.13 * rtt_stats_.latest_rtt()); VerifyLosses(2, packets_acked, {1}); EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); } diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/loss_detection_interface.h b/chromium/net/third_party/quiche/src/quic/core/congestion_control/loss_detection_interface.h index 8d91976de45..6799de97ae5 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/loss_detection_interface.h +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/loss_detection_interface.h @@ -29,6 +29,10 @@ class QUIC_EXPORT_PRIVATE LossDetectionInterface { struct QUIC_NO_EXPORT DetectionStats { // Maximum sequence reordering observed in newly acked packets. QuicPacketCount sent_packets_max_sequence_reordering = 0; + QuicPacketCount sent_packets_num_borderline_time_reorderings = 0; + // Total detection response time for lost packets from this detection. + // See QuicConnectionStats for the definition of detection response time. + float total_loss_detection_response_time = 0.0; }; // Called when a new ack arrives or the loss alarm fires. @@ -56,6 +60,8 @@ class QUIC_EXPORT_PRIVATE LossDetectionInterface { virtual void OnMinRttAvailable() = 0; + virtual void OnUserAgentIdKnown() = 0; + virtual void OnConnectionClosed() = 0; }; diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm.cc index 0f294d6b94e..5debad62c6b 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm.cc +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm.cc @@ -54,6 +54,10 @@ LossDetectionInterface::DetectionStats UberLossAlgorithm::DetectLosses( overall_stats.sent_packets_max_sequence_reordering = std::max(overall_stats.sent_packets_max_sequence_reordering, stats.sent_packets_max_sequence_reordering); + overall_stats.sent_packets_num_borderline_time_reorderings += + stats.sent_packets_num_borderline_time_reorderings; + overall_stats.total_loss_detection_response_time += + stats.total_loss_detection_response_time; } return overall_stats; @@ -96,11 +100,27 @@ void UberLossAlgorithm::SetLossDetectionTuner( } void UberLossAlgorithm::MaybeStartTuning() { - if (tuner_started_ || !tuning_enabled_ || !min_rtt_available_) { + if (tuner_started_ || !tuning_enabled_ || !min_rtt_available_ || + !user_agent_known_) { return; } tuner_started_ = tuner_->Start(&tuned_parameters_); + if (!tuner_started_) { + return; + } + + if (tuned_parameters_.reordering_shift.has_value() && + tuned_parameters_.reordering_threshold.has_value()) { + QUIC_DLOG(INFO) << "Setting reordering shift to " + << *tuned_parameters_.reordering_shift + << ", and reordering threshold to " + << *tuned_parameters_.reordering_threshold; + SetReorderingShift(*tuned_parameters_.reordering_shift); + SetReorderingThreshold(*tuned_parameters_.reordering_threshold); + } else { + QUIC_BUG << "Tuner started but some parameters are missing"; + } } void UberLossAlgorithm::OnConfigNegotiated() {} @@ -110,6 +130,11 @@ void UberLossAlgorithm::OnMinRttAvailable() { MaybeStartTuning(); } +void UberLossAlgorithm::OnUserAgentIdKnown() { + user_agent_known_ = true; + MaybeStartTuning(); +} + void UberLossAlgorithm::OnConnectionClosed() { if (tuner_ != nullptr && tuner_started_) { tuner_->Finish(tuned_parameters_); @@ -151,6 +176,10 @@ QuicPacketCount UberLossAlgorithm::GetPacketReorderingThreshold() const { return general_loss_algorithms_[APPLICATION_DATA].reordering_threshold(); } +int UberLossAlgorithm::GetPacketReorderingShift() const { + return general_loss_algorithms_[APPLICATION_DATA].reordering_shift(); +} + void UberLossAlgorithm::DisablePacketThresholdForRuntPackets() { for (int8_t i = INITIAL_DATA; i < NUM_PACKET_NUMBER_SPACES; ++i) { general_loss_algorithms_[i].disable_packet_threshold_for_runt_packets(); diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm.h b/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm.h index 86b652572b7..0d1453c07b3 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm.h +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm.h @@ -7,6 +7,7 @@ #include "net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm.h" #include "net/third_party/quiche/src/quic/core/quic_types.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" #include "net/third_party/quiche/src/common/platform/api/quiche_optional.h" namespace quic { @@ -72,6 +73,7 @@ class QUIC_EXPORT_PRIVATE UberLossAlgorithm : public LossDetectionInterface { std::unique_ptr<LossDetectionTunerInterface> tuner); void OnConfigNegotiated() override; void OnMinRttAvailable() override; + void OnUserAgentIdKnown() override; void OnConnectionClosed() override; // Sets reordering_shift for all packet number spaces. @@ -93,12 +95,25 @@ class QUIC_EXPORT_PRIVATE UberLossAlgorithm : public LossDetectionInterface { // Always 3 when adaptive reordering is not enabled. QuicPacketCount GetPacketReorderingThreshold() const; + // Get the packet reordering shift from the APPLICATION_DATA PN space. + int GetPacketReorderingShift() const; + // Disable packet threshold loss detection for *runt* packets. void DisablePacketThresholdForRuntPackets(); // Called to reset loss detection of |space|. void ResetLossDetection(PacketNumberSpace space); + bool use_adaptive_reordering_threshold() const { + return general_loss_algorithms_[APPLICATION_DATA] + .use_adaptive_reordering_threshold(); + } + + bool use_adaptive_time_threshold() const { + return general_loss_algorithms_[APPLICATION_DATA] + .use_adaptive_time_threshold(); + } + private: friend class test::QuicSentPacketManagerPeer; @@ -112,6 +127,10 @@ class QUIC_EXPORT_PRIVATE UberLossAlgorithm : public LossDetectionInterface { LossDetectionParameters tuned_parameters_; bool tuner_started_ = false; bool min_rtt_available_ = false; + // If flag is false, set |user_agent_known_| to true, so loss detection tuner + // will start once SetFromConfig is called and min rtt is available. + bool user_agent_known_ = + !GetQuicReloadableFlag(quic_save_user_agent_in_quic_session); bool tuning_enabled_ = false; // Whether tuning is enabled by config. }; diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm_test.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm_test.cc index 6fd949f317a..e6635402d68 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm_test.cc @@ -4,9 +4,12 @@ #include "net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm.h" +#include <memory> #include <utility> #include "net/third_party/quiche/src/quic/core/congestion_control/rtt_stats.h" +#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" #include "net/third_party/quiche/src/quic/core/quic_utils.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" #include "net/third_party/quiche/src/quic/test_tools/mock_clock.h" @@ -204,6 +207,143 @@ TEST_F(UberLossAlgorithmTest, PacketInLimbo) { VerifyLosses(6, packets_acked_, std::vector<uint64_t>{2}); } +class TestLossTuner : public LossDetectionTunerInterface { + public: + TestLossTuner(bool forced_start_result, + LossDetectionParameters forced_parameters) + : forced_start_result_(forced_start_result), + forced_parameters_(std::move(forced_parameters)) {} + + ~TestLossTuner() override = default; + + bool Start(LossDetectionParameters* params) override { + start_called_ = true; + *params = forced_parameters_; + return forced_start_result_; + } + + void Finish(const LossDetectionParameters& /*params*/) override {} + + bool start_called() const { return start_called_; } + + private: + bool forced_start_result_; + LossDetectionParameters forced_parameters_; + bool start_called_ = false; +}; + +// Verify the parameters are changed if first call SetFromConfig(), then call +// OnMinRttAvailable(). +TEST_F(UberLossAlgorithmTest, LossDetectionTuning_SetFromConfigFirst) { + const int old_reordering_shift = loss_algorithm_.GetPacketReorderingShift(); + const QuicPacketCount old_reordering_threshold = + loss_algorithm_.GetPacketReorderingThreshold(); + + loss_algorithm_.OnUserAgentIdKnown(); + + // Not owned. + TestLossTuner* test_tuner = new TestLossTuner( + /*forced_start_result=*/true, + LossDetectionParameters{ + /*reordering_shift=*/old_reordering_shift + 1, + /*reordering_threshold=*/old_reordering_threshold * 2}); + loss_algorithm_.SetLossDetectionTuner( + std::unique_ptr<LossDetectionTunerInterface>(test_tuner)); + + QuicConfig config; + QuicTagVector connection_options; + connection_options.push_back(kELDT); + config.SetInitialReceivedConnectionOptions(connection_options); + loss_algorithm_.SetFromConfig(config, Perspective::IS_SERVER); + + // MinRtt was not available when SetFromConfig was called. + EXPECT_FALSE(test_tuner->start_called()); + EXPECT_EQ(old_reordering_shift, loss_algorithm_.GetPacketReorderingShift()); + EXPECT_EQ(old_reordering_threshold, + loss_algorithm_.GetPacketReorderingThreshold()); + + // Tuning should start when MinRtt becomes available. + loss_algorithm_.OnMinRttAvailable(); + EXPECT_TRUE(test_tuner->start_called()); + EXPECT_NE(old_reordering_shift, loss_algorithm_.GetPacketReorderingShift()); + EXPECT_NE(old_reordering_threshold, + loss_algorithm_.GetPacketReorderingThreshold()); +} + +// Verify the parameters are changed if first call OnMinRttAvailable(), then +// call SetFromConfig(). +TEST_F(UberLossAlgorithmTest, LossDetectionTuning_OnMinRttAvailableFirst) { + const int old_reordering_shift = loss_algorithm_.GetPacketReorderingShift(); + const QuicPacketCount old_reordering_threshold = + loss_algorithm_.GetPacketReorderingThreshold(); + + loss_algorithm_.OnUserAgentIdKnown(); + + // Not owned. + TestLossTuner* test_tuner = new TestLossTuner( + /*forced_start_result=*/true, + LossDetectionParameters{ + /*reordering_shift=*/old_reordering_shift + 1, + /*reordering_threshold=*/old_reordering_threshold * 2}); + loss_algorithm_.SetLossDetectionTuner( + std::unique_ptr<LossDetectionTunerInterface>(test_tuner)); + + loss_algorithm_.OnMinRttAvailable(); + EXPECT_FALSE(test_tuner->start_called()); + EXPECT_EQ(old_reordering_shift, loss_algorithm_.GetPacketReorderingShift()); + EXPECT_EQ(old_reordering_threshold, + loss_algorithm_.GetPacketReorderingThreshold()); + + QuicConfig config; + QuicTagVector connection_options; + connection_options.push_back(kELDT); + config.SetInitialReceivedConnectionOptions(connection_options); + // Should start tuning since MinRtt is available. + loss_algorithm_.SetFromConfig(config, Perspective::IS_SERVER); + + EXPECT_TRUE(test_tuner->start_called()); + EXPECT_NE(old_reordering_shift, loss_algorithm_.GetPacketReorderingShift()); + EXPECT_NE(old_reordering_threshold, + loss_algorithm_.GetPacketReorderingThreshold()); +} + +// Verify the parameters are not changed if Tuner.Start() returns false. +TEST_F(UberLossAlgorithmTest, LossDetectionTuning_StartFailed) { + const int old_reordering_shift = loss_algorithm_.GetPacketReorderingShift(); + const QuicPacketCount old_reordering_threshold = + loss_algorithm_.GetPacketReorderingThreshold(); + + loss_algorithm_.OnUserAgentIdKnown(); + + // Not owned. + TestLossTuner* test_tuner = new TestLossTuner( + /*forced_start_result=*/false, + LossDetectionParameters{ + /*reordering_shift=*/old_reordering_shift + 1, + /*reordering_threshold=*/old_reordering_threshold * 2}); + loss_algorithm_.SetLossDetectionTuner( + std::unique_ptr<LossDetectionTunerInterface>(test_tuner)); + + QuicConfig config; + QuicTagVector connection_options; + connection_options.push_back(kELDT); + config.SetInitialReceivedConnectionOptions(connection_options); + loss_algorithm_.SetFromConfig(config, Perspective::IS_SERVER); + + // MinRtt was not available when SetFromConfig was called. + EXPECT_FALSE(test_tuner->start_called()); + EXPECT_EQ(old_reordering_shift, loss_algorithm_.GetPacketReorderingShift()); + EXPECT_EQ(old_reordering_threshold, + loss_algorithm_.GetPacketReorderingThreshold()); + + // Parameters should not change since test_tuner->Start() returns false. + loss_algorithm_.OnMinRttAvailable(); + EXPECT_TRUE(test_tuner->start_called()); + EXPECT_EQ(old_reordering_shift, loss_algorithm_.GetPacketReorderingShift()); + EXPECT_EQ(old_reordering_threshold, + loss_algorithm_.GetPacketReorderingThreshold()); +} + } // namespace } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view.cc index 0f17d121ca0..af6b54c5863 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view.cc @@ -4,6 +4,7 @@ #include "net/third_party/quiche/src/quic/core/crypto/certificate_view.h" +#include <algorithm> #include <cstdint> #include <memory> #include <string> @@ -17,6 +18,8 @@ #include "third_party/boringssl/src/include/openssl/rsa.h" #include "third_party/boringssl/src/include/openssl/ssl.h" #include "net/third_party/quiche/src/quic/core/crypto/boring_utils.h" +#include "net/third_party/quiche/src/quic/core/quic_time.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" #include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" #include "net/third_party/quiche/src/quic/platform/api/quic_ip_address.h" #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" @@ -24,10 +27,17 @@ #include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h" #include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" #include "net/third_party/quiche/src/common/platform/api/quiche_text_utils.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_time_utils.h" +#include "net/third_party/quiche/src/common/quiche_data_reader.h" + +namespace { + +using ::quiche::QuicheOptional; +using ::quiche::QuicheStringPiece; +using ::quiche::QuicheTextUtils; // The literals below were encoded using `ascii2der | xxd -i`. The comments // above the literals are the contents in the der2ascii syntax. -namespace { // X.509 version 3 (version numbering starts with zero). // INTEGER { 2 } @@ -94,22 +104,54 @@ PublicKeyType PublicKeyTypeFromSignatureAlgorithm( namespace quic { +QuicheOptional<quic::QuicWallTime> ParseDerTime(unsigned tag, + QuicheStringPiece payload) { + if (tag != CBS_ASN1_GENERALIZEDTIME && tag != CBS_ASN1_UTCTIME) { + QUIC_BUG << "Invalid tag supplied for a DER timestamp"; + return QUICHE_NULLOPT; + } + + const size_t year_length = tag == CBS_ASN1_GENERALIZEDTIME ? 4 : 2; + uint64_t year, month, day, hour, minute, second; + quiche::QuicheDataReader reader(payload); + if (!reader.ReadDecimal64(year_length, &year) || + !reader.ReadDecimal64(2, &month) || !reader.ReadDecimal64(2, &day) || + !reader.ReadDecimal64(2, &hour) || !reader.ReadDecimal64(2, &minute) || + !reader.ReadDecimal64(2, &second) || + reader.ReadRemainingPayload() != "Z") { + QUIC_DLOG(WARNING) << "Failed to parse the DER timestamp"; + return QUICHE_NULLOPT; + } + + if (tag == CBS_ASN1_UTCTIME) { + DCHECK_LE(year, 100u); + year += (year >= 50) ? 1900 : 2000; + } + + const QuicheOptional<int64_t> unix_time = + quiche::QuicheUtcDateTimeToUnixSeconds(year, month, day, hour, minute, + second); + if (!unix_time.has_value() || *unix_time < 0) { + return QUICHE_NULLOPT; + } + return QuicWallTime::FromUNIXSeconds(*unix_time); +} + PemReadResult ReadNextPemMessage(std::istream* input) { - constexpr quiche::QuicheStringPiece kPemBegin = "-----BEGIN "; - constexpr quiche::QuicheStringPiece kPemEnd = "-----END "; - constexpr quiche::QuicheStringPiece kPemDashes = "-----"; + constexpr QuicheStringPiece kPemBegin = "-----BEGIN "; + constexpr QuicheStringPiece kPemEnd = "-----END "; + constexpr QuicheStringPiece kPemDashes = "-----"; std::string line_buffer, encoded_message_contents, expected_end; bool pending_message = false; PemReadResult result; while (std::getline(*input, line_buffer)) { - quiche::QuicheStringPiece line(line_buffer); - quiche::QuicheTextUtils::RemoveLeadingAndTrailingWhitespace(&line); + QuicheStringPiece line(line_buffer); + QuicheTextUtils::RemoveLeadingAndTrailingWhitespace(&line); // Handle BEGIN lines. - if (!pending_message && - quiche::QuicheTextUtils::StartsWith(line, kPemBegin) && - quiche::QuicheTextUtils::EndsWith(line, kPemDashes)) { + if (!pending_message && QuicheTextUtils::StartsWith(line, kPemBegin) && + QuicheTextUtils::EndsWith(line, kPemDashes)) { result.type = std::string( line.substr(kPemBegin.size(), line.size() - kPemDashes.size() - kPemBegin.size())); @@ -120,8 +162,8 @@ PemReadResult ReadNextPemMessage(std::istream* input) { // Handle END lines. if (pending_message && line == expected_end) { - quiche::QuicheOptional<std::string> data = - quiche::QuicheTextUtils::Base64Decode(encoded_message_contents); + QuicheOptional<std::string> data = + QuicheTextUtils::Base64Decode(encoded_message_contents); if (data.has_value()) { result.status = PemReadResult::kOk; result.contents = data.value(); @@ -137,11 +179,11 @@ PemReadResult ReadNextPemMessage(std::istream* input) { } bool eof_reached = input->eof() && !pending_message; return PemReadResult{ - .status = (eof_reached ? PemReadResult::kEof : PemReadResult::kError)}; + (eof_reached ? PemReadResult::kEof : PemReadResult::kError), "", ""}; } std::unique_ptr<CertificateView> CertificateView::ParseSingleCertificate( - quiche::QuicheStringPiece certificate) { + QuicheStringPiece certificate) { std::unique_ptr<CertificateView> result(new CertificateView()); CBS top = StringPieceToCbs(certificate); @@ -215,6 +257,25 @@ std::unique_ptr<CertificateView> CertificateView::ParseSingleCertificate( return nullptr; } + unsigned not_before_tag, not_after_tag; + CBS not_before, not_after; + if (!CBS_get_any_asn1(&validity, ¬_before, ¬_before_tag) || + !CBS_get_any_asn1(&validity, ¬_after, ¬_after_tag) || + CBS_len(&validity) != 0) { + QUIC_DLOG(WARNING) << "Failed to extract the validity dates"; + return nullptr; + } + QuicheOptional<QuicWallTime> not_before_parsed = + ParseDerTime(not_before_tag, CbsToStringPiece(not_before)); + QuicheOptional<QuicWallTime> not_after_parsed = + ParseDerTime(not_after_tag, CbsToStringPiece(not_after)); + if (!not_before_parsed.has_value() || !not_after_parsed.has_value()) { + QUIC_DLOG(WARNING) << "Failed to parse validity dates"; + return nullptr; + } + result->validity_start_ = *not_before_parsed; + result->validity_end_ = *not_after_parsed; + result->public_key_.reset(EVP_parse_public_key(&spki)); if (result->public_key_ == nullptr) { QUIC_DLOG(WARNING) << "Failed to parse the public key"; @@ -286,7 +347,7 @@ bool CertificateView::ParseExtensions(CBS extensions) { return false; } - quiche::QuicheStringPiece alt_name = CbsToStringPiece(alt_name_cbs); + QuicheStringPiece alt_name = CbsToStringPiece(alt_name_cbs); QuicIpAddress ip_address; // GeneralName ::= CHOICE { switch (alt_name_tag) { @@ -306,8 +367,8 @@ bool CertificateView::ParseExtensions(CBS extensions) { break; default: - QUIC_DLOG(WARNING) << "Invalid subjectAltName tag"; - return false; + QUIC_DLOG(INFO) << "Unknown subjectAltName tag " << alt_name_tag; + continue; } } } @@ -355,8 +416,8 @@ bool CertificateView::ValidatePublicKeyParameters() { } } -bool CertificateView::VerifySignature(quiche::QuicheStringPiece data, - quiche::QuicheStringPiece signature, +bool CertificateView::VerifySignature(QuicheStringPiece data, + QuicheStringPiece signature, uint16_t signature_algorithm) const { if (PublicKeyTypeFromSignatureAlgorithm(signature_algorithm) != PublicKeyTypeFromKey(public_key_.get())) { @@ -386,7 +447,7 @@ bool CertificateView::VerifySignature(quiche::QuicheStringPiece data, } std::unique_ptr<CertificatePrivateKey> CertificatePrivateKey::LoadFromDer( - quiche::QuicheStringPiece private_key) { + QuicheStringPiece private_key) { std::unique_ptr<CertificatePrivateKey> result(new CertificatePrivateKey()); CBS private_key_cbs = StringPieceToCbs(private_key); result->private_key_.reset(EVP_parse_private_key(&private_key_cbs)); @@ -423,7 +484,7 @@ std::unique_ptr<CertificatePrivateKey> CertificatePrivateKey::LoadPemFromStream( return nullptr; } -std::string CertificatePrivateKey::Sign(quiche::QuicheStringPiece input, +std::string CertificatePrivateKey::Sign(QuicheStringPiece input, uint16_t signature_algorithm) { if (PublicKeyTypeFromSignatureAlgorithm(signature_algorithm) != PublicKeyTypeFromKey(private_key_.get())) { diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view.h b/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view.h index 286226d7e20..13bb5ff14ae 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view.h +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view.h @@ -13,8 +13,11 @@ #include "third_party/boringssl/src/include/openssl/bytestring.h" #include "third_party/boringssl/src/include/openssl/evp.h" #include "net/third_party/quiche/src/quic/core/crypto/boring_utils.h" +#include "net/third_party/quiche/src/quic/core/quic_time.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" #include "net/third_party/quiche/src/quic/platform/api/quic_export.h" #include "net/third_party/quiche/src/quic/platform/api/quic_ip_address.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_optional.h" #include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" namespace quic { @@ -46,6 +49,8 @@ class QUIC_EXPORT_PRIVATE CertificateView { // without parsing them. Returns an empty vector if any parsing error occurs. static std::vector<std::string> LoadPemFromStream(std::istream* input); + QuicWallTime validity_start() const { return validity_start_; } + QuicWallTime validity_end() const { return validity_end_; } const EVP_PKEY* public_key() const { return public_key_.get(); } const std::vector<quiche::QuicheStringPiece>& subject_alt_name_domains() @@ -64,6 +69,9 @@ class QUIC_EXPORT_PRIVATE CertificateView { private: CertificateView() = default; + QuicWallTime validity_start_ = QuicWallTime::Zero(); + QuicWallTime validity_end_ = QuicWallTime::Zero(); + // Public key parsed from SPKI. bssl::UniquePtr<EVP_PKEY> public_key_; @@ -103,6 +111,12 @@ class QUIC_EXPORT_PRIVATE CertificatePrivateKey { bssl::UniquePtr<EVP_PKEY> private_key_; }; +// Parses a DER time based on the specified ASN.1 tag. Exposed primarily for +// testing. +QUIC_EXPORT_PRIVATE quiche::QuicheOptional<quic::QuicWallTime> ParseDerTime( + unsigned tag, + quiche::QuicheStringPiece payload); + } // namespace quic #endif // QUICHE_QUIC_CORE_CRYPTO_CERTIFICATE_VIEW_H_ diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view_test.cc index b0b52f14f3b..ad512143243 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/certificate_view_test.cc @@ -8,19 +8,23 @@ #include <sstream> #include "third_party/boringssl/src/include/openssl/base.h" +#include "third_party/boringssl/src/include/openssl/bytestring.h" #include "third_party/boringssl/src/include/openssl/evp.h" #include "third_party/boringssl/src/include/openssl/ssl.h" +#include "net/third_party/quiche/src/quic/core/quic_time.h" #include "net/third_party/quiche/src/quic/platform/api/quic_ip_address.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" #include "net/third_party/quiche/src/quic/test_tools/test_certificates.h" #include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_time_utils.h" namespace quic { namespace test { namespace { -using testing::ElementsAre; -using testing::HasSubstr; +using ::testing::ElementsAre; +using ::testing::HasSubstr; +using ::testing::Optional; TEST(CertificateViewTest, PemParser) { std::stringstream stream(kTestCertificatePem); @@ -45,6 +49,24 @@ TEST(CertificateViewTest, Parse) { EXPECT_THAT(view->subject_alt_name_ips(), ElementsAre(QuicIpAddress::Loopback4())); EXPECT_EQ(EVP_PKEY_id(view->public_key()), EVP_PKEY_RSA); + + const QuicWallTime validity_start = QuicWallTime::FromUNIXSeconds( + *quiche::QuicheUtcDateTimeToUnixSeconds(2020, 1, 30, 18, 13, 59)); + EXPECT_EQ(view->validity_start(), validity_start); + const QuicWallTime validity_end = QuicWallTime::FromUNIXSeconds( + *quiche::QuicheUtcDateTimeToUnixSeconds(2020, 2, 2, 18, 13, 59)); + EXPECT_EQ(view->validity_end(), validity_end); +} + +TEST(CertificateViewTest, ParseCertWithUnknownSanType) { + std::stringstream stream(kTestCertWithUnknownSanTypePem); + PemReadResult result = ReadNextPemMessage(&stream); + EXPECT_EQ(result.status, PemReadResult::kOk); + EXPECT_EQ(result.type, "CERTIFICATE"); + + std::unique_ptr<CertificateView> view = + CertificateView::ParseSingleCertificate(result.contents); + EXPECT_TRUE(view != nullptr); } TEST(CertificateViewTest, PemSingleCertificate) { @@ -109,6 +131,47 @@ TEST(CertificateViewTest, PrivateKeyPem) { EXPECT_TRUE(legacy_key->MatchesPublicKey(*view)); } +TEST(CertificateViewTest, DerTime) { + EXPECT_THAT(ParseDerTime(CBS_ASN1_GENERALIZEDTIME, "19700101000024Z"), + Optional(QuicWallTime::FromUNIXSeconds(24))); + EXPECT_THAT(ParseDerTime(CBS_ASN1_GENERALIZEDTIME, "19710101000024Z"), + Optional(QuicWallTime::FromUNIXSeconds(365 * 86400 + 24))); + EXPECT_THAT(ParseDerTime(CBS_ASN1_UTCTIME, "700101000024Z"), + Optional(QuicWallTime::FromUNIXSeconds(24))); + EXPECT_TRUE(ParseDerTime(CBS_ASN1_UTCTIME, "200101000024Z").has_value()); + + EXPECT_EQ(ParseDerTime(CBS_ASN1_GENERALIZEDTIME, ""), QUICHE_NULLOPT); + EXPECT_EQ(ParseDerTime(CBS_ASN1_GENERALIZEDTIME, "19700101000024.001Z"), + QUICHE_NULLOPT); + EXPECT_EQ(ParseDerTime(CBS_ASN1_GENERALIZEDTIME, "19700101000024Q"), + QUICHE_NULLOPT); + EXPECT_EQ(ParseDerTime(CBS_ASN1_GENERALIZEDTIME, "19700101000024-0500"), + QUICHE_NULLOPT); + EXPECT_EQ(ParseDerTime(CBS_ASN1_GENERALIZEDTIME, "700101000024ZZ"), + QUICHE_NULLOPT); + EXPECT_EQ(ParseDerTime(CBS_ASN1_GENERALIZEDTIME, "19700101000024.00Z"), + QUICHE_NULLOPT); + EXPECT_EQ(ParseDerTime(CBS_ASN1_GENERALIZEDTIME, "19700101000024.Z"), + QUICHE_NULLOPT); + EXPECT_EQ(ParseDerTime(CBS_ASN1_GENERALIZEDTIME, "197O0101000024Z"), + QUICHE_NULLOPT); + EXPECT_EQ(ParseDerTime(CBS_ASN1_GENERALIZEDTIME, "19700101000024.0O1Z"), + QUICHE_NULLOPT); + EXPECT_EQ(ParseDerTime(CBS_ASN1_GENERALIZEDTIME, "-9700101000024Z"), + QUICHE_NULLOPT); + EXPECT_EQ(ParseDerTime(CBS_ASN1_GENERALIZEDTIME, "1970-101000024Z"), + QUICHE_NULLOPT); + + EXPECT_TRUE(ParseDerTime(CBS_ASN1_UTCTIME, "490101000024Z").has_value()); + // This should parse as 1950, which predates UNIX epoch. + EXPECT_FALSE(ParseDerTime(CBS_ASN1_UTCTIME, "500101000024Z").has_value()); + + EXPECT_THAT(ParseDerTime(CBS_ASN1_GENERALIZEDTIME, "19700101230000Z"), + Optional(QuicWallTime::FromUNIXSeconds(23 * 3600))); + EXPECT_EQ(ParseDerTime(CBS_ASN1_GENERALIZEDTIME, "19700101240000Z"), + QUICHE_NULLOPT); +} + } // namespace } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h index 172fd822d0b..4beec0bdf90 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h @@ -125,6 +125,8 @@ const QuicTag kB2CL = TAG('B', '2', 'C', 'L'); // For BBRv2, allow PROBE_BW // cwnd to be below BDP + ack // height. const QuicTag kB2LO = TAG('B', '2', 'L', 'O'); // Ignore inflight_lo in BBR2 +const QuicTag kB2HI = TAG('B', '2', 'H', 'I'); // Limit inflight_hi reduction + // based on CWND. const QuicTag kBSAO = TAG('B', 'S', 'A', 'O'); // Avoid Overestimation in // Bandwidth Sampler with ack // aggregation @@ -160,7 +162,13 @@ const QuicTag kACKQ = TAG('A', 'C', 'K', 'Q'); // Send an immediate ack after // 1 RTT of not receiving. const QuicTag kSSLR = TAG('S', 'S', 'L', 'R'); // Slow Start Large Reduction. const QuicTag kNPRR = TAG('N', 'P', 'R', 'R'); // Pace at unity instead of PRR +const QuicTag k2RTO = TAG('2', 'R', 'T', 'O'); // Close connection on 2 RTOs +const QuicTag k3RTO = TAG('3', 'R', 'T', 'O'); // Close connection on 3 RTOs +const QuicTag k4RTO = TAG('4', 'R', 'T', 'O'); // Close connection on 4 RTOs const QuicTag k5RTO = TAG('5', 'R', 'T', 'O'); // Close connection on 5 RTOs +const QuicTag k6RTO = TAG('6', 'R', 'T', 'O'); // Close connection on 6 RTOs +const QuicTag kCBHD = TAG('C', 'B', 'H', 'D'); // Client only blackhole + // detection. const QuicTag kCONH = TAG('C', 'O', 'N', 'H'); // Conservative Handshake // Retransmissions. const QuicTag kLFAK = TAG('L', 'F', 'A', 'K'); // Don't invoke FACK on the @@ -225,6 +233,8 @@ const QuicTag kPLE2 = TAG('P', 'L', 'E', '2'); // Arm the 1st PTO with // earliest in flight sent time // and at least 1.5*srtt from // last sent packet. +const QuicTag kAPTO = TAG('A', 'P', 'T', 'O'); // Use 1.5 * initial RTT before + // any RTT sample is available. const QuicTag kELDT = TAG('E', 'L', 'D', 'T'); // Enable Loss Detection Tuning @@ -329,6 +339,9 @@ const QuicTag kCFCW = TAG('C', 'F', 'C', 'W'); // Initial session/connection // flow control receive window. const QuicTag kUAID = TAG('U', 'A', 'I', 'D'); // Client's User Agent ID. const QuicTag kXLCT = TAG('X', 'L', 'C', 'T'); // Expected leaf certificate. +const QuicTag kQLVE = TAG('Q', 'L', 'V', 'E'); // Legacy Version + // Encapsulation. +const QuicTag kQNZR = TAG('Q', 'N', 'Z', 'R'); // Turn off QUIC crypto 0-RTT. const QuicTag kMAD = TAG('M', 'A', 'D', 0); // Max Ack Delay (IETF QUIC) diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_server_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_server_test.cc index ee9dc53cf64..58d39b8f7d6 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_server_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_server_test.cc @@ -508,6 +508,12 @@ TEST_P(CryptoServerTest, RejectTooLargeButValidSTK) { } TEST_P(CryptoServerTest, TooSmall) { + if (GetQuicReloadableFlag(quic_dont_pad_chlo)) { + // This test validates that non-padded CHLOs are rejected, it cannot pass + // when the padding is no longer required. + // TODO(dschinazi) remove this test when we deprecate quic_dont_pad_chlo. + return; + } ShouldFailMentioning( "too small", crypto_test_utils::CreateCHLO( {{"PDMD", "X509"}, {"VER\0", client_version_string_}})); diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils.cc index b6c6b7ae434..3127edec87b 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils.cc @@ -117,10 +117,16 @@ namespace { // Salt from https://tools.ietf.org/html/draft-ietf-quic-tls-25#section-5.2 // and https://tools.ietf.org/html/draft-ietf-quic-tls-27#section-5.2 +// and https://tools.ietf.org/html/draft-ietf-quic-tls-28#section-5.2 const uint8_t kDraft25InitialSalt[] = {0xc3, 0xee, 0xf7, 0x12, 0xc7, 0x2e, 0xbb, 0x5a, 0x11, 0xa7, 0xd2, 0x43, 0x2b, 0xb4, 0x63, 0x65, 0xbe, 0xf9, 0xf5, 0x02}; +// Salt from https://tools.ietf.org/html/draft-ietf-quic-tls-29#section-5.2 +const uint8_t kDraft29InitialSalt[] = {0xaf, 0xbf, 0xec, 0x28, 0x99, 0x93, 0xd2, + 0x4c, 0x9e, 0x97, 0x86, 0xf1, 0x9c, 0x61, + 0x11, 0xe0, 0x43, 0x90, 0xa8, 0x99}; + // Salts used by deployed versions of QUIC. When introducing a new version, // generate a new salt by running `openssl rand -hex 20`. @@ -135,7 +141,7 @@ const uint8_t kT050Salt[] = {0x7f, 0xf5, 0x79, 0xe5, 0xac, 0xd0, 0x72, const uint8_t* InitialSaltForVersion(const ParsedQuicVersion& version, size_t* out_len) { - static_assert(SupportedVersions().size() == 8u, + static_assert(SupportedVersions().size() == 9u, "Supported versions out of sync with initial encryption salts"); switch (version.handshake_protocol) { case PROTOCOL_QUIC_CRYPTO: @@ -166,6 +172,9 @@ const uint8_t* InitialSaltForVersion(const ParsedQuicVersion& version, // draft-27 uses the same salt as draft-25. *out_len = QUICHE_ARRAYSIZE(kDraft25InitialSalt); return kDraft25InitialSalt; + case QUIC_VERSION_IETF_DRAFT_29: + *out_len = QUICHE_ARRAYSIZE(kDraft29InitialSalt); + return kDraft29InitialSalt; default: QUIC_BUG << "No initial obfuscation salt for version " << version; } @@ -183,11 +192,20 @@ const char kPreSharedKeyLabel[] = "QUIC PSK"; // Retry Integrity Protection Keys and Nonces. // https://tools.ietf.org/html/draft-ietf-quic-tls-25#section-5.8 // https://tools.ietf.org/html/draft-ietf-quic-tls-27#section-5.8 +// https://tools.ietf.org/html/draft-ietf-quic-tls-28#section-5.8 const uint8_t kDraft25RetryIntegrityKey[] = {0x4d, 0x32, 0xec, 0xdb, 0x2a, 0x21, 0x33, 0xc8, 0x41, 0xe4, 0x04, 0x3d, 0xf2, 0x7d, 0x44, 0x30}; const uint8_t kDraft25RetryIntegrityNonce[] = { 0x4d, 0x16, 0x11, 0xd0, 0x55, 0x13, 0xa5, 0x52, 0xc5, 0x87, 0xd5, 0x75}; + +// https://tools.ietf.org/html/draft-ietf-quic-tls-29#section-5.8 +const uint8_t kDraft29RetryIntegrityKey[] = {0xcc, 0xce, 0x18, 0x7e, 0xd0, 0x9a, + 0x09, 0xd0, 0x57, 0x28, 0x15, 0x5a, + 0x6c, 0xb9, 0x6b, 0xe1}; +const uint8_t kDraft29RetryIntegrityNonce[] = { + 0xe5, 0x49, 0x30, 0xf9, 0x7f, 0x21, 0x36, 0xf0, 0x53, 0x0a, 0x8c, 0x1c}; + // Keys used by Google versions of QUIC. When introducing a new version, // generate a new key by running `openssl rand -hex 16`. const uint8_t kT050RetryIntegrityKey[] = {0xc9, 0x2d, 0x32, 0x3d, 0x9c, 0xe3, @@ -227,6 +245,15 @@ bool RetryIntegrityKeysForVersion(const ParsedQuicVersion& version, QUICHE_ARRAYSIZE(kDraft25RetryIntegrityNonce)); return true; } + if (version == ParsedQuicVersion::Draft29()) { + *key = quiche::QuicheStringPiece( + reinterpret_cast<const char*>(kDraft29RetryIntegrityKey), + QUICHE_ARRAYSIZE(kDraft29RetryIntegrityKey)); + *nonce = quiche::QuicheStringPiece( + reinterpret_cast<const char*>(kDraft29RetryIntegrityNonce), + QUICHE_ARRAYSIZE(kDraft29RetryIntegrityNonce)); + return true; + } QUIC_BUG << "Attempted to get retry integrity keys for version " << version; return false; } diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/proof_source_x509.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/proof_source_x509.cc index 6afc65f557a..e432682bddd 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/proof_source_x509.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/proof_source_x509.cc @@ -104,8 +104,8 @@ bool ProofSourceX509::AddCertificateChain( } certificates_.push_front(Certificate{ - .chain = chain, - .key = std::move(key), + chain, + std::move(key), }); Certificate* certificate = &certificates_.front(); diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.cc index 7f8edc22cfe..9314e99f293 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.cc @@ -67,7 +67,10 @@ QuicCryptoClientConfig::QuicCryptoClientConfig( std::unique_ptr<SessionCache> session_cache) : proof_verifier_(std::move(proof_verifier)), session_cache_(std::move(session_cache)), - ssl_ctx_(TlsClientConnection::CreateSslCtx()) { + enable_zero_rtt_for_tls_( + GetQuicReloadableFlag(quic_enable_zero_rtt_for_tls)), + ssl_ctx_(TlsClientConnection::CreateSslCtx(enable_zero_rtt_for_tls_)), + disable_chlo_padding_(GetQuicReloadableFlag(quic_dont_pad_chlo)) { DCHECK(proof_verifier_.get()); SetDefaults(); } @@ -132,16 +135,6 @@ QuicCryptoClientConfig::CachedState::GetServerConfig() const { return scfg_.get(); } -void QuicCryptoClientConfig::CachedState::add_server_designated_connection_id( - QuicConnectionId connection_id) { - server_designated_connection_ids_.push(connection_id); -} - -bool QuicCryptoClientConfig::CachedState::has_server_designated_connection_id() - const { - return !server_designated_connection_ids_.empty(); -} - void QuicCryptoClientConfig::CachedState::add_server_nonce( const std::string& server_nonce) { server_nonces_.push(server_nonce); @@ -204,9 +197,6 @@ void QuicCryptoClientConfig::CachedState::InvalidateServerConfig() { server_config_.clear(); scfg_.reset(); SetProofInvalid(); - QuicQueue<QuicConnectionId> empty_queue; - using std::swap; - swap(server_designated_connection_ids_, empty_queue); } void QuicCryptoClientConfig::CachedState::SetProof( @@ -249,9 +239,6 @@ void QuicCryptoClientConfig::CachedState::Clear() { proof_verify_details_.reset(); scfg_.reset(); ++generation_counter_; - QuicQueue<QuicConnectionId> empty_queue; - using std::swap; - swap(server_designated_connection_ids_, empty_queue); } void QuicCryptoClientConfig::CachedState::ClearProof() { @@ -370,7 +357,6 @@ void QuicCryptoClientConfig::CachedState::InitializeFrom( chlo_hash_ = other.chlo_hash_; server_config_sig_ = other.server_config_sig_; server_config_valid_ = other.server_config_valid_; - server_designated_connection_ids_ = other.server_designated_connection_ids_; expiration_time_ = other.expiration_time_; if (other.proof_verify_details_ != nullptr) { proof_verify_details_.reset(other.proof_verify_details_->Clone()); @@ -378,18 +364,6 @@ void QuicCryptoClientConfig::CachedState::InitializeFrom( ++generation_counter_; } -QuicConnectionId -QuicCryptoClientConfig::CachedState::GetNextServerDesignatedConnectionId() { - if (server_designated_connection_ids_.empty()) { - QUIC_BUG - << "Attempting to consume a connection id that was never designated."; - return EmptyQuicConnectionId(); - } - const QuicConnectionId next_id = server_designated_connection_ids_.front(); - server_designated_connection_ids_.pop(); - return next_id; -} - std::string QuicCryptoClientConfig::CachedState::GetNextServerNonce() { if (server_nonces_.empty()) { QUIC_BUG @@ -447,7 +421,7 @@ void QuicCryptoClientConfig::FillInchoateClientHello( CryptoHandshakeMessage* out) const { out->set_tag(kCHLO); // TODO(rch): Remove this when we remove quic_use_chlo_packet_size flag. - if (pad_inchoate_hello_) { + if (pad_inchoate_hello_ && !disable_chlo_padding_) { out->set_minimum_size(kClientHelloMinimumSize); } else { out->set_minimum_size(1); @@ -536,7 +510,7 @@ QuicErrorCode QuicCryptoClientConfig::FillClientHello( FillInchoateClientHello(server_id, preferred_version, cached, rand, /* demand_x509_proof= */ true, out_params, out); - if (pad_full_hello_) { + if (pad_full_hello_ && !disable_chlo_padding_) { out->set_minimum_size(kClientHelloMinimumSize); } else { out->set_minimum_size(1); diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.h b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.h index e3867c8e7b2..ce0efe530c7 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.h +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.h @@ -76,6 +76,10 @@ class QUIC_EXPORT_PRIVATE SessionCache { virtual std::unique_ptr<QuicResumptionState> Lookup( const QuicServerId& server_id, const SSL_CTX* ctx) = 0; + + // Called when 0-RTT is rejected. Disables early data for all the TLS tickets + // associated with |server_id|. + virtual void ClearEarlyData(const QuicServerId& server_id) = 0; }; // QuicCryptoClientConfig contains crypto-related configuration settings for a @@ -171,20 +175,6 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig { void set_cert_sct(quiche::QuicheStringPiece cert_sct); - // Adds the connection ID to the queue of server-designated connection-ids. - void add_server_designated_connection_id(QuicConnectionId connection_id); - - // If true, the crypto config contains at least one connection ID specified - // by the server, and the client should use one of these IDs when initiating - // the next connection. - bool has_server_designated_connection_id() const; - - // This function should only be called when - // has_server_designated_connection_id is true. Returns the next - // connection_id specified by the server and removes it from the - // queue of ids. - QuicConnectionId GetNextServerDesignatedConnectionId(); - // Adds the servernonce to the queue of server nonces. void add_server_nonce(const std::string& server_nonce); @@ -238,10 +228,6 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig { // scfg contains the cached, parsed value of |server_config|. mutable std::unique_ptr<CryptoHandshakeMessage> scfg_; - // TODO(jokulik): Consider using a hash-set as extra book-keeping to ensure - // that no connection-id is added twice. Also, consider keeping the server - // nonces and connection_ids together in one queue. - QuicQueue<QuicConnectionId> server_designated_connection_ids_; QuicQueue<std::string> server_nonces_; }; @@ -368,6 +354,8 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig { void set_proof_source(std::unique_ptr<ProofSource> proof_source); SSL_CTX* ssl_ctx() const; + bool early_data_enabled_for_tls() const { return enable_zero_rtt_for_tls_; } + // Initialize the CachedState from |canonical_crypto_config| for the // |canonical_server_id| as the initial CachedState for |server_id|. We will // copy config data only if |canonical_crypto_config| has valid proof. @@ -409,6 +397,10 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig { bool pad_full_hello() const { return pad_full_hello_; } void set_pad_full_hello(bool new_value) { pad_full_hello_ = new_value; } + void set_disable_chlo_padding(bool disabled) { + disable_chlo_padding_ = disabled; + } + private: // Sets the members to reasonable, default values. void SetDefaults(); @@ -450,6 +442,9 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig { std::unique_ptr<ProofVerifier> proof_verifier_; std::unique_ptr<SessionCache> session_cache_; std::unique_ptr<ProofSource> proof_source_; + + // Latched value of reloadable flag quic_enable_zero_rtt_for_tls + bool enable_zero_rtt_for_tls_; bssl::UniquePtr<SSL_CTX> ssl_ctx_; // The |user_agent_id_| passed in QUIC's CHLO message. @@ -475,6 +470,7 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig { // other means of verifying the client. bool pad_inchoate_hello_ = true; bool pad_full_hello_ = true; + bool disable_chlo_padding_; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config_test.cc index 4b6dcd71bcb..c995e8a87c0 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config_test.cc @@ -81,46 +81,6 @@ TEST_F(QuicCryptoClientConfigTest, CachedState_SetProofVerifyDetails) { EXPECT_EQ(details, state.proof_verify_details()); } -TEST_F(QuicCryptoClientConfigTest, CachedState_ServerDesignatedConnectionId) { - QuicCryptoClientConfig::CachedState state; - EXPECT_FALSE(state.has_server_designated_connection_id()); - - uint64_t conn_id = 1234; - QuicConnectionId connection_id = TestConnectionId(conn_id); - state.add_server_designated_connection_id(connection_id); - EXPECT_TRUE(state.has_server_designated_connection_id()); - EXPECT_EQ(connection_id, state.GetNextServerDesignatedConnectionId()); - EXPECT_FALSE(state.has_server_designated_connection_id()); - - // Allow the ID to be set multiple times. It's unusual that this would - // happen, but not impossible. - connection_id = TestConnectionId(++conn_id); - state.add_server_designated_connection_id(connection_id); - EXPECT_TRUE(state.has_server_designated_connection_id()); - EXPECT_EQ(connection_id, state.GetNextServerDesignatedConnectionId()); - connection_id = TestConnectionId(++conn_id); - state.add_server_designated_connection_id(connection_id); - EXPECT_EQ(connection_id, state.GetNextServerDesignatedConnectionId()); - EXPECT_FALSE(state.has_server_designated_connection_id()); - - // Test FIFO behavior. - const QuicConnectionId first_cid = TestConnectionId(0xdeadbeef); - const QuicConnectionId second_cid = TestConnectionId(0xfeedbead); - state.add_server_designated_connection_id(first_cid); - state.add_server_designated_connection_id(second_cid); - EXPECT_TRUE(state.has_server_designated_connection_id()); - EXPECT_EQ(first_cid, state.GetNextServerDesignatedConnectionId()); - EXPECT_EQ(second_cid, state.GetNextServerDesignatedConnectionId()); -} - -TEST_F(QuicCryptoClientConfigTest, CachedState_ServerIdConsumedBeforeSet) { - QuicCryptoClientConfig::CachedState state; - EXPECT_FALSE(state.has_server_designated_connection_id()); - EXPECT_QUIC_BUG(state.GetNextServerDesignatedConnectionId(), - "Attempting to consume a connection id " - "that was never designated."); -} - TEST_F(QuicCryptoClientConfigTest, CachedState_ServerNonce) { QuicCryptoClientConfig::CachedState state; EXPECT_FALSE(state.has_server_nonce()); @@ -170,7 +130,6 @@ TEST_F(QuicCryptoClientConfigTest, CachedState_InitializeFrom) { EXPECT_EQ(state.source_address_token(), other.source_address_token()); EXPECT_EQ(state.certs(), other.certs()); EXPECT_EQ(1u, other.generation_counter()); - EXPECT_FALSE(state.has_server_designated_connection_id()); EXPECT_FALSE(state.has_server_nonce()); } @@ -200,7 +159,11 @@ TEST_F(QuicCryptoClientConfigTest, InchoateChlo) { EXPECT_TRUE(msg.GetStringPiece(kALPN, &alpn)); EXPECT_EQ("hq", alpn); - EXPECT_EQ(msg.minimum_size(), 1024u); + if (GetQuicReloadableFlag(quic_dont_pad_chlo)) { + EXPECT_EQ(msg.minimum_size(), 1u); + } else { + EXPECT_EQ(msg.minimum_size(), 1024u); + } } TEST_F(QuicCryptoClientConfigTest, InchoateChloIsNotPadded) { @@ -532,7 +495,6 @@ TEST_F(QuicCryptoClientConfigTest, ProcessReject) { AllSupportedTransportVersions().front(), "", &cached, out_params, &error), IsQuicNoError()); - EXPECT_FALSE(cached.has_server_designated_connection_id()); EXPECT_FALSE(cached.has_server_nonce()); } diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.cc index 9cb089bf0e8..c07b8d3bf11 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.cc @@ -1211,10 +1211,14 @@ void QuicCryptoServerConfig::EvaluateClientHello( const CryptoHandshakeMessage& client_hello = client_hello_state->client_hello; ClientHelloInfo* info = &(client_hello_state->info); - if (validate_chlo_size_ && client_hello.size() < kClientHelloMinimumSize) { - helper.ValidationComplete(QUIC_CRYPTO_INVALID_VALUE_LENGTH, - "Client hello too small", nullptr); - return; + if (GetQuicReloadableFlag(quic_dont_pad_chlo)) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_dont_pad_chlo, 1, 2); + } else { + if (validate_chlo_size_ && client_hello.size() < kClientHelloMinimumSize) { + helper.ValidationComplete(QUIC_CRYPTO_INVALID_VALUE_LENGTH, + "Client hello too small", nullptr); + return; + } } if (client_hello.GetStringPiece(kSNI, &info->sni) && diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/tls_client_connection.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/tls_client_connection.cc index 7d112245b3c..79088473bbc 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/tls_client_connection.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/tls_client_connection.cc @@ -11,7 +11,8 @@ TlsClientConnection::TlsClientConnection(SSL_CTX* ssl_ctx, Delegate* delegate) delegate_(delegate) {} // static -bssl::UniquePtr<SSL_CTX> TlsClientConnection::CreateSslCtx() { +bssl::UniquePtr<SSL_CTX> TlsClientConnection::CreateSslCtx( + bool enable_early_data) { bssl::UniquePtr<SSL_CTX> ssl_ctx = TlsConnection::CreateSslCtx(); // Configure certificate verification. SSL_CTX_set_custom_verify(ssl_ctx.get(), SSL_VERIFY_PEER, &VerifyCallback); @@ -22,6 +23,8 @@ bssl::UniquePtr<SSL_CTX> TlsClientConnection::CreateSslCtx() { SSL_CTX_set_session_cache_mode( ssl_ctx.get(), SSL_SESS_CACHE_CLIENT | SSL_SESS_CACHE_NO_INTERNAL); SSL_CTX_sess_set_new_cb(ssl_ctx.get(), NewSessionCallback); + + SSL_CTX_set_early_data_enabled(ssl_ctx.get(), enable_early_data); return ssl_ctx; } diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/tls_client_connection.h b/chromium/net/third_party/quiche/src/quic/core/crypto/tls_client_connection.h index 035f420a835..a7ef209792f 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/tls_client_connection.h +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/tls_client_connection.h @@ -39,7 +39,7 @@ class QUIC_EXPORT_PRIVATE TlsClientConnection : public TlsConnection { TlsClientConnection(SSL_CTX* ssl_ctx, Delegate* delegate); // Creates and configures an SSL_CTX that is appropriate for clients to use. - static bssl::UniquePtr<SSL_CTX> CreateSslCtx(); + static bssl::UniquePtr<SSL_CTX> CreateSslCtx(bool enable_early_data); private: // Registered as the callback for SSL_CTX_set_custom_verify. The diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/tls_connection.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/tls_connection.cc index 75d28c55d60..8e4d391db4b 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/tls_connection.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/tls_connection.cc @@ -114,28 +114,6 @@ const SSL_QUIC_METHOD TlsConnection::kSslQuicMethod{ TlsConnection::SendAlertCallback}; // static -int TlsConnection::SetEncryptionSecretCallback( - SSL* ssl, - enum ssl_encryption_level_t level, - const uint8_t* read_key, - const uint8_t* write_key, - size_t key_length) { - // TODO(nharper): replace these vectors and memcpys with spans (which - // unfortunately doesn't yet exist in quic/platform/api). - std::vector<uint8_t> read_secret(key_length), write_secret(key_length); - memcpy(read_secret.data(), read_key, key_length); - memcpy(write_secret.data(), write_key, key_length); - TlsConnection::Delegate* delegate = ConnectionFromSsl(ssl)->delegate_; - const SSL_CIPHER* cipher = SSL_get_pending_cipher(ssl); - delegate->SetWriteSecret(QuicEncryptionLevel(level), cipher, write_secret); - if (!delegate->SetReadSecret(QuicEncryptionLevel(level), cipher, - read_secret)) { - return 0; - } - return 1; -} - -// static int TlsConnection::SetReadSecretCallback(SSL* ssl, enum ssl_encryption_level_t level, const SSL_CIPHER* cipher, diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/tls_connection.h b/chromium/net/third_party/quiche/src/quic/core/crypto/tls_connection.h index d65f63c68e5..15a4f4f9a3a 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/tls_connection.h +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/tls_connection.h @@ -101,11 +101,6 @@ class QUIC_EXPORT_PRIVATE TlsConnection { static const SSL_QUIC_METHOD kSslQuicMethod; // The following static functions make up the members of kSslQuicMethod: - static int SetEncryptionSecretCallback(SSL* ssl, - enum ssl_encryption_level_t level, - const uint8_t* read_key, - const uint8_t* write_key, - size_t key_length); static int SetReadSecretCallback(SSL* ssl, enum ssl_encryption_level_t level, const SSL_CIPHER* cipher, diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.cc index 3e286adc84b..330a14d5ea2 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.cc @@ -10,6 +10,8 @@ #include <memory> #include <utility> +#include "third_party/boringssl/src/include/openssl/digest.h" +#include "third_party/boringssl/src/include/openssl/sha.h" #include "net/third_party/quiche/src/quic/core/crypto/crypto_framer.h" #include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.h" #include "net/third_party/quiche/src/quic/core/quic_connection_id.h" @@ -31,8 +33,8 @@ namespace quic { // which parameter is encoded. The supported draft version is noted in // transport_parameters.h. enum TransportParameters::TransportParameterId : uint64_t { - kOriginalConnectionId = 0, - kIdleTimeout = 1, + kOriginalDestinationConnectionId = 0, + kMaxIdleTimeout = 1, kStatelessResetToken = 2, kMaxPacketSize = 3, kInitialMaxData = 4, @@ -43,15 +45,18 @@ enum TransportParameters::TransportParameterId : uint64_t { kInitialMaxStreamsUni = 9, kAckDelayExponent = 0xa, kMaxAckDelay = 0xb, - kDisableMigration = 0xc, + kDisableActiveMigration = 0xc, kPreferredAddress = 0xd, kActiveConnectionIdLimit = 0xe, + kInitialSourceConnectionId = 0xf, + kRetrySourceConnectionId = 0x10, kMaxDatagramFrameSize = 0x20, kInitialRoundTripTime = 0x3127, kGoogleConnectionOptions = 0x3128, kGoogleUserAgentId = 0x3129, + kGoogleSupportHandshakeDone = 0x312A, // Only used in T050. kGoogleQuicParam = 18257, // Used for non-standard Google-specific params. kGoogleQuicVersion = 18258, // Used to transmit version and supported_versions. @@ -74,14 +79,14 @@ constexpr uint64_t kDefaultActiveConnectionIdLimitTransportParam = 2; std::string TransportParameterIdToString( TransportParameters::TransportParameterId param_id) { switch (param_id) { - case TransportParameters::kOriginalConnectionId: - return "original_connection_id"; - case TransportParameters::kIdleTimeout: - return "idle_timeout"; + case TransportParameters::kOriginalDestinationConnectionId: + return "original_destination_connection_id"; + case TransportParameters::kMaxIdleTimeout: + return "max_idle_timeout"; case TransportParameters::kStatelessResetToken: return "stateless_reset_token"; case TransportParameters::kMaxPacketSize: - return "max_packet_size"; + return "max_udp_payload_size"; case TransportParameters::kInitialMaxData: return "initial_max_data"; case TransportParameters::kInitialMaxStreamDataBidiLocal: @@ -98,12 +103,16 @@ std::string TransportParameterIdToString( return "ack_delay_exponent"; case TransportParameters::kMaxAckDelay: return "max_ack_delay"; - case TransportParameters::kDisableMigration: - return "disable_migration"; + case TransportParameters::kDisableActiveMigration: + return "disable_active_migration"; case TransportParameters::kPreferredAddress: return "preferred_address"; case TransportParameters::kActiveConnectionIdLimit: return "active_connection_id_limit"; + case TransportParameters::kInitialSourceConnectionId: + return "initial_source_connection_id"; + case TransportParameters::kRetrySourceConnectionId: + return "retry_source_connection_id"; case TransportParameters::kMaxDatagramFrameSize: return "max_datagram_frame_size"; case TransportParameters::kInitialRoundTripTime: @@ -112,6 +121,8 @@ std::string TransportParameterIdToString( return "google_connection_options"; case TransportParameters::kGoogleUserAgentId: return "user_agent_id"; + case TransportParameters::kGoogleSupportHandshakeDone: + return "support_handshake_done"; case TransportParameters::kGoogleQuicParam: return "google"; case TransportParameters::kGoogleQuicVersion: @@ -123,8 +134,8 @@ std::string TransportParameterIdToString( bool TransportParameterIdIsKnown( TransportParameters::TransportParameterId param_id) { switch (param_id) { - case TransportParameters::kOriginalConnectionId: - case TransportParameters::kIdleTimeout: + case TransportParameters::kOriginalDestinationConnectionId: + case TransportParameters::kMaxIdleTimeout: case TransportParameters::kStatelessResetToken: case TransportParameters::kMaxPacketSize: case TransportParameters::kInitialMaxData: @@ -135,13 +146,16 @@ bool TransportParameterIdIsKnown( case TransportParameters::kInitialMaxStreamsUni: case TransportParameters::kAckDelayExponent: case TransportParameters::kMaxAckDelay: - case TransportParameters::kDisableMigration: + case TransportParameters::kDisableActiveMigration: case TransportParameters::kPreferredAddress: case TransportParameters::kActiveConnectionIdLimit: + case TransportParameters::kInitialSourceConnectionId: + case TransportParameters::kRetrySourceConnectionId: case TransportParameters::kMaxDatagramFrameSize: case TransportParameters::kInitialRoundTripTime: case TransportParameters::kGoogleConnectionOptions: case TransportParameters::kGoogleUserAgentId: + case TransportParameters::kGoogleSupportHandshakeDone: case TransportParameters::kGoogleQuicParam: case TransportParameters::kGoogleQuicVersion: return true; @@ -401,18 +415,18 @@ std::string TransportParameters::ToString() const { rv += " supported_versions " + QuicVersionLabelVectorToString(supported_versions); } - if (original_connection_id.has_value()) { - rv += " " + TransportParameterIdToString(kOriginalConnectionId) + " " + - original_connection_id.value().ToString(); + if (original_destination_connection_id.has_value()) { + rv += " " + TransportParameterIdToString(kOriginalDestinationConnectionId) + + " " + original_destination_connection_id.value().ToString(); } - rv += idle_timeout_milliseconds.ToString(/*for_use_in_list=*/true); + rv += max_idle_timeout_ms.ToString(/*for_use_in_list=*/true); if (!stateless_reset_token.empty()) { rv += " " + TransportParameterIdToString(kStatelessResetToken) + " " + quiche::QuicheTextUtils::HexEncode( reinterpret_cast<const char*>(stateless_reset_token.data()), stateless_reset_token.size()); } - rv += max_packet_size.ToString(/*for_use_in_list=*/true); + rv += max_udp_payload_size.ToString(/*for_use_in_list=*/true); rv += initial_max_data.ToString(/*for_use_in_list=*/true); rv += initial_max_stream_data_bidi_local.ToString(/*for_use_in_list=*/true); rv += initial_max_stream_data_bidi_remote.ToString(/*for_use_in_list=*/true); @@ -421,14 +435,22 @@ std::string TransportParameters::ToString() const { rv += initial_max_streams_uni.ToString(/*for_use_in_list=*/true); rv += ack_delay_exponent.ToString(/*for_use_in_list=*/true); rv += max_ack_delay.ToString(/*for_use_in_list=*/true); - if (disable_migration) { - rv += " " + TransportParameterIdToString(kDisableMigration); + if (disable_active_migration) { + rv += " " + TransportParameterIdToString(kDisableActiveMigration); } if (preferred_address) { rv += " " + TransportParameterIdToString(kPreferredAddress) + " " + preferred_address->ToString(); } rv += active_connection_id_limit.ToString(/*for_use_in_list=*/true); + if (initial_source_connection_id.has_value()) { + rv += " " + TransportParameterIdToString(kInitialSourceConnectionId) + " " + + initial_source_connection_id.value().ToString(); + } + if (retry_source_connection_id.has_value()) { + rv += " " + TransportParameterIdToString(kRetrySourceConnectionId) + " " + + retry_source_connection_id.value().ToString(); + } rv += max_datagram_frame_size.ToString(/*for_use_in_list=*/true); rv += initial_round_trip_time_us.ToString(/*for_use_in_list=*/true); if (google_connection_options.has_value()) { @@ -447,12 +469,24 @@ std::string TransportParameters::ToString() const { rv += " " + TransportParameterIdToString(kGoogleUserAgentId) + " \"" + user_agent_id.value() + "\""; } + if (support_handshake_done) { + rv += " " + TransportParameterIdToString(kGoogleSupportHandshakeDone); + } if (google_quic_params) { rv += " " + TransportParameterIdToString(kGoogleQuicParam); } for (const auto& kv : custom_parameters) { rv += " 0x" + quiche::QuicheTextUtils::Hex(static_cast<uint32_t>(kv.first)); - rv += "=" + quiche::QuicheTextUtils::HexEncode(kv.second); + rv += "="; + static constexpr size_t kMaxPrintableLength = 32; + if (kv.second.length() <= kMaxPrintableLength) { + rv += quiche::QuicheTextUtils::HexEncode(kv.second); + } else { + quiche::QuicheStringPiece truncated(kv.second.data(), + kMaxPrintableLength); + rv += quiche::QuicheStrCat(quiche::QuicheTextUtils::HexEncode(truncated), + "...(length ", kv.second.length(), ")"); + } } rv += "]"; return rv; @@ -460,11 +494,11 @@ std::string TransportParameters::ToString() const { TransportParameters::TransportParameters() : version(0), - idle_timeout_milliseconds(kIdleTimeout), - max_packet_size(kMaxPacketSize, - kDefaultMaxPacketSizeTransportParam, - kMinMaxPacketSizeTransportParam, - kVarInt62MaxValue), + max_idle_timeout_ms(kMaxIdleTimeout), + max_udp_payload_size(kMaxPacketSize, + kDefaultMaxPacketSizeTransportParam, + kMinMaxPacketSizeTransportParam, + kVarInt62MaxValue), initial_max_data(kInitialMaxData), initial_max_stream_data_bidi_local(kInitialMaxStreamDataBidiLocal), initial_max_stream_data_bidi_remote(kInitialMaxStreamDataBidiRemote), @@ -479,13 +513,14 @@ TransportParameters::TransportParameters() kDefaultMaxAckDelayTransportParam, 0, kMaxMaxAckDelayTransportParam), - disable_migration(false), + disable_active_migration(false), active_connection_id_limit(kActiveConnectionIdLimit, kDefaultActiveConnectionIdLimitTransportParam, kMinActiveConnectionIdLimitTransportParam, kVarInt62MaxValue), max_datagram_frame_size(kMaxDatagramFrameSize), - initial_round_trip_time_us(kInitialRoundTripTime) + initial_round_trip_time_us(kInitialRoundTripTime), + support_handshake_done(false) // Important note: any new transport parameters must be added // to TransportParameters::AreValid, SerializeTransportParameters and // ParseTransportParameters, TransportParameters's custom copy constructor, the @@ -496,10 +531,11 @@ TransportParameters::TransportParameters(const TransportParameters& other) : perspective(other.perspective), version(other.version), supported_versions(other.supported_versions), - original_connection_id(other.original_connection_id), - idle_timeout_milliseconds(other.idle_timeout_milliseconds), + original_destination_connection_id( + other.original_destination_connection_id), + max_idle_timeout_ms(other.max_idle_timeout_ms), stateless_reset_token(other.stateless_reset_token), - max_packet_size(other.max_packet_size), + max_udp_payload_size(other.max_udp_payload_size), initial_max_data(other.initial_max_data), initial_max_stream_data_bidi_local( other.initial_max_stream_data_bidi_local), @@ -510,12 +546,15 @@ TransportParameters::TransportParameters(const TransportParameters& other) initial_max_streams_uni(other.initial_max_streams_uni), ack_delay_exponent(other.ack_delay_exponent), max_ack_delay(other.max_ack_delay), - disable_migration(other.disable_migration), + disable_active_migration(other.disable_active_migration), active_connection_id_limit(other.active_connection_id_limit), + initial_source_connection_id(other.initial_source_connection_id), + retry_source_connection_id(other.retry_source_connection_id), max_datagram_frame_size(other.max_datagram_frame_size), initial_round_trip_time_us(other.initial_round_trip_time_us), google_connection_options(other.google_connection_options), user_agent_id(other.user_agent_id), + support_handshake_done(other.support_handshake_done), custom_parameters(other.custom_parameters) { if (other.preferred_address) { preferred_address = std::make_unique<TransportParameters::PreferredAddress>( @@ -530,11 +569,11 @@ TransportParameters::TransportParameters(const TransportParameters& other) bool TransportParameters::operator==(const TransportParameters& rhs) const { if (!(perspective == rhs.perspective && version == rhs.version && supported_versions == rhs.supported_versions && - original_connection_id == rhs.original_connection_id && - idle_timeout_milliseconds.value() == - rhs.idle_timeout_milliseconds.value() && + original_destination_connection_id == + rhs.original_destination_connection_id && + max_idle_timeout_ms.value() == rhs.max_idle_timeout_ms.value() && stateless_reset_token == rhs.stateless_reset_token && - max_packet_size.value() == rhs.max_packet_size.value() && + max_udp_payload_size.value() == rhs.max_udp_payload_size.value() && initial_max_data.value() == rhs.initial_max_data.value() && initial_max_stream_data_bidi_local.value() == rhs.initial_max_stream_data_bidi_local.value() && @@ -548,15 +587,18 @@ bool TransportParameters::operator==(const TransportParameters& rhs) const { rhs.initial_max_streams_uni.value() && ack_delay_exponent.value() == rhs.ack_delay_exponent.value() && max_ack_delay.value() == rhs.max_ack_delay.value() && - disable_migration == rhs.disable_migration && + disable_active_migration == rhs.disable_active_migration && active_connection_id_limit.value() == rhs.active_connection_id_limit.value() && + initial_source_connection_id == rhs.initial_source_connection_id && + retry_source_connection_id == rhs.retry_source_connection_id && max_datagram_frame_size.value() == rhs.max_datagram_frame_size.value() && initial_round_trip_time_us.value() == rhs.initial_round_trip_time_us.value() && google_connection_options == rhs.google_connection_options && user_agent_id == rhs.user_agent_id && + support_handshake_done == rhs.support_handshake_done && custom_parameters == rhs.custom_parameters)) { return false; } @@ -591,8 +633,8 @@ bool TransportParameters::AreValid(std::string* error_details) const { return false; } if (perspective == Perspective::IS_CLIENT && - original_connection_id.has_value()) { - *error_details = "Client cannot send original connection ID"; + original_destination_connection_id.has_value()) { + *error_details = "Client cannot send original_destination_connection_id"; return false; } if (!stateless_reset_token.empty() && @@ -619,6 +661,11 @@ bool TransportParameters::AreValid(std::string* error_details) const { *error_details = "Internal preferred address family failure"; return false; } + if (perspective == Perspective::IS_CLIENT && + retry_source_connection_id.has_value()) { + *error_details = "Client cannot send retry_source_connection_id"; + return false; + } for (const auto& kv : custom_parameters) { if (TransportParameterIdIsKnown(kv.first)) { *error_details = quiche::QuicheStrCat( @@ -637,7 +684,7 @@ bool TransportParameters::AreValid(std::string* error_details) const { return false; } const bool ok = - idle_timeout_milliseconds.IsValid() && max_packet_size.IsValid() && + max_idle_timeout_ms.IsValid() && max_udp_payload_size.IsValid() && initial_max_data.IsValid() && initial_max_stream_data_bidi_local.IsValid() && initial_max_stream_data_bidi_remote.IsValid() && @@ -669,11 +716,78 @@ bool SerializeTransportParameters(ParsedQuicVersion version, return false; } - // Empirically transport parameters generally fit within 128 bytes. - // For now we hope this will be enough. - // TODO(dschinazi) make this grow if needed. - static const size_t kMaxTransportParametersLength = 4096; - out->resize(kMaxTransportParametersLength); + // Maximum length of the GREASE transport parameter (see below). + static constexpr size_t kMaxGreaseLength = 16; + + // Empirically transport parameters generally fit within 128 bytes, but we + // need to allocate the size up front. Integer transport parameters + // have a maximum encoded length of 24 bytes (3 variable length integers), + // other transport parameters have a length of 16 + the maximum value length. + static constexpr size_t kTypeAndValueLength = 2 * sizeof(uint64_t); + static constexpr size_t kIntegerParameterLength = + kTypeAndValueLength + sizeof(uint64_t); + static constexpr size_t kStatelessResetParameterLength = + kTypeAndValueLength + 16 /* stateless reset token length */; + static constexpr size_t kConnectionIdParameterLength = + kTypeAndValueLength + 255 /* maximum connection ID length */; + static constexpr size_t kPreferredAddressParameterLength = + kTypeAndValueLength + 4 /*IPv4 address */ + 2 /* IPv4 port */ + + 16 /* IPv6 address */ + 1 /* Connection ID length */ + + 255 /* maximum connection ID length */ + 16 /* stateless reset token */; + static constexpr size_t kGreaseParameterLength = + kTypeAndValueLength + kMaxGreaseLength; + static constexpr size_t kKnownTransportParamLength = + kConnectionIdParameterLength + // original_destination_connection_id + kIntegerParameterLength + // max_idle_timeout + kStatelessResetParameterLength + // stateless_reset_token + kIntegerParameterLength + // max_udp_payload_size + kIntegerParameterLength + // initial_max_data + kIntegerParameterLength + // initial_max_stream_data_bidi_local + kIntegerParameterLength + // initial_max_stream_data_bidi_remote + kIntegerParameterLength + // initial_max_stream_data_uni + kIntegerParameterLength + // initial_max_streams_bidi + kIntegerParameterLength + // initial_max_streams_uni + kIntegerParameterLength + // ack_delay_exponent + kIntegerParameterLength + // max_ack_delay + kTypeAndValueLength + // disable_active_migration + kPreferredAddressParameterLength + // preferred_address + kIntegerParameterLength + // active_connection_id_limit + kConnectionIdParameterLength + // initial_source_connection_id + kConnectionIdParameterLength + // retry_source_connection_id + kIntegerParameterLength + // max_datagram_frame_size + kIntegerParameterLength + // initial_round_trip_time_us + kTypeAndValueLength + // google_connection_options + kTypeAndValueLength + // user_agent_id + kTypeAndValueLength + // support_handshake_done + kTypeAndValueLength + // google + kTypeAndValueLength + // google-version + kGreaseParameterLength; // GREASE + + size_t max_transport_param_length = kKnownTransportParamLength; + // google_connection_options. + if (in.google_connection_options.has_value()) { + max_transport_param_length += + in.google_connection_options.value().size() * sizeof(QuicTag); + } + // user_agent_id. + if (in.user_agent_id.has_value()) { + max_transport_param_length += in.user_agent_id.value().length(); + } + // Google-specific version extension. + max_transport_param_length += + sizeof(in.version) + 1 /* versions length */ + + in.supported_versions.size() * sizeof(QuicVersionLabel); + // Custom parameters. + for (const auto& kv : in.custom_parameters) { + max_transport_param_length += kTypeAndValueLength + kv.second.length(); + } + // Google-specific non-standard parameter. + if (in.google_quic_params) { + max_transport_param_length += + in.google_quic_params->GetSerialized().length(); + } + + out->resize(max_transport_param_length); QuicDataWriter writer(out->size(), reinterpret_cast<char*>(out->data())); if (!version.HasVarIntTransportParams()) { @@ -688,24 +802,27 @@ bool SerializeTransportParameters(ParsedQuicVersion version, } } - // original_connection_id - if (in.original_connection_id.has_value()) { + // original_destination_connection_id + if (in.original_destination_connection_id.has_value()) { DCHECK_EQ(Perspective::IS_SERVER, in.perspective); - QuicConnectionId original_connection_id = in.original_connection_id.value(); + QuicConnectionId original_destination_connection_id = + in.original_destination_connection_id.value(); if (!WriteTransportParameterId( - &writer, TransportParameters::kOriginalConnectionId, version) || + &writer, TransportParameters::kOriginalDestinationConnectionId, + version) || !WriteTransportParameterStringPiece( &writer, - quiche::QuicheStringPiece(original_connection_id.data(), - original_connection_id.length()), + quiche::QuicheStringPiece( + original_destination_connection_id.data(), + original_destination_connection_id.length()), version)) { - QUIC_BUG << "Failed to write original_connection_id " - << in.original_connection_id.value() << " for " << in; + QUIC_BUG << "Failed to write original_destination_connection_id " + << original_destination_connection_id << " for " << in; return false; } } - if (!in.idle_timeout_milliseconds.Write(&writer, version)) { + if (!in.max_idle_timeout_ms.Write(&writer, version)) { QUIC_BUG << "Failed to write idle_timeout for " << in; return false; } @@ -728,7 +845,7 @@ bool SerializeTransportParameters(ParsedQuicVersion version, } } - if (!in.max_packet_size.Write(&writer, version) || + if (!in.max_udp_payload_size.Write(&writer, version) || !in.initial_max_data.Write(&writer, version) || !in.initial_max_stream_data_bidi_local.Write(&writer, version) || !in.initial_max_stream_data_bidi_remote.Write(&writer, version) || @@ -744,12 +861,12 @@ bool SerializeTransportParameters(ParsedQuicVersion version, return false; } - // disable_migration - if (in.disable_migration) { + // disable_active_migration + if (in.disable_active_migration) { if (!WriteTransportParameterId( - &writer, TransportParameters::kDisableMigration, version) || + &writer, TransportParameters::kDisableActiveMigration, version) || !WriteTransportParameterLength(&writer, /*length=*/0, version)) { - QUIC_BUG << "Failed to write disable_migration for " << in; + QUIC_BUG << "Failed to write disable_active_migration for " << in; return false; } } @@ -791,6 +908,42 @@ bool SerializeTransportParameters(ParsedQuicVersion version, } } + // initial_source_connection_id + if (in.initial_source_connection_id.has_value()) { + QuicConnectionId initial_source_connection_id = + in.initial_source_connection_id.value(); + if (!WriteTransportParameterId( + &writer, TransportParameters::kInitialSourceConnectionId, + version) || + !WriteTransportParameterStringPiece( + &writer, + quiche::QuicheStringPiece(initial_source_connection_id.data(), + initial_source_connection_id.length()), + version)) { + QUIC_BUG << "Failed to write initial_source_connection_id " + << initial_source_connection_id << " for " << in; + return false; + } + } + + // retry_source_connection_id + if (in.retry_source_connection_id.has_value()) { + DCHECK_EQ(Perspective::IS_SERVER, in.perspective); + QuicConnectionId retry_source_connection_id = + in.retry_source_connection_id.value(); + if (!WriteTransportParameterId( + &writer, TransportParameters::kRetrySourceConnectionId, version) || + !WriteTransportParameterStringPiece( + &writer, + quiche::QuicheStringPiece(retry_source_connection_id.data(), + retry_source_connection_id.length()), + version)) { + QUIC_BUG << "Failed to write retry_source_connection_id " + << retry_source_connection_id << " for " << in; + return false; + } + } + // Google-specific connection options. if (in.google_connection_options.has_value()) { static_assert(sizeof(in.google_connection_options.value().front()) == 4, @@ -827,6 +980,17 @@ bool SerializeTransportParameters(ParsedQuicVersion version, } } + // Google-specific support handshake done. + if (in.support_handshake_done) { + if (!WriteTransportParameterId( + &writer, TransportParameters::kGoogleSupportHandshakeDone, + version) || + !WriteTransportParameterLength(&writer, /*length=*/0, version)) { + QUIC_BUG << "Failed to write support_handshake_done for " << in; + return false; + } + } + // Google-specific non-standard parameter. if (in.google_quic_params) { const QuicData& serialized_google_quic_params = @@ -910,7 +1074,6 @@ bool SerializeTransportParameters(ParsedQuicVersion version, << grease_id64 << " invalid for " << version; TransportParameters::TransportParameterId grease_id = static_cast<TransportParameters::TransportParameterId>(grease_id64); - const size_t kMaxGreaseLength = 16; const size_t grease_length = random->RandUint64() % kMaxGreaseLength; DCHECK_GE(kMaxGreaseLength, grease_length); char grease_contents[kMaxGreaseLength]; @@ -989,41 +1152,43 @@ bool ParseTransportParameters(ParsedQuicVersion version, QuicDataReader value_reader(value); bool parse_success = true; switch (param_id) { - case TransportParameters::kOriginalConnectionId: { - if (out->original_connection_id.has_value()) { - *error_details = "Received a second original connection ID"; + case TransportParameters::kOriginalDestinationConnectionId: { + if (out->original_destination_connection_id.has_value()) { + *error_details = + "Received a second original_destination_connection_id"; return false; } const size_t connection_id_length = value_reader.BytesRemaining(); if (!QuicUtils::IsConnectionIdLengthValidForVersion( connection_id_length, version.transport_version)) { *error_details = quiche::QuicheStrCat( - "Received original connection ID of invalid length ", + "Received original_destination_connection_id of invalid length ", connection_id_length); return false; } - QuicConnectionId original_connection_id; - if (!value_reader.ReadConnectionId(&original_connection_id, + QuicConnectionId original_destination_connection_id; + if (!value_reader.ReadConnectionId(&original_destination_connection_id, connection_id_length)) { - *error_details = "Failed to read original connection ID"; + *error_details = "Failed to read original_destination_connection_id"; return false; } - out->original_connection_id = original_connection_id; + out->original_destination_connection_id = + original_destination_connection_id; } break; - case TransportParameters::kIdleTimeout: + case TransportParameters::kMaxIdleTimeout: parse_success = - out->idle_timeout_milliseconds.Read(&value_reader, error_details); + out->max_idle_timeout_ms.Read(&value_reader, error_details); break; case TransportParameters::kStatelessResetToken: { if (!out->stateless_reset_token.empty()) { - *error_details = "Received a second stateless reset token"; + *error_details = "Received a second stateless_reset_token"; return false; } quiche::QuicheStringPiece stateless_reset_token = value_reader.ReadRemainingPayload(); if (stateless_reset_token.length() != kStatelessResetTokenLength) { *error_details = quiche::QuicheStrCat( - "Received stateless reset token of invalid length ", + "Received stateless_reset_token of invalid length ", stateless_reset_token.length()); return false; } @@ -1032,7 +1197,8 @@ bool ParseTransportParameters(ParsedQuicVersion version, stateless_reset_token.data() + stateless_reset_token.length()); } break; case TransportParameters::kMaxPacketSize: - parse_success = out->max_packet_size.Read(&value_reader, error_details); + parse_success = + out->max_udp_payload_size.Read(&value_reader, error_details); break; case TransportParameters::kInitialMaxData: parse_success = @@ -1065,12 +1231,12 @@ bool ParseTransportParameters(ParsedQuicVersion version, case TransportParameters::kMaxAckDelay: parse_success = out->max_ack_delay.Read(&value_reader, error_details); break; - case TransportParameters::kDisableMigration: - if (out->disable_migration) { - *error_details = "Received a second disable migration"; + case TransportParameters::kDisableActiveMigration: + if (out->disable_active_migration) { + *error_details = "Received a second disable_active_migration"; return false; } - out->disable_migration = true; + out->disable_active_migration = true; break; case TransportParameters::kPreferredAddress: { TransportParameters::PreferredAddress preferred_address; @@ -1087,7 +1253,7 @@ bool ParseTransportParameters(ParsedQuicVersion version, &preferred_address.connection_id) || !value_reader.ReadBytes(&preferred_address.stateless_reset_token[0], kStatelessResetTokenLength)) { - *error_details = "Failed to read preferred address"; + *error_details = "Failed to read preferred_address"; return false; } preferred_address.ipv4_socket_address = @@ -1096,13 +1262,13 @@ bool ParseTransportParameters(ParsedQuicVersion version, QuicSocketAddress(QuicIpAddress(ipv6_address), ipv6_port); if (!preferred_address.ipv4_socket_address.host().IsIPv4() || !preferred_address.ipv6_socket_address.host().IsIPv6()) { - *error_details = "Received preferred addresses of bad families " + + *error_details = "Received preferred_address of bad families " + preferred_address.ToString(); return false; } if (!QuicUtils::IsConnectionIdValidForVersion( preferred_address.connection_id, version.transport_version)) { - *error_details = "Received invalid preferred address connection ID " + + *error_details = "Received invalid preferred_address connection ID " + preferred_address.ToString(); return false; } @@ -1114,6 +1280,48 @@ bool ParseTransportParameters(ParsedQuicVersion version, parse_success = out->active_connection_id_limit.Read(&value_reader, error_details); break; + case TransportParameters::kInitialSourceConnectionId: { + if (out->initial_source_connection_id.has_value()) { + *error_details = "Received a second initial_source_connection_id"; + return false; + } + const size_t connection_id_length = value_reader.BytesRemaining(); + if (!QuicUtils::IsConnectionIdLengthValidForVersion( + connection_id_length, version.transport_version)) { + *error_details = quiche::QuicheStrCat( + "Received initial_source_connection_id of invalid length ", + connection_id_length); + return false; + } + QuicConnectionId initial_source_connection_id; + if (!value_reader.ReadConnectionId(&initial_source_connection_id, + connection_id_length)) { + *error_details = "Failed to read initial_source_connection_id"; + return false; + } + out->initial_source_connection_id = initial_source_connection_id; + } break; + case TransportParameters::kRetrySourceConnectionId: { + if (out->retry_source_connection_id.has_value()) { + *error_details = "Received a second retry_source_connection_id"; + return false; + } + const size_t connection_id_length = value_reader.BytesRemaining(); + if (!QuicUtils::IsConnectionIdLengthValidForVersion( + connection_id_length, version.transport_version)) { + *error_details = quiche::QuicheStrCat( + "Received retry_source_connection_id of invalid length ", + connection_id_length); + return false; + } + QuicConnectionId retry_source_connection_id; + if (!value_reader.ReadConnectionId(&retry_source_connection_id, + connection_id_length)) { + *error_details = "Failed to read retry_source_connection_id"; + return false; + } + out->retry_source_connection_id = retry_source_connection_id; + } break; case TransportParameters::kMaxDatagramFrameSize: parse_success = out->max_datagram_frame_size.Read(&value_reader, error_details); @@ -1124,14 +1332,14 @@ bool ParseTransportParameters(ParsedQuicVersion version, break; case TransportParameters::kGoogleConnectionOptions: { if (out->google_connection_options.has_value()) { - *error_details = "Received a second Google connection options"; + *error_details = "Received a second google_connection_options"; return false; } out->google_connection_options = QuicTagVector{}; while (!value_reader.IsDoneReading()) { QuicTag connection_option; if (!value_reader.ReadTag(&connection_option)) { - *error_details = "Failed to read a Google connection option"; + *error_details = "Failed to read a google_connection_options"; return false; } out->google_connection_options.value().push_back(connection_option); @@ -1139,11 +1347,18 @@ bool ParseTransportParameters(ParsedQuicVersion version, } break; case TransportParameters::kGoogleUserAgentId: if (out->user_agent_id.has_value()) { - *error_details = "Received a second user agent ID"; + *error_details = "Received a second user_agent_id"; return false; } out->user_agent_id = std::string(value_reader.ReadRemainingPayload()); break; + case TransportParameters::kGoogleSupportHandshakeDone: + if (out->support_handshake_done) { + *error_details = "Received a second support_handshake_done"; + return false; + } + out->support_handshake_done = true; + break; case TransportParameters::kGoogleQuicParam: { if (out->google_quic_params) { *error_details = "Received a second Google parameter"; @@ -1208,4 +1423,87 @@ bool ParseTransportParameters(ParsedQuicVersion version, return true; } +namespace { + +bool DigestUpdateIntegerParam( + EVP_MD_CTX* hash_ctx, + const TransportParameters::IntegerParameter& param) { + uint64_t value = param.value(); + return EVP_DigestUpdate(hash_ctx, &value, sizeof(value)); +} + +} // namespace + +bool SerializeTransportParametersForTicket( + const TransportParameters& in, + const std::vector<uint8_t>& application_data, + std::vector<uint8_t>* out) { + std::string error_details; + if (!in.AreValid(&error_details)) { + QUIC_BUG << "Not serializing invalid transport parameters: " + << error_details; + return false; + } + + out->resize(SHA256_DIGEST_LENGTH + 1); + const uint8_t serialization_version = 0; + (*out)[0] = serialization_version; + + bssl::ScopedEVP_MD_CTX hash_ctx; + // Write application data: + uint64_t app_data_len = application_data.size(); + const uint64_t parameter_version = 0; + // The format of the input to the hash function is as follows: + // - The application data, prefixed with a 64-bit length field. + // - Transport parameters: + // - A 64-bit version field indicating which version of encoding is used + // for transport parameters. + // - A list of 64-bit integers representing the relevant parameters. + // + // When changing which parameters are included, additional parameters can be + // added to the end of the list without changing the version field. New + // parameters that are variable length must be length prefixed. If + // parameters are removed from the list, the version field must be + // incremented. + // + // Integers happen to be written in host byte order, not network byte order. + if (!EVP_DigestInit(hash_ctx.get(), EVP_sha256()) || + !EVP_DigestUpdate(hash_ctx.get(), &app_data_len, sizeof(app_data_len)) || + !EVP_DigestUpdate(hash_ctx.get(), application_data.data(), + application_data.size()) || + !EVP_DigestUpdate(hash_ctx.get(), ¶meter_version, + sizeof(parameter_version))) { + QUIC_BUG << "Unexpected failure of EVP_Digest functions when hashing " + "Transport Parameters for ticket"; + return false; + } + + // Write transport parameters specified by draft-ietf-quic-transport-28, + // section 7.4.1, that are remembered for 0-RTT. + if (!DigestUpdateIntegerParam(hash_ctx.get(), in.initial_max_data) || + !DigestUpdateIntegerParam(hash_ctx.get(), + in.initial_max_stream_data_bidi_local) || + !DigestUpdateIntegerParam(hash_ctx.get(), + in.initial_max_stream_data_bidi_remote) || + !DigestUpdateIntegerParam(hash_ctx.get(), + in.initial_max_stream_data_uni) || + !DigestUpdateIntegerParam(hash_ctx.get(), in.initial_max_streams_bidi) || + !DigestUpdateIntegerParam(hash_ctx.get(), in.initial_max_streams_uni) || + !DigestUpdateIntegerParam(hash_ctx.get(), + in.active_connection_id_limit)) { + QUIC_BUG << "Unexpected failure of EVP_Digest functions when hashing " + "Transport Parameters for ticket"; + return false; + } + uint8_t disable_active_migration = in.disable_active_migration ? 1 : 0; + if (!EVP_DigestUpdate(hash_ctx.get(), &disable_active_migration, + sizeof(disable_active_migration)) || + !EVP_DigestFinal(hash_ctx.get(), out->data() + 1, nullptr)) { + QUIC_BUG << "Unexpected failure of EVP_Digest functions when hashing " + "Transport Parameters for ticket"; + return false; + } + return true; +} + } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.h b/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.h index 9dec484a552..093bb09de2a 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.h +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.h @@ -28,7 +28,7 @@ struct QUIC_EXPORT_PRIVATE TransportParameters { // The identifier used to differentiate transport parameters. enum TransportParameterId : uint64_t; // A map used to specify custom parameters. - using ParameterMap = QuicUnorderedMap<TransportParameterId, std::string>; + using ParameterMap = QuicHashMap<TransportParameterId, std::string>; // Represents an individual QUIC transport parameter that only encodes a // variable length integer. Can only be created inside the constructor for // TransportParameters. @@ -132,17 +132,17 @@ struct QUIC_EXPORT_PRIVATE TransportParameters { // The value of the Destination Connection ID field from the first // Initial packet sent by the client. - quiche::QuicheOptional<QuicConnectionId> original_connection_id; + quiche::QuicheOptional<QuicConnectionId> original_destination_connection_id; - // Idle timeout expressed in milliseconds. - IntegerParameter idle_timeout_milliseconds; + // Maximum idle timeout expressed in milliseconds. + IntegerParameter max_idle_timeout_ms; // Stateless reset token used in verifying stateless resets. std::vector<uint8_t> stateless_reset_token; // Limits the size of packets that the endpoint is willing to receive. // This indicates that packets larger than this limit will be dropped. - IntegerParameter max_packet_size; + IntegerParameter max_udp_payload_size; // Contains the initial value for the maximum amount of data that can // be sent on the connection. @@ -171,7 +171,7 @@ struct QUIC_EXPORT_PRIVATE TransportParameters { IntegerParameter max_ack_delay; // Indicates lack of support for connection migration. - bool disable_migration; + bool disable_active_migration; // Used to effect a change in server address at the end of the handshake. std::unique_ptr<PreferredAddress> preferred_address; @@ -180,6 +180,14 @@ struct QUIC_EXPORT_PRIVATE TransportParameters { // to store. IntegerParameter active_connection_id_limit; + // The value that the endpoint included in the Source Connection ID field of + // the first Initial packet it sent. + quiche::QuicheOptional<QuicConnectionId> initial_source_connection_id; + + // The value that the server included in the Source Connection ID field of a + // Retry packet it sent. + quiche::QuicheOptional<QuicConnectionId> retry_source_connection_id; + // Indicates support for the DATAGRAM frame and the maximum frame size that // the sender accepts. See draft-ietf-quic-datagram. IntegerParameter max_datagram_frame_size; @@ -194,6 +202,9 @@ struct QUIC_EXPORT_PRIVATE TransportParameters { // Google-specific user agent identifier. quiche::QuicheOptional<std::string> user_agent_id; + // Google-specific handshake done support. This is only used for T050. + bool support_handshake_done; + // Transport parameters used by Google QUIC but not IETF QUIC. This is // serialized into a TransportParameter struct with a TransportParameterId of // kGoogleQuicParamId. @@ -235,6 +246,19 @@ QUIC_EXPORT_PRIVATE bool ParseTransportParameters(ParsedQuicVersion version, TransportParameters* out, std::string* error_details); +// Serializes |in| and |application_data| in a deterministic format so that +// multiple calls to SerializeTransportParametersForTicket with the same inputs +// will generate the same output, and if the inputs differ, then the output will +// differ. The output of this function is used by the server in +// SSL_set_quic_early_data_context to determine whether early data should be +// accepted: Early data will only be accepted if the inputs to this function +// match what they were on the connection that issued an early data capable +// ticket. +QUIC_EXPORT_PRIVATE bool SerializeTransportParametersForTicket( + const TransportParameters& in, + const std::vector<uint8_t>& application_data, + std::vector<uint8_t>* out); + } // namespace quic #endif // QUICHE_QUIC_CORE_CRYPTO_TRANSPORT_PARAMETERS_H_ diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters_test.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters_test.cc index 1fc1f5c5c93..39919532dc6 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters_test.cc @@ -44,6 +44,7 @@ const uint64_t kFakeInitialRoundTripTime = 53; const uint8_t kFakePreferredStatelessResetTokenData[16] = { 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F}; +const bool kFakeSupportHandshakeDone = true; const auto kCustomParameter1 = static_cast<TransportParameters::TransportParameterId>(0xffcd); @@ -52,10 +53,18 @@ const auto kCustomParameter2 = static_cast<TransportParameters::TransportParameterId>(0xff34); const char* kCustomParameter2Value = "bar"; -QuicConnectionId CreateFakeOriginalConnectionId() { +QuicConnectionId CreateFakeOriginalDestinationConnectionId() { return TestConnectionId(0x1337); } +QuicConnectionId CreateFakeInitialSourceConnectionId() { + return TestConnectionId(0x2345); +} + +QuicConnectionId CreateFakeRetrySourceConnectionId() { + return TestConnectionId(0x9876); +} + QuicConnectionId CreateFakePreferredConnectionId() { return TestConnectionId(0xBEEF); } @@ -151,8 +160,8 @@ TEST_P(TransportParametersTest, Comparator) { new_params.perspective = Perspective::IS_CLIENT; orig_params.version = kFakeVersionLabel; new_params.version = kFakeVersionLabel; - orig_params.disable_migration = true; - new_params.disable_migration = true; + orig_params.disable_active_migration = true; + new_params.disable_active_migration = true; EXPECT_EQ(orig_params, new_params); EXPECT_TRUE(orig_params == new_params); EXPECT_FALSE(orig_params != new_params); @@ -172,12 +181,12 @@ TEST_P(TransportParametersTest, Comparator) { EXPECT_FALSE(orig_params != new_params); // Test comparison on IntegerParameters. - orig_params.max_packet_size.set_value(kFakeMaxPacketSize); - new_params.max_packet_size.set_value(kFakeMaxPacketSize + 1); + orig_params.max_udp_payload_size.set_value(kFakeMaxPacketSize); + new_params.max_udp_payload_size.set_value(kFakeMaxPacketSize + 1); EXPECT_NE(orig_params, new_params); EXPECT_FALSE(orig_params == new_params); EXPECT_TRUE(orig_params != new_params); - new_params.max_packet_size.set_value(kFakeMaxPacketSize); + new_params.max_udp_payload_size.set_value(kFakeMaxPacketSize); EXPECT_EQ(orig_params, new_params); EXPECT_TRUE(orig_params == new_params); EXPECT_FALSE(orig_params != new_params); @@ -222,6 +231,23 @@ TEST_P(TransportParametersTest, Comparator) { EXPECT_EQ(orig_params, new_params); EXPECT_TRUE(orig_params == new_params); EXPECT_FALSE(orig_params != new_params); + + // Test comparison on connection IDs. + orig_params.initial_source_connection_id = + CreateFakeInitialSourceConnectionId(); + new_params.initial_source_connection_id = QUICHE_NULLOPT; + EXPECT_NE(orig_params, new_params); + EXPECT_FALSE(orig_params == new_params); + EXPECT_TRUE(orig_params != new_params); + new_params.initial_source_connection_id = TestConnectionId(0xbadbad); + EXPECT_NE(orig_params, new_params); + EXPECT_FALSE(orig_params == new_params); + EXPECT_TRUE(orig_params != new_params); + new_params.initial_source_connection_id = + CreateFakeInitialSourceConnectionId(); + EXPECT_EQ(orig_params, new_params); + EXPECT_TRUE(orig_params == new_params); + EXPECT_FALSE(orig_params != new_params); } TEST_P(TransportParametersTest, CopyConstructor) { @@ -230,10 +256,11 @@ TEST_P(TransportParametersTest, CopyConstructor) { orig_params.version = kFakeVersionLabel; orig_params.supported_versions.push_back(kFakeVersionLabel); orig_params.supported_versions.push_back(kFakeVersionLabel2); - orig_params.original_connection_id = CreateFakeOriginalConnectionId(); - orig_params.idle_timeout_milliseconds.set_value(kFakeIdleTimeoutMilliseconds); + orig_params.original_destination_connection_id = + CreateFakeOriginalDestinationConnectionId(); + orig_params.max_idle_timeout_ms.set_value(kFakeIdleTimeoutMilliseconds); orig_params.stateless_reset_token = CreateFakeStatelessResetToken(); - orig_params.max_packet_size.set_value(kFakeMaxPacketSize); + orig_params.max_udp_payload_size.set_value(kFakeMaxPacketSize); orig_params.initial_max_data.set_value(kFakeInitialMaxData); orig_params.initial_max_stream_data_bidi_local.set_value( kFakeInitialMaxStreamDataBidiLocal); @@ -245,13 +272,17 @@ TEST_P(TransportParametersTest, CopyConstructor) { orig_params.initial_max_streams_uni.set_value(kFakeInitialMaxStreamsUni); orig_params.ack_delay_exponent.set_value(kFakeAckDelayExponent); orig_params.max_ack_delay.set_value(kFakeMaxAckDelay); - orig_params.disable_migration = kFakeDisableMigration; + orig_params.disable_active_migration = kFakeDisableMigration; orig_params.preferred_address = CreateFakePreferredAddress(); orig_params.active_connection_id_limit.set_value( kFakeActiveConnectionIdLimit); + orig_params.initial_source_connection_id = + CreateFakeInitialSourceConnectionId(); + orig_params.retry_source_connection_id = CreateFakeRetrySourceConnectionId(); orig_params.initial_round_trip_time_us.set_value(kFakeInitialRoundTripTime); orig_params.google_connection_options = CreateFakeGoogleConnectionOptions(); orig_params.user_agent_id = CreateFakeUserAgentId(); + orig_params.support_handshake_done = kFakeSupportHandshakeDone; orig_params.custom_parameters[kCustomParameter1] = kCustomParameter1Value; orig_params.custom_parameters[kCustomParameter2] = kCustomParameter2Value; @@ -263,8 +294,8 @@ TEST_P(TransportParametersTest, RoundTripClient) { TransportParameters orig_params; orig_params.perspective = Perspective::IS_CLIENT; orig_params.version = kFakeVersionLabel; - orig_params.idle_timeout_milliseconds.set_value(kFakeIdleTimeoutMilliseconds); - orig_params.max_packet_size.set_value(kFakeMaxPacketSize); + orig_params.max_idle_timeout_ms.set_value(kFakeIdleTimeoutMilliseconds); + orig_params.max_udp_payload_size.set_value(kFakeMaxPacketSize); orig_params.initial_max_data.set_value(kFakeInitialMaxData); orig_params.initial_max_stream_data_bidi_local.set_value( kFakeInitialMaxStreamDataBidiLocal); @@ -276,12 +307,15 @@ TEST_P(TransportParametersTest, RoundTripClient) { orig_params.initial_max_streams_uni.set_value(kFakeInitialMaxStreamsUni); orig_params.ack_delay_exponent.set_value(kFakeAckDelayExponent); orig_params.max_ack_delay.set_value(kFakeMaxAckDelay); - orig_params.disable_migration = kFakeDisableMigration; + orig_params.disable_active_migration = kFakeDisableMigration; orig_params.active_connection_id_limit.set_value( kFakeActiveConnectionIdLimit); + orig_params.initial_source_connection_id = + CreateFakeInitialSourceConnectionId(); orig_params.initial_round_trip_time_us.set_value(kFakeInitialRoundTripTime); orig_params.google_connection_options = CreateFakeGoogleConnectionOptions(); orig_params.user_agent_id = CreateFakeUserAgentId(); + orig_params.support_handshake_done = kFakeSupportHandshakeDone; orig_params.custom_parameters[kCustomParameter1] = kCustomParameter1Value; orig_params.custom_parameters[kCustomParameter2] = kCustomParameter2Value; @@ -305,10 +339,11 @@ TEST_P(TransportParametersTest, RoundTripServer) { orig_params.version = kFakeVersionLabel; orig_params.supported_versions.push_back(kFakeVersionLabel); orig_params.supported_versions.push_back(kFakeVersionLabel2); - orig_params.original_connection_id = CreateFakeOriginalConnectionId(); - orig_params.idle_timeout_milliseconds.set_value(kFakeIdleTimeoutMilliseconds); + orig_params.original_destination_connection_id = + CreateFakeOriginalDestinationConnectionId(); + orig_params.max_idle_timeout_ms.set_value(kFakeIdleTimeoutMilliseconds); orig_params.stateless_reset_token = CreateFakeStatelessResetToken(); - orig_params.max_packet_size.set_value(kFakeMaxPacketSize); + orig_params.max_udp_payload_size.set_value(kFakeMaxPacketSize); orig_params.initial_max_data.set_value(kFakeInitialMaxData); orig_params.initial_max_stream_data_bidi_local.set_value( kFakeInitialMaxStreamDataBidiLocal); @@ -320,10 +355,13 @@ TEST_P(TransportParametersTest, RoundTripServer) { orig_params.initial_max_streams_uni.set_value(kFakeInitialMaxStreamsUni); orig_params.ack_delay_exponent.set_value(kFakeAckDelayExponent); orig_params.max_ack_delay.set_value(kFakeMaxAckDelay); - orig_params.disable_migration = kFakeDisableMigration; + orig_params.disable_active_migration = kFakeDisableMigration; orig_params.preferred_address = CreateFakePreferredAddress(); orig_params.active_connection_id_limit.set_value( kFakeActiveConnectionIdLimit); + orig_params.initial_source_connection_id = + CreateFakeInitialSourceConnectionId(); + orig_params.retry_source_connection_id = CreateFakeRetrySourceConnectionId(); orig_params.google_connection_options = CreateFakeGoogleConnectionOptions(); std::vector<uint8_t> serialized; @@ -354,10 +392,10 @@ TEST_P(TransportParametersTest, AreValid) { params.perspective = Perspective::IS_CLIENT; EXPECT_TRUE(params.AreValid(&error_details)); EXPECT_TRUE(error_details.empty()); - params.idle_timeout_milliseconds.set_value(kFakeIdleTimeoutMilliseconds); + params.max_idle_timeout_ms.set_value(kFakeIdleTimeoutMilliseconds); EXPECT_TRUE(params.AreValid(&error_details)); EXPECT_TRUE(error_details.empty()); - params.idle_timeout_milliseconds.set_value(601000); + params.max_idle_timeout_ms.set_value(601000); EXPECT_TRUE(params.AreValid(&error_details)); EXPECT_TRUE(error_details.empty()); } @@ -367,27 +405,27 @@ TEST_P(TransportParametersTest, AreValid) { params.perspective = Perspective::IS_CLIENT; EXPECT_TRUE(params.AreValid(&error_details)); EXPECT_TRUE(error_details.empty()); - params.max_packet_size.set_value(1200); + params.max_udp_payload_size.set_value(1200); EXPECT_TRUE(params.AreValid(&error_details)); EXPECT_TRUE(error_details.empty()); - params.max_packet_size.set_value(65535); + params.max_udp_payload_size.set_value(65535); EXPECT_TRUE(params.AreValid(&error_details)); EXPECT_TRUE(error_details.empty()); - params.max_packet_size.set_value(9999999); + params.max_udp_payload_size.set_value(9999999); EXPECT_TRUE(params.AreValid(&error_details)); EXPECT_TRUE(error_details.empty()); - params.max_packet_size.set_value(0); + params.max_udp_payload_size.set_value(0); error_details = ""; EXPECT_FALSE(params.AreValid(&error_details)); - EXPECT_EQ( - error_details, - "Invalid transport parameters [Client max_packet_size 0 (Invalid)]"); - params.max_packet_size.set_value(1199); + EXPECT_EQ(error_details, + "Invalid transport parameters [Client max_udp_payload_size 0 " + "(Invalid)]"); + params.max_udp_payload_size.set_value(1199); error_details = ""; EXPECT_FALSE(params.AreValid(&error_details)); - EXPECT_EQ( - error_details, - "Invalid transport parameters [Client max_packet_size 1199 (Invalid)]"); + EXPECT_EQ(error_details, + "Invalid transport parameters [Client max_udp_payload_size 1199 " + "(Invalid)]"); } { TransportParameters params; @@ -436,9 +474,9 @@ TEST_P(TransportParametersTest, NoClientParamsWithStatelessResetToken) { TransportParameters orig_params; orig_params.perspective = Perspective::IS_CLIENT; orig_params.version = kFakeVersionLabel; - orig_params.idle_timeout_milliseconds.set_value(kFakeIdleTimeoutMilliseconds); + orig_params.max_idle_timeout_ms.set_value(kFakeIdleTimeoutMilliseconds); orig_params.stateless_reset_token = CreateFakeStatelessResetToken(); - orig_params.max_packet_size.set_value(kFakeMaxPacketSize); + orig_params.max_udp_payload_size.set_value(kFakeMaxPacketSize); std::vector<uint8_t> out; bool ok; @@ -452,12 +490,12 @@ TEST_P(TransportParametersTest, NoClientParamsWithStatelessResetToken) { TEST_P(TransportParametersTest, ParseClientParams) { // clang-format off const uint8_t kClientParamsOld[] = { - 0x00, 0x6a, // length of the parameters array that follows - // idle_timeout + 0x00, 0x7A, // length of the parameters array that follows + // max_idle_timeout 0x00, 0x01, // parameter id 0x00, 0x02, // length 0x6e, 0xec, // value - // max_packet_size + // max_udp_payload_size 0x00, 0x03, // parameter id 0x00, 0x02, // length 0x63, 0x29, // value @@ -493,13 +531,17 @@ TEST_P(TransportParametersTest, ParseClientParams) { 0x00, 0x0b, // parameter id 0x00, 0x01, // length 0x33, // value - // disable_migration + // disable_active_migration 0x00, 0x0c, // parameter id 0x00, 0x00, // length // active_connection_id_limit 0x00, 0x0e, // parameter id 0x00, 0x01, // length 0x34, // value + // initial_source_connection_id + 0x00, 0x0f, // parameter id + 0x00, 0x08, // length + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x45, // initial_round_trip_time_us 0x31, 0x27, // parameter id 0x00, 0x01, // length @@ -514,17 +556,20 @@ TEST_P(TransportParametersTest, ParseClientParams) { 0x31, 0x29, // parameter id 0x00, 0x08, // length 'F', 'a', 'k', 'e', 'U', 'A', 'I', 'D', // value + // support_handshake_done + 0x31, 0x2A, // parameter id + 0x00, 0x00, // value // Google version extension 0x47, 0x52, // parameter id 0x00, 0x04, // length 0x01, 0x23, 0x45, 0x67, // initial version }; const uint8_t kClientParams[] = { - // idle_timeout + // max_idle_timeout 0x01, // parameter id 0x02, // length 0x6e, 0xec, // value - // max_packet_size + // max_udp_payload_size 0x03, // parameter id 0x02, // length 0x63, 0x29, // value @@ -560,13 +605,17 @@ TEST_P(TransportParametersTest, ParseClientParams) { 0x0b, // parameter id 0x01, // length 0x33, // value - // disable_migration + // disable_active_migration 0x0c, // parameter id 0x00, // length // active_connection_id_limit 0x0e, // parameter id 0x01, // length 0x34, // value + // initial_source_connection_id + 0x0f, // parameter id + 0x08, // length + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x45, // initial_round_trip_time_us 0x71, 0x27, // parameter id 0x01, // length @@ -581,6 +630,9 @@ TEST_P(TransportParametersTest, ParseClientParams) { 0x71, 0x29, // parameter id 0x08, // length 'F', 'a', 'k', 'e', 'U', 'A', 'I', 'D', // value + // support_handshake_done + 0x71, 0x2A, // parameter id + 0x00, // length // Google version extension 0x80, 0x00, 0x47, 0x52, // parameter id 0x04, // length @@ -604,11 +656,11 @@ TEST_P(TransportParametersTest, ParseClientParams) { EXPECT_EQ(Perspective::IS_CLIENT, new_params.perspective); EXPECT_EQ(kFakeVersionLabel, new_params.version); EXPECT_TRUE(new_params.supported_versions.empty()); - EXPECT_FALSE(new_params.original_connection_id.has_value()); + EXPECT_FALSE(new_params.original_destination_connection_id.has_value()); EXPECT_EQ(kFakeIdleTimeoutMilliseconds, - new_params.idle_timeout_milliseconds.value()); + new_params.max_idle_timeout_ms.value()); EXPECT_TRUE(new_params.stateless_reset_token.empty()); - EXPECT_EQ(kFakeMaxPacketSize, new_params.max_packet_size.value()); + EXPECT_EQ(kFakeMaxPacketSize, new_params.max_udp_payload_size.value()); EXPECT_EQ(kFakeInitialMaxData, new_params.initial_max_data.value()); EXPECT_EQ(kFakeInitialMaxStreamDataBidiLocal, new_params.initial_max_stream_data_bidi_local.value()); @@ -622,9 +674,13 @@ TEST_P(TransportParametersTest, ParseClientParams) { new_params.initial_max_streams_uni.value()); EXPECT_EQ(kFakeAckDelayExponent, new_params.ack_delay_exponent.value()); EXPECT_EQ(kFakeMaxAckDelay, new_params.max_ack_delay.value()); - EXPECT_EQ(kFakeDisableMigration, new_params.disable_migration); + EXPECT_EQ(kFakeDisableMigration, new_params.disable_active_migration); EXPECT_EQ(kFakeActiveConnectionIdLimit, new_params.active_connection_id_limit.value()); + ASSERT_TRUE(new_params.initial_source_connection_id.has_value()); + EXPECT_EQ(CreateFakeInitialSourceConnectionId(), + new_params.initial_source_connection_id.value()); + EXPECT_FALSE(new_params.retry_source_connection_id.has_value()); EXPECT_EQ(kFakeInitialRoundTripTime, new_params.initial_round_trip_time_us.value()); ASSERT_TRUE(new_params.google_connection_options.has_value()); @@ -632,6 +688,7 @@ TEST_P(TransportParametersTest, ParseClientParams) { new_params.google_connection_options.value()); ASSERT_TRUE(new_params.user_agent_id.has_value()); EXPECT_EQ(CreateFakeUserAgentId(), new_params.user_agent_id.value()); + EXPECT_TRUE(new_params.support_handshake_done); } TEST_P(TransportParametersTest, @@ -639,7 +696,7 @@ TEST_P(TransportParametersTest, // clang-format off const uint8_t kClientParamsWithFullTokenOld[] = { 0x00, 0x26, // length parameters array that follows - // idle_timeout + // max_idle_timeout 0x00, 0x01, // parameter id 0x00, 0x02, // length 0x6e, 0xec, // value @@ -648,7 +705,7 @@ TEST_P(TransportParametersTest, 0x00, 0x10, // length 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, - // max_packet_size + // max_udp_payload_size 0x00, 0x03, // parameter id 0x00, 0x02, // length 0x63, 0x29, // value @@ -658,7 +715,7 @@ TEST_P(TransportParametersTest, 0x40, 0x65, // value }; const uint8_t kClientParamsWithFullToken[] = { - // idle_timeout + // max_idle_timeout 0x01, // parameter id 0x02, // length 0x6e, 0xec, // value @@ -667,7 +724,7 @@ TEST_P(TransportParametersTest, 0x10, // length 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, - // max_packet_size + // max_udp_payload_size 0x03, // parameter id 0x02, // length 0x63, 0x29, // value @@ -698,14 +755,14 @@ TEST_P(TransportParametersTest, // clang-format off const uint8_t kClientParamsWithEmptyTokenOld[] = { 0x00, 0x16, // length parameters array that follows - // idle_timeout + // max_idle_timeout 0x00, 0x01, // parameter id 0x00, 0x02, // length 0x6e, 0xec, // value // stateless_reset_token 0x00, 0x02, // parameter id 0x00, 0x00, - // max_packet_size + // max_udp_payload_size 0x00, 0x03, // parameter id 0x00, 0x02, // length 0x63, 0x29, // value @@ -715,14 +772,14 @@ TEST_P(TransportParametersTest, 0x40, 0x65, // value }; const uint8_t kClientParamsWithEmptyToken[] = { - // idle_timeout + // max_idle_timeout 0x01, // parameter id 0x02, // length 0x6e, 0xec, // value // stateless_reset_token 0x02, // parameter id 0x00, // length - // max_packet_size + // max_udp_payload_size 0x03, // parameter id 0x02, // length 0x63, 0x29, // value @@ -746,36 +803,36 @@ TEST_P(TransportParametersTest, client_params, client_params_length, &out_params, &error_details)); EXPECT_EQ(error_details, - "Received stateless reset token of invalid length 0"); + "Received stateless_reset_token of invalid length 0"); } TEST_P(TransportParametersTest, ParseClientParametersRepeated) { // clang-format off const uint8_t kClientParamsRepeatedOld[] = { 0x00, 0x12, // length parameters array that follows - // idle_timeout + // max_idle_timeout 0x00, 0x01, // parameter id 0x00, 0x02, // length 0x6e, 0xec, // value - // max_packet_size + // max_udp_payload_size 0x00, 0x03, // parameter id 0x00, 0x02, // length 0x63, 0x29, // value - // idle_timeout (repeated) + // max_idle_timeout (repeated) 0x00, 0x01, // parameter id 0x00, 0x02, // length 0x6e, 0xec, // value }; const uint8_t kClientParamsRepeated[] = { - // idle_timeout + // max_idle_timeout 0x01, // parameter id 0x02, // length 0x6e, 0xec, // value - // max_packet_size + // max_udp_payload_size 0x03, // parameter id 0x02, // length 0x63, 0x29, // value - // idle_timeout (repeated) + // max_idle_timeout (repeated) 0x01, // parameter id 0x02, // length 0x6e, 0xec, // value @@ -793,18 +850,18 @@ TEST_P(TransportParametersTest, ParseClientParametersRepeated) { EXPECT_FALSE(ParseTransportParameters(version_, Perspective::IS_CLIENT, client_params, client_params_length, &out_params, &error_details)); - EXPECT_EQ(error_details, "Received a second idle_timeout"); + EXPECT_EQ(error_details, "Received a second max_idle_timeout"); } TEST_P(TransportParametersTest, ParseServerParams) { // clang-format off const uint8_t kServerParamsOld[] = { - 0x00, 0xb7, // length of parameters array that follows - // original_connection_id + 0x00, 0xd3, // length of parameters array that follows + // original_destination_connection_id 0x00, 0x00, // parameter id 0x00, 0x08, // length 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x37, - // idle_timeout + // max_idle_timeout 0x00, 0x01, // parameter id 0x00, 0x02, // length 0x6e, 0xec, // value @@ -813,7 +870,7 @@ TEST_P(TransportParametersTest, ParseServerParams) { 0x00, 0x10, // length 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, - // max_packet_size + // max_udp_payload_size 0x00, 0x03, // parameter id 0x00, 0x02, // length 0x63, 0x29, // value @@ -849,7 +906,7 @@ TEST_P(TransportParametersTest, ParseServerParams) { 0x00, 0x0b, // parameter id 0x00, 0x01, // length 0x33, // value - // disable_migration + // disable_active_migration 0x00, 0x0c, // parameter id 0x00, 0x00, // length // preferred_address @@ -868,12 +925,23 @@ TEST_P(TransportParametersTest, ParseServerParams) { 0x00, 0x0e, // parameter id 0x00, 0x01, // length 0x34, // value + // initial_source_connection_id + 0x00, 0x0f, // parameter id + 0x00, 0x08, // length + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x45, + // retry_source_connection_id + 0x00, 0x10, // parameter id + 0x00, 0x08, // length + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x76, // google_connection_options 0x31, 0x28, // parameter id 0x00, 0x0c, // length 'A', 'L', 'P', 'N', // value 'E', 'F', 'G', 0x00, 'H', 'I', 'J', 0xff, + // support_handshake_done + 0x31, 0x2A, // parameter id + 0x00, 0x00, // value // Google version extension 0x47, 0x52, // parameter id 0x00, 0x0d, // length @@ -883,11 +951,11 @@ TEST_P(TransportParametersTest, ParseServerParams) { 0x89, 0xab, 0xcd, 0xef, }; const uint8_t kServerParams[] = { - // original_connection_id + // original_destination_connection_id 0x00, // parameter id 0x08, // length 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x37, - // idle_timeout + // max_idle_timeout 0x01, // parameter id 0x02, // length 0x6e, 0xec, // value @@ -896,7 +964,7 @@ TEST_P(TransportParametersTest, ParseServerParams) { 0x10, // length 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, - // max_packet_size + // max_udp_payload_size 0x03, // parameter id 0x02, // length 0x63, 0x29, // value @@ -932,7 +1000,7 @@ TEST_P(TransportParametersTest, ParseServerParams) { 0x0b, // parameter id 0x01, // length 0x33, // value - // disable_migration + // disable_active_migration 0x0c, // parameter id 0x00, // length // preferred_address @@ -951,12 +1019,23 @@ TEST_P(TransportParametersTest, ParseServerParams) { 0x0e, // parameter id 0x01, // length 0x34, // value + // initial_source_connection_id + 0x0f, // parameter id + 0x08, // length + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x45, + // retry_source_connection_id + 0x10, // parameter id + 0x08, // length + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x76, // google_connection_options 0x71, 0x28, // parameter id 0x0c, // length 'A', 'L', 'P', 'N', // value 'E', 'F', 'G', 0x00, 'H', 'I', 'J', 0xff, + // support_handshake_done + 0x71, 0x2A, // parameter id + 0x00, // length // Google version extension 0x80, 0x00, 0x47, 0x52, // parameter id 0x0d, // length @@ -985,13 +1064,13 @@ TEST_P(TransportParametersTest, ParseServerParams) { EXPECT_EQ(2u, new_params.supported_versions.size()); EXPECT_EQ(kFakeVersionLabel, new_params.supported_versions[0]); EXPECT_EQ(kFakeVersionLabel2, new_params.supported_versions[1]); - ASSERT_TRUE(new_params.original_connection_id.has_value()); - EXPECT_EQ(CreateFakeOriginalConnectionId(), - new_params.original_connection_id.value()); + ASSERT_TRUE(new_params.original_destination_connection_id.has_value()); + EXPECT_EQ(CreateFakeOriginalDestinationConnectionId(), + new_params.original_destination_connection_id.value()); EXPECT_EQ(kFakeIdleTimeoutMilliseconds, - new_params.idle_timeout_milliseconds.value()); + new_params.max_idle_timeout_ms.value()); EXPECT_EQ(CreateFakeStatelessResetToken(), new_params.stateless_reset_token); - EXPECT_EQ(kFakeMaxPacketSize, new_params.max_packet_size.value()); + EXPECT_EQ(kFakeMaxPacketSize, new_params.max_udp_payload_size.value()); EXPECT_EQ(kFakeInitialMaxData, new_params.initial_max_data.value()); EXPECT_EQ(kFakeInitialMaxStreamDataBidiLocal, new_params.initial_max_stream_data_bidi_local.value()); @@ -1005,7 +1084,7 @@ TEST_P(TransportParametersTest, ParseServerParams) { new_params.initial_max_streams_uni.value()); EXPECT_EQ(kFakeAckDelayExponent, new_params.ack_delay_exponent.value()); EXPECT_EQ(kFakeMaxAckDelay, new_params.max_ack_delay.value()); - EXPECT_EQ(kFakeDisableMigration, new_params.disable_migration); + EXPECT_EQ(kFakeDisableMigration, new_params.disable_active_migration); ASSERT_NE(nullptr, new_params.preferred_address.get()); EXPECT_EQ(CreateFakeV4SocketAddress(), new_params.preferred_address->ipv4_socket_address); @@ -1017,21 +1096,28 @@ TEST_P(TransportParametersTest, ParseServerParams) { new_params.preferred_address->stateless_reset_token); EXPECT_EQ(kFakeActiveConnectionIdLimit, new_params.active_connection_id_limit.value()); + ASSERT_TRUE(new_params.initial_source_connection_id.has_value()); + EXPECT_EQ(CreateFakeInitialSourceConnectionId(), + new_params.initial_source_connection_id.value()); + ASSERT_TRUE(new_params.retry_source_connection_id.has_value()); + EXPECT_EQ(CreateFakeRetrySourceConnectionId(), + new_params.retry_source_connection_id.value()); ASSERT_TRUE(new_params.google_connection_options.has_value()); EXPECT_EQ(CreateFakeGoogleConnectionOptions(), new_params.google_connection_options.value()); EXPECT_FALSE(new_params.user_agent_id.has_value()); + EXPECT_TRUE(new_params.support_handshake_done); } TEST_P(TransportParametersTest, ParseServerParametersRepeated) { // clang-format off const uint8_t kServerParamsRepeatedOld[] = { 0x00, 0x2c, // length of parameters array that follows - // original_connection_id + // original_destination_connection_id 0x00, 0x00, // parameter id 0x00, 0x08, // length 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x37, - // idle_timeout + // max_idle_timeout 0x00, 0x01, // parameter id 0x00, 0x02, // length 0x6e, 0xec, // value @@ -1040,17 +1126,17 @@ TEST_P(TransportParametersTest, ParseServerParametersRepeated) { 0x00, 0x10, // length 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, - // idle_timeout (repeated) + // max_idle_timeout (repeated) 0x00, 0x01, // parameter id 0x00, 0x02, // length 0x6e, 0xec, // value }; const uint8_t kServerParamsRepeated[] = { - // original_connection_id + // original_destination_connection_id 0x00, // parameter id 0x08, // length 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x37, - // idle_timeout + // max_idle_timeout 0x01, // parameter id 0x02, // length 0x6e, 0xec, // value @@ -1059,7 +1145,7 @@ TEST_P(TransportParametersTest, ParseServerParametersRepeated) { 0x10, // length 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, - // idle_timeout (repeated) + // max_idle_timeout (repeated) 0x01, // parameter id 0x02, // length 0x6e, 0xec, // value @@ -1077,7 +1163,7 @@ TEST_P(TransportParametersTest, ParseServerParametersRepeated) { EXPECT_FALSE(ParseTransportParameters(version_, Perspective::IS_SERVER, server_params, server_params_length, &out_params, &error_details)); - EXPECT_EQ(error_details, "Received a second idle_timeout"); + EXPECT_EQ(error_details, "Received a second max_idle_timeout"); } TEST_P(TransportParametersTest, @@ -1085,10 +1171,10 @@ TEST_P(TransportParametersTest, // clang-format off const uint8_t kServerParamsEmptyOriginalConnectionIdOld[] = { 0x00, 0x1e, // length of parameters array that follows - // original_connection_id + // original_destination_connection_id 0x00, 0x00, // parameter id 0x00, 0x00, // length - // idle_timeout + // max_idle_timeout 0x00, 0x01, // parameter id 0x00, 0x02, // length 0x6e, 0xec, // value @@ -1099,10 +1185,10 @@ TEST_P(TransportParametersTest, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, }; const uint8_t kServerParamsEmptyOriginalConnectionId[] = { - // original_connection_id + // original_destination_connection_id 0x00, // parameter id 0x00, // length - // idle_timeout + // max_idle_timeout 0x01, // parameter id 0x02, // length 0x6e, 0xec, // value @@ -1129,15 +1215,16 @@ TEST_P(TransportParametersTest, server_params, server_params_length, &out_params, &error_details)) << error_details; - ASSERT_TRUE(out_params.original_connection_id.has_value()); - EXPECT_EQ(out_params.original_connection_id.value(), EmptyQuicConnectionId()); + ASSERT_TRUE(out_params.original_destination_connection_id.has_value()); + EXPECT_EQ(out_params.original_destination_connection_id.value(), + EmptyQuicConnectionId()); } TEST_P(TransportParametersTest, CryptoHandshakeMessageRoundtrip) { TransportParameters orig_params; orig_params.perspective = Perspective::IS_CLIENT; orig_params.version = kFakeVersionLabel; - orig_params.max_packet_size.set_value(kFakeMaxPacketSize); + orig_params.max_udp_payload_size.set_value(kFakeMaxPacketSize); orig_params.google_quic_params = std::make_unique<CryptoHandshakeMessage>(); const std::string kTestString = "test string"; @@ -1166,7 +1253,132 @@ TEST_P(TransportParametersTest, CryptoHandshakeMessageRoundtrip) { IsQuicNoError()); EXPECT_EQ(test_value, kTestValue); EXPECT_EQ(kFakeVersionLabel, new_params.version); - EXPECT_EQ(kFakeMaxPacketSize, new_params.max_packet_size.value()); + EXPECT_EQ(kFakeMaxPacketSize, new_params.max_udp_payload_size.value()); +} + +TEST_P(TransportParametersTest, VeryLongCustomParameter) { + // Ensure we can handle a 70KB custom parameter on both send and receive. + size_t custom_value_length = 70000; + if (!version_.HasVarIntTransportParams()) { + // These versions encode lengths as uint16 so they cannot send as much. + custom_value_length = 65000; + } + std::string custom_value(custom_value_length, '?'); + TransportParameters orig_params; + orig_params.perspective = Perspective::IS_CLIENT; + orig_params.version = kFakeVersionLabel; + orig_params.custom_parameters[kCustomParameter1] = custom_value; + + std::vector<uint8_t> serialized; + ASSERT_TRUE(SerializeTransportParameters(version_, orig_params, &serialized)); + + TransportParameters new_params; + std::string error_details; + ASSERT_TRUE(ParseTransportParameters(version_, Perspective::IS_CLIENT, + serialized.data(), serialized.size(), + &new_params, &error_details)) + << error_details; + EXPECT_TRUE(error_details.empty()); + RemoveGreaseParameters(&new_params); + EXPECT_EQ(new_params, orig_params); +} + +class TransportParametersTicketSerializationTest : public QuicTest { + protected: + void SetUp() override { + original_params_.perspective = Perspective::IS_SERVER; + original_params_.version = kFakeVersionLabel; + original_params_.supported_versions.push_back(kFakeVersionLabel); + original_params_.supported_versions.push_back(kFakeVersionLabel2); + original_params_.original_destination_connection_id = + CreateFakeOriginalDestinationConnectionId(); + original_params_.max_idle_timeout_ms.set_value( + kFakeIdleTimeoutMilliseconds); + original_params_.stateless_reset_token = CreateFakeStatelessResetToken(); + original_params_.max_udp_payload_size.set_value(kFakeMaxPacketSize); + original_params_.initial_max_data.set_value(kFakeInitialMaxData); + original_params_.initial_max_stream_data_bidi_local.set_value( + kFakeInitialMaxStreamDataBidiLocal); + original_params_.initial_max_stream_data_bidi_remote.set_value( + kFakeInitialMaxStreamDataBidiRemote); + original_params_.initial_max_stream_data_uni.set_value( + kFakeInitialMaxStreamDataUni); + original_params_.initial_max_streams_bidi.set_value( + kFakeInitialMaxStreamsBidi); + original_params_.initial_max_streams_uni.set_value( + kFakeInitialMaxStreamsUni); + original_params_.ack_delay_exponent.set_value(kFakeAckDelayExponent); + original_params_.max_ack_delay.set_value(kFakeMaxAckDelay); + original_params_.disable_active_migration = kFakeDisableMigration; + original_params_.preferred_address = CreateFakePreferredAddress(); + original_params_.active_connection_id_limit.set_value( + kFakeActiveConnectionIdLimit); + original_params_.initial_source_connection_id = + CreateFakeInitialSourceConnectionId(); + original_params_.retry_source_connection_id = + CreateFakeRetrySourceConnectionId(); + original_params_.google_connection_options = + CreateFakeGoogleConnectionOptions(); + + ASSERT_TRUE(SerializeTransportParametersForTicket( + original_params_, application_state_, &original_serialized_params_)); + } + + TransportParameters original_params_; + std::vector<uint8_t> application_state_ = {0, 1}; + std::vector<uint8_t> original_serialized_params_; +}; + +TEST_F(TransportParametersTicketSerializationTest, + StatelessResetTokenDoesntChangeOutput) { + // Test that changing the stateless reset token doesn't change the ticket + // serialization. + TransportParameters new_params = original_params_; + new_params.stateless_reset_token = CreateFakePreferredStatelessResetToken(); + EXPECT_NE(new_params, original_params_); + + std::vector<uint8_t> serialized; + ASSERT_TRUE(SerializeTransportParametersForTicket( + new_params, application_state_, &serialized)); + EXPECT_EQ(original_serialized_params_, serialized); +} + +TEST_F(TransportParametersTicketSerializationTest, + ConnectionIDDoesntChangeOutput) { + // Changing original destination CID doesn't change serialization. + TransportParameters new_params = original_params_; + new_params.original_destination_connection_id = TestConnectionId(0xCAFE); + EXPECT_NE(new_params, original_params_); + + std::vector<uint8_t> serialized; + ASSERT_TRUE(SerializeTransportParametersForTicket( + new_params, application_state_, &serialized)); + EXPECT_EQ(original_serialized_params_, serialized); +} + +TEST_F(TransportParametersTicketSerializationTest, StreamLimitChangesOutput) { + // Changing a stream limit does change the serialization. + TransportParameters new_params = original_params_; + new_params.initial_max_stream_data_bidi_local.set_value( + kFakeInitialMaxStreamDataBidiLocal + 1); + EXPECT_NE(new_params, original_params_); + + std::vector<uint8_t> serialized; + ASSERT_TRUE(SerializeTransportParametersForTicket( + new_params, application_state_, &serialized)); + EXPECT_NE(original_serialized_params_, serialized); +} + +TEST_F(TransportParametersTicketSerializationTest, + ApplicationStateChangesOutput) { + // Changing the application state changes the serialization. + std::vector<uint8_t> new_application_state = {0}; + EXPECT_NE(new_application_state, application_state_); + + std::vector<uint8_t> serialized; + ASSERT_TRUE(SerializeTransportParametersForTicket( + original_params_, new_application_state, &serialized)); + EXPECT_NE(original_serialized_params_, serialized); } } // namespace test diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.cc new file mode 100644 index 00000000000..b8c7efafa98 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.cc @@ -0,0 +1,20 @@ +// Copyright (c) 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.h" +#include <cstdint> +#include <limits> + +namespace quic { + +std::ostream& operator<<(std::ostream& os, const QuicAckFrequencyFrame& frame) { + os << "{ control_frame_id: " << frame.control_frame_id + << ", sequence_number: " << frame.sequence_number + << ", packet_tolerance: " << frame.packet_tolerance + << ", max_ack_delay_ms: " << frame.max_ack_delay.ToMilliseconds() + << ", ignore_order: " << frame.ignore_order << " }\n"; + return os; +} + +} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.h b/chromium/net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.h new file mode 100644 index 00000000000..52b70daff2e --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.h @@ -0,0 +1,45 @@ +// Copyright (c) 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_FRAMES_QUIC_ACK_FREQUENCY_FRAME_H_ +#define QUICHE_QUIC_CORE_FRAMES_QUIC_ACK_FREQUENCY_FRAME_H_ + +#include <cstdint> +#include <ostream> + +#include "net/third_party/quiche/src/quic/core/quic_constants.h" +#include "net/third_party/quiche/src/quic/core/quic_time.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" + +namespace quic { + +// A frame that allows sender control of acknowledgement delays. +struct QUIC_EXPORT_PRIVATE QuicAckFrequencyFrame { + friend QUIC_EXPORT_PRIVATE std::ostream& operator<<( + std::ostream& os, + const QuicAckFrequencyFrame& ack_frequency_frame); + + // A unique identifier of this control frame. 0 when this frame is received, + // and non-zero when sent. + QuicControlFrameId control_frame_id = kInvalidControlFrameId; + + // If true, do not ack immediately upon observeation of packet reordering. + bool ignore_order = false; + + // Sequence number assigned to the ACK_FREQUENCY frame by the sender to allow + // receivers to ignore obsolete frames. + uint64_t sequence_number = 0; + + // The maximum number of ack-eliciting packets after which the receiver sends + // an acknowledgement. Invald if == 0. + uint64_t packet_tolerance = 0; + + // The maximum time that ack packets can be delayed. + QuicTime::Delta max_ack_delay = QuicTime::Delta::Zero(); +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_FRAMES_QUIC_ACK_FREQUENCY_FRAME_H_ diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_crypto_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_crypto_frame.cc index 81b3e18a6b2..bef5f286d23 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_crypto_frame.cc +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_crypto_frame.cc @@ -32,8 +32,7 @@ QuicCryptoFrame::~QuicCryptoFrame() {} std::ostream& operator<<(std::ostream& os, const QuicCryptoFrame& stream_frame) { - os << "{ level: " << EncryptionLevelToString(stream_frame.level) - << ", offset: " << stream_frame.offset + os << "{ level: " << stream_frame.level << ", offset: " << stream_frame.offset << ", length: " << stream_frame.data_length << " }\n"; return os; } diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_frame.cc index d40202f1930..99b0963a2dc 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_frame.cc +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_frame.cc @@ -6,6 +6,7 @@ #include "net/third_party/quiche/src/quic/core/quic_buffer_allocator.h" #include "net/third_party/quiche/src/quic/core/quic_constants.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" #include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" @@ -75,6 +76,9 @@ QuicFrame::QuicFrame(QuicMessageFrame* frame) QuicFrame::QuicFrame(QuicNewTokenFrame* frame) : type(NEW_TOKEN_FRAME), new_token_frame(frame) {} +QuicFrame::QuicFrame(QuicAckFrequencyFrame* frame) + : type(ACK_FREQUENCY_FRAME), ack_frequency_frame(frame) {} + void DeleteFrames(QuicFrames* frames) { for (QuicFrame& frame : *frames) { DeleteFrame(&frame); @@ -136,7 +140,9 @@ void DeleteFrame(QuicFrame* frame) { case NEW_TOKEN_FRAME: delete frame->new_token_frame; break; - + case ACK_FREQUENCY_FRAME: + delete frame->ack_frequency_frame; + break; case NUM_FRAME_TYPES: DCHECK(false) << "Cannot delete type: " << frame->type; } @@ -164,6 +170,7 @@ bool IsControlFrame(QuicFrameType type) { case PING_FRAME: case STOP_SENDING_FRAME: case HANDSHAKE_DONE_FRAME: + case ACK_FREQUENCY_FRAME: return true; default: return false; @@ -190,6 +197,8 @@ QuicControlFrameId GetControlFrameId(const QuicFrame& frame) { return frame.stop_sending_frame->control_frame_id; case HANDSHAKE_DONE_FRAME: return frame.handshake_done_frame.control_frame_id; + case ACK_FREQUENCY_FRAME: + return frame.ack_frequency_frame->control_frame_id; default: return kInvalidControlFrameId; } @@ -224,6 +233,9 @@ void SetControlFrameId(QuicControlFrameId control_frame_id, QuicFrame* frame) { case HANDSHAKE_DONE_FRAME: frame->handshake_done_frame.control_frame_id = control_frame_id; return; + case ACK_FREQUENCY_FRAME: + frame->ack_frequency_frame->control_frame_id = control_frame_id; + return; default: QUIC_BUG << "Try to set control frame id of a frame without control frame id"; @@ -261,6 +273,9 @@ QuicFrame CopyRetransmittableControlFrame(const QuicFrame& frame) { copy = QuicFrame( QuicHandshakeDoneFrame(frame.handshake_done_frame.control_frame_id)); break; + case ACK_FREQUENCY_FRAME: + copy = QuicFrame(new QuicAckFrequencyFrame(*frame.ack_frequency_frame)); + break; default: QUIC_BUG << "Try to copy a non-retransmittable control frame: " << frame; copy = QuicFrame(QuicPingFrame(kInvalidControlFrameId)); @@ -352,6 +367,9 @@ QuicFrame CopyQuicFrame(QuicBufferAllocator* allocator, copy = QuicFrame( QuicHandshakeDoneFrame(frame.handshake_done_frame.control_frame_id)); break; + case ACK_FREQUENCY_FRAME: + copy = QuicFrame(new QuicAckFrequencyFrame(*frame.ack_frequency_frame)); + break; default: QUIC_BUG << "Cannot copy frame: " << frame; copy = QuicFrame(QuicPingFrame(kInvalidControlFrameId)); @@ -451,6 +469,9 @@ std::ostream& operator<<(std::ostream& os, const QuicFrame& frame) { case HANDSHAKE_DONE_FRAME: os << "type { HANDSHAKE_DONE_FRAME } " << frame.handshake_done_frame; break; + case ACK_FREQUENCY_FRAME: + os << "type { ACK_FREQUENCY_FRAME } " << *(frame.ack_frequency_frame); + break; default: { QUIC_LOG(ERROR) << "Unknown frame type: " << frame.type; break; diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_frame.h b/chromium/net/third_party/quiche/src/quic/core/frames/quic_frame.h index 756b69f1db0..a8aabfc4ca5 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_frame.h +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_frame.h @@ -9,6 +9,7 @@ #include <vector> #include "net/third_party/quiche/src/quic/core/frames/quic_ack_frame.h" +#include "net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.h" #include "net/third_party/quiche/src/quic/core/frames/quic_blocked_frame.h" #include "net/third_party/quiche/src/quic/core/frames/quic_connection_close_frame.h" #include "net/third_party/quiche/src/quic/core/frames/quic_crypto_frame.h" @@ -62,6 +63,7 @@ struct QUIC_EXPORT_PRIVATE QuicFrame { explicit QuicFrame(QuicStopSendingFrame* frame); explicit QuicFrame(QuicMessageFrame* message_frame); explicit QuicFrame(QuicCryptoFrame* crypto_frame); + explicit QuicFrame(QuicAckFrequencyFrame* ack_frequency_frame); QUIC_EXPORT_PRIVATE friend std::ostream& operator<<(std::ostream& os, const QuicFrame& frame); @@ -102,6 +104,7 @@ struct QUIC_EXPORT_PRIVATE QuicFrame { QuicStopSendingFrame* stop_sending_frame; QuicMessageFrame* message_frame; QuicCryptoFrame* crypto_frame; + QuicAckFrequencyFrame* ack_frequency_frame; QuicNewTokenFrame* new_token_frame; }; }; diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_frames_test.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_frames_test.cc index 22322ed8ee2..3f04c8c0704 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_frames_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_frames_test.cc @@ -15,6 +15,7 @@ #include "net/third_party/quiche/src/quic/core/frames/quic_stream_frame.h" #include "net/third_party/quiche/src/quic/core/frames/quic_window_update_frame.h" #include "net/third_party/quiche/src/quic/core/quic_interval.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" #include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" #include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" @@ -243,6 +244,25 @@ TEST_F(QuicFramesTest, HandshakeDoneFrameToString) { EXPECT_TRUE(IsControlFrame(frame.type)); } +TEST_F(QuicFramesTest, QuicAckFreuqncyFrameToString) { + QuicAckFrequencyFrame ack_frequency_frame; + ack_frequency_frame.sequence_number = 1; + ack_frequency_frame.packet_tolerance = 2; + ack_frequency_frame.max_ack_delay = QuicTime::Delta::FromMilliseconds(25); + ack_frequency_frame.ignore_order = false; + QuicFrame frame(&ack_frequency_frame); + ASSERT_EQ(ACK_FREQUENCY_FRAME, frame.type); + SetControlFrameId(6, &frame); + EXPECT_EQ(6u, GetControlFrameId(frame)); + std::ostringstream stream; + stream << *frame.ack_frequency_frame; + EXPECT_EQ( + "{ control_frame_id: 6, sequence_number: 1, packet_tolerance: 2, " + "max_ack_delay_ms: 25, ignore_order: 0 }\n", + stream.str()); + EXPECT_TRUE(IsControlFrame(frame.type)); +} + TEST_F(QuicFramesTest, StreamFrameToString) { QuicStreamFrame frame; frame.stream_id = 1; @@ -558,6 +578,9 @@ TEST_F(QuicFramesTest, CopyQuicFrames) { case HANDSHAKE_DONE_FRAME: frames.push_back(QuicFrame(QuicHandshakeDoneFrame())); break; + case ACK_FREQUENCY_FRAME: + frames.push_back(QuicFrame(new QuicAckFrequencyFrame())); + break; default: ASSERT_TRUE(false) << "Please fix CopyQuicFrames if a new frame type is added."; diff --git a/chromium/net/third_party/quiche/src/quic/core/handshaker_delegate_interface.h b/chromium/net/third_party/quiche/src/quic/core/handshaker_delegate_interface.h index 0e8e0454483..bfc87610fd4 100644 --- a/chromium/net/third_party/quiche/src/quic/core/handshaker_delegate_interface.h +++ b/chromium/net/third_party/quiche/src/quic/core/handshaker_delegate_interface.h @@ -5,6 +5,7 @@ #ifndef QUICHE_QUIC_CORE_HANDSHAKER_DELEGATE_INTERFACE_H_ #define QUICHE_QUIC_CORE_HANDSHAKER_DELEGATE_INTERFACE_H_ +#include "net/third_party/quiche/src/quic/core/crypto/transport_parameters.h" #include "net/third_party/quiche/src/quic/core/quic_types.h" namespace quic { @@ -54,6 +55,22 @@ class QUIC_EXPORT_PRIVATE HandshakerDelegateInterface { // encryption level and 2) a server successfully processes a forward secure // packet. virtual void NeuterHandshakeData() = 0; + + // Called when 0-RTT data is rejected by the server. This is only called in + // TLS handshakes and only called on clients. + virtual void OnZeroRttRejected() = 0; + + // Fills in |params| with values from the delegate's QuicConfig. + // Returns whether the operation succeeded. + virtual bool FillTransportParameters(TransportParameters* params) = 0; + + // Read |params| and apply the values to the delegate's QuicConfig. + // On failure, returns a QuicErrorCode and saves a detailed error in + // |error_details|. + virtual QuicErrorCode ProcessTransportParameters( + const TransportParameters& params, + bool is_resumption, + std::string* error_details) = 0; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/http/end_to_end_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/end_to_end_test.cc index 782394427f4..8d274d03739 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/end_to_end_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/end_to_end_test.cc @@ -37,7 +37,9 @@ #include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h" #include "net/third_party/quiche/src/quic/test_tools/packet_dropping_test_writer.h" #include "net/third_party/quiche/src/quic/test_tools/packet_reordering_writer.h" +#include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_encoder_peer.h" #include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_encoder_test_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_header_table_peer.h" #include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_test_utils.h" #include "net/third_party/quiche/src/quic/test_tools/quic_client_peer.h" #include "net/third_party/quiche/src/quic/test_tools/quic_config_peer.h" @@ -55,6 +57,7 @@ #include "net/third_party/quiche/src/quic/test_tools/quic_test_server.h" #include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" #include "net/third_party/quiche/src/quic/test_tools/server_thread.h" +#include "net/third_party/quiche/src/quic/test_tools/simple_session_cache.h" #include "net/third_party/quiche/src/quic/tools/quic_backend_response.h" #include "net/third_party/quiche/src/quic/tools/quic_client.h" #include "net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.h" @@ -70,6 +73,9 @@ using spdy::SpdyFramer; using spdy::SpdyHeaderBlock; using spdy::SpdySerializedFrame; using spdy::SpdySettingsIR; +using ::testing::_; +using ::testing::Invoke; +using ::testing::NiceMock; namespace quic { namespace test { @@ -77,6 +83,7 @@ namespace { const char kFooResponseBody[] = "Artichoke hearts make me happy."; const char kBarResponseBody[] = "Palm hearts are pretty delicious, also."; +const char kTestUserAgentId[] = "quic/core/http/end_to_end_test.cc"; const float kSessionToStreamRatio = 1.5; // Run all tests with the cross products of all versions. @@ -191,6 +198,16 @@ class EndToEndTest : public QuicTestWithParam<TestParams> { AddToCache("/foo", 200, kFooResponseBody); AddToCache("/bar", 200, kBarResponseBody); + // Enable fixes for bugs found in tests and prod. + SetQuicReloadableFlag(quic_donot_change_queued_ack, true); + SetQuicReloadableFlag(quic_fix_last_inflight_packets_sent_time, true); + SetQuicReloadableFlag(quic_fix_server_pto_timeout, true); + SetQuicReloadableFlag(quic_do_not_retransmit_immediately_on_zero_rtt_reject, + true); + + SetQuicReloadableFlag(quic_support_handshake_done_in_t050, true); + SetQuicReloadableFlag(quic_enable_tls_resumption, true); + SetQuicReloadableFlag(quic_enable_zero_rtt_for_tls, true); } ~EndToEndTest() override { QuicRecyclePort(server_address_.port()); } @@ -203,7 +220,9 @@ class EndToEndTest : public QuicTestWithParam<TestParams> { QuicTestClient* client = new QuicTestClient(server_address_, server_hostname_, client_config_, client_supported_versions_, - crypto_test_utils::ProofVerifierForTesting()); + crypto_test_utils::ProofVerifierForTesting(), + std::make_unique<SimpleSessionCache>()); + client->SetUserAgentID(kTestUserAgentId); client->UseWriter(writer); if (!pre_shared_key_client_.empty()) { client->client()->SetPreSharedKey(pre_shared_key_client_); @@ -441,6 +460,13 @@ class EndToEndTest : public QuicTestWithParam<TestParams> { EXPECT_EQ(0u, server_stats.packets_lost); } EXPECT_EQ(0u, server_stats.packets_discarded); + if (GetQuicReloadableFlag(quic_save_user_agent_in_quic_session)) { + EXPECT_EQ( + GetServerSession()->user_agent_id().value_or("MissingUserAgent"), + kTestUserAgentId); + } else { + EXPECT_FALSE(GetServerSession()->user_agent_id().has_value()); + } // TODO(ianswett): Restore the check for packets_dropped equals 0. // The expect for packets received is equal to packets processed fails // due to version negotiation packets. @@ -529,7 +555,7 @@ INSTANTIATE_TEST_SUITE_P(EndToEndTests, TEST_P(EndToEndTest, HandshakeSuccessful) { ASSERT_TRUE(Initialize()); - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); server_thread_->WaitForCryptoHandshakeConfirmed(); QuicCryptoStream* crypto_stream = QuicSessionPeer::GetMutableCryptoStream(GetClientSession()); @@ -568,7 +594,7 @@ TEST_P(EndToEndTest, SimpleRequestResponse) { TEST_P(EndToEndTest, HandshakeConfirmed) { ASSERT_TRUE(Initialize()); - if (!version_.HasHandshakeDone()) { + if (!version_.UsesTls()) { return; } EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); @@ -599,44 +625,27 @@ TEST_P(EndToEndTest, SendAndReceiveCoalescedPackets) { // Simple transaction, but set a non-default ack delay at the client // and ensure it gets to the server. TEST_P(EndToEndTest, SimpleRequestResponseWithAckDelayChange) { - if (version_.UsesTls()) { - // TODO(b/155316241): Enable this test for TLS. - Initialize(); - return; - } // Force the ACK delay to be something other than the default. - // Note that it is sent only if doing IETF QUIC. - client_config_.SetMaxAckDelayToSendMs(kDefaultDelayedAckTimeMs + 100u); + constexpr uint32_t kClientMaxAckDelay = kDefaultDelayedAckTimeMs + 100u; + client_config_.SetMaxAckDelayToSendMs(kClientMaxAckDelay); ASSERT_TRUE(Initialize()); EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); EXPECT_EQ("200", client_->response_headers()->find(":status")->second); EXPECT_FALSE(client_->client()->EarlyDataAccepted()); EXPECT_FALSE(client_->client()->ReceivedInchoateReject()); - if (GetQuicReloadableFlag(quic_negotiate_ack_delay_time)) { - EXPECT_EQ(kDefaultDelayedAckTimeMs + 100u, - GetSentPacketManagerFromFirstServerSession() - ->peer_max_ack_delay() - .ToMilliseconds()); - } else { - EXPECT_EQ(kDefaultDelayedAckTimeMs, - GetSentPacketManagerFromFirstServerSession() - ->peer_max_ack_delay() - .ToMilliseconds()); - } + EXPECT_EQ(kClientMaxAckDelay, GetSentPacketManagerFromFirstServerSession() + ->peer_max_ack_delay() + .ToMilliseconds()); } // Simple transaction, but set a non-default ack exponent at the client // and ensure it gets to the server. TEST_P(EndToEndTest, SimpleRequestResponseWithAckExponentChange) { - if (version_.UsesTls()) { - // TODO(b/155316241): Enable this test for TLS. - Initialize(); - return; - } - const uint32_t kClientAckDelayExponent = kDefaultAckDelayExponent + 100u; + const uint32_t kClientAckDelayExponent = 19; + EXPECT_NE(kClientAckDelayExponent, kDefaultAckDelayExponent); // Force the ACK exponent to be something other than the default. - // Note that it is sent only if doing IETF QUIC. + // Note that it is sent only with QUIC+TLS. client_config_.SetAckDelayExponentToSend(kClientAckDelayExponent); ASSERT_TRUE(Initialize()); @@ -645,12 +654,12 @@ TEST_P(EndToEndTest, SimpleRequestResponseWithAckExponentChange) { EXPECT_FALSE(client_->client()->EarlyDataAccepted()); EXPECT_FALSE(client_->client()->ReceivedInchoateReject()); - if (VersionHasIetfQuicFrames(version_.transport_version)) { - // Should be only for IETF QUIC. + if (version_.UsesTls()) { + // Should be only sent with QUIC+TLS. EXPECT_EQ(kClientAckDelayExponent, GetServerConnection()->framer().peer_ack_delay_exponent()); } else { - // No change for Google QUIC. + // No change for QUIC_CRYPTO. EXPECT_EQ(kDefaultAckDelayExponent, GetServerConnection()->framer().peer_ack_delay_exponent()); } @@ -662,9 +671,9 @@ TEST_P(EndToEndTest, SimpleRequestResponseWithAckExponentChange) { TEST_P(EndToEndTest, SimpleRequestResponseForcedVersionNegotiation) { client_supported_versions_.insert(client_supported_versions_.begin(), QuicVersionReservedForNegotiation()); - testing::NiceMock<MockQuicConnectionDebugVisitor> visitor; + NiceMock<MockQuicConnectionDebugVisitor> visitor; connection_debug_visitor_ = &visitor; - EXPECT_CALL(visitor, OnVersionNegotiationPacket(testing::_)).Times(1); + EXPECT_CALL(visitor, OnVersionNegotiationPacket(_)).Times(1); ASSERT_TRUE(Initialize()); ASSERT_TRUE(ServerSendsVersionNegotiation()); @@ -1103,7 +1112,7 @@ TEST_P(EndToEndTest, PostMissingBytes) { TEST_P(EndToEndTest, LargePostNoPacketLoss) { ASSERT_TRUE(Initialize()); - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); // 1 MB body. std::string body(1024 * 1024, 'a'); @@ -1124,7 +1133,7 @@ TEST_P(EndToEndTest, LargePostNoPacketLoss1sRTT) { ASSERT_TRUE(Initialize()); SetPacketSendDelay(QuicTime::Delta::FromMilliseconds(1000)); - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); // 100 KB body. std::string body(100 * 1024, 'a'); @@ -1145,9 +1154,7 @@ TEST_P(EndToEndTest, LargePostWithPacketLoss) { // brutal. SetPacketLossPercentage(5); ASSERT_TRUE(Initialize()); - - // Wait for the server SHLO before upping the packet loss. - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForHandshakeConfirmed()); SetPacketLossPercentage(30); // 10 KB body. @@ -1166,9 +1173,7 @@ TEST_P(EndToEndTest, LargePostWithPacketLoss) { // Regression test for b/80090281. TEST_P(EndToEndTest, LargePostWithPacketLossAndAlwaysBundleWindowUpdates) { ASSERT_TRUE(Initialize()); - - // Wait for the server SHLO before upping the packet loss. - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForHandshakeConfirmed()); server_thread_->WaitForCryptoHandshakeConfirmed(); // Normally server only bundles a retransmittable frame once every other @@ -1199,9 +1204,7 @@ TEST_P(EndToEndTest, LargePostWithPacketLossAndBlockedSocket) { // b/10126687 is fixed, losing handshake packets is pretty brutal. SetPacketLossPercentage(5); ASSERT_TRUE(Initialize()); - - // Wait for the server SHLO before upping the packet loss. - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForHandshakeConfirmed()); SetPacketLossPercentage(10); client_writer_->set_fake_blocked_socket_percentage(10); @@ -1219,8 +1222,7 @@ TEST_P(EndToEndTest, LargePostWithPacketLossAndBlockedSocket) { TEST_P(EndToEndTest, LargePostNoPacketLossWithDelayAndReordering) { ASSERT_TRUE(Initialize()); - - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForHandshakeConfirmed()); // Both of these must be called when the writer is not actively used. SetPacketSendDelay(QuicTime::Delta::FromMilliseconds(2)); SetReorderPercentage(30); @@ -1238,11 +1240,6 @@ TEST_P(EndToEndTest, LargePostNoPacketLossWithDelayAndReordering) { } TEST_P(EndToEndTest, LargePostZeroRTTFailure) { - if (version_.UsesTls()) { - // TODO(b/152551499): Re-enable this test when TLS supports 0-RTT. - Initialize(); - return; - } // Send a request and then disconnect. This prepares the client to attempt // a 0-RTT handshake for the next request. ASSERT_TRUE(Initialize()); @@ -1265,7 +1262,7 @@ TEST_P(EndToEndTest, LargePostZeroRTTFailure) { // The 0-RTT handshake should succeed. client_->Connect(); - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); ASSERT_TRUE(client_->client()->connected()); EXPECT_EQ(kFooResponseBody, client_->SendCustomSynchronousRequest(headers, body)); @@ -1281,7 +1278,7 @@ TEST_P(EndToEndTest, LargePostZeroRTTFailure) { StartServer(); client_->Connect(); - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); ASSERT_TRUE(client_->client()->connected()); EXPECT_EQ(kFooResponseBody, client_->SendCustomSynchronousRequest(headers, body)); @@ -1294,11 +1291,6 @@ TEST_P(EndToEndTest, LargePostZeroRTTFailure) { } TEST_P(EndToEndTest, SynchronousRequestZeroRTTFailure) { - if (version_.UsesTls()) { - // TODO(b/152551499): Re-enable this test when TLS supports 0-RTT. - Initialize(); - return; - } // Send a request and then disconnect. This prepares the client to attempt // a 0-RTT handshake for the next request. ASSERT_TRUE(Initialize()); @@ -1313,7 +1305,7 @@ TEST_P(EndToEndTest, SynchronousRequestZeroRTTFailure) { // The 0-RTT handshake should succeed. client_->Connect(); - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); ASSERT_TRUE(client_->client()->connected()); EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); @@ -1328,7 +1320,7 @@ TEST_P(EndToEndTest, SynchronousRequestZeroRTTFailure) { StartServer(); client_->Connect(); - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); ASSERT_TRUE(client_->client()->connected()); EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); @@ -1360,14 +1352,10 @@ TEST_P(EndToEndTest, LargePostSynchronousRequest) { EXPECT_FALSE(client_->client()->ReceivedInchoateReject()); client_->Disconnect(); - if (version_.UsesTls()) { - // TODO(b/152551499): remove this when TLS supports 0-RTT. - return; - } // The 0-RTT handshake should succeed. client_->Connect(); - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); ASSERT_TRUE(client_->client()->connected()); EXPECT_EQ(kFooResponseBody, client_->SendCustomSynchronousRequest(headers, body)); @@ -1383,7 +1371,7 @@ TEST_P(EndToEndTest, LargePostSynchronousRequest) { StartServer(); client_->Connect(); - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); ASSERT_TRUE(client_->client()->connected()); EXPECT_EQ(kFooResponseBody, client_->SendCustomSynchronousRequest(headers, body)); @@ -1413,7 +1401,7 @@ TEST_P(EndToEndTest, SetInitialReceivedConnectionOptions) { initial_received_options)); ASSERT_TRUE(Initialize()); - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); server_thread_->WaitForCryptoHandshakeConfirmed(); EXPECT_FALSE(server_config_.SetInitialReceivedConnectionOptions( @@ -1438,7 +1426,7 @@ TEST_P(EndToEndTest, LargePostSmallBandwidthLargeBuffer) { server_writer_->set_max_bandwidth_and_buffer_size( QuicBandwidth::FromBytesPerSecond(256 * 1024), 256 * 1024); - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); // 1 MB body. std::string body(1024 * 1024, 'a'); @@ -1462,7 +1450,7 @@ TEST_P(EndToEndTest, DoNotSetSendAlarmIfConnectionFlowControlBlocked) { // an infinite loop in the EpollServer, as the alarm fires and is immediately // rescheduled. ASSERT_TRUE(Initialize()); - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); // Ensure both stream and connection level are flow control blocked by setting // the send window offset to 0. @@ -1498,7 +1486,7 @@ TEST_P(EndToEndTest, DoNotSetSendAlarmIfConnectionFlowControlBlocked) { TEST_P(EndToEndTest, InvalidStream) { ASSERT_TRUE(Initialize()); - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); std::string body(kMaxOutgoingPacketSize, 'a'); SpdyHeaderBlock headers; @@ -1523,7 +1511,7 @@ TEST_P(EndToEndTest, InvalidStream) { // with overly large headers. TEST_P(EndToEndTest, LargeHeaders) { ASSERT_TRUE(Initialize()); - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); std::string body(kMaxOutgoingPacketSize, 'a'); SpdyHeaderBlock headers; @@ -1552,7 +1540,7 @@ TEST_P(EndToEndTest, LargeHeaders) { TEST_P(EndToEndTest, EarlyResponseWithQuicStreamNoError) { ASSERT_TRUE(Initialize()); - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); std::string large_body(1024 * 1024, 'a'); SpdyHeaderBlock headers; @@ -1618,7 +1606,7 @@ TEST_P(EndToEndTest, MaxDynamicStreamsLimitRespected) { // not properly set up. return; } - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); // Make the client misbehave after negotiation. const int kServerMaxStreams = kMaxStreamsMinimumIncrement + 1; @@ -1654,7 +1642,7 @@ TEST_P(EndToEndTest, SetIndependentMaxDynamicStreamsLimits) { server_config_.SetMaxUnidirectionalStreamsToSend(kServerMaxDynamicStreams); ASSERT_TRUE(Initialize()); - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); // The client has received the server's limit and vice versa. QuicSpdyClientSession* client_session = GetClientSession(); @@ -1711,7 +1699,7 @@ TEST_P(EndToEndTest, SetIndependentMaxDynamicStreamsLimits) { TEST_P(EndToEndTest, NegotiateCongestionControl) { ASSERT_TRUE(Initialize()); - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); CongestionControlType expected_congestion_control_type = kRenoBytes; switch (GetParam().congestion_control_tag) { @@ -1745,7 +1733,7 @@ TEST_P(EndToEndTest, ClientSuggestsRTT) { client_config_.SetInitialRoundTripTimeUsToSend(kInitialRTT.ToMicroseconds()); ASSERT_TRUE(Initialize()); - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); server_thread_->WaitForCryptoHandshakeConfirmed(); // Pause the server so we can access the server's internals without races. @@ -1774,7 +1762,7 @@ TEST_P(EndToEndTest, ClientSuggestsIgnoredRTT) { client_config_.SetConnectionOptionsToSend(options); ASSERT_TRUE(Initialize()); - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); server_thread_->WaitForCryptoHandshakeConfirmed(); // Pause the server so we can access the server's internals without races. @@ -1801,7 +1789,7 @@ TEST_P(EndToEndTest, MaxInitialRTT) { kMaxInitialRoundTripTimeUs); ASSERT_TRUE(Initialize()); - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); server_thread_->WaitForCryptoHandshakeConfirmed(); // Pause the server so we can access the server's internals without races. @@ -1827,7 +1815,7 @@ TEST_P(EndToEndTest, MinInitialRTT) { client_config_.SetInitialRoundTripTimeUsToSend(0); ASSERT_TRUE(Initialize()); - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); server_thread_->WaitForCryptoHandshakeConfirmed(); // Pause the server so we can access the server's internals without races. @@ -1908,7 +1896,7 @@ TEST_P(EndToEndTest, ResetConnection) { EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); EXPECT_EQ("200", client_->response_headers()->find(":status")->second); client_->ResetConnection(); - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); EXPECT_EQ(kBarResponseBody, client_->SendSynchronousRequest("/bar")); EXPECT_EQ("200", client_->response_headers()->find(":status")->second); } @@ -1923,7 +1911,7 @@ TEST_P(EndToEndTest, MaxStreamsUberTest) { AddToCache("/large_response", 200, large_body); - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); SetPacketLossPercentage(10); for (int i = 0; i < max_streams; ++i) { @@ -1942,7 +1930,7 @@ TEST_P(EndToEndTest, StreamCancelErrorTest) { AddToCache("/small_response", 200, small_body); - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); QuicSession* session = GetClientSession(); // Lose the request. @@ -1952,11 +1940,7 @@ TEST_P(EndToEndTest, StreamCancelErrorTest) { // Transmit the cancel, and ensure the connection is torn down properly. SetPacketLossPercentage(0); QuicStreamId stream_id = GetNthClientInitiatedBidirectionalId(0); - if (session->break_close_loop()) { - session->ResetStream(stream_id, QUIC_STREAM_CANCELLED, 0); - } else { - session->SendRstStream(stream_id, QUIC_STREAM_CANCELLED, 0); - } + session->ResetStream(stream_id, QUIC_STREAM_CANCELLED, 0); // WaitForEvents waits 50ms and returns true if there are outstanding // requests. @@ -2050,7 +2034,7 @@ TEST_P(EndToEndTest, NegotiatedInitialCongestionWindow) { ASSERT_TRUE(Initialize()); // Values are exchanged during crypto handshake, so wait for that to finish. - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); server_thread_->WaitForCryptoHandshakeConfirmed(); server_thread_->Pause(); @@ -2060,11 +2044,6 @@ TEST_P(EndToEndTest, NegotiatedInitialCongestionWindow) { } TEST_P(EndToEndTest, DifferentFlowControlWindows) { - if (version_.UsesTls()) { - // TODO(b/155316241): Enable this test for TLS. - Initialize(); - return; - } // Client and server can set different initial flow control receive windows. // These are sent in CHLO/SHLO. Tests that these values are exchanged properly // in the crypto handshake. @@ -2081,7 +2060,7 @@ TEST_P(EndToEndTest, DifferentFlowControlWindows) { ASSERT_TRUE(Initialize()); // Values are exchanged during crypto handshake, so wait for that to finish. - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); server_thread_->WaitForCryptoHandshakeConfirmed(); // Open a data stream to make sure the stream level flow control is updated. @@ -2089,17 +2068,28 @@ TEST_P(EndToEndTest, DifferentFlowControlWindows) { WriteHeadersOnStream(stream); stream->WriteOrBufferBody("hello", false); - // Client should have the right values for server's receive window. - EXPECT_EQ(kServerStreamIFCW, - client_->client() - ->client_session() - ->config() - ->ReceivedInitialStreamFlowControlWindowBytes()); - EXPECT_EQ(kServerSessionIFCW, - client_->client() - ->client_session() - ->config() - ->ReceivedInitialSessionFlowControlWindowBytes()); + if (!version_.UsesTls()) { + // IFWA only exists with QUIC_CRYPTO. + // Client should have the right values for server's receive window. + ASSERT_TRUE(client_->client() + ->client_session() + ->config() + ->HasReceivedInitialStreamFlowControlWindowBytes()); + EXPECT_EQ(kServerStreamIFCW, + client_->client() + ->client_session() + ->config() + ->ReceivedInitialStreamFlowControlWindowBytes()); + ASSERT_TRUE(client_->client() + ->client_session() + ->config() + ->HasReceivedInitialSessionFlowControlWindowBytes()); + EXPECT_EQ(kServerSessionIFCW, + client_->client() + ->client_session() + ->config() + ->ReceivedInitialSessionFlowControlWindowBytes()); + } EXPECT_EQ(kServerStreamIFCW, QuicFlowControllerPeer::SendWindowOffset( stream->flow_controller())); EXPECT_EQ(kServerSessionIFCW, QuicFlowControllerPeer::SendWindowOffset( @@ -2107,23 +2097,24 @@ TEST_P(EndToEndTest, DifferentFlowControlWindows) { // Server should have the right values for client's receive window. server_thread_->Pause(); - QuicSession* session = GetServerSession(); - EXPECT_EQ(kClientStreamIFCW, - session->config()->ReceivedInitialStreamFlowControlWindowBytes()); - EXPECT_EQ(kClientSessionIFCW, - session->config()->ReceivedInitialSessionFlowControlWindowBytes()); + QuicConfig server_config = *GetServerSession()->config(); EXPECT_EQ(kClientSessionIFCW, QuicFlowControllerPeer::SendWindowOffset( - session->flow_controller())); + GetServerSession()->flow_controller())); server_thread_->Resume(); + if (version_.UsesTls()) { + // IFWA only exists with QUIC_CRYPTO. + return; + } + ASSERT_TRUE(server_config.HasReceivedInitialStreamFlowControlWindowBytes()); + EXPECT_EQ(kClientStreamIFCW, + server_config.ReceivedInitialStreamFlowControlWindowBytes()); + ASSERT_TRUE(server_config.HasReceivedInitialSessionFlowControlWindowBytes()); + EXPECT_EQ(kClientSessionIFCW, + server_config.ReceivedInitialSessionFlowControlWindowBytes()); } // Test negotiation of IFWA connection option. TEST_P(EndToEndTest, NegotiatedServerInitialFlowControlWindow) { - if (version_.UsesTls()) { - // TODO(b/155316241): Enable this test for TLS. - Initialize(); - return; - } const uint32_t kClientStreamIFCW = 123456; const uint32_t kClientSessionIFCW = 234567; set_client_initial_stream_flow_control_receive_window(kClientStreamIFCW); @@ -2142,7 +2133,7 @@ TEST_P(EndToEndTest, NegotiatedServerInitialFlowControlWindow) { ASSERT_TRUE(Initialize()); // Values are exchanged during crypto handshake, so wait for that to finish. - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); server_thread_->WaitForCryptoHandshakeConfirmed(); // Open a data stream to make sure the stream level flow control is updated. @@ -2150,17 +2141,28 @@ TEST_P(EndToEndTest, NegotiatedServerInitialFlowControlWindow) { WriteHeadersOnStream(stream); stream->WriteOrBufferBody("hello", false); - // Client should have the right values for server's receive window. - EXPECT_EQ(kExpectedStreamIFCW, - client_->client() - ->client_session() - ->config() - ->ReceivedInitialStreamFlowControlWindowBytes()); - EXPECT_EQ(kExpectedSessionIFCW, - client_->client() - ->client_session() - ->config() - ->ReceivedInitialSessionFlowControlWindowBytes()); + if (!version_.UsesTls()) { + // IFWA only exists with QUIC_CRYPTO. + // Client should have the right values for server's receive window. + ASSERT_TRUE(client_->client() + ->client_session() + ->config() + ->HasReceivedInitialStreamFlowControlWindowBytes()); + EXPECT_EQ(kExpectedStreamIFCW, + client_->client() + ->client_session() + ->config() + ->ReceivedInitialStreamFlowControlWindowBytes()); + ASSERT_TRUE(client_->client() + ->client_session() + ->config() + ->HasReceivedInitialSessionFlowControlWindowBytes()); + EXPECT_EQ(kExpectedSessionIFCW, + client_->client() + ->client_session() + ->config() + ->ReceivedInitialSessionFlowControlWindowBytes()); + } EXPECT_EQ(kExpectedStreamIFCW, QuicFlowControllerPeer::SendWindowOffset( stream->flow_controller())); EXPECT_EQ(kExpectedSessionIFCW, QuicFlowControllerPeer::SendWindowOffset( @@ -2182,7 +2184,7 @@ TEST_P(EndToEndTest, HeadersAndCryptoStreamsNoConnectionFlowControl) { // Wait for crypto handshake to finish. This should have contributed to the // crypto stream flow control window, but not affected the session flow // control window. - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); server_thread_->WaitForCryptoHandshakeConfirmed(); QuicCryptoStream* crypto_stream = @@ -2236,7 +2238,7 @@ TEST_P(EndToEndTest, FlowControlsSynced) { ASSERT_TRUE(Initialize()); - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); server_thread_->WaitForCryptoHandshakeConfirmed(); QuicSpdySession* const client_session = GetClientSession(); @@ -2353,28 +2355,26 @@ TEST_P(EndToEndTest, RequestWithNoBodyWillNeverSendStreamFrameWithFIN) { server_thread_->Resume(); } -// A TestAckListener verifies that exactly |bytes_to_ack| bytes are acked during -// its lifetime. +// TestAckListener counts how many bytes are acked during its lifetime. class TestAckListener : public QuicAckListenerInterface { public: - explicit TestAckListener(int bytes_to_ack) : bytes_to_ack_(bytes_to_ack) {} + TestAckListener() {} void OnPacketAcked(int acked_bytes, QuicTime::Delta /*delta_largest_observed*/) override { - ASSERT_LE(acked_bytes, bytes_to_ack_); - bytes_to_ack_ -= acked_bytes; + total_bytes_acked_ += acked_bytes; } void OnPacketRetransmitted(int /*retransmitted_bytes*/) override {} - bool has_been_notified() const { return bytes_to_ack_ == 0; } + int total_bytes_acked() const { return total_bytes_acked_; } protected: // Object is ref counted. - ~TestAckListener() override { EXPECT_EQ(0, bytes_to_ack_); } + ~TestAckListener() override {} private: - int bytes_to_ack_; + int total_bytes_acked_ = 0; }; class TestResponseListener : public QuicSpdyClientBase::ResponseListener { @@ -2388,22 +2388,35 @@ class TestResponseListener : public QuicSpdyClientBase::ResponseListener { } }; -// TODO(dschinazi) Fix this test's flakiness in Chrome. -TEST_P( - EndToEndTest, - QUIC_TEST_DISABLED_IN_CHROME(AckNotifierWithPacketLossAndBlockedSocket)) { +TEST_P(EndToEndTest, AckNotifierWithPacketLossAndBlockedSocket) { // Verify that even in the presence of packet loss and occasionally blocked // socket, an AckNotifierDelegate will get informed that the data it is // interested in has been ACKed. This tests end-to-end ACK notification, and // demonstrates that retransmissions do not break this functionality. SetPacketLossPercentage(5); ASSERT_TRUE(Initialize()); - // Wait for the server SHLO before upping the packet loss. - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForHandshakeConfirmed()); SetPacketLossPercentage(30); client_writer_->set_fake_blocked_socket_percentage(10); + // Wait for SETTINGS frame from server that sets QPACK dynamic table capacity + // to make sure request headers will be compressed using the dynamic table. + if (version_.UsesHttp3()) { + while (true) { + // Waits for up to 50 ms. + client_->client()->WaitForEvents(); + if (!GetClientSession() || !GetClientSession()->qpack_encoder()) { + continue; + } + QpackHeaderTable* header_table = + QpackEncoderPeer::header_table(GetClientSession()->qpack_encoder()); + if (QpackHeaderTablePeer::dynamic_table_capacity(header_table) > 0) { + break; + } + } + } + // Create a POST request and send the headers only. SpdyHeaderBlock headers; headers[":method"] = "POST"; @@ -2413,14 +2426,11 @@ TEST_P( client_->SendMessage(headers, "", /*fin=*/false); - // Size of headers on the request stream. Zero if headers are sent on the - // header stream. + // Size of headers on the request stream. This is zero if headers are sent on + // the header stream. size_t header_size = 0; - if (VersionUsesHttp3(client_->client() - ->client_session() - ->connection() - ->transport_version())) { - // Determine size of compressed headers. + if (version_.UsesHttp3()) { + // Determine size of headers after QPACK compression in both scenarios. NoopDecoderStreamErrorDelegate decoder_stream_error_delegate; NoopQpackStreamSenderDelegate encoder_stream_sender_delegate; QpackEncoder qpack_encoder(&decoder_stream_error_delegate); @@ -2432,8 +2442,8 @@ TEST_P( qpack_encoder.SetDynamicTableCapacity(kDefaultQpackMaxDynamicTableCapacity); qpack_encoder.SetMaximumBlockedStreams(kDefaultMaximumBlockedStreams); - std::string encoded_headers = - qpack_encoder.EncodeHeaderList(/* stream_id = */ 0, headers, nullptr); + std::string encoded_headers = qpack_encoder.EncodeHeaderList( + /* stream_id = */ 0, headers, nullptr); header_size = encoded_headers.size(); } @@ -2442,9 +2452,11 @@ TEST_P( std::string request_string = "a request body bigger than one packet" + std::string(kMaxOutgoingPacketSize, '.'); + const int expected_bytes_acked = header_size + request_string.length(); + // The TestAckListener will cause a failure if not notified. QuicReferenceCountedPointer<TestAckListener> ack_listener( - new TestAckListener(header_size + request_string.length())); + new TestAckListener()); // Send the request, and register the delegate for ACKs. client_->SendData(request_string, true, ack_listener); @@ -2456,17 +2468,20 @@ TEST_P( client_->SendSynchronousRequest("/bar"); // Make sure the delegate does get the notification it expects. - while (!ack_listener->has_been_notified()) { + while (ack_listener->total_bytes_acked() < expected_bytes_acked) { // Waits for up to 50 ms. client_->client()->WaitForEvents(); } + EXPECT_EQ(ack_listener->total_bytes_acked(), expected_bytes_acked) + << " header_size " << header_size << " request length " + << request_string.length(); } // Send a public reset from the server. TEST_P(EndToEndTest, ServerSendPublicReset) { ASSERT_TRUE(Initialize()); - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); QuicConnection* client_connection = GetClientConnection(); QuicConfig* config = client_->client()->session()->config(); EXPECT_TRUE(config->HasReceivedStatelessResetToken()); @@ -2504,7 +2519,7 @@ TEST_P(EndToEndTest, ServerSendPublicReset) { TEST_P(EndToEndTest, ServerSendPublicResetWithDifferentConnectionId) { ASSERT_TRUE(Initialize()); - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); QuicConnection* client_connection = GetClientConnection(); QuicConfig* config = client_->client()->session()->config(); EXPECT_TRUE(config->HasReceivedStatelessResetToken()); @@ -2517,7 +2532,7 @@ TEST_P(EndToEndTest, ServerSendPublicResetWithDifferentConnectionId) { QuicFramer framer(server_supported_versions_, QuicTime::Zero(), Perspective::IS_SERVER, kQuicDefaultConnectionIdLength); std::unique_ptr<QuicEncryptedPacket> packet; - testing::NiceMock<MockQuicConnectionDebugVisitor> visitor; + NiceMock<MockQuicConnectionDebugVisitor> visitor; GetClientConnection()->set_debug_visitor(&visitor); if (VersionHasIetfInvariantHeader(client_connection->transport_version())) { packet = framer.BuildIetfStatelessResetPacket(incorrect_connection_id, @@ -2581,7 +2596,7 @@ TEST_P(EndToEndTest, ClientSendPublicResetWithDifferentConnectionId) { TEST_P(EndToEndTest, ServerSendVersionNegotiationWithDifferentConnectionId) { ASSERT_TRUE(Initialize()); - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); // Send the version negotiation packet. QuicConnection* client_connection = GetClientConnection(); @@ -2593,7 +2608,7 @@ TEST_P(EndToEndTest, ServerSendVersionNegotiationWithDifferentConnectionId) { VersionHasIetfInvariantHeader(client_connection->transport_version()), client_connection->version().HasLengthPrefixedConnectionIds(), server_supported_versions_)); - testing::NiceMock<MockQuicConnectionDebugVisitor> visitor; + NiceMock<MockQuicConnectionDebugVisitor> visitor; client_connection->set_debug_visitor(&visitor); EXPECT_CALL(visitor, OnIncorrectConnectionId(incorrect_connection_id)) .Times(1); @@ -2733,7 +2748,7 @@ TEST_P(EndToEndTest, BadEncryptedData) { TEST_P(EndToEndTest, CanceledStreamDoesNotBecomeZombie) { ASSERT_TRUE(Initialize()); - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); // Lose the request. SetPacketLossPercentage(100); SpdyHeaderBlock headers; @@ -2934,7 +2949,7 @@ TEST_P(EndToEndTest, EarlyResponseFinRecording) { ASSERT_TRUE(Initialize()); - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); // A POST that gets an early error response, after the headers are received // and before the body is received, due to invalid content-length. @@ -2982,7 +2997,7 @@ TEST_P(EndToEndTest, EarlyResponseFinRecording) { TEST_P(EndToEndTest, Trailers) { // Test sending and receiving HTTP/2 Trailers (trailing HEADERS frames). ASSERT_TRUE(Initialize()); - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); // Set reordering to ensure that Trailers arriving before body is ok. SetPacketSendDelay(QuicTime::Delta::FromMilliseconds(2)); @@ -3014,6 +3029,7 @@ class EndToEndTestServerPush : public EndToEndTest { const size_t kNumMaxStreams = 10; EndToEndTestServerPush() : EndToEndTest() { + SetQuicFlag(FLAGS_quic_enable_http3_server_push, true); client_config_.SetMaxBidirectionalStreamsToSend(kNumMaxStreams); server_config_.SetMaxBidirectionalStreamsToSend(kNumMaxStreams); client_config_.SetMaxUnidirectionalStreamsToSend(kNumMaxStreams); @@ -3068,7 +3084,7 @@ INSTANTIATE_TEST_SUITE_P(EndToEndTestsServerPush, TEST_P(EndToEndTestServerPush, ServerPush) { ASSERT_TRUE(Initialize()); - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); // Set reordering to ensure that body arriving before PUSH_PROMISE is ok. SetPacketSendDelay(QuicTime::Delta::FromMilliseconds(2)); @@ -3092,10 +3108,7 @@ TEST_P(EndToEndTestServerPush, ServerPush) { EXPECT_EQ(kBody, client_->SendSynchronousRequest( "https://example.com/push_example")); QuicStreamSequencer* sequencer; - if (!VersionUsesHttp3(client_->client() - ->client_session() - ->connection() - ->transport_version())) { + if (!version_.UsesHttp3()) { QuicHeadersStream* headers_stream = QuicSpdySessionPeer::GetHeadersStream(GetClientSession()); sequencer = QuicStreamPeer::sequencer(headers_stream); @@ -3113,27 +3126,23 @@ TEST_P(EndToEndTestServerPush, ServerPush) { QUIC_DVLOG(1) << "response body " << response_body; EXPECT_EQ(expected_body, response_body); } - if (!VersionUsesHttp3(client_->client() - ->client_session() - ->connection() - ->transport_version())) { + if (!version_.UsesHttp3()) { EXPECT_FALSE( QuicStreamSequencerPeer::IsUnderlyingBufferAllocated(sequencer)); } } TEST_P(EndToEndTestServerPush, ServerPushUnderLimit) { - if (version_.UsesTls()) { - // TODO(b/155316241): Enable this test for TLS. - Initialize(); - return; - } // Tests that sending a request which has 4 push resources will trigger server // to push those 4 resources and client can handle pushed resources and match // them with requests later. ASSERT_TRUE(Initialize()); - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); + if (version_.UsesHttp3()) { + static_cast<QuicSpdySession*>(client_->client()->session()) + ->SetMaxPushId(kMaxQuicStreamId); + } // Set reordering to ensure that body arriving before PUSH_PROMISE is ok. SetPacketSendDelay(QuicTime::Delta::FromMilliseconds(2)); @@ -3177,9 +3186,10 @@ TEST_P(EndToEndTestServerPush, ServerPushUnderLimit) { } TEST_P(EndToEndTestServerPush, ServerPushOverLimitNonBlocking) { - if (version_.UsesTls()) { - // TODO(b/155316241): Enable this test for TLS. - Initialize(); + if (version_.UsesHttp3()) { + // TODO(b/142504641): Re-enable this test when we support push streams + // arriving before the corresponding promises. + ASSERT_TRUE(Initialize()); return; } // Tests that when streams are not blocked by flow control or congestion @@ -3187,15 +3197,10 @@ TEST_P(EndToEndTestServerPush, ServerPushOverLimitNonBlocking) { // streams should still work because all response streams get closed // immediately after pushing resources. ASSERT_TRUE(Initialize()); - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); - - if (VersionUsesHttp3(client_->client() - ->client_session() - ->connection() - ->transport_version())) { - // TODO(b/142504641): Re-enable this test when we support push streams - // arriving before the corresponding promises. - return; + EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); + if (version_.UsesHttp3()) { + static_cast<QuicSpdySession*>(client_->client()->session()) + ->SetMaxPushId(kMaxQuicStreamId); } // Set reordering to ensure that body arriving before PUSH_PROMISE is ok. @@ -3240,11 +3245,6 @@ TEST_P(EndToEndTestServerPush, ServerPushOverLimitNonBlocking) { } TEST_P(EndToEndTestServerPush, ServerPushOverLimitWithBlocking) { - if (version_.UsesTls()) { - // TODO(b/155316241): Enable this test for TLS. - Initialize(); - return; - } // Tests that when server tries to send more large resources(large enough to // be blocked by flow control window or congestion control window) than max // open outgoing streams , server can open upto max number of outgoing @@ -3261,7 +3261,11 @@ TEST_P(EndToEndTestServerPush, ServerPushOverLimitWithBlocking) { kBodySize * kNumMaxStreams + 1024); ASSERT_TRUE(Initialize()); - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); + if (version_.UsesHttp3()) { + static_cast<QuicSpdySession*>(client_->client()->session()) + ->SetMaxPushId(kMaxQuicStreamId); + } // Set reordering to ensure that body arriving before PUSH_PROMISE is ok. SetPacketSendDelay(QuicTime::Delta::FromMilliseconds(2)); @@ -3293,9 +3297,13 @@ TEST_P(EndToEndTestServerPush, ServerPushOverLimitWithBlocking) { // Check server session to see if it has max number of outgoing streams opened // though more resources need to be pushed. - server_thread_->Pause(); - EXPECT_EQ(kNumMaxStreams, GetServerSession()->GetNumOpenOutgoingStreams()); - server_thread_->Resume(); + if (!version_.HasIetfQuicFrames()) { + server_thread_->Pause(); + EXPECT_EQ(kNumMaxStreams, + QuicSessionPeer::GetStreamIdManager(GetServerSession()) + ->num_open_outgoing_streams()); + server_thread_->Resume(); + } EXPECT_EQ(1u, client_->num_requests()); EXPECT_EQ(1u, client_->num_responses()); @@ -3334,7 +3342,7 @@ TEST_P(EndToEndTest, DISABLED_TestHugePostWithPacketLoss) { // within a short time. client_->epoll_server()->set_timeout_in_us(0); - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); SetPacketLossPercentage(1); // To avoid storing the whole request body in memory, use a loop to repeatedly // send body size of kSizeBytes until the whole request body size is reached. @@ -3392,7 +3400,7 @@ TEST_P(EndToEndTest, DISABLED_TestHugeResponseWithPacketLoss) { initialized_ = true; ASSERT_TRUE(client_->client()->connected()); - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); SetPacketLossPercentage(1); client_->SendRequest("/huge_response"); client_->WaitForResponse(); @@ -3402,7 +3410,7 @@ TEST_P(EndToEndTest, DISABLED_TestHugeResponseWithPacketLoss) { // Regression test for b/111515567 TEST_P(EndToEndTest, AgreeOnStopWaiting) { ASSERT_TRUE(Initialize()); - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); QuicConnection* client_connection = GetClientConnection(); server_thread_->Pause(); @@ -3420,7 +3428,7 @@ TEST_P(EndToEndTest, AgreeOnStopWaitingWithNoStopWaitingOption) { options.push_back(kNSTP); client_config_.SetConnectionOptionsToSend(options); ASSERT_TRUE(Initialize()); - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); QuicConnection* client_connection = GetClientConnection(); server_thread_->Pause(); @@ -3451,6 +3459,13 @@ TEST_P(EndToEndTest, ReleaseHeadersStreamBufferWhenIdle) { TEST_P(EndToEndTest, WayTooLongRequestHeaders) { ASSERT_TRUE(Initialize()); + if (version_.UsesTls() && !version_.UsesHttp3()) { + // In T050, it took relatively long time for HPACK to compress the header + // while server will detect blackhole on NST message. + // TODO(b/157248143): remove this when the HPACK compression issue is + // understood. + return; + } SpdyHeaderBlock headers; headers[":method"] = "GET"; headers[":path"] = "/foo"; @@ -3493,7 +3508,7 @@ class WindowUpdateObserver : public QuicConnectionDebugVisitor { TEST_P(EndToEndTest, WindowUpdateInAck) { ASSERT_TRUE(Initialize()); - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); WindowUpdateObserver observer; QuicConnection* client_connection = GetClientConnection(); client_connection->set_debug_visitor(&observer); @@ -3514,7 +3529,7 @@ TEST_P(EndToEndTest, WindowUpdateInAck) { TEST_P(EndToEndTest, SendStatelessResetTokenInShlo) { ASSERT_TRUE(Initialize()); - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); QuicConfig* config = client_->client()->session()->config(); EXPECT_TRUE(config->HasReceivedStatelessResetToken()); EXPECT_EQ(QuicUtils::GenerateStatelessResetToken( @@ -3526,10 +3541,6 @@ TEST_P(EndToEndTest, SendStatelessResetTokenInShlo) { // Regression test for b/116200989. TEST_P(EndToEndTest, SendStatelessResetIfServerConnectionClosedLocallyDuringHandshake) { - if (!GetQuicReloadableFlag(quic_notify_handshaker_on_connection_close)) { - ASSERT_TRUE(Initialize()); - return; - } connect_to_server_on_initialize_ = false; ASSERT_TRUE(Initialize()); @@ -3674,8 +3685,7 @@ TEST_P(EndToEndTest, QUIC_TEST_DISABLED_IN_CHROME(PreSharedKeyMismatch)) { // 2. Crypto handshake has not completed, Initialize() returns true. The call // to WaitForCryptoHandshakeConfirmed() will wait for the handshake and // return whether it is successful. - ASSERT_FALSE(Initialize() && - client_->client()->WaitForCryptoHandshakeConfirmed()); + ASSERT_FALSE(Initialize() && client_->client()->WaitForOneRttKeysAvailable()); EXPECT_THAT(client_->connection_error(), IsError(QUIC_HANDSHAKE_TIMEOUT)); } @@ -3696,8 +3706,7 @@ TEST_P(EndToEndTest, QUIC_TEST_DISABLED_IN_CHROME(PreSharedKeyNoClient)) { return; } - ASSERT_FALSE(Initialize() && - client_->client()->WaitForCryptoHandshakeConfirmed()); + ASSERT_FALSE(Initialize() && client_->client()->WaitForOneRttKeysAvailable()); EXPECT_THAT(client_->connection_error(), IsError(QUIC_HANDSHAKE_TIMEOUT)); } @@ -3718,8 +3727,7 @@ TEST_P(EndToEndTest, QUIC_TEST_DISABLED_IN_CHROME(PreSharedKeyNoServer)) { return; } - ASSERT_FALSE(Initialize() && - client_->client()->WaitForCryptoHandshakeConfirmed()); + ASSERT_FALSE(Initialize() && client_->client()->WaitForOneRttKeysAvailable()); EXPECT_THAT(client_->connection_error(), IsError(QUIC_HANDSHAKE_TIMEOUT)); } @@ -3738,7 +3746,7 @@ TEST_P(EndToEndTest, RequestAndStreamRstInOnePacket) { server_hostname_, "/test_url", std::move(response_headers), response_body, QuicBackendResponse::INCOMPLETE_RESPONSE); - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); client_->WaitForDelayedAcks(); QuicSession* session = GetClientSession(); @@ -3760,7 +3768,7 @@ TEST_P(EndToEndTest, RequestAndStreamRstInOnePacket) { TEST_P(EndToEndTest, ResetStreamOnTtlExpires) { ASSERT_TRUE(Initialize()); - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForHandshakeConfirmed()); SetPacketLossPercentage(30); QuicSpdyClientStream* stream = client_->GetOrCreateStream(); @@ -3781,7 +3789,7 @@ TEST_P(EndToEndTest, SendMessages) { return; } ASSERT_TRUE(Initialize()); - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); QuicSession* client_session = GetClientSession(); QuicConnection* client_connection = client_session->connection(); @@ -3911,16 +3919,14 @@ TEST_P(EndToEndPacketReorderingTest, ReorderedConnectivityProbing) { server_connection->GetStats().num_connectivity_probing_received); server_thread_->Resume(); - EXPECT_EQ( + // Server definitely responded to the connectivity probing. Sometime it also + // sends a padded ping that is not a connectivity probing, which is recognized + // as connectivity probing because client's self address is ANY. + EXPECT_LE( 1u, GetClientConnection()->GetStats().num_connectivity_probing_received); } TEST_P(EndToEndPacketReorderingTest, Buffer0RttRequest) { - if (version_.UsesTls()) { - // TODO(b/152551499): Re-enable this test when TLS supports 0-RTT. - Initialize(); - return; - } ASSERT_TRUE(Initialize()); // Finish one request to make sure handshake established. client_->SendSynchronousRequest("/foo"); @@ -3933,7 +3939,7 @@ TEST_P(EndToEndPacketReorderingTest, Buffer0RttRequest) { // Only send out a CHLO. client_->client()->Initialize(); client_->client()->StartConnect(); - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); ASSERT_TRUE(client_->client()->connected()); // Send a request before handshake finishes. @@ -3947,14 +3953,10 @@ TEST_P(EndToEndPacketReorderingTest, Buffer0RttRequest) { client_->WaitForResponse(); EXPECT_EQ(kBarResponseBody, client_->response_body()); QuicConnectionStats client_stats = GetClientConnection()->GetStats(); - if (GetQuicReloadableFlag(quic_advance_ack_timeout_update)) { - // Client sends CHLO in packet 1 and retransmitted in packet 2. Because of - // the delay, server processes packet 2 and later drops packet 1. ACK is - // bundled with SHLO, such that 1 can be detected loss by time threshold. - EXPECT_LE(0u, client_stats.packets_lost); - } else { - EXPECT_EQ(0u, client_stats.packets_lost); - } + // Client sends CHLO in packet 1 and retransmitted in packet 2. Because of + // the delay, server processes packet 2 and later drops packet 1. ACK is + // bundled with SHLO, such that 1 can be detected loss by time threshold. + EXPECT_LE(0u, client_stats.packets_lost); EXPECT_TRUE(client_->client()->EarlyDataAccepted()); } @@ -4010,7 +4012,7 @@ TEST_P(EndToEndTest, SimpleStopSendingTest) { server_hostname_, "/test_url", std::move(response_headers), response_body, kStopSendingTestCode); - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); client_->WaitForDelayedAcks(); QuicSession* session = GetClientSession(); @@ -4188,7 +4190,7 @@ TEST_P(EndToEndTest, TooBigStreamIdClosesConnection) { // Only runs for IETF QUIC. return; } - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); std::string body(kMaxOutgoingPacketSize, 'a'); SpdyHeaderBlock headers; @@ -4216,17 +4218,15 @@ TEST_P(EndToEndTest, TooBigStreamIdClosesConnection) { } TEST_P(EndToEndTest, TestMaxPushId) { - if (version_.UsesTls() || - !VersionHasIetfQuicFrames(version_.transport_version)) { - // TODO(b/155316241): Enable this test for TLS. - // Only runs for IETF QUIC. + if (!version_.HasIetfQuicFrames()) { + // MaxPushId is only implemented for IETF QUIC. Initialize(); return; } - // Has to be before version test, see EndToEndTest::TearDown() + SetQuicFlag(FLAGS_quic_enable_http3_server_push, true); ASSERT_TRUE(Initialize()); - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); static_cast<QuicSpdySession*>(client_->client()->session()) ->SetMaxPushId(kMaxQuicStreamId); @@ -4239,18 +4239,135 @@ TEST_P(EndToEndTest, TestMaxPushId) { ->CanCreatePushStreamWithId(kMaxQuicStreamId)); } -TEST_P(EndToEndTest, DISABLED_CustomTransportParameters) { - // TODO(b/155316241): Enable this test. +TEST_P(EndToEndTest, CustomTransportParameters) { + if (!version_.UsesTls()) { + // Custom transport parameters are only supported with TLS. + ASSERT_TRUE(Initialize()); + return; + } constexpr auto kCustomParameter = static_cast<TransportParameters::TransportParameterId>(0xff34); client_config_.custom_transport_parameters_to_send()[kCustomParameter] = "test"; + NiceMock<MockQuicConnectionDebugVisitor> visitor; + connection_debug_visitor_ = &visitor; + EXPECT_CALL(visitor, OnTransportParametersSent(_)) + .WillOnce(Invoke([kCustomParameter]( + const TransportParameters& transport_parameters) { + ASSERT_NE(transport_parameters.custom_parameters.find(kCustomParameter), + transport_parameters.custom_parameters.end()); + EXPECT_EQ(transport_parameters.custom_parameters.at(kCustomParameter), + "test"); + })); + EXPECT_CALL(visitor, OnTransportParametersReceived(_)).Times(1); ASSERT_TRUE(Initialize()); - EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); - EXPECT_EQ(server_config_.received_custom_transport_parameters().at( + EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); + + server_thread_->Pause(); + QuicConfig server_config = *GetServerSession()->config(); + if (GetQuicReloadableFlag(quic_save_user_agent_in_quic_session)) { + EXPECT_EQ(GetServerSession()->user_agent_id().value_or("MissingUserAgent"), + kTestUserAgentId); + } else { + EXPECT_FALSE(GetServerSession()->user_agent_id().has_value()); + } + server_thread_->Resume(); + ASSERT_NE(server_config.received_custom_transport_parameters().find( kCustomParameter), - "test"); + server_config.received_custom_transport_parameters().end()); + EXPECT_EQ( + server_config.received_custom_transport_parameters().at(kCustomParameter), + "test"); +} + +TEST_P(EndToEndTest, LegacyVersionEncapsulation) { + if (!version_.HasLongHeaderLengths()) { + // Decapsulating Legacy Version Encapsulation packets from these versions + // is not currently supported in QuicDispatcher. + ASSERT_TRUE(Initialize()); + return; + } + SetQuicReloadableFlag(quic_dont_pad_chlo, true); + SetQuicReloadableFlag(quic_dispatcher_legacy_version_encapsulation, true); + client_config_.SetClientConnectionOptions(QuicTagVector{kQLVE}); + ASSERT_TRUE(Initialize()); + EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); + EXPECT_EQ("200", client_->response_headers()->find(":status")->second); + EXPECT_GT(GetClientConnection() + ->GetStats() + .sent_legacy_version_encapsulated_packets, + 0u); +} + +TEST_P(EndToEndTest, LegacyVersionEncapsulationWithMultiPacketChlo) { + if (!version_.HasLongHeaderLengths()) { + // Decapsulating Legacy Version Encapsulation packets from these versions + // is not currently supported in QuicDispatcher. + ASSERT_TRUE(Initialize()); + return; + } + if (!version_.UsesTls()) { + // This test uses custom transport parameters to increase the size of the + // CHLO, and those are only supported with TLS. + ASSERT_TRUE(Initialize()); + return; + } + SetQuicReloadableFlag(quic_dont_pad_chlo, true); + SetQuicReloadableFlag(quic_dispatcher_legacy_version_encapsulation, true); + client_config_.SetClientConnectionOptions(QuicTagVector{kQLVE}); + constexpr auto kCustomParameter = + static_cast<TransportParameters::TransportParameterId>(0xff34); + client_config_.custom_transport_parameters_to_send()[kCustomParameter] = + std::string(2000, '?'); + ASSERT_TRUE(Initialize()); + EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); + EXPECT_EQ("200", client_->response_headers()->find(":status")->second); + EXPECT_GT(GetClientConnection() + ->GetStats() + .sent_legacy_version_encapsulated_packets, + 0u); +} + +TEST_P(EndToEndTest, LegacyVersionEncapsulationWithVersionNegotiation) { + if (!version_.HasLongHeaderLengths()) { + // Decapsulating Legacy Version Encapsulation packets from these versions + // is not currently supported in QuicDispatcher. + ASSERT_TRUE(Initialize()); + return; + } + client_supported_versions_.insert(client_supported_versions_.begin(), + QuicVersionReservedForNegotiation()); + SetQuicReloadableFlag(quic_dont_pad_chlo, true); + SetQuicReloadableFlag(quic_dispatcher_legacy_version_encapsulation, true); + client_config_.SetClientConnectionOptions(QuicTagVector{kQLVE}); + ASSERT_TRUE(Initialize()); + EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); + EXPECT_EQ("200", client_->response_headers()->find(":status")->second); + EXPECT_GT(GetClientConnection() + ->GetStats() + .sent_legacy_version_encapsulated_packets, + 0u); +} + +TEST_P(EndToEndTest, LegacyVersionEncapsulationWithLoss) { + if (!version_.HasLongHeaderLengths()) { + // Decapsulating Legacy Version Encapsulation packets from these versions + // is not currently supported in QuicDispatcher. + ASSERT_TRUE(Initialize()); + return; + } + SetPacketLossPercentage(30); + SetQuicReloadableFlag(quic_dont_pad_chlo, true); + SetQuicReloadableFlag(quic_dispatcher_legacy_version_encapsulation, true); + client_config_.SetClientConnectionOptions(QuicTagVector{kQLVE}); + ASSERT_TRUE(Initialize()); + EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); + EXPECT_EQ("200", client_->response_headers()->find(":status")->second); + EXPECT_GT(GetClientConnection() + ->GetStats() + .sent_legacy_version_encapsulated_packets, + 0u); } } // namespace diff --git a/chromium/net/third_party/quiche/src/quic/core/http/http_constants.h b/chromium/net/third_party/quiche/src/quic/core/http/http_constants.h index 17afe1bea19..285d3792d7a 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/http_constants.h +++ b/chromium/net/third_party/quiche/src/quic/core/http/http_constants.h @@ -42,6 +42,7 @@ const QuicByteCount kDefaultQpackMaxDynamicTableCapacity = 64 * 1024; // 64 KB // SETTINGS_QPACK_BLOCKED_STREAMS. const uint64_t kDefaultMaximumBlockedStreams = 100; +const char kUserAgentHeaderName[] = "user-agent"; } // namespace quic #endif // QUICHE_QUIC_CORE_HTTP_HTTP_CONSTANTS_H_ diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_client_promised_info_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_client_promised_info_test.cc index a5996260d23..0836f9a0d56 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_client_promised_info_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_client_promised_info_test.cc @@ -227,9 +227,6 @@ TEST_F(QuicClientPromisedInfoTest, PushPromiseMismatch) { EXPECT_CALL(*connection_, SendControlFrame(_)); EXPECT_CALL(*connection_, OnStreamReset(promise_id_, QUIC_PROMISE_VARY_MISMATCH)); - if (!session_.break_close_loop()) { - EXPECT_CALL(session_, CloseStream(promise_id_)); - } promised->HandleClientRequest(client_request_, &delegate); } @@ -305,9 +302,6 @@ TEST_F(QuicClientPromisedInfoTest, PushPromiseWaitCancels) { session_.GetOrCreateStream(promise_id_); // Cancel the promised stream. - if (!session_.break_close_loop()) { - EXPECT_CALL(session_, CloseStream(promise_id_)); - } EXPECT_CALL(*connection_, SendControlFrame(_)); EXPECT_CALL(*connection_, OnStreamReset(promise_id_, QUIC_STREAM_CANCELLED)); promised->Cancel(); @@ -331,17 +325,10 @@ TEST_F(QuicClientPromisedInfoTest, PushPromiseDataClosed) { promise_stream->OnStreamHeaderList(false, headers.uncompressed_header_bytes(), headers); - if (!session_.break_close_loop()) { - EXPECT_CALL(session_, CloseStream(promise_id_)); - } EXPECT_CALL(*connection_, SendControlFrame(_)); EXPECT_CALL(*connection_, OnStreamReset(promise_id_, QUIC_STREAM_PEER_GOING_AWAY)); - if (session_.break_close_loop()) { - session_.ResetStream(promise_id_, QUIC_STREAM_PEER_GOING_AWAY, 0); - } else { - session_.SendRstStream(promise_id_, QUIC_STREAM_PEER_GOING_AWAY, 0); - } + session_.ResetStream(promise_id_, QUIC_STREAM_PEER_GOING_AWAY, 0); // Now initiate rendezvous. TestPushPromiseDelegate delegate(/*match=*/true); diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream.cc index d24e3ddaa88..27de70d3fa4 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream.cc @@ -131,8 +131,7 @@ bool QuicReceiveControlStream::OnSettingsFrameStart( bool QuicReceiveControlStream::OnSettingsFrame(const SettingsFrame& frame) { QUIC_DVLOG(1) << "Control Stream " << id() << " received settings frame: " << frame; - spdy_session_->OnSettingsFrame(frame); - return true; + return spdy_session_->OnSettingsFrame(frame); } bool QuicReceiveControlStream::OnDataFrameStart(QuicByteCount /*header_length*/, diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream.cc index 64c306a4431..59574a146b9 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream.cc @@ -18,18 +18,12 @@ namespace quic { -QuicSendControlStream::QuicSendControlStream( - QuicStreamId id, - QuicSpdySession* spdy_session, - uint64_t qpack_maximum_dynamic_table_capacity, - uint64_t qpack_maximum_blocked_streams, - uint64_t max_inbound_header_list_size) +QuicSendControlStream::QuicSendControlStream(QuicStreamId id, + QuicSpdySession* spdy_session, + const SettingsFrame& settings) : QuicStream(id, spdy_session, /*is_static = */ true, WRITE_UNIDIRECTIONAL), settings_sent_(false), - qpack_maximum_dynamic_table_capacity_( - qpack_maximum_dynamic_table_capacity), - qpack_maximum_blocked_streams_(qpack_maximum_blocked_streams), - max_inbound_header_list_size_(max_inbound_header_list_size), + settings_(settings), spdy_session_(spdy_session) {} void QuicSendControlStream::OnStreamReset(const QuicRstStreamFrame& /*frame*/) { @@ -56,13 +50,7 @@ void QuicSendControlStream::MaybeSendSettingsFrame() { WriteOrBufferData(quiche::QuicheStringPiece(writer.data(), writer.length()), false, nullptr); - SettingsFrame settings; - settings.values[SETTINGS_QPACK_MAX_TABLE_CAPACITY] = - qpack_maximum_dynamic_table_capacity_; - settings.values[SETTINGS_QPACK_BLOCKED_STREAMS] = - qpack_maximum_blocked_streams_; - settings.values[SETTINGS_MAX_HEADER_LIST_SIZE] = - max_inbound_header_list_size_; + SettingsFrame settings = settings_; // https://tools.ietf.org/html/draft-ietf-quic-http-25#section-7.2.4.1 // specifies that setting identifiers of 0x1f * N + 0x21 are reserved and // greasing should be attempted. diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream.h b/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream.h index 03bd1f747aa..c14254f4cb7 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream.h +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream.h @@ -23,9 +23,7 @@ class QUIC_EXPORT_PRIVATE QuicSendControlStream : public QuicStream { // only be accessed through the session. QuicSendControlStream(QuicStreamId id, QuicSpdySession* session, - uint64_t qpack_maximum_dynamic_table_capacity, - uint64_t qpack_maximum_blocked_streams, - uint64_t max_inbound_header_list_size); + const SettingsFrame& settings); QuicSendControlStream(const QuicSendControlStream&) = delete; QuicSendControlStream& operator=(const QuicSendControlStream&) = delete; ~QuicSendControlStream() override = default; @@ -59,12 +57,8 @@ class QUIC_EXPORT_PRIVATE QuicSendControlStream : public QuicStream { // Track if a settings frame is already sent. bool settings_sent_; - // SETTINGS_QPACK_MAX_TABLE_CAPACITY value to send. - const uint64_t qpack_maximum_dynamic_table_capacity_; - // SETTINGS_QPACK_BLOCKED_STREAMS value to send. - const uint64_t qpack_maximum_blocked_streams_; - // SETTINGS_MAX_HEADER_LIST_SIZE value to send. - const uint64_t max_inbound_header_list_size_; + // SETTINGS values to send. + const SettingsFrame settings_; QuicSpdySession* const spdy_session_; }; diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base.cc index 27db719fccd..ef367d98cb5 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base.cc @@ -39,6 +39,9 @@ void QuicServerSessionBase::Initialize() { crypto_stream_ = CreateQuicCryptoServerStream(crypto_config_, compressed_certs_cache_); QuicSpdySession::Initialize(); + if (GetQuicReloadableFlag(quic_enable_zero_rtt_for_tls)) { + SendSettingsToCryptoStream(); + } } void QuicServerSessionBase::OnConfigNegotiated() { @@ -260,4 +263,19 @@ int32_t QuicServerSessionBase::BandwidthToCachedParameterBytesPerSecond( bandwidth.ToBytesPerSecond(), std::numeric_limits<uint32_t>::max())); } +void QuicServerSessionBase::SendSettingsToCryptoStream() { + if (!version().UsesTls()) { + return; + } + std::unique_ptr<char[]> buffer; + QuicByteCount buffer_size = + HttpEncoder::SerializeSettingsFrame(settings(), &buffer); + + std::unique_ptr<ApplicationState> serialized_settings = + std::make_unique<ApplicationState>(buffer.get(), + buffer.get() + buffer_size); + GetMutableCryptoStream()->SetServerApplicationStateForResumption( + std::move(serialized_settings)); +} + } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base.h b/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base.h index bf7a5bbb693..b4a467fedff 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base.h +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base.h @@ -99,6 +99,11 @@ class QUIC_EXPORT_PRIVATE QuicServerSessionBase : public QuicSpdySession { friend class test::QuicServerSessionBasePeer; friend class test::QuicSimpleServerSessionPeer; + // Informs the QuicCryptoStream of the SETTINGS that will be used on this + // connection, so that the server crypto stream knows whether to accept 0-RTT + // data. + void SendSettingsToCryptoStream(); + const QuicCryptoServerConfig* crypto_config_; // The cache which contains most recently compressed certs. diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base_test.cc index c482856b61b..6af67a656f4 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base_test.cc @@ -157,6 +157,9 @@ class QuicServerSessionBaseTest : public QuicTestWithParam<ParsedQuicVersion> { QuicConfigPeer::SetReceivedInitialSessionFlowControlWindow( session_->config(), kMinimumFlowControlSendWindow); session_->OnConfigNegotiated(); + if (connection_->version().SupportsAntiAmplificationLimit()) { + QuicConnectionPeer::SetAddressValidated(connection_); + } } QuicStreamId GetNthClientInitiatedBidirectionalId(int n) { @@ -349,6 +352,7 @@ TEST_P(QuicServerSessionBaseTest, MaxOpenStreams) { // more than the negotiated stream limit to deal with rare cases where a // client FIN/RST is lost. + connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); session_->OnConfigNegotiated(); if (!VersionHasIetfQuicFrames(transport_version())) { // The slightly increased stream limit is set during config negotiation. It @@ -401,6 +405,7 @@ TEST_P(QuicServerSessionBaseTest, MaxAvailableBidirectionalStreams) { // streams available. The server accepts slightly more than the negotiated // stream limit to deal with rare cases where a client FIN/RST is lost. + connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); session_->OnConfigNegotiated(); const size_t kAvailableStreamLimit = session_->MaxAvailableBidirectionalStreams(); @@ -506,6 +511,7 @@ TEST_P(QuicServerSessionBaseTest, BandwidthEstimates) { QuicTagVector copt; copt.push_back(kBWRE); QuicConfigPeer::SetReceivedConnectionOptions(session_->config(), copt); + connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); session_->OnConfigNegotiated(); EXPECT_TRUE( QuicServerSessionBasePeer::IsBandwidthResumptionEnabled(session_.get())); @@ -696,6 +702,7 @@ TEST_P(QuicServerSessionBaseTest, BandwidthMaxEnablesResumption) { QuicTagVector copt; copt.push_back(kBWMX); QuicConfigPeer::SetReceivedConnectionOptions(session_->config(), copt); + connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); session_->OnConfigNegotiated(); EXPECT_TRUE( QuicServerSessionBasePeer::IsBandwidthResumptionEnabled(session_.get())); @@ -704,6 +711,7 @@ TEST_P(QuicServerSessionBaseTest, BandwidthMaxEnablesResumption) { TEST_P(QuicServerSessionBaseTest, NoBandwidthResumptionByDefault) { EXPECT_FALSE( QuicServerSessionBasePeer::IsBandwidthResumptionEnabled(session_.get())); + connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); session_->OnConfigNegotiated(); EXPECT_FALSE( QuicServerSessionBasePeer::IsBandwidthResumptionEnabled(session_.get())); diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session.cc index 6127e1b682e..066adb9f859 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session.cc @@ -39,6 +39,13 @@ QuicSpdyClientSession::~QuicSpdyClientSession() = default; void QuicSpdyClientSession::Initialize() { crypto_stream_ = CreateQuicCryptoStream(); + if (config()->HasClientRequestedIndependentOption(kQLVE, + Perspective::IS_CLIENT)) { + connection()->EnableLegacyVersionEncapsulation(server_id_.host()); + // Legacy Version Encapsulation needs CHLO padding to be disabled. + // TODO(dschinazi) remove this line once we deprecate quic_dont_pad_chlo. + crypto_config_->set_disable_chlo_padding(true); + } QuicSpdyClientSessionBase::Initialize(); } @@ -152,7 +159,7 @@ bool QuicSpdyClientSession::ShouldCreateIncomingStream(QuicStreamId id) { } if (VersionHasIetfQuicFrames(transport_version()) && - QuicUtils::IsBidirectionalStreamId(id)) { + QuicUtils::IsBidirectionalStreamId(id, version())) { connection()->CloseConnection( QUIC_HTTP_SERVER_INITIATED_BIDIRECTIONAL_STREAM, "Server created bidirectional stream.", @@ -186,7 +193,7 @@ QuicSpdyClientSession::CreateQuicCryptoStream() { return std::make_unique<QuicCryptoClientStream>( server_id_, this, crypto_config_->proof_verifier()->CreateDefaultContext(), crypto_config_, - this, /*has_application_state = */ true); + this, /*has_application_state = */ version().UsesHttp3()); } bool QuicSpdyClientSession::IsAuthorized(const std::string& /*authority*/) { diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.cc index 63de57c31bc..b433c56f687 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.cc @@ -204,26 +204,20 @@ void QuicSpdyClientSessionBase::ResetPromised( QuicStreamId id, QuicRstStreamErrorCode error_code) { DCHECK(QuicUtils::IsServerInitiatedStreamId(transport_version(), id)); - if (break_close_loop()) { - ResetStream(id, error_code, 0); - } else { - SendRstStream(id, error_code, 0); - } + ResetStream(id, error_code, 0); if (!IsOpenStream(id) && !IsClosedStream(id)) { MaybeIncreaseLargestPeerStreamId(id); } } -void QuicSpdyClientSessionBase::CloseStreamInner(QuicStreamId stream_id, - bool rst_sent) { - QuicSpdySession::CloseStreamInner(stream_id, rst_sent); +void QuicSpdyClientSessionBase::CloseStream(QuicStreamId stream_id) { + QuicSpdySession::CloseStream(stream_id); if (!VersionUsesHttp3(transport_version())) { headers_stream()->MaybeReleaseSequencerBuffer(); } } void QuicSpdyClientSessionBase::OnStreamClosed(QuicStreamId stream_id) { - DCHECK(break_close_loop()); QuicSpdySession::OnStreamClosed(stream_id); if (!VersionUsesHttp3(transport_version())) { headers_stream()->MaybeReleaseSequencerBuffer(); @@ -234,15 +228,55 @@ bool QuicSpdyClientSessionBase::ShouldReleaseHeadersStreamSequencerBuffer() { return !HasActiveRequestStreams() && promised_by_id_.empty(); } -void QuicSpdyClientSessionBase::OnSettingsFrame(const SettingsFrame& frame) { - QuicSpdySession::OnSettingsFrame(frame); +bool QuicSpdyClientSessionBase::ShouldKeepConnectionAlive() const { + return QuicSpdySession::ShouldKeepConnectionAlive() || + num_outgoing_draining_streams() > 0; +} + +bool QuicSpdyClientSessionBase::OnSettingsFrame(const SettingsFrame& frame) { + if (!was_zero_rtt_rejected()) { + if (max_outbound_header_list_size() != std::numeric_limits<size_t>::max() && + frame.values.find(SETTINGS_MAX_HEADER_LIST_SIZE) == + frame.values.end()) { + CloseConnectionWithDetails( + QUIC_HTTP_ZERO_RTT_RESUMPTION_SETTINGS_MISMATCH, + "Server accepted 0-RTT but omitted non-default " + "SETTINGS_MAX_HEADER_LIST_SIZE"); + return false; + } + + if (qpack_encoder()->maximum_blocked_streams() != 0 && + frame.values.find(SETTINGS_QPACK_BLOCKED_STREAMS) == + frame.values.end()) { + CloseConnectionWithDetails( + QUIC_HTTP_ZERO_RTT_RESUMPTION_SETTINGS_MISMATCH, + "Server accepted 0-RTT but omitted non-default " + "SETTINGS_QPACK_BLOCKED_STREAMS"); + return false; + } + + if (qpack_encoder()->MaximumDynamicTableCapacity() != 0 && + frame.values.find(SETTINGS_QPACK_MAX_TABLE_CAPACITY) == + frame.values.end()) { + CloseConnectionWithDetails( + QUIC_HTTP_ZERO_RTT_RESUMPTION_SETTINGS_MISMATCH, + "Server accepted 0-RTT but omitted non-default " + "SETTINGS_QPACK_MAX_TABLE_CAPACITY"); + return false; + } + } + + if (!QuicSpdySession::OnSettingsFrame(frame)) { + return false; + } std::unique_ptr<char[]> buffer; QuicByteCount frame_length = HttpEncoder::SerializeSettingsFrame(frame, &buffer); auto serialized_data = std::make_unique<ApplicationState>( buffer.get(), buffer.get() + frame_length); - static_cast<QuicCryptoClientStreamBase*>(GetMutableCryptoStream()) - ->OnApplicationState(std::move(serialized_data)); + GetMutableCryptoStream()->SetServerApplicationStateForResumption( + std::move(serialized_data)); + return true; } } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.h b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.h index a109d185a46..31924793f6b 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.h +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.h @@ -102,7 +102,7 @@ class QUIC_EXPORT_PRIVATE QuicSpdyClientSessionBase void ResetPromised(QuicStreamId id, QuicRstStreamErrorCode error_code); // Release headers stream's sequencer buffer if it's empty. - void CloseStreamInner(QuicStreamId stream_id, bool rst_sent) override; + void CloseStream(QuicStreamId stream_id) override; // Release headers stream's sequencer buffer if it's empty. void OnStreamClosed(QuicStreamId stream_id) override; @@ -110,6 +110,9 @@ class QUIC_EXPORT_PRIVATE QuicSpdyClientSessionBase // Returns true if there are no active requests and no promised streams. bool ShouldReleaseHeadersStreamSequencerBuffer() override; + // Override to wait for all received responses to be consumed by application. + bool ShouldKeepConnectionAlive() const override; + size_t get_max_promises() const { return max_open_incoming_unidirectional_streams() * kMaxPromisedStreamsMultiplier; @@ -120,7 +123,7 @@ class QUIC_EXPORT_PRIVATE QuicSpdyClientSessionBase } // Override to serialize the settings and pass it down to the handshaker. - void OnSettingsFrame(const SettingsFrame& frame) override; + bool OnSettingsFrame(const SettingsFrame& frame) override; private: // For QuicSpdyClientStream to detect that a response corresponds to a diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_test.cc index 7d4ae810115..3464a7eda90 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_test.cc @@ -16,10 +16,12 @@ #include "net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream.h" #include "net/third_party/quiche/src/quic/core/http/spdy_server_push_utils.h" #include "net/third_party/quiche/src/quic/core/quic_constants.h" +#include "net/third_party/quiche/src/quic/core/quic_error_codes.h" #include "net/third_party/quiche/src/quic/core/quic_utils.h" #include "net/third_party/quiche/src/quic/core/quic_versions.h" #include "net/third_party/quiche/src/quic/core/tls_client_handshaker.h" #include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" #include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" #include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" @@ -38,12 +40,13 @@ #include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" using spdy::SpdyHeaderBlock; -using testing::_; -using testing::AnyNumber; -using testing::AtLeast; -using testing::AtMost; -using testing::Invoke; -using testing::Truly; +using ::testing::_; +using ::testing::AnyNumber; +using ::testing::AtLeast; +using ::testing::AtMost; +using ::testing::Invoke; +using ::testing::StrictMock; +using ::testing::Truly; namespace quic { namespace test { @@ -93,8 +96,12 @@ class QuicSpdyClientSessionTest : public QuicTestWithParam<ParsedQuicVersion> { QuicUtils::GetInvalidStreamId(GetParam().transport_version)) { auto client_cache = std::make_unique<test::SimpleSessionCache>(); client_session_cache_ = client_cache.get(); - crypto_config_ = std::make_unique<QuicCryptoClientConfig>( + SetQuicReloadableFlag(quic_enable_tls_resumption, true); + SetQuicReloadableFlag(quic_enable_zero_rtt_for_tls, true); + SetQuicReloadableFlag(quic_fix_gquic_stream_type, true); + client_crypto_config_ = std::make_unique<QuicCryptoClientConfig>( crypto_test_utils::ProofVerifierForTesting(), std::move(client_cache)); + server_crypto_config_ = crypto_test_utils::CryptoServerConfigForTesting(); Initialize(); // Advance the time, because timers do not like uninitialized times. connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1)); @@ -107,14 +114,16 @@ class QuicSpdyClientSessionTest : public QuicTestWithParam<ParsedQuicVersion> { void Initialize() { session_.reset(); - connection_ = new PacketSavingConnection(&helper_, &alarm_factory_, - Perspective::IS_CLIENT, - SupportedVersions(GetParam())); + connection_ = new ::testing::NiceMock<PacketSavingConnection>( + &helper_, &alarm_factory_, Perspective::IS_CLIENT, + SupportedVersions(GetParam())); session_ = std::make_unique<TestQuicSpdyClientSession>( DefaultQuicConfig(), SupportedVersions(GetParam()), connection_, - QuicServerId(kServerHostname, kPort, false), crypto_config_.get(), - &push_promise_index_); + QuicServerId(kServerHostname, kPort, false), + client_crypto_config_.get(), &push_promise_index_); session_->Initialize(); + crypto_stream_ = static_cast<QuicCryptoClientStream*>( + session_->GetMutableCryptoStream()); push_promise_[":path"] = "/bar"; push_promise_[":authority"] = "www.google.com"; push_promise_[":method"] = "GET"; @@ -157,13 +166,11 @@ class QuicSpdyClientSessionTest : public QuicTestWithParam<ParsedQuicVersion> { void CompleteCryptoHandshake(uint32_t server_max_incoming_streams) { if (VersionHasIetfQuicFrames(connection_->transport_version())) { EXPECT_CALL(*connection_, SendControlFrame(_)) - .Times(testing::AnyNumber()) + .Times(::testing::AnyNumber()) .WillRepeatedly(Invoke( this, &QuicSpdyClientSessionTest::ClearMaxStreamsControlFrame)); } session_->CryptoConnect(); - QuicCryptoClientStream* stream = static_cast<QuicCryptoClientStream*>( - session_->GetMutableCryptoStream()); QuicConfig config = DefaultQuicConfig(); if (VersionHasIetfQuicFrames(connection_->transport_version())) { config.SetMaxUnidirectionalStreamsToSend(server_max_incoming_streams); @@ -171,32 +178,45 @@ class QuicSpdyClientSessionTest : public QuicTestWithParam<ParsedQuicVersion> { } else { config.SetMaxBidirectionalStreamsToSend(server_max_incoming_streams); } - SetQuicReloadableFlag(quic_enable_tls_resumption, true); - SetQuicReloadableFlag(quic_enable_zero_rtt_for_tls, true); - std::unique_ptr<QuicCryptoServerConfig> crypto_config = - crypto_test_utils::CryptoServerConfigForTesting(); crypto_test_utils::HandshakeWithFakeServer( - &config, crypto_config.get(), &helper_, &alarm_factory_, connection_, - stream, AlpnForVersion(connection_->version())); + &config, server_crypto_config_.get(), &helper_, &alarm_factory_, + connection_, crypto_stream_, AlpnForVersion(connection_->version())); } void CreateConnection() { - connection_ = new PacketSavingConnection(&helper_, &alarm_factory_, - Perspective::IS_CLIENT, - SupportedVersions(GetParam())); + connection_ = new ::testing::NiceMock<PacketSavingConnection>( + &helper_, &alarm_factory_, Perspective::IS_CLIENT, + SupportedVersions(GetParam())); // Advance the time, because timers do not like uninitialized times. connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1)); session_ = std::make_unique<TestQuicSpdyClientSession>( DefaultQuicConfig(), SupportedVersions(GetParam()), connection_, - QuicServerId(kServerHostname, kPort, false), crypto_config_.get(), - &push_promise_index_); + QuicServerId(kServerHostname, kPort, false), + client_crypto_config_.get(), &push_promise_index_); session_->Initialize(); + crypto_stream_ = static_cast<QuicCryptoClientStream*>( + session_->GetMutableCryptoStream()); } - std::unique_ptr<QuicCryptoClientConfig> crypto_config_; + void CompleteFirstConnection() { + CompleteCryptoHandshake(); + EXPECT_FALSE(session_->GetCryptoStream()->IsResumption()); + if (session_->version().UsesHttp3()) { + SettingsFrame settings; + settings.values[SETTINGS_QPACK_MAX_TABLE_CAPACITY] = 2; + settings.values[SETTINGS_MAX_HEADER_LIST_SIZE] = 5; + settings.values[256] = 4; // unknown setting + session_->OnSettingsFrame(settings); + } + } + + // Owned by |session_|. + QuicCryptoClientStream* crypto_stream_; + std::unique_ptr<QuicCryptoServerConfig> server_crypto_config_; + std::unique_ptr<QuicCryptoClientConfig> client_crypto_config_; MockQuicConnectionHelper helper_; MockAlarmFactory alarm_factory_; - PacketSavingConnection* connection_; + ::testing::NiceMock<PacketSavingConnection>* connection_; std::unique_ptr<TestQuicSpdyClientSession> session_; QuicClientPushPromiseIndex push_promise_index_; SpdyHeaderBlock push_promise_; @@ -219,8 +239,6 @@ TEST_P(QuicSpdyClientSessionTest, NoEncryptionAfterInitialEncryption) { if (GetParam().handshake_protocol == PROTOCOL_TLS1_3) { // This test relies on resumption and is QUIC crypto specific, so it is // disabled for TLS. - // TODO(nharper): Add support for resumption to the TLS handshake, and fix - // this test to not rely on QUIC crypto. return; } // Complete a handshake in order to prime the crypto config for 0-RTT. @@ -229,7 +247,6 @@ TEST_P(QuicSpdyClientSessionTest, NoEncryptionAfterInitialEncryption) { // Now create a second session using the same crypto config. Initialize(); - EXPECT_CALL(*connection_, OnCanWrite()); // Starting the handshake should move immediately to encryption // established and will allow streams to be created. session_->CryptoConnect(); @@ -257,7 +274,7 @@ TEST_P(QuicSpdyClientSessionTest, NoEncryptionAfterInitialEncryption) { char data[] = "hello world"; EXPECT_QUIC_BUG( session_->WritevData(stream->id(), QUICHE_ARRAYSIZE(data), 0, NO_FIN, - NOT_RETRANSMISSION, QuicheNullOpt), + NOT_RETRANSMISSION, QUICHE_NULLOPT), "Client: Try to send data of stream"); } @@ -343,11 +360,7 @@ TEST_P(QuicSpdyClientSessionTest, ResetAndTrailers) { .Times(AtLeast(1)) .WillRepeatedly(Invoke(&ClearControlFrame)); EXPECT_CALL(*connection_, OnStreamReset(_, _)).Times(1); - if (session_->break_close_loop()) { - session_->ResetStream(stream_id, QUIC_STREAM_PEER_GOING_AWAY, 0); - } else { - session_->SendRstStream(stream_id, QUIC_STREAM_PEER_GOING_AWAY, 0); - } + session_->ResetStream(stream_id, QUIC_STREAM_PEER_GOING_AWAY, 0); // A new stream cannot be created as the reset stream still counts as an open // outgoing stream until closed by the server. @@ -399,11 +412,7 @@ TEST_P(QuicSpdyClientSessionTest, ReceivedMalformedTrailersAfterSendingRst) { .Times(AtLeast(1)) .WillRepeatedly(Invoke(&ClearControlFrame)); EXPECT_CALL(*connection_, OnStreamReset(_, _)).Times(1); - if (session_->break_close_loop()) { - session_->ResetStream(stream_id, QUIC_STREAM_PEER_GOING_AWAY, 0); - } else { - session_->SendRstStream(stream_id, QUIC_STREAM_PEER_GOING_AWAY, 0); - } + session_->ResetStream(stream_id, QUIC_STREAM_PEER_GOING_AWAY, 0); // The stream receives trailers with final byte offset, but the header value // is non-numeric and should be treated as malformed. @@ -853,12 +862,7 @@ TEST_P(QuicSpdyClientSessionTest, ResetPromised) { EXPECT_CALL(*connection_, SendControlFrame(_)); EXPECT_CALL(*connection_, OnStreamReset(promised_stream_id_, QUIC_STREAM_PEER_GOING_AWAY)); - if (session_->break_close_loop()) { - session_->ResetStream(promised_stream_id_, QUIC_STREAM_PEER_GOING_AWAY, 0); - } else { - session_->SendRstStream(promised_stream_id_, QUIC_STREAM_PEER_GOING_AWAY, - 0); - } + session_->ResetStream(promised_stream_id_, QUIC_STREAM_PEER_GOING_AWAY, 0); QuicClientPromisedInfo* promised = session_->GetPromisedById(promised_stream_id_); EXPECT_NE(promised, nullptr); @@ -983,44 +987,50 @@ TEST_P(QuicSpdyClientSessionTest, OnSettingsFrame) { } TEST_P(QuicSpdyClientSessionTest, IetfZeroRttSetup) { - // This feature is HTTP/3 only - if (!VersionUsesHttp3(session_->transport_version())) { + // This feature is TLS-only. + if (session_->version().UsesQuicCrypto()) { return; } - CompleteCryptoHandshake(); - EXPECT_FALSE(session_->GetCryptoStream()->IsResumption()); - SettingsFrame settings; - settings.values[SETTINGS_QPACK_MAX_TABLE_CAPACITY] = 2; - settings.values[SETTINGS_MAX_HEADER_LIST_SIZE] = 5; - settings.values[256] = 4; // unknown setting - session_->OnSettingsFrame(settings); + + CompleteFirstConnection(); CreateConnection(); // Session configs should be in initial state. - EXPECT_EQ(0u, session_->flow_controller()->send_window_offset()); - EXPECT_EQ(std::numeric_limits<size_t>::max(), - session_->max_outbound_header_list_size()); + if (session_->version().UsesHttp3()) { + EXPECT_EQ(0u, session_->flow_controller()->send_window_offset()); + EXPECT_EQ(std::numeric_limits<size_t>::max(), + session_->max_outbound_header_list_size()); + } else { + EXPECT_EQ(kMinimumFlowControlSendWindow, + session_->flow_controller()->send_window_offset()); + } session_->CryptoConnect(); + EXPECT_TRUE(session_->IsEncryptionEstablished()); + EXPECT_EQ(ENCRYPTION_ZERO_RTT, session_->connection()->encryption_level()); // The client session should have a basic setup ready before the handshake // succeeds. EXPECT_EQ(kInitialSessionFlowControlWindowForTest, session_->flow_controller()->send_window_offset()); - auto* id_manager = QuicSessionPeer::v99_streamid_manager(session_.get()); - EXPECT_EQ(kDefaultMaxStreamsPerConnection, - id_manager->max_outgoing_bidirectional_streams()); - EXPECT_EQ( - kDefaultMaxStreamsPerConnection + kHttp3StaticUnidirectionalStreamCount, - id_manager->max_outgoing_unidirectional_streams()); - auto* control_stream = - QuicSpdySessionPeer::GetSendControlStream(session_.get()); - EXPECT_EQ(kInitialStreamFlowControlWindowForTest, - control_stream->flow_controller()->send_window_offset()); - EXPECT_EQ(5u, session_->max_outbound_header_list_size()); + if (session_->version().UsesHttp3()) { + auto* id_manager = QuicSessionPeer::v99_streamid_manager(session_.get()); + EXPECT_EQ(kDefaultMaxStreamsPerConnection, + id_manager->max_outgoing_bidirectional_streams()); + EXPECT_EQ( + kDefaultMaxStreamsPerConnection + kHttp3StaticUnidirectionalStreamCount, + id_manager->max_outgoing_unidirectional_streams()); + auto* control_stream = + QuicSpdySessionPeer::GetSendControlStream(session_.get()); + EXPECT_EQ(kInitialStreamFlowControlWindowForTest, + control_stream->flow_controller()->send_window_offset()); + EXPECT_EQ(5u, session_->max_outbound_header_list_size()); + } else { + auto* id_manager = QuicSessionPeer::GetStreamIdManager(session_.get()); + EXPECT_EQ(kDefaultMaxStreamsPerConnection, + id_manager->max_open_outgoing_streams()); + } // Complete the handshake with a different config. - QuicCryptoClientStream* stream = - static_cast<QuicCryptoClientStream*>(session_->GetMutableCryptoStream()); QuicConfig config = DefaultQuicConfig(); config.SetInitialMaxStreamDataBytesUnidirectionalToSend( kInitialStreamFlowControlWindowForTest + 1); @@ -1028,23 +1038,415 @@ TEST_P(QuicSpdyClientSessionTest, IetfZeroRttSetup) { kInitialSessionFlowControlWindowForTest + 1); config.SetMaxBidirectionalStreamsToSend(kDefaultMaxStreamsPerConnection + 1); config.SetMaxUnidirectionalStreamsToSend(kDefaultMaxStreamsPerConnection + 1); - SetQuicReloadableFlag(quic_enable_tls_resumption, true); - std::unique_ptr<QuicCryptoServerConfig> crypto_config = - crypto_test_utils::CryptoServerConfigForTesting(); crypto_test_utils::HandshakeWithFakeServer( - &config, crypto_config.get(), &helper_, &alarm_factory_, connection_, - stream, AlpnForVersion(connection_->version())); + &config, server_crypto_config_.get(), &helper_, &alarm_factory_, + connection_, crypto_stream_, AlpnForVersion(connection_->version())); EXPECT_TRUE(session_->GetCryptoStream()->IsResumption()); EXPECT_EQ(kInitialSessionFlowControlWindowForTest + 1, session_->flow_controller()->send_window_offset()); - EXPECT_EQ(kDefaultMaxStreamsPerConnection + 1, - id_manager->max_outgoing_bidirectional_streams()); - EXPECT_EQ(kDefaultMaxStreamsPerConnection + - kHttp3StaticUnidirectionalStreamCount + 1, - id_manager->max_outgoing_unidirectional_streams()); - EXPECT_EQ(kInitialStreamFlowControlWindowForTest + 1, - control_stream->flow_controller()->send_window_offset()); + if (session_->version().UsesHttp3()) { + auto* id_manager = QuicSessionPeer::v99_streamid_manager(session_.get()); + auto* control_stream = + QuicSpdySessionPeer::GetSendControlStream(session_.get()); + EXPECT_EQ(kDefaultMaxStreamsPerConnection + 1, + id_manager->max_outgoing_bidirectional_streams()); + EXPECT_EQ(kDefaultMaxStreamsPerConnection + + kHttp3StaticUnidirectionalStreamCount + 1, + id_manager->max_outgoing_unidirectional_streams()); + EXPECT_EQ(kInitialStreamFlowControlWindowForTest + 1, + control_stream->flow_controller()->send_window_offset()); + } else { + auto* id_manager = QuicSessionPeer::GetStreamIdManager(session_.get()); + EXPECT_EQ(kDefaultMaxStreamsPerConnection + 1, + id_manager->max_open_outgoing_streams()); + } + + EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0); + // Let the session receive a new SETTINGS frame to complete the second + // connection. + if (session_->version().UsesHttp3()) { + SettingsFrame settings; + settings.values[SETTINGS_QPACK_MAX_TABLE_CAPACITY] = 2; + settings.values[SETTINGS_MAX_HEADER_LIST_SIZE] = 5; + settings.values[256] = 4; // unknown setting + session_->OnSettingsFrame(settings); + } +} + +// Regression test for b/159168475 +TEST_P(QuicSpdyClientSessionTest, RetransmitDataOnZeroRttReject) { + SetQuicReloadableFlag(quic_do_not_retransmit_immediately_on_zero_rtt_reject, + true); + // This feature is TLS-only. + if (session_->version().UsesQuicCrypto()) { + return; + } + + CompleteFirstConnection(); + + // Create a second connection, but disable 0-RTT on the server. + CreateConnection(); + ON_CALL(*connection_, OnCanWrite()) + .WillByDefault( + testing::Invoke(connection_, &MockQuicConnection::ReallyOnCanWrite)); + EXPECT_CALL(*connection_, OnCanWrite()).Times(0); + + QuicConfig config = DefaultQuicConfig(); + config.SetMaxUnidirectionalStreamsToSend(kDefaultMaxStreamsPerConnection); + config.SetMaxBidirectionalStreamsToSend(kDefaultMaxStreamsPerConnection); + SSL_CTX_set_early_data_enabled(server_crypto_config_->ssl_ctx(), false); + + // Packets will be written: CHLO, HTTP/3 SETTINGS (H/3 only), and request + // data. + EXPECT_CALL(*connection_, + OnPacketSent(ENCRYPTION_INITIAL, NOT_RETRANSMISSION)); + EXPECT_CALL(*connection_, + OnPacketSent(ENCRYPTION_ZERO_RTT, NOT_RETRANSMISSION)) + .Times(session_->version().UsesHttp3() ? 2 : 1); + session_->CryptoConnect(); + EXPECT_TRUE(session_->IsEncryptionEstablished()); + EXPECT_EQ(ENCRYPTION_ZERO_RTT, session_->connection()->encryption_level()); + QuicSpdyClientStream* stream = session_->CreateOutgoingBidirectionalStream(); + ASSERT_TRUE(stream); + stream->WriteOrBufferData("hello", true, nullptr); + + // When handshake is done, the client sends 2 packet: HANDSHAKE FINISHED, and + // coalesced retransmission of HTTP/3 SETTINGS and request data. + EXPECT_CALL(*connection_, + OnPacketSent(ENCRYPTION_HANDSHAKE, NOT_RETRANSMISSION)); + // TODO(b/158027651): change transmission type to ALL_ZERO_RTT_RETRANSMISSION. + EXPECT_CALL(*connection_, + OnPacketSent(ENCRYPTION_FORWARD_SECURE, LOSS_RETRANSMISSION)); + crypto_test_utils::HandshakeWithFakeServer( + &config, server_crypto_config_.get(), &helper_, &alarm_factory_, + connection_, crypto_stream_, AlpnForVersion(connection_->version())); + EXPECT_TRUE(session_->GetCryptoStream()->IsResumption()); +} + +// When IETF QUIC 0-RTT is rejected, a server-sent fresh transport params is +// available. If the new transport params reduces stream/flow control limit to +// lower than what the client has already used, connection will be closed. +TEST_P(QuicSpdyClientSessionTest, ZeroRttRejectReducesStreamLimitTooMuch) { + // This feature is TLS-only. + if (session_->version().UsesQuicCrypto()) { + return; + } + + CompleteFirstConnection(); + + // Create a second connection, but disable 0-RTT on the server. + CreateConnection(); + QuicConfig config = DefaultQuicConfig(); + // Server doesn't allow any bidirectional streams. + config.SetMaxBidirectionalStreamsToSend(0); + SSL_CTX_set_early_data_enabled(server_crypto_config_->ssl_ctx(), false); + session_->CryptoConnect(); + EXPECT_TRUE(session_->IsEncryptionEstablished()); + QuicSpdyClientStream* stream = session_->CreateOutgoingBidirectionalStream(); + ASSERT_TRUE(stream); + + if (session_->version().UsesHttp3()) { + EXPECT_CALL( + *connection_, + CloseConnection( + QUIC_ZERO_RTT_UNRETRANSMITTABLE, + "Server rejected 0-RTT, aborting because new bidirectional initial " + "stream limit 0 is less than current open streams: 1", + _)) + .WillOnce(testing::Invoke(connection_, + &MockQuicConnection::ReallyCloseConnection)); + } else { + EXPECT_CALL( + *connection_, + CloseConnection(QUIC_INTERNAL_ERROR, + "Server rejected 0-RTT, aborting because new stream " + "limit 0 is less than current open streams: 1", + _)) + .WillOnce(testing::Invoke(connection_, + &MockQuicConnection::ReallyCloseConnection)); + } + EXPECT_CALL(*connection_, CloseConnection(QUIC_HANDSHAKE_FAILED, _, _)); + + crypto_test_utils::HandshakeWithFakeServer( + &config, server_crypto_config_.get(), &helper_, &alarm_factory_, + connection_, crypto_stream_, AlpnForVersion(connection_->version())); +} + +TEST_P(QuicSpdyClientSessionTest, + ZeroRttRejectReducesStreamFlowControlTooMuch) { + // This feature is TLS-only. + if (session_->version().UsesQuicCrypto()) { + return; + } + + CompleteFirstConnection(); + + // Create a second connection, but disable 0-RTT on the server. + CreateConnection(); + QuicConfig config = DefaultQuicConfig(); + // Server doesn't allow any outgoing streams. + config.SetInitialMaxStreamDataBytesIncomingBidirectionalToSend(2); + config.SetInitialMaxStreamDataBytesUnidirectionalToSend(1); + SSL_CTX_set_early_data_enabled(server_crypto_config_->ssl_ctx(), false); + session_->CryptoConnect(); + EXPECT_TRUE(session_->IsEncryptionEstablished()); + QuicSpdyClientStream* stream = session_->CreateOutgoingBidirectionalStream(); + ASSERT_TRUE(stream); + // Let the stream write more than 1 byte of data. + stream->WriteOrBufferData("hello", true, nullptr); + + if (session_->version().UsesHttp3()) { + // Both control stream and the request stream will report errors. + EXPECT_CALL(*connection_, + CloseConnection(QUIC_ZERO_RTT_UNRETRANSMITTABLE, _, _)) + .Times(2) + .WillOnce(testing::Invoke(connection_, + &MockQuicConnection::ReallyCloseConnection)); + } else { + EXPECT_CALL(*connection_, + CloseConnection( + QUIC_ZERO_RTT_UNRETRANSMITTABLE, + "Server rejected 0-RTT, aborting because new stream max " + "data 2 for stream 3 is less than currently used: 5", + _)) + .Times(1) + .WillOnce(testing::Invoke(connection_, + &MockQuicConnection::ReallyCloseConnection)); + } + EXPECT_CALL(*connection_, CloseConnection(QUIC_HANDSHAKE_FAILED, _, _)); + + crypto_test_utils::HandshakeWithFakeServer( + &config, server_crypto_config_.get(), &helper_, &alarm_factory_, + connection_, crypto_stream_, AlpnForVersion(connection_->version())); +} + +TEST_P(QuicSpdyClientSessionTest, + ZeroRttRejectReducesSessionFlowControlTooMuch) { + // This feature is TLS-only. + if (session_->version().UsesQuicCrypto()) { + return; + } + + CompleteFirstConnection(); + + // Create a second connection, but disable 0-RTT on the server. + CreateConnection(); + QuicConfig config = DefaultQuicConfig(); + // Server doesn't allow minimum data in session. + config.SetInitialSessionFlowControlWindowToSend( + kMinimumFlowControlSendWindow); + SSL_CTX_set_early_data_enabled(server_crypto_config_->ssl_ctx(), false); + session_->CryptoConnect(); + EXPECT_TRUE(session_->IsEncryptionEstablished()); + QuicSpdyClientStream* stream = session_->CreateOutgoingBidirectionalStream(); + ASSERT_TRUE(stream); + std::string data_to_send(kMinimumFlowControlSendWindow + 1, 'x'); + // Let the stream write some data. + stream->WriteOrBufferData(data_to_send, true, nullptr); + + EXPECT_CALL(*connection_, + CloseConnection(QUIC_ZERO_RTT_UNRETRANSMITTABLE, _, _)) + .WillOnce(testing::Invoke(connection_, + &MockQuicConnection::ReallyCloseConnection)); + EXPECT_CALL(*connection_, CloseConnection(QUIC_HANDSHAKE_FAILED, _, _)); + + crypto_test_utils::HandshakeWithFakeServer( + &config, server_crypto_config_.get(), &helper_, &alarm_factory_, + connection_, crypto_stream_, AlpnForVersion(connection_->version())); +} + +TEST_P(QuicSpdyClientSessionTest, SetMaxPushIdBeforeEncryptionEstablished) { + // 0-RTT is TLS-only, MAX_PUSH_ID frame is HTTP/3-only. + if (!session_->version().UsesTls() || !session_->version().UsesHttp3()) { + return; + } + + CompleteFirstConnection(); + + CreateConnection(); + StrictMock<MockHttp3DebugVisitor> debug_visitor; + session_->set_debug_visitor(&debug_visitor); + + // No MAX_PUSH_ID frame is sent before encryption is established. + session_->SetMaxPushId(5); + + EXPECT_FALSE(session_->IsEncryptionEstablished()); + EXPECT_FALSE(session_->OneRttKeysAvailable()); + EXPECT_EQ(ENCRYPTION_INITIAL, session_->connection()->encryption_level()); + + // MAX_PUSH_ID frame is sent upon encryption establishment with the value set + // by the earlier SetMaxPushId() call. + EXPECT_CALL(debug_visitor, OnSettingsFrameSent(_)); + EXPECT_CALL(debug_visitor, OnMaxPushIdFrameSent(_)) + .WillOnce(Invoke( + [](const MaxPushIdFrame& frame) { EXPECT_EQ(5u, frame.push_id); })); + session_->CryptoConnect(); + testing::Mock::VerifyAndClearExpectations(&debug_visitor); + + EXPECT_TRUE(session_->IsEncryptionEstablished()); + EXPECT_FALSE(session_->OneRttKeysAvailable()); + EXPECT_EQ(ENCRYPTION_ZERO_RTT, session_->connection()->encryption_level()); + + // Another SetMaxPushId() call with the same value does not trigger sending + // another MAX_PUSH_ID frame. + session_->SetMaxPushId(5); + + // Calling SetMaxPushId() with a different value results in sending another + // MAX_PUSH_ID frame. + EXPECT_CALL(debug_visitor, OnMaxPushIdFrameSent(_)) + .WillOnce(Invoke( + [](const MaxPushIdFrame& frame) { EXPECT_EQ(10u, frame.push_id); })); + session_->SetMaxPushId(10); + testing::Mock::VerifyAndClearExpectations(&debug_visitor); + + QuicConfig config = DefaultQuicConfig(); + crypto_test_utils::HandshakeWithFakeServer( + &config, server_crypto_config_.get(), &helper_, &alarm_factory_, + connection_, crypto_stream_, AlpnForVersion(connection_->version())); + + EXPECT_TRUE(session_->IsEncryptionEstablished()); + EXPECT_TRUE(session_->OneRttKeysAvailable()); + EXPECT_EQ(ENCRYPTION_FORWARD_SECURE, + session_->connection()->encryption_level()); + EXPECT_TRUE(session_->GetCryptoStream()->IsResumption()); +} + +TEST_P(QuicSpdyClientSessionTest, SetMaxPushIdAfterEncryptionEstablished) { + // 0-RTT is TLS-only, MAX_PUSH_ID frame is HTTP/3-only. + if (!session_->version().UsesTls() || !session_->version().UsesHttp3()) { + return; + } + + CompleteFirstConnection(); + + CreateConnection(); + StrictMock<MockHttp3DebugVisitor> debug_visitor; + session_->set_debug_visitor(&debug_visitor); + + EXPECT_FALSE(session_->IsEncryptionEstablished()); + EXPECT_FALSE(session_->OneRttKeysAvailable()); + EXPECT_EQ(ENCRYPTION_INITIAL, session_->connection()->encryption_level()); + + // No MAX_PUSH_ID frame is sent if SetMaxPushId() has not been called. + EXPECT_CALL(debug_visitor, OnSettingsFrameSent(_)); + session_->CryptoConnect(); + testing::Mock::VerifyAndClearExpectations(&debug_visitor); + + EXPECT_TRUE(session_->IsEncryptionEstablished()); + EXPECT_FALSE(session_->OneRttKeysAvailable()); + EXPECT_EQ(ENCRYPTION_ZERO_RTT, session_->connection()->encryption_level()); + + // Calling SetMaxPushId() for the first time after encryption is established + // results in sending a MAX_PUSH_ID frame. + EXPECT_CALL(debug_visitor, OnMaxPushIdFrameSent(_)) + .WillOnce(Invoke( + [](const MaxPushIdFrame& frame) { EXPECT_EQ(5u, frame.push_id); })); + session_->SetMaxPushId(5); + testing::Mock::VerifyAndClearExpectations(&debug_visitor); + + // Another SetMaxPushId() call with the same value does not trigger sending + // another MAX_PUSH_ID frame. + session_->SetMaxPushId(5); + + // Calling SetMaxPushId() with a different value results in sending another + // MAX_PUSH_ID frame. + EXPECT_CALL(debug_visitor, OnMaxPushIdFrameSent(_)) + .WillOnce(Invoke( + [](const MaxPushIdFrame& frame) { EXPECT_EQ(10u, frame.push_id); })); + session_->SetMaxPushId(10); + testing::Mock::VerifyAndClearExpectations(&debug_visitor); + + QuicConfig config = DefaultQuicConfig(); + crypto_test_utils::HandshakeWithFakeServer( + &config, server_crypto_config_.get(), &helper_, &alarm_factory_, + connection_, crypto_stream_, AlpnForVersion(connection_->version())); + + EXPECT_TRUE(session_->IsEncryptionEstablished()); + EXPECT_TRUE(session_->OneRttKeysAvailable()); + EXPECT_EQ(ENCRYPTION_FORWARD_SECURE, + session_->connection()->encryption_level()); + EXPECT_TRUE(session_->GetCryptoStream()->IsResumption()); +} + +TEST_P(QuicSpdyClientSessionTest, BadSettingsInZeroRttResumption) { + if (!session_->version().UsesHttp3()) { + return; + } + + CompleteFirstConnection(); + + CreateConnection(); + CompleteCryptoHandshake(); + EXPECT_TRUE(session_->GetCryptoStream()->EarlyDataAccepted()); + + EXPECT_CALL( + *connection_, + CloseConnection(QUIC_HTTP_ZERO_RTT_RESUMPTION_SETTINGS_MISMATCH, _, _)) + .WillOnce(testing::Invoke(connection_, + &MockQuicConnection::ReallyCloseConnection)); + // Let the session receive a different SETTINGS frame. + SettingsFrame settings; + settings.values[SETTINGS_QPACK_MAX_TABLE_CAPACITY] = 1; + settings.values[SETTINGS_MAX_HEADER_LIST_SIZE] = 5; + settings.values[256] = 4; // unknown setting + session_->OnSettingsFrame(settings); +} + +TEST_P(QuicSpdyClientSessionTest, BadSettingsInZeroRttRejection) { + if (!session_->version().UsesHttp3()) { + return; + } + + CompleteFirstConnection(); + + CreateConnection(); + SSL_CTX_set_early_data_enabled(server_crypto_config_->ssl_ctx(), false); + session_->CryptoConnect(); + EXPECT_TRUE(session_->IsEncryptionEstablished()); + QuicConfig config = DefaultQuicConfig(); + crypto_test_utils::HandshakeWithFakeServer( + &config, server_crypto_config_.get(), &helper_, &alarm_factory_, + connection_, crypto_stream_, AlpnForVersion(connection_->version())); + EXPECT_FALSE(session_->GetCryptoStream()->EarlyDataAccepted()); + + EXPECT_CALL( + *connection_, + CloseConnection(QUIC_HTTP_ZERO_RTT_REJECTION_SETTINGS_MISMATCH, _, _)) + .WillOnce(testing::Invoke(connection_, + &MockQuicConnection::ReallyCloseConnection)); + // Let the session receive a different SETTINGS frame. + SettingsFrame settings; + settings.values[SETTINGS_QPACK_MAX_TABLE_CAPACITY] = 2; + // setting on SETTINGS_MAX_HEADER_LIST_SIZE is reduced. + settings.values[SETTINGS_MAX_HEADER_LIST_SIZE] = 4; + settings.values[256] = 4; // unknown setting + session_->OnSettingsFrame(settings); +} + +TEST_P(QuicSpdyClientSessionTest, ServerAcceptsZeroRttButOmitSetting) { + if (!session_->version().UsesHttp3()) { + return; + } + + CompleteFirstConnection(); + + CreateConnection(); + CompleteCryptoHandshake(); + EXPECT_TRUE(session_->GetMutableCryptoStream()->EarlyDataAccepted()); + + EXPECT_CALL( + *connection_, + CloseConnection(QUIC_HTTP_ZERO_RTT_RESUMPTION_SETTINGS_MISMATCH, _, _)) + .WillOnce(testing::Invoke(connection_, + &MockQuicConnection::ReallyCloseConnection)); + // Let the session receive a different SETTINGS frame. + SettingsFrame settings; + settings.values[SETTINGS_QPACK_MAX_TABLE_CAPACITY] = 1; + // Intentionally omit SETTINGS_MAX_HEADER_LIST_SIZE which was previously sent + // with a non-zero value. + settings.values[256] = 4; // unknown setting + session_->OnSettingsFrame(settings); } } // namespace diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream.cc index 7232f76c755..f50e756d1b3 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream.cc @@ -53,24 +53,41 @@ void QuicSpdyClientStream::OnInitialHeadersComplete( if (!SpdyUtils::CopyAndValidateHeaders(header_list, &content_length_, &response_headers_)) { QUIC_DLOG(ERROR) << "Failed to parse header list: " - << header_list.DebugString(); + << header_list.DebugString() << " on stream " << id(); Reset(QUIC_BAD_APPLICATION_PAYLOAD); return; } if (!ParseHeaderStatusCode(response_headers_, &response_code_)) { QUIC_DLOG(ERROR) << "Received invalid response code: " - << response_headers_[":status"].as_string(); + << response_headers_[":status"].as_string() + << " on stream " << id(); + Reset(QUIC_BAD_APPLICATION_PAYLOAD); + return; + } + + if (response_code_ == 101) { + // 101 "Switching Protocols" is forbidden in HTTP/3 as per the + // "HTTP Upgrade" section of draft-ietf-quic-http. + QUIC_DLOG(ERROR) << "Received forbidden 101 response code" + << " on stream " << id(); Reset(QUIC_BAD_APPLICATION_PAYLOAD); return; } - if (response_code_ == 100 && !has_preliminary_headers_) { - // These are preliminary 100 Continue headers, not the actual response - // headers. + if (response_code_ >= 100 && response_code_ < 200) { + // These are Informational 1xx headers, not the actual response headers. + QUIC_DLOG(INFO) << "Received informational response code: " + << response_headers_[":status"].as_string() << " on stream " + << id(); set_headers_decompressed(false); - has_preliminary_headers_ = true; - preliminary_headers_ = std::move(response_headers_); + if (response_code_ == 100 && !has_preliminary_headers_) { + // This is 100 Continue, save it to enable "Expect: 100-continue". + has_preliminary_headers_ = true; + preliminary_headers_ = std::move(response_headers_); + } else { + response_headers_.clear(); + } } ConsumeHeaderList(); diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream_test.cc index fdc0e298371..1aba0005981 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream_test.cc @@ -133,17 +133,77 @@ TEST_P(QuicSpdyClientStreamTest, TestFraming) { EXPECT_EQ(body_, stream_->data()); } -TEST_P(QuicSpdyClientStreamTest, TestFraming100Continue) { +TEST_P(QuicSpdyClientStreamTest, Test100ContinueBeforeSuccessful) { + // First send 100 Continue. headers_[":status"] = "100"; auto headers = AsHeaderList(headers_); stream_->OnStreamHeaderList(false, headers.uncompressed_header_bytes(), headers); - stream_->OnStreamFrame( - QuicStreamFrame(stream_->id(), /*fin=*/false, /*offset=*/0, body_)); EXPECT_EQ("100", stream_->preliminary_headers().find(":status")->second); EXPECT_EQ(0u, stream_->response_headers().size()); EXPECT_EQ(100, stream_->response_code()); EXPECT_EQ("", stream_->data()); + // Then send 200 OK. + headers_[":status"] = "200"; + headers = AsHeaderList(headers_); + stream_->OnStreamHeaderList(false, headers.uncompressed_header_bytes(), + headers); + std::unique_ptr<char[]> buffer; + QuicByteCount header_length = + HttpEncoder::SerializeDataFrameHeader(body_.length(), &buffer); + std::string header = std::string(buffer.get(), header_length); + std::string data = + connection_->version().UsesHttp3() ? header + body_ : body_; + stream_->OnStreamFrame( + QuicStreamFrame(stream_->id(), /*fin=*/false, /*offset=*/0, data)); + // Make sure the 200 response got parsed correctly. + EXPECT_EQ("200", stream_->response_headers().find(":status")->second); + EXPECT_EQ(200, stream_->response_code()); + EXPECT_EQ(body_, stream_->data()); + // Make sure the 100 response is still available. + EXPECT_EQ("100", stream_->preliminary_headers().find(":status")->second); +} + +TEST_P(QuicSpdyClientStreamTest, TestUnknownInformationalBeforeSuccessful) { + // First send 199, an unknown Informational (1XX). + headers_[":status"] = "199"; + auto headers = AsHeaderList(headers_); + stream_->OnStreamHeaderList(false, headers.uncompressed_header_bytes(), + headers); + EXPECT_EQ(0u, stream_->response_headers().size()); + EXPECT_EQ(199, stream_->response_code()); + EXPECT_EQ("", stream_->data()); + // Then send 200 OK. + headers_[":status"] = "200"; + headers = AsHeaderList(headers_); + stream_->OnStreamHeaderList(false, headers.uncompressed_header_bytes(), + headers); + std::unique_ptr<char[]> buffer; + QuicByteCount header_length = + HttpEncoder::SerializeDataFrameHeader(body_.length(), &buffer); + std::string header = std::string(buffer.get(), header_length); + std::string data = + connection_->version().UsesHttp3() ? header + body_ : body_; + stream_->OnStreamFrame( + QuicStreamFrame(stream_->id(), /*fin=*/false, /*offset=*/0, data)); + // Make sure the 200 response got parsed correctly. + EXPECT_EQ("200", stream_->response_headers().find(":status")->second); + EXPECT_EQ(200, stream_->response_code()); + EXPECT_EQ(body_, stream_->data()); +} + +TEST_P(QuicSpdyClientStreamTest, TestReceiving101) { + // 101 "Switching Protocols" is forbidden in HTTP/3 as per the + // "HTTP Upgrade" section of draft-ietf-quic-http. + headers_[":status"] = "101"; + EXPECT_CALL(*connection_, SendControlFrame(_)); + EXPECT_CALL(*connection_, + OnStreamReset(stream_->id(), QUIC_BAD_APPLICATION_PAYLOAD)); + auto headers = AsHeaderList(headers_); + stream_->OnStreamHeaderList(false, headers.uncompressed_header_bytes(), + headers); + EXPECT_THAT(stream_->stream_error(), + IsStreamError(QUIC_BAD_APPLICATION_PAYLOAD)); } TEST_P(QuicSpdyClientStreamTest, TestFramingOnePacket) { diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.cc index 27643c87294..d6b5a0e7629 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.cc @@ -434,6 +434,7 @@ QuicSpdySession::~QuicSpdySession() { void QuicSpdySession::Initialize() { QuicSession::Initialize(); + FillSettingsFrame(); if (!VersionUsesHttp3(transport_version())) { if (perspective() == Perspective::IS_SERVER) { set_largest_peer_created_stream_id( @@ -464,6 +465,15 @@ void QuicSpdySession::Initialize() { 2 * max_inbound_header_list_size_); } +void QuicSpdySession::FillSettingsFrame() { + settings_.values[SETTINGS_QPACK_MAX_TABLE_CAPACITY] = + qpack_maximum_dynamic_table_capacity_; + settings_.values[SETTINGS_QPACK_BLOCKED_STREAMS] = + qpack_maximum_blocked_streams_; + settings_.values[SETTINGS_MAX_HEADER_LIST_SIZE] = + max_inbound_header_list_size_; +} + void QuicSpdySession::OnDecoderStreamError( quiche::QuicheStringPiece error_message) { DCHECK(VersionUsesHttp3(transport_version())); @@ -548,7 +558,7 @@ void QuicSpdySession::OnPriorityFrame( bool QuicSpdySession::OnPriorityUpdateForRequestStream(QuicStreamId stream_id, int urgency) { if (perspective() == Perspective::IS_CLIENT || - !QuicUtils::IsBidirectionalStreamId(stream_id) || + !QuicUtils::IsBidirectionalStreamId(stream_id, version()) || !QuicUtils::IsClientInitiatedStreamId(transport_version(), stream_id)) { return true; } @@ -647,7 +657,7 @@ void QuicSpdySession::WriteHttp3PriorityUpdate( void QuicSpdySession::OnHttp3GoAway(QuicStreamId stream_id) { DCHECK_EQ(perspective(), Perspective::IS_CLIENT); - if (!QuicUtils::IsBidirectionalStreamId(stream_id) || + if (!QuicUtils::IsBidirectionalStreamId(stream_id, version()) || IsIncomingStream(stream_id)) { CloseConnectionWithDetails( QUIC_INVALID_STREAM_ID, @@ -736,9 +746,9 @@ void QuicSpdySession::SendInitialData() { } QuicConnection::ScopedPacketFlusher flusher(connection()); send_control_stream_->MaybeSendSettingsFrame(); - if (perspective() == Perspective::IS_CLIENT && !http3_max_push_id_sent_) { + if (perspective() == Perspective::IS_CLIENT && max_push_id_.has_value() && + !http3_max_push_id_sent_) { SendMaxPushId(); - http3_max_push_id_sent_ = true; } } @@ -856,7 +866,7 @@ void QuicSpdySession::OnPromiseHeaderList( ConnectionCloseBehavior::SILENT_CLOSE); } -bool QuicSpdySession::SetApplicationState(ApplicationState* cached_state) { +bool QuicSpdySession::ResumeApplicationState(ApplicationState* cached_state) { DCHECK_EQ(perspective(), Perspective::IS_CLIENT); DCHECK(VersionUsesHttp3(transport_version())); @@ -874,52 +884,102 @@ bool QuicSpdySession::SetApplicationState(ApplicationState* cached_state) { return true; } -void QuicSpdySession::OnSettingsFrame(const SettingsFrame& frame) { +bool QuicSpdySession::OnSettingsFrame(const SettingsFrame& frame) { DCHECK(VersionUsesHttp3(transport_version())); if (debug_visitor_ != nullptr) { debug_visitor_->OnSettingsFrameReceived(frame); } for (const auto& setting : frame.values) { - OnSetting(setting.first, setting.second); + if (!OnSetting(setting.first, setting.second)) { + return false; + } } + return true; } -void QuicSpdySession::OnSetting(uint64_t id, uint64_t value) { +bool QuicSpdySession::OnSetting(uint64_t id, uint64_t value) { if (VersionUsesHttp3(transport_version())) { // SETTINGS frame received on the control stream. switch (id) { - case SETTINGS_QPACK_MAX_TABLE_CAPACITY: + case SETTINGS_QPACK_MAX_TABLE_CAPACITY: { QUIC_DVLOG(1) << ENDPOINT << "SETTINGS_QPACK_MAX_TABLE_CAPACITY received with value " << value; // Communicate |value| to encoder, because it is used for encoding // Required Insert Count. - qpack_encoder_->SetMaximumDynamicTableCapacity(value); + bool success = qpack_encoder_->SetMaximumDynamicTableCapacity(value); + if (GetQuicReloadableFlag(quic_enable_zero_rtt_for_tls) && !success) { + CloseConnectionWithDetails( + was_zero_rtt_rejected() + ? QUIC_HTTP_ZERO_RTT_REJECTION_SETTINGS_MISMATCH + : QUIC_HTTP_ZERO_RTT_RESUMPTION_SETTINGS_MISMATCH, + quiche::QuicheStrCat( + was_zero_rtt_rejected() + ? "Server rejected 0-RTT, aborting because " + : "", + "Server sent an SETTINGS_QPACK_MAX_TABLE_CAPACITY: ", value, + "while current value is: ", + qpack_encoder_->MaximumDynamicTableCapacity())); + return false; + } // However, limit the dynamic table capacity to // |qpack_maximum_dynamic_table_capacity_|. qpack_encoder_->SetDynamicTableCapacity( std::min(value, qpack_maximum_dynamic_table_capacity_)); break; + } case SETTINGS_MAX_HEADER_LIST_SIZE: QUIC_DVLOG(1) << ENDPOINT << "SETTINGS_MAX_HEADER_LIST_SIZE received with value " << value; + if (GetQuicReloadableFlag(quic_enable_zero_rtt_for_tls) && + max_outbound_header_list_size_ != + std::numeric_limits<size_t>::max() && + max_outbound_header_list_size_ > value) { + CloseConnectionWithDetails( + was_zero_rtt_rejected() + ? QUIC_HTTP_ZERO_RTT_REJECTION_SETTINGS_MISMATCH + : QUIC_HTTP_ZERO_RTT_RESUMPTION_SETTINGS_MISMATCH, + quiche::QuicheStrCat( + was_zero_rtt_rejected() + ? "Server rejected 0-RTT, aborting because " + : "", + "Server sent an SETTINGS_MAX_HEADER_LIST_SIZE: ", value, + "which reduces current value: ", + max_outbound_header_list_size_)); + return false; + } max_outbound_header_list_size_ = value; break; - case SETTINGS_QPACK_BLOCKED_STREAMS: + case SETTINGS_QPACK_BLOCKED_STREAMS: { QUIC_DVLOG(1) << ENDPOINT << "SETTINGS_QPACK_BLOCKED_STREAMS received with value " << value; - qpack_encoder_->SetMaximumBlockedStreams(value); + bool success = qpack_encoder_->SetMaximumBlockedStreams(value); + if (GetQuicReloadableFlag(quic_enable_zero_rtt_for_tls) && !success) { + CloseConnectionWithDetails( + was_zero_rtt_rejected() + ? QUIC_HTTP_ZERO_RTT_REJECTION_SETTINGS_MISMATCH + : QUIC_HTTP_ZERO_RTT_RESUMPTION_SETTINGS_MISMATCH, + quiche::QuicheStrCat( + was_zero_rtt_rejected() + ? "Server rejected 0-RTT, aborting because " + : "", + "Server sent an SETTINGS_QPACK_BLOCKED_STREAMS: ", value, + "which reduces current value: ", + qpack_encoder_->maximum_blocked_streams())); + return false; + } break; + } default: QUIC_DVLOG(1) << ENDPOINT << "Unknown setting identifier " << id << " received with value " << value; // Ignore unknown settings. break; } - return; + return true; } // SETTINGS frame received on the headers stream. @@ -942,7 +1002,7 @@ void QuicSpdySession::OnSetting(uint64_t id, uint64_t value) { quiche::QuicheStrCat("Invalid value for SETTINGS_ENABLE_PUSH: ", value)); } - return; + return true; } QUIC_DVLOG(1) << ENDPOINT << "SETTINGS_ENABLE_PUSH received with value " << value; @@ -977,6 +1037,7 @@ void QuicSpdySession::OnSetting(uint64_t id, uint64_t value) { id)); } } + return true; } bool QuicSpdySession::ShouldReleaseHeadersStreamSequencerBuffer() { @@ -1076,11 +1137,8 @@ void QuicSpdySession::CloseConnectionWithDetails(QuicErrorCode error, } bool QuicSpdySession::HasActiveRequestStreams() const { - DCHECK_GE(static_cast<size_t>(stream_map().size()), - num_incoming_static_streams() + num_outgoing_static_streams()); - return stream_map().size() - num_incoming_static_streams() - - num_outgoing_static_streams() > - 0; + DCHECK_GE(static_cast<size_t>(stream_map().size()), num_static_streams()); + return stream_map().size() - num_static_streams() > 0; } bool QuicSpdySession::ProcessPendingStream(PendingStream* pending) { @@ -1176,9 +1234,7 @@ void QuicSpdySession::MaybeInitializeHttp3UnidirectionalStreams() { DCHECK(VersionUsesHttp3(transport_version())); if (!send_control_stream_ && CanOpenNextOutgoingUnidirectionalStream()) { auto send_control = std::make_unique<QuicSendControlStream>( - GetNextOutgoingUnidirectionalStreamId(), this, - qpack_maximum_dynamic_table_capacity_, qpack_maximum_blocked_streams_, - max_inbound_header_list_size_); + GetNextOutgoingUnidirectionalStreamId(), this, settings_); send_control_stream_ = send_control.get(); ActivateStream(std::move(send_control)); if (debug_visitor_) { @@ -1231,15 +1287,19 @@ void QuicSpdySession::SetMaxPushId(PushId max_push_id) { ietf_server_push_enabled_ = true; if (max_push_id_.has_value()) { - QUIC_DVLOG(1) << "Setting max_push_id to: " << max_push_id + if (max_push_id == max_push_id_.value()) { + QUIC_DVLOG(1) << "Not changing max_push_id: " << max_push_id; + return; + } + + QUIC_DVLOG(1) << "Setting max_push_id to: " << max_push_id << " from: " << max_push_id_.value(); } else { - QUIC_DVLOG(1) << "Setting max_push_id to: " << max_push_id - << " from unset"; + QUIC_DVLOG(1) << "Setting max_push_id to: " << max_push_id << " from unset"; } max_push_id_ = max_push_id; - if (OneRttKeysAvailable()) { + if (IsEncryptionEstablished()) { SendMaxPushId(); } } @@ -1281,9 +1341,8 @@ void QuicSpdySession::SendMaxPushId() { DCHECK(VersionUsesHttp3(transport_version())); DCHECK_EQ(Perspective::IS_CLIENT, perspective()); - if (max_push_id_.has_value()) { - send_control_stream_->SendMaxPushIdFrame(max_push_id_.value()); - } + send_control_stream_->SendMaxPushIdFrame(max_push_id_.value()); + http3_max_push_id_sent_ = true; } void QuicSpdySession::EnableServerPush() { diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.h b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.h index 703dffaf41e..4d6ee6370e3 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.h +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.h @@ -247,10 +247,14 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession bool server_push_enabled() const; // Called when the control stream receives HTTP/3 SETTINGS. - virtual void OnSettingsFrame(const SettingsFrame& frame); + // Returns false in case of 0-RTT if received settings are incompatible with + // cached values, true otherwise. + virtual bool OnSettingsFrame(const SettingsFrame& frame); - // Called when a setting is parsed from an incoming SETTINGS frame. - void OnSetting(uint64_t id, uint64_t value); + // Called when a SETTINGS is parsed from an incoming SETTINGS frame. + // Returns false in case of 0-RTT if received SETTINGS is incompatible with + // cached value, true otherwise. + bool OnSetting(uint64_t id, uint64_t value); // Return true if this session wants to release headers stream's buffer // aggressively. @@ -378,7 +382,7 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession void OnStreamCreated(QuicSpdyStream* stream); // Decode SETTINGS from |cached_state| and apply it to the session. - bool SetApplicationState(ApplicationState* cached_state) override; + bool ResumeApplicationState(ApplicationState* cached_state) override; protected: // Override CreateIncomingStream(), CreateOutgoingBidirectionalStream() and @@ -443,11 +447,11 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession return receive_control_stream_; } + const SettingsFrame& settings() const { return settings_; } + // Initializes HTTP/3 unidirectional streams if not yet initialzed. virtual void MaybeInitializeHttp3UnidirectionalStreams(); - void SendMaxPushId(); - private: friend class test::QuicSpdySessionPeer; @@ -468,10 +472,18 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession void CloseConnectionOnDuplicateHttp3UnidirectionalStreams( quiche::QuicheStringPiece type); - // Sends any data which should be sent at the start of a connection, - // including the initial SETTINGS frame, etc. + // Sends any data which should be sent at the start of a connection, including + // the initial SETTINGS frame, and (when IETF QUIC is used) also a MAX_PUSH_ID + // frame if SetMaxPushId() had been called before encryption was established. + // When using 0-RTT, this method is called twice: once when encryption is + // established, and again when 1-RTT keys are available. void SendInitialData(); + // Send a MAX_PUSH_ID frame. Used in IETF QUIC only. + void SendMaxPushId(); + + void FillSettingsFrame(); + std::unique_ptr<QpackEncoder> qpack_encoder_; std::unique_ptr<QpackDecoder> qpack_decoder_; @@ -489,6 +501,8 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession QpackSendStream* qpack_encoder_send_stream_; QpackSendStream* qpack_decoder_send_stream_; + SettingsFrame settings_; + // Maximum dynamic table capacity as defined at // https://quicwg.org/base-drafts/draft-ietf-quic-qpack.html#maximum-dynamic-table-capacity // for the decoding context. Value will be sent via @@ -533,12 +547,17 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession // Server push is enabled for a client by calling SetMaxPushId(). bool ietf_server_push_enabled_; - // Used in IETF QUIC only. Unset until a MAX_PUSH_ID frame is received/sent. - // For a server, the push ID in the most recently received MAX_PUSH_ID frame. - // For a client before 1-RTT keys are available, the push ID to be sent in the - // initial MAX_PUSH_ID frame. - // For a client after 1-RTT keys are available, the push ID in the most - // recently sent MAX_PUSH_ID frame. + // Used in IETF QUIC only. + // For a server: + // the push ID in the most recently received MAX_PUSH_ID frame, + // or unset if no MAX_PUSH_ID frame has been received. + // For a client: + // unset until SetMaxPushId() is called; + // before encryption is established, the push ID to be sent in the initial + // MAX_PUSH_ID frame; + // after encryption is established, the push ID in the most recently sent + // MAX_PUSH_ID frame. + // Once set, never goes back to unset. quiche::QuicheOptional<PushId> max_push_id_; // An integer used for live check. The indicator is assigned a value in @@ -554,14 +573,14 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession // If the endpoint has sent HTTP/3 GOAWAY frame. bool http3_goaway_sent_; - // If SendMaxPushId() has been called from SendInitialData(). Note that a - // MAX_PUSH_ID frame is only sent if SetMaxPushId() had been called - // beforehand. + // Only used by a client, only with IETF QUIC. True if a MAX_PUSH_ID frame + // has been sent, in which case |max_push_id_| has the value sent in the most + // recent MAX_PUSH_ID frame. Once true, never goes back to false. bool http3_max_push_id_sent_; // Priority values received in PRIORITY_UPDATE frames for streams that are not // open yet. - QuicUnorderedMap<QuicStreamId, int> buffered_stream_priorities_; + QuicHashMap<QuicStreamId, int> buffered_stream_priorities_; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session_test.cc index 8b78d7f0883..b2bcaa3bf28 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session_test.cc @@ -91,6 +91,17 @@ class TestCryptoStream : public QuicCryptoStream, public QuicCryptoHandshaker { kInitialStreamFlowControlWindowForTest); session()->config()->SetInitialSessionFlowControlWindowToSend( kInitialSessionFlowControlWindowForTest); + if (session()->version().AuthenticatesHandshakeConnectionIds()) { + if (session()->perspective() == Perspective::IS_CLIENT) { + session()->config()->SetOriginalConnectionIdToSend( + session()->connection()->connection_id()); + session()->config()->SetInitialSourceConnectionIdToSend( + session()->connection()->connection_id()); + } else { + session()->config()->SetInitialSourceConnectionIdToSend( + session()->connection()->client_connection_id()); + } + } if (session()->connection()->version().handshake_protocol == PROTOCOL_TLS1_3) { TransportParameters transport_parameters; @@ -129,6 +140,8 @@ class TestCryptoStream : public QuicCryptoStream, public QuicCryptoHandshaker { HandshakeState GetHandshakeState() const override { return one_rtt_keys_available() ? HANDSHAKE_COMPLETE : HANDSHAKE_START; } + void SetServerApplicationStateForResumption( + std::unique_ptr<ApplicationState> /*application_state*/) override {} const QuicCryptoNegotiatedParameters& crypto_negotiated_params() const override { return *params_; @@ -197,6 +210,9 @@ class TestSession : public QuicSpdySession { this->connection()->SetEncrypter( ENCRYPTION_FORWARD_SECURE, std::make_unique<NullEncrypter>(connection->perspective())); + if (this->connection()->version().SupportsAntiAmplificationLimit()) { + QuicConnectionPeer::SetAddressValidated(this->connection()); + } } ~TestSession() override { DeleteConnection(); } @@ -226,7 +242,7 @@ class TestSession : public QuicSpdySession { TestStream* CreateIncomingStream(QuicStreamId id) override { // Enforce the limit on the number of open streams. if (!VersionHasIetfQuicFrames(connection()->transport_version()) && - GetNumOpenIncomingStreams() + 1 > + stream_id_manager().num_open_incoming_streams() + 1 > max_open_incoming_bidirectional_streams()) { connection()->CloseConnection( QUIC_TOO_MANY_OPEN_STREAMS, "Too many streams!", @@ -235,9 +251,8 @@ class TestSession : public QuicSpdySession { } else { TestStream* stream = new TestStream( id, this, - DetermineStreamType(id, connection()->transport_version(), - perspective(), /*is_incoming=*/true, - BIDIRECTIONAL)); + DetermineStreamType(id, connection()->version(), perspective(), + /*is_incoming=*/true, BIDIRECTIONAL)); ActivateStream(QuicWrapUnique(stream)); return stream; } @@ -245,11 +260,10 @@ class TestSession : public QuicSpdySession { TestStream* CreateIncomingStream(PendingStream* pending) override { QuicStreamId id = pending->id(); - TestStream* stream = - new TestStream(pending, this, - DetermineStreamType( - id, connection()->transport_version(), perspective(), - /*is_incoming=*/true, BIDIRECTIONAL)); + TestStream* stream = new TestStream( + pending, this, + DetermineStreamType(id, connection()->version(), perspective(), + /*is_incoming=*/true, BIDIRECTIONAL)); ActivateStream(QuicWrapUnique(stream)); return stream; } @@ -299,7 +313,7 @@ class TestSession : public QuicSpdySession { MakeIOVector("not empty", &iov); QuicStreamPeer::SendBuffer(stream).SaveStreamData(&iov, 1, 0, 9); QuicConsumedData consumed = - WritevData(stream->id(), 9, 0, FIN, NOT_RETRANSMISSION, QuicheNullOpt); + WritevData(stream->id(), 9, 0, FIN, NOT_RETRANSMISSION, QUICHE_NULLOPT); QuicStreamPeer::SendBuffer(stream).OnStreamDataConsumed( consumed.bytes_consumed); return consumed; @@ -308,7 +322,7 @@ class TestSession : public QuicSpdySession { QuicConsumedData SendLargeFakeData(QuicStream* stream, int bytes) { DCHECK(writev_consumes_all_data_); return WritevData(stream->id(), bytes, 0, FIN, NOT_RETRANSMISSION, - QuicheNullOpt); + QUICHE_NULLOPT); } using QuicSession::closed_streams; @@ -1599,6 +1613,7 @@ TEST_P(QuicSpdySessionTestServer, TooLowUnidirectionalStreamLimitHttp3) { return; } QuicConfigPeer::SetReceivedMaxUnidirectionalStreams(session_.config(), 2u); + connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); EXPECT_CALL( *connection_, @@ -1613,6 +1628,7 @@ TEST_P(QuicSpdySessionTestServer, CustomFlowControlWindow) { copt.push_back(kIFW7); QuicConfigPeer::SetReceivedConnectionOptions(session_.config(), copt); + connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); session_.OnConfigNegotiated(); EXPECT_EQ(192 * 1024u, QuicFlowControllerPeer::ReceiveWindowSize( session_.flow_controller())); @@ -2985,6 +3001,26 @@ TEST_P(QuicSpdySessionTestServer, PeerClosesCriticalReceiveStream) { } } +TEST_P(QuicSpdySessionTestServer, + H3ControlStreamsLimitedByConnectionFlowControl) { + if (!VersionUsesHttp3(transport_version())) { + return; + } + // Ensure connection level flow control blockage. + QuicFlowControllerPeer::SetSendWindowOffset(session_.flow_controller(), 0); + EXPECT_TRUE(session_.IsConnectionFlowControlBlocked()); + + QuicSendControlStream* send_control_stream = + QuicSpdySessionPeer::GetSendControlStream(&session_); + // Mark send_control stream write blocked. + session_.MarkConnectionLevelWriteBlocked(send_control_stream->id()); + if (GetQuicReloadableFlag(quic_fix_willing_and_able_to_write)) { + EXPECT_FALSE(session_.WillingAndAbleToWrite()); + } else { + EXPECT_TRUE(session_.WillingAndAbleToWrite()); + } +} + TEST_P(QuicSpdySessionTestServer, PeerClosesCriticalSendStream) { if (!VersionUsesHttp3(transport_version())) { return; diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream.cc index 51f7c5c9525..4c979c1784f 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream.cc @@ -529,6 +529,21 @@ void QuicSpdyStream::OnStreamHeadersPriority( void QuicSpdyStream::OnStreamHeaderList(bool fin, size_t frame_len, const QuicHeaderList& header_list) { + if (GetQuicReloadableFlag(quic_save_user_agent_in_quic_session)) { + if (!spdy_session()->user_agent_id().has_value()) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_save_user_agent_in_quic_session, 3, 3); + std::string uaid; + for (const auto& kv : header_list) { + if (quiche::QuicheTextUtils::ToLower(kv.first) == + kUserAgentHeaderName) { + uaid = kv.second; + break; + } + } + spdy_session()->SetUserAgentId(std::move(uaid)); + } + } + // TODO(b/134706391): remove |fin| argument. // When using Google QUIC, an empty header list indicates that the size limit // has been exceeded. diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_test.cc index bafb0f282f0..e769a9d6027 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_test.cc @@ -78,6 +78,17 @@ class TestCryptoStream : public QuicCryptoStream, public QuicCryptoHandshaker { kInitialStreamFlowControlWindowForTest); session()->config()->SetInitialSessionFlowControlWindowToSend( kInitialSessionFlowControlWindowForTest); + if (session()->version().AuthenticatesHandshakeConnectionIds()) { + if (session()->perspective() == Perspective::IS_CLIENT) { + session()->config()->SetOriginalConnectionIdToSend( + session()->connection()->connection_id()); + session()->config()->SetInitialSourceConnectionIdToSend( + session()->connection()->connection_id()); + } else { + session()->config()->SetInitialSourceConnectionIdToSend( + session()->connection()->client_connection_id()); + } + } if (session()->connection()->version().handshake_protocol == PROTOCOL_TLS1_3) { TransportParameters transport_parameters; @@ -116,6 +127,8 @@ class TestCryptoStream : public QuicCryptoStream, public QuicCryptoHandshaker { HandshakeState GetHandshakeState() const override { return one_rtt_keys_available() ? HANDSHAKE_COMPLETE : HANDSHAKE_START; } + void SetServerApplicationStateForResumption( + std::unique_ptr<ApplicationState> /*application_state*/) override {} const QuicCryptoNegotiatedParameters& crypto_negotiated_params() const override { return *params_; @@ -324,6 +337,9 @@ class QuicSpdyStreamTest : public QuicTestWithParam<ParsedQuicVersion> { &helper_, &alarm_factory_, perspective, SupportedVersions(GetParam())); session_ = std::make_unique<StrictMock<TestSession>>(connection_); session_->Initialize(); + if (connection_->version().SupportsAntiAmplificationLimit()) { + QuicConnectionPeer::SetAddressValidated(connection_); + } connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1)); ON_CALL(*session_, WritevData(_, _, _, _, _, _)) .WillByDefault( diff --git a/chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager.cc b/chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager.cc index 6120f850bbc..af4de8b1c8c 100644 --- a/chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager.cc +++ b/chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager.cc @@ -31,42 +31,20 @@ LegacyQuicStreamIdManager::LegacyQuicStreamIdManager( : QuicUtils::GetCryptoStreamId(transport_version_)) : QuicUtils::GetInvalidStreamId(transport_version_)), num_open_incoming_streams_(0), - num_open_outgoing_streams_(0), - handles_accounting_( - GetQuicReloadableFlag(quic_stream_id_manager_handles_accounting)) { - if (handles_accounting_) { - QUIC_RELOADABLE_FLAG_COUNT(quic_stream_id_manager_handles_accounting); - } -} + num_open_outgoing_streams_(0) {} LegacyQuicStreamIdManager::~LegacyQuicStreamIdManager() {} -bool LegacyQuicStreamIdManager::CanOpenNextOutgoingStream( - size_t current_num_open_outgoing_streams) const { - if (handles_accounting_) { - DCHECK_LE(num_open_outgoing_streams_, max_open_outgoing_streams_); - QUIC_DLOG_IF(INFO, num_open_outgoing_streams_ == max_open_outgoing_streams_) - << "Failed to create a new outgoing stream. " - << "Already " << num_open_outgoing_streams_ << " open."; - return num_open_outgoing_streams_ < max_open_outgoing_streams_; - } - if (current_num_open_outgoing_streams >= max_open_outgoing_streams_) { - QUIC_DLOG(INFO) << "Failed to create a new outgoing stream. " - << "Already " << current_num_open_outgoing_streams - << " open."; - return false; - } - return true; +bool LegacyQuicStreamIdManager::CanOpenNextOutgoingStream() const { + DCHECK_LE(num_open_outgoing_streams_, max_open_outgoing_streams_); + QUIC_DLOG_IF(INFO, num_open_outgoing_streams_ == max_open_outgoing_streams_) + << "Failed to create a new outgoing stream. " + << "Already " << num_open_outgoing_streams_ << " open."; + return num_open_outgoing_streams_ < max_open_outgoing_streams_; } -bool LegacyQuicStreamIdManager::CanOpenIncomingStream( - size_t current_num_open_incoming_streams) const { - if (handles_accounting_) { - return num_open_incoming_streams_ < max_open_incoming_streams_; - } - // Check if the new number of open streams would cause the number of - // open streams to exceed the limit. - return current_num_open_incoming_streams < max_open_incoming_streams_; +bool LegacyQuicStreamIdManager::CanOpenIncomingStream() const { + return num_open_incoming_streams_ < max_open_incoming_streams_; } bool LegacyQuicStreamIdManager::MaybeIncreaseLargestPeerStreamId( @@ -121,7 +99,6 @@ QuicStreamId LegacyQuicStreamIdManager::GetNextOutgoingStreamId() { } void LegacyQuicStreamIdManager::ActivateStream(bool is_incoming) { - DCHECK(handles_accounting_); if (is_incoming) { ++num_open_incoming_streams_; return; @@ -130,7 +107,6 @@ void LegacyQuicStreamIdManager::ActivateStream(bool is_incoming) { } void LegacyQuicStreamIdManager::OnStreamClosed(bool is_incoming) { - DCHECK(handles_accounting_); if (is_incoming) { QUIC_BUG_IF(num_open_incoming_streams_ == 0); --num_open_incoming_streams_; diff --git a/chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager.h b/chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager.h index 6c1309ebbc9..01315872fb8 100644 --- a/chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager.h +++ b/chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager.h @@ -29,11 +29,10 @@ class QUIC_EXPORT_PRIVATE LegacyQuicStreamIdManager { ~LegacyQuicStreamIdManager(); // Returns true if the next outgoing stream ID can be allocated. - bool CanOpenNextOutgoingStream( - size_t current_num_open_outgoing_streams) const; + bool CanOpenNextOutgoingStream() const; // Returns true if a new incoming stream can be opened. - bool CanOpenIncomingStream(size_t current_num_open_incoming_streams) const; + bool CanOpenIncomingStream() const; // Returns false when increasing the largest created stream id to |id| would // violate the limit, so the connection should be closed. @@ -95,8 +94,6 @@ class QUIC_EXPORT_PRIVATE LegacyQuicStreamIdManager { return num_open_outgoing_streams_; } - bool handles_accounting() const { return handles_accounting_; } - private: friend class test::QuicSessionPeer; @@ -118,16 +115,11 @@ class QUIC_EXPORT_PRIVATE LegacyQuicStreamIdManager { QuicStreamId largest_peer_created_stream_id_; - // A counter for peer initiated open streams. Used when handles_accounting_ is - // true. + // A counter for peer initiated open streams. size_t num_open_incoming_streams_; - // A counter for self initiated open streams. Used when handles_accounting_ is - // true. + // A counter for self initiated open streams. size_t num_open_outgoing_streams_; - - // Latched value of quic_stream_id_manager_handles_accounting. - const bool handles_accounting_; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager_test.cc b/chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager_test.cc index 00654b48c45..b7ba1d27035 100644 --- a/chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager_test.cc @@ -78,33 +78,21 @@ INSTANTIATE_TEST_SUITE_P(Tests, ::testing::PrintToStringParamName()); TEST_P(LegacyQuicStreamIdManagerTest, CanOpenNextOutgoingStream) { - if (GetQuicReloadableFlag(quic_stream_id_manager_handles_accounting)) { - for (size_t i = 0; i < manager_.max_open_outgoing_streams() - 1; ++i) { - manager_.ActivateStream(/*is_incoming=*/false); - } - } - EXPECT_TRUE(manager_.CanOpenNextOutgoingStream( - manager_.max_open_outgoing_streams() - 1)); - if (GetQuicReloadableFlag(quic_stream_id_manager_handles_accounting)) { + for (size_t i = 0; i < manager_.max_open_outgoing_streams() - 1; ++i) { manager_.ActivateStream(/*is_incoming=*/false); } - EXPECT_FALSE( - manager_.CanOpenNextOutgoingStream(manager_.max_open_outgoing_streams())); + EXPECT_TRUE(manager_.CanOpenNextOutgoingStream()); + manager_.ActivateStream(/*is_incoming=*/false); + EXPECT_FALSE(manager_.CanOpenNextOutgoingStream()); } TEST_P(LegacyQuicStreamIdManagerTest, CanOpenIncomingStream) { - if (GetQuicReloadableFlag(quic_stream_id_manager_handles_accounting)) { - for (size_t i = 0; i < manager_.max_open_incoming_streams() - 1; ++i) { - manager_.ActivateStream(/*is_incoming=*/true); - } - } - EXPECT_TRUE( - manager_.CanOpenIncomingStream(manager_.max_open_incoming_streams() - 1)); - if (GetQuicReloadableFlag(quic_stream_id_manager_handles_accounting)) { + for (size_t i = 0; i < manager_.max_open_incoming_streams() - 1; ++i) { manager_.ActivateStream(/*is_incoming=*/true); } - EXPECT_FALSE( - manager_.CanOpenIncomingStream(manager_.max_open_incoming_streams())); + EXPECT_TRUE(manager_.CanOpenIncomingStream()); + manager_.ActivateStream(/*is_incoming=*/true); + EXPECT_FALSE(manager_.CanOpenIncomingStream()); } TEST_P(LegacyQuicStreamIdManagerTest, AvailableStreams) { diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager.h index f1659a64fc9..ecb56993381 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager.h +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager.h @@ -77,7 +77,7 @@ class QUIC_EXPORT_PRIVATE QpackBlockingManager { // same time. Use std::list instead of QuicCircularDeque because it has lower // memory footprint when holding few elements. using HeaderBlocksForStream = std::list<IndexSet>; - using HeaderBlocks = QuicUnorderedMap<QuicStreamId, HeaderBlocksForStream>; + using HeaderBlocks = QuicHashMap<QuicStreamId, HeaderBlocksForStream>; // Increase or decrease the reference count for each index in |indices|. void IncreaseReferenceCounts(const IndexSet& indices); diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.cc index db7ec794268..67adf1268eb 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.cc +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.cc @@ -378,9 +378,10 @@ std::string QpackEncoder::EncodeHeaderList( return SecondPassEncode(std::move(instructions), required_insert_count); } -void QpackEncoder::SetMaximumDynamicTableCapacity( +bool QpackEncoder::SetMaximumDynamicTableCapacity( uint64_t maximum_dynamic_table_capacity) { - header_table_.SetMaximumDynamicTableCapacity(maximum_dynamic_table_capacity); + return header_table_.SetMaximumDynamicTableCapacity( + maximum_dynamic_table_capacity); } void QpackEncoder::SetDynamicTableCapacity(uint64_t dynamic_table_capacity) { @@ -392,8 +393,12 @@ void QpackEncoder::SetDynamicTableCapacity(uint64_t dynamic_table_capacity) { DCHECK(success); } -void QpackEncoder::SetMaximumBlockedStreams(uint64_t maximum_blocked_streams) { +bool QpackEncoder::SetMaximumBlockedStreams(uint64_t maximum_blocked_streams) { + if (maximum_blocked_streams < maximum_blocked_streams_) { + return false; + } maximum_blocked_streams_ = maximum_blocked_streams; + return true; } void QpackEncoder::OnInsertCountIncrement(uint64_t increment) { diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.h index 0f1d14ca539..202fc6d8ef1 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.h +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.h @@ -63,7 +63,10 @@ class QUIC_EXPORT_PRIVATE QpackEncoder // measured in bytes. Called when SETTINGS_QPACK_MAX_TABLE_CAPACITY is // received. Encoder needs to know this value so that it can calculate // MaxEntries, used as a modulus to encode Required Insert Count. - void SetMaximumDynamicTableCapacity(uint64_t maximum_dynamic_table_capacity); + // Returns true if |maximum_dynamic_table_capacity| is set for the first time + // or if it doesn't change current value. The setting is not changed when + // returning false. + bool SetMaximumDynamicTableCapacity(uint64_t maximum_dynamic_table_capacity); // Set dynamic table capacity to |dynamic_table_capacity|. // |dynamic_table_capacity| must not exceed maximum dynamic table capacity. @@ -72,7 +75,9 @@ class QUIC_EXPORT_PRIVATE QpackEncoder // Set maximum number of blocked streams. // Called when SETTINGS_QPACK_BLOCKED_STREAMS is received. - void SetMaximumBlockedStreams(uint64_t maximum_blocked_streams); + // Returns true if |maximum_blocked_streams| doesn't decrease current value. + // The setting is not changed when returning false. + bool SetMaximumBlockedStreams(uint64_t maximum_blocked_streams); // QpackDecoderStreamReceiver::Delegate implementation void OnInsertCountIncrement(uint64_t increment) override; @@ -94,6 +99,12 @@ class QUIC_EXPORT_PRIVATE QpackEncoder return header_table_.dynamic_table_entry_referenced(); } + uint64_t maximum_blocked_streams() const { return maximum_blocked_streams_; } + + uint64_t MaximumDynamicTableCapacity() const { + return header_table_.maximum_dynamic_table_capacity(); + } + private: friend class test::QpackEncoderPeer; diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table.cc index 472db893540..29e71488bda 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table.cc +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table.cc @@ -186,16 +186,15 @@ bool QpackHeaderTable::SetDynamicTableCapacity(uint64_t capacity) { return true; } -void QpackHeaderTable::SetMaximumDynamicTableCapacity( +bool QpackHeaderTable::SetMaximumDynamicTableCapacity( uint64_t maximum_dynamic_table_capacity) { - // This method can only be called once: in the decoding context, shortly after - // construction; in the encoding context, upon receiving the SETTINGS frame. - DCHECK_EQ(0u, dynamic_table_capacity_); - DCHECK_EQ(0u, maximum_dynamic_table_capacity_); - DCHECK_EQ(0u, max_entries_); - - maximum_dynamic_table_capacity_ = maximum_dynamic_table_capacity; - max_entries_ = maximum_dynamic_table_capacity / 32; + if (maximum_dynamic_table_capacity_ == 0) { + maximum_dynamic_table_capacity_ = maximum_dynamic_table_capacity; + max_entries_ = maximum_dynamic_table_capacity / 32; + return true; + } + // If the value is already set, it should not be changed. + return maximum_dynamic_table_capacity == maximum_dynamic_table_capacity_; } void QpackHeaderTable::RegisterObserver(uint64_t required_insert_count, diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table.h index e3fb97504b3..bed1cc84afa 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table.h +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table.h @@ -97,7 +97,10 @@ class QUIC_EXPORT_PRIVATE QpackHeaderTable { // value can be set upon connection establishment, whereas in the encoding // context it can be set when the SETTINGS frame is received. // This method must only be called at most once. - void SetMaximumDynamicTableCapacity(uint64_t maximum_dynamic_table_capacity); + // Returns true if |maximum_dynamic_table_capacity| is set for the first time + // or if it doesn't change current value. The setting is not changed when + // returning false. + bool SetMaximumDynamicTableCapacity(uint64_t maximum_dynamic_table_capacity); // Get |maximum_dynamic_table_capacity_|. uint64_t maximum_dynamic_table_capacity() const { diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_send_stream_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_send_stream_test.cc index c77a6218bca..63e0f12e3cc 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_send_stream_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_send_stream_test.cc @@ -7,6 +7,7 @@ #include "net/third_party/quiche/src/quic/core/http/http_constants.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" #include "net/third_party/quiche/src/quic/test_tools/quic_config_peer.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h" #include "net/third_party/quiche/src/quic/test_tools/quic_spdy_session_peer.h" #include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" #include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h" @@ -66,6 +67,9 @@ class QpackSendStreamTest : public QuicTestWithParam<TestParams> { SupportedVersions(GetParam().version))), session_(connection_) { session_.Initialize(); + if (connection_->version().SupportsAntiAmplificationLimit()) { + QuicConnectionPeer::SetAddressValidated(connection_); + } QuicConfigPeer::SetReceivedInitialSessionFlowControlWindow( session_.config(), kMinimumFlowControlSendWindow); QuicConfigPeer::SetReceivedInitialMaxStreamDataBytesUnidirectional( diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_coalesced_packet.cc b/chromium/net/third_party/quiche/src/quic/core/quic_coalesced_packet.cc index c18369eac9b..3b22180750d 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_coalesced_packet.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_coalesced_packet.cc @@ -61,7 +61,7 @@ bool QuicCoalescedPacket::MaybeCoalescePacket( return false; } QUIC_DVLOG(1) << "Successfully coalesced packet: encryption_level: " - << EncryptionLevelToString(packet.encryption_level) + << packet.encryption_level << ", encrypted_length: " << packet.encrypted_length << ", current length: " << length_ << ", max_packet_length: " << max_packet_length_; diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_config.cc b/chromium/net/third_party/quiche/src/quic/core/quic_config.cc index 7c781f4def0..30a5e2ba568 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_config.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_config.cc @@ -434,7 +434,7 @@ QuicConfig::QuicConfig() max_undecryptable_packets_(0), connection_options_(kCOPT, PRESENCE_OPTIONAL), client_connection_options_(kCLOP, PRESENCE_OPTIONAL), - idle_timeout_to_send_(QuicTime::Delta::Infinite()), + max_idle_timeout_to_send_(QuicTime::Delta::Infinite()), max_bidirectional_streams_(kMIBS, PRESENCE_REQUIRED), max_unidirectional_streams_(kMIUS, PRESENCE_OPTIONAL), bytes_for_connection_id_(kTCID, PRESENCE_OPTIONAL), @@ -447,12 +447,13 @@ QuicConfig::QuicConfig() initial_stream_flow_control_window_bytes_(kSFCW, PRESENCE_OPTIONAL), initial_session_flow_control_window_bytes_(kCFCW, PRESENCE_OPTIONAL), connection_migration_disabled_(kNCMR, PRESENCE_OPTIONAL), + support_handshake_done_(0, PRESENCE_OPTIONAL), alternate_server_address_ipv6_(kASAD, PRESENCE_OPTIONAL), alternate_server_address_ipv4_(kASAD, PRESENCE_OPTIONAL), stateless_reset_token_(kSRST, PRESENCE_OPTIONAL), max_ack_delay_ms_(kMAD, PRESENCE_OPTIONAL), ack_delay_exponent_(kADE, PRESENCE_OPTIONAL), - max_packet_size_(0, PRESENCE_OPTIONAL), + max_udp_payload_size_(0, PRESENCE_OPTIONAL), max_datagram_frame_size_(0, PRESENCE_OPTIONAL), active_connection_id_limit_(0, PRESENCE_OPTIONAL) { SetDefaults(); @@ -543,17 +544,17 @@ void QuicConfig::SetIdleNetworkTimeout(QuicTime::Delta idle_network_timeout) { QUIC_BUG << "Invalid idle network timeout " << idle_network_timeout; return; } - idle_timeout_to_send_ = idle_network_timeout; + max_idle_timeout_to_send_ = idle_network_timeout; } QuicTime::Delta QuicConfig::IdleNetworkTimeout() const { // TODO(b/152032210) add a QUIC_BUG to ensure that is not called before we've // received the peer's values. This is true in production code but not in all // of our tests that use a fake QuicConfig. - if (!received_idle_timeout_.has_value()) { - return idle_timeout_to_send_; + if (!received_max_idle_timeout_.has_value()) { + return max_idle_timeout_to_send_; } - return received_idle_timeout_.value(); + return received_max_idle_timeout_.value(); } void QuicConfig::SetMaxBidirectionalStreamsToSend(uint32_t max_streams) { @@ -592,7 +593,7 @@ void QuicConfig::SetMaxAckDelayToSendMs(uint32_t max_ack_delay_ms) { return max_ack_delay_ms_.SetSendValue(max_ack_delay_ms); } -uint32_t QuicConfig::GetMaxAckDelayToToSendMs() const { +uint32_t QuicConfig::GetMaxAckDelayToSendMs() const { return max_ack_delay_ms_.GetSendValue(); } @@ -620,20 +621,20 @@ uint32_t QuicConfig::ReceivedAckDelayExponent() const { return ack_delay_exponent_.GetReceivedValue(); } -void QuicConfig::SetMaxPacketSizeToSend(uint64_t max_packet_size) { - max_packet_size_.SetSendValue(max_packet_size); +void QuicConfig::SetMaxPacketSizeToSend(uint64_t max_udp_payload_size) { + max_udp_payload_size_.SetSendValue(max_udp_payload_size); } uint64_t QuicConfig::GetMaxPacketSizeToSend() const { - return max_packet_size_.GetSendValue(); + return max_udp_payload_size_.GetSendValue(); } bool QuicConfig::HasReceivedMaxPacketSize() const { - return max_packet_size_.HasReceivedValue(); + return max_udp_payload_size_.HasReceivedValue(); } uint64_t QuicConfig::ReceivedMaxPacketSize() const { - return max_packet_size_.GetReceivedValue(); + return max_udp_payload_size_.GetReceivedValue(); } void QuicConfig::SetMaxDatagramFrameSizeToSend( @@ -832,6 +833,19 @@ bool QuicConfig::DisableConnectionMigration() const { return connection_migration_disabled_.HasReceivedValue(); } +void QuicConfig::SetSupportHandshakeDone() { + support_handshake_done_.SetSendValue(1); +} + +bool QuicConfig::HandshakeDoneSupported() const { + return support_handshake_done_.HasSendValue() && + support_handshake_done_.GetSendValue() > 0; +} + +bool QuicConfig::PeerSupportsHandshakeDone() const { + return support_handshake_done_.HasReceivedValue(); +} + void QuicConfig::SetIPv6AlternateServerAddressToSend( const QuicSocketAddress& alternate_server_address_ipv6) { if (!alternate_server_address_ipv6.host().IsIPv6()) { @@ -871,12 +885,13 @@ const QuicSocketAddress& QuicConfig::ReceivedIPv4AlternateServerAddress() } void QuicConfig::SetOriginalConnectionIdToSend( - const QuicConnectionId& original_connection_id) { - original_connection_id_to_send_ = original_connection_id; + const QuicConnectionId& original_destination_connection_id) { + original_destination_connection_id_to_send_ = + original_destination_connection_id; } bool QuicConfig::HasReceivedOriginalConnectionId() const { - return received_original_connection_id_.has_value(); + return received_original_destination_connection_id_.has_value(); } QuicConnectionId QuicConfig::ReceivedOriginalConnectionId() const { @@ -884,7 +899,41 @@ QuicConnectionId QuicConfig::ReceivedOriginalConnectionId() const { QUIC_BUG << "No received original connection ID"; return EmptyQuicConnectionId(); } - return received_original_connection_id_.value(); + return received_original_destination_connection_id_.value(); +} + +void QuicConfig::SetInitialSourceConnectionIdToSend( + const QuicConnectionId& initial_source_connection_id) { + initial_source_connection_id_to_send_ = initial_source_connection_id; +} + +bool QuicConfig::HasReceivedInitialSourceConnectionId() const { + return received_initial_source_connection_id_.has_value(); +} + +QuicConnectionId QuicConfig::ReceivedInitialSourceConnectionId() const { + if (!HasReceivedInitialSourceConnectionId()) { + QUIC_BUG << "No received initial source connection ID"; + return EmptyQuicConnectionId(); + } + return received_initial_source_connection_id_.value(); +} + +void QuicConfig::SetRetrySourceConnectionIdToSend( + const QuicConnectionId& retry_source_connection_id) { + retry_source_connection_id_to_send_ = retry_source_connection_id; +} + +bool QuicConfig::HasReceivedRetrySourceConnectionId() const { + return received_retry_source_connection_id_.has_value(); +} + +QuicConnectionId QuicConfig::ReceivedRetrySourceConnectionId() const { + if (!HasReceivedRetrySourceConnectionId()) { + QUIC_BUG << "No received retry source connection ID"; + return EmptyQuicConnectionId(); + } + return received_retry_source_connection_id_.value(); } void QuicConfig::SetStatelessResetTokenToSend( @@ -938,14 +987,16 @@ void QuicConfig::ToHandshakeMessage( // the one received. Additionally, when QUIC_CRYPTO is used, the server // MUST send an idle timeout no greater than the idle timeout it received // from the client. We therefore send the received value if it is lower. - QuicFixedUint32 idle_timeout_seconds(kICSL, PRESENCE_REQUIRED); - uint32_t idle_timeout_to_send_seconds = idle_timeout_to_send_.ToSeconds(); - if (received_idle_timeout_.has_value() && - received_idle_timeout_->ToSeconds() < idle_timeout_to_send_seconds) { - idle_timeout_to_send_seconds = received_idle_timeout_->ToSeconds(); + QuicFixedUint32 max_idle_timeout_seconds(kICSL, PRESENCE_REQUIRED); + uint32_t max_idle_timeout_to_send_seconds = + max_idle_timeout_to_send_.ToSeconds(); + if (received_max_idle_timeout_.has_value() && + received_max_idle_timeout_->ToSeconds() < + max_idle_timeout_to_send_seconds) { + max_idle_timeout_to_send_seconds = received_max_idle_timeout_->ToSeconds(); } - idle_timeout_seconds.SetSendValue(idle_timeout_to_send_seconds); - idle_timeout_seconds.ToHandshakeMessage(out); + max_idle_timeout_seconds.SetSendValue(max_idle_timeout_to_send_seconds); + max_idle_timeout_seconds.ToHandshakeMessage(out); // Do not need a version check here, max...bi... will encode // as "MIDS" -- the max initial dynamic streams tag -- if @@ -955,8 +1006,15 @@ void QuicConfig::ToHandshakeMessage( max_unidirectional_streams_.ToHandshakeMessage(out); ack_delay_exponent_.ToHandshakeMessage(out); } - if (GetQuicReloadableFlag(quic_negotiate_ack_delay_time)) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_negotiate_ack_delay_time, 1, 4); + if (GetQuicReloadableFlag(quic_dont_send_max_ack_delay_if_default)) { + QUIC_RELOADABLE_FLAG_COUNT(quic_dont_send_max_ack_delay_if_default); + if (max_ack_delay_ms_.GetSendValue() != kDefaultDelayedAckTimeMs) { + // Only send max ack delay if it is using a non-default value, because + // the default value is used by QuicSentPacketManager if it is not + // sent during the handshake, and we want to save bytes. + max_ack_delay_ms_.ToHandshakeMessage(out); + } + } else { max_ack_delay_ms_.ToHandshakeMessage(out); } bytes_for_connection_id_.ToHandshakeMessage(out); @@ -986,12 +1044,12 @@ QuicErrorCode QuicConfig::ProcessPeerHello( // the one received. Additionally, when QUIC_CRYPTO is used, the server // MUST send an idle timeout no greater than the idle timeout it received // from the client. - QuicFixedUint32 idle_timeout_seconds(kICSL, PRESENCE_REQUIRED); - error = idle_timeout_seconds.ProcessPeerHello(peer_hello, hello_type, - error_details); + QuicFixedUint32 max_idle_timeout_seconds(kICSL, PRESENCE_REQUIRED); + error = max_idle_timeout_seconds.ProcessPeerHello(peer_hello, hello_type, + error_details); if (error == QUIC_NO_ERROR) { - if (idle_timeout_seconds.GetReceivedValue() > - idle_timeout_to_send_.ToSeconds()) { + if (max_idle_timeout_seconds.GetReceivedValue() > + max_idle_timeout_to_send_.ToSeconds()) { // The received value is higher than ours, ignore it if from the client // and raise an error if from the server. if (hello_type == SERVER) { @@ -1000,8 +1058,8 @@ QuicErrorCode QuicConfig::ProcessPeerHello( "Invalid value received for " + QuicTagToString(kICSL); } } else { - received_idle_timeout_ = QuicTime::Delta::FromSeconds( - idle_timeout_seconds.GetReceivedValue()); + received_max_idle_timeout_ = QuicTime::Delta::FromSeconds( + max_idle_timeout_seconds.GetReceivedValue()); } } } @@ -1056,9 +1114,7 @@ QuicErrorCode QuicConfig::ProcessPeerHello( error_details); } - if (GetQuicReloadableFlag(quic_negotiate_ack_delay_time) && - error == QUIC_NO_ERROR) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_negotiate_ack_delay_time, 2, 4); + if (error == QUIC_NO_ERROR) { error = max_ack_delay_ms_.ProcessPeerHello(peer_hello, hello_type, error_details); } @@ -1073,12 +1129,13 @@ QuicErrorCode QuicConfig::ProcessPeerHello( } bool QuicConfig::FillTransportParameters(TransportParameters* params) const { - if (original_connection_id_to_send_.has_value()) { - params->original_connection_id = original_connection_id_to_send_.value(); + if (original_destination_connection_id_to_send_.has_value()) { + params->original_destination_connection_id = + original_destination_connection_id_to_send_.value(); } - params->idle_timeout_milliseconds.set_value( - idle_timeout_to_send_.ToMilliseconds()); + params->max_idle_timeout_ms.set_value( + max_idle_timeout_to_send_.ToMilliseconds()); if (stateless_reset_token_.HasSendValue()) { QuicUint128 stateless_reset_token = stateless_reset_token_.GetSendValue(); @@ -1088,7 +1145,7 @@ bool QuicConfig::FillTransportParameters(TransportParameters* params) const { sizeof(stateless_reset_token)); } - params->max_packet_size.set_value(GetMaxPacketSizeToSend()); + params->max_udp_payload_size.set_value(GetMaxPacketSizeToSend()); params->max_datagram_frame_size.set_value(GetMaxDatagramFrameSizeToSend()); params->initial_max_data.set_value( GetInitialSessionFlowControlWindowToSend()); @@ -1108,14 +1165,12 @@ bool QuicConfig::FillTransportParameters(TransportParameters* params) const { GetMaxBidirectionalStreamsToSend()); params->initial_max_streams_uni.set_value( GetMaxUnidirectionalStreamsToSend()); - if (GetQuicReloadableFlag(quic_negotiate_ack_delay_time)) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_negotiate_ack_delay_time, 3, 4); - params->max_ack_delay.set_value(kDefaultDelayedAckTimeMs); - } + params->max_ack_delay.set_value(GetMaxAckDelayToSendMs()); params->ack_delay_exponent.set_value(GetAckDelayExponentToSend()); - params->disable_migration = + params->disable_active_migration = connection_migration_disabled_.HasSendValue() && connection_migration_disabled_.GetSendValue() != 0; + params->support_handshake_done = HandshakeDoneSupported(); if (alternate_server_address_ipv6_.HasSendValue() || alternate_server_address_ipv4_.HasSendValue()) { @@ -1138,6 +1193,16 @@ bool QuicConfig::FillTransportParameters(TransportParameters* params) const { active_connection_id_limit_.GetSendValue()); } + if (initial_source_connection_id_to_send_.has_value()) { + params->initial_source_connection_id = + initial_source_connection_id_to_send_.value(); + } + + if (retry_source_connection_id_to_send_.has_value()) { + params->retry_source_connection_id = + retry_source_connection_id_to_send_.value(); + } + if (GetQuicRestartFlag(quic_google_transport_param_send_new)) { QUIC_RESTART_FLAG_COUNT_N(quic_google_transport_param_send_new, 1, 3); if (initial_round_trip_time_us_.HasSendValue()) { @@ -1171,18 +1236,19 @@ QuicErrorCode QuicConfig::ProcessTransportParameters( HelloType hello_type, bool is_resumption, std::string* error_details) { - if (!is_resumption && params.original_connection_id.has_value()) { - received_original_connection_id_ = params.original_connection_id.value(); + if (!is_resumption && params.original_destination_connection_id.has_value()) { + received_original_destination_connection_id_ = + params.original_destination_connection_id.value(); } - if (params.idle_timeout_milliseconds.value() > 0 && - params.idle_timeout_milliseconds.value() < - static_cast<uint64_t>(idle_timeout_to_send_.ToMilliseconds())) { + if (params.max_idle_timeout_ms.value() > 0 && + params.max_idle_timeout_ms.value() < + static_cast<uint64_t>(max_idle_timeout_to_send_.ToMilliseconds())) { // An idle timeout of zero indicates it is disabled. // We also ignore values higher than ours which will cause us to use the // smallest value between ours and our peer's. - received_idle_timeout_ = QuicTime::Delta::FromMilliseconds( - params.idle_timeout_milliseconds.value()); + received_max_idle_timeout_ = + QuicTime::Delta::FromMilliseconds(params.max_idle_timeout_ms.value()); } if (!is_resumption && !params.stateless_reset_token.empty()) { @@ -1198,8 +1264,8 @@ QuicErrorCode QuicConfig::ProcessTransportParameters( stateless_reset_token_.SetReceivedValue(stateless_reset_token); } - if (params.max_packet_size.IsValid()) { - max_packet_size_.SetReceivedValue(params.max_packet_size.value()); + if (params.max_udp_payload_size.IsValid()) { + max_udp_payload_size_.SetReceivedValue(params.max_udp_payload_size.value()); } if (params.max_datagram_frame_size.IsValid()) { @@ -1233,10 +1299,7 @@ QuicErrorCode QuicConfig::ProcessTransportParameters( params.initial_max_stream_data_uni.value()); if (!is_resumption) { - if (GetQuicReloadableFlag(quic_negotiate_ack_delay_time)) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_negotiate_ack_delay_time, 4, 4); - max_ack_delay_ms_.SetReceivedValue(params.max_ack_delay.value()); - } + max_ack_delay_ms_.SetReceivedValue(params.max_ack_delay.value()); if (params.ack_delay_exponent.IsValid()) { ack_delay_exponent_.SetReceivedValue(params.ack_delay_exponent.value()); } @@ -1252,13 +1315,27 @@ QuicErrorCode QuicConfig::ProcessTransportParameters( } } - if (params.disable_migration) { + if (params.disable_active_migration) { connection_migration_disabled_.SetReceivedValue(1u); } + if (params.support_handshake_done) { + support_handshake_done_.SetReceivedValue(1u); + } active_connection_id_limit_.SetReceivedValue( params.active_connection_id_limit.value()); + if (!is_resumption) { + if (params.initial_source_connection_id.has_value()) { + received_initial_source_connection_id_ = + params.initial_source_connection_id.value(); + } + if (params.retry_source_connection_id.has_value()) { + received_retry_source_connection_id_ = + params.retry_source_connection_id.value(); + } + } + bool google_params_already_parsed = false; if (GetQuicRestartFlag(quic_google_transport_param_send_new)) { QUIC_RESTART_FLAG_COUNT_N(quic_google_transport_param_send_new, 2, 3); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_config.h b/chromium/net/third_party/quiche/src/quic/core/quic_config.h index 4d2bacce383..6f041b82f45 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_config.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_config.h @@ -382,6 +382,11 @@ class QUIC_EXPORT_PRIVATE QuicConfig { void SetDisableConnectionMigration(); bool DisableConnectionMigration() const; + // Support handshake done. + void SetSupportHandshakeDone(); + bool HandshakeDoneSupported() const; + bool PeerSupportsHandshakeDone() const; + // IPv6 alternate server address. void SetIPv6AlternateServerAddressToSend( const QuicSocketAddress& alternate_server_address_ipv6); @@ -394,9 +399,9 @@ class QUIC_EXPORT_PRIVATE QuicConfig { bool HasReceivedIPv4AlternateServerAddress() const; const QuicSocketAddress& ReceivedIPv4AlternateServerAddress() const; - // Original connection ID. + // Original destination connection ID. void SetOriginalConnectionIdToSend( - const QuicConnectionId& original_connection_id); + const QuicConnectionId& original_destination_connection_id); bool HasReceivedOriginalConnectionId() const; QuicConnectionId ReceivedOriginalConnectionId() const; @@ -411,7 +416,7 @@ class QUIC_EXPORT_PRIVATE QuicConfig { // The received delay is the value received from // the peer (QuicSentPacketManager::peer_max_ack_delay_). void SetMaxAckDelayToSendMs(uint32_t max_ack_delay_ms); - uint32_t GetMaxAckDelayToToSendMs() const; + uint32_t GetMaxAckDelayToSendMs() const; bool HasReceivedMaxAckDelayMs() const; uint32_t ReceivedMaxAckDelayMs() const; @@ -420,8 +425,8 @@ class QUIC_EXPORT_PRIVATE QuicConfig { bool HasReceivedAckDelayExponent() const; uint32_t ReceivedAckDelayExponent() const; - // IETF QUIC max_packet_size transport parameter. - void SetMaxPacketSizeToSend(uint64_t max_packet_size); + // IETF QUIC max_udp_payload_size transport parameter. + void SetMaxPacketSizeToSend(uint64_t max_udp_payload_size); uint64_t GetMaxPacketSizeToSend() const; bool HasReceivedMaxPacketSize() const; uint64_t ReceivedMaxPacketSize() const; @@ -438,6 +443,18 @@ class QUIC_EXPORT_PRIVATE QuicConfig { bool HasReceivedActiveConnectionIdLimit() const; uint64_t ReceivedActiveConnectionIdLimit() const; + // Initial source connection ID. + void SetInitialSourceConnectionIdToSend( + const QuicConnectionId& initial_source_connection_id); + bool HasReceivedInitialSourceConnectionId() const; + QuicConnectionId ReceivedInitialSourceConnectionId() const; + + // Retry source connection ID. + void SetRetrySourceConnectionIdToSend( + const QuicConnectionId& retry_source_connection_id); + bool HasReceivedRetrySourceConnectionId() const; + QuicConnectionId ReceivedRetrySourceConnectionId() const; + bool negotiated() const; void SetCreateSessionTagIndicators(QuicTagVector tags); @@ -501,12 +518,12 @@ class QUIC_EXPORT_PRIVATE QuicConfig { QuicFixedTagVector connection_options_; // Connection options which only affect the client side. QuicFixedTagVector client_connection_options_; - // Idle network timeout. + // Maximum idle network timeout. // Uses the max_idle_timeout transport parameter in IETF QUIC. - // Note that received_idle_timeout_ is only populated if we receive the + // Note that received_max_idle_timeout_ is only populated if we receive the // peer's value, which isn't guaranteed in IETF QUIC as sending is optional. - QuicTime::Delta idle_timeout_to_send_; - quiche::QuicheOptional<QuicTime::Delta> received_idle_timeout_; + QuicTime::Delta max_idle_timeout_to_send_; + quiche::QuicheOptional<QuicTime::Delta> received_max_idle_timeout_; // Maximum number of dynamic streams that a Google QUIC connection // can support or the maximum number of bidirectional streams that // an IETF QUIC connection can support. @@ -554,6 +571,10 @@ class QUIC_EXPORT_PRIVATE QuicConfig { // Uses the disable_active_migration transport parameter in IETF QUIC. QuicFixedUint32 connection_migration_disabled_; + // Whether handshake done is supported. Only used in T050. + // Uses the support_handshake_done transport parameter in IETF QUIC. + QuicFixedUint32 support_handshake_done_; + // Alternate server addresses the client could connect to. // Uses the preferred_address transport parameter in IETF QUIC. // Note that when QUIC_CRYPTO is in use, only one of the addresses is sent. @@ -583,8 +604,8 @@ class QUIC_EXPORT_PRIVATE QuicConfig { QuicFixedUint32 ack_delay_exponent_; // Maximum packet size in bytes. - // Uses the max_packet_size transport parameter in IETF QUIC. - QuicFixedUint62 max_packet_size_; + // Uses the max_udp_payload_size transport parameter in IETF QUIC. + QuicFixedUint62 max_udp_payload_size_; // Maximum DATAGRAM/MESSAGE frame size in bytes. // Uses the max_datagram_frame_size transport parameter in IETF QUIC. @@ -594,10 +615,28 @@ class QUIC_EXPORT_PRIVATE QuicConfig { // Uses the active_connection_id_limit transport parameter in IETF QUIC. QuicFixedUint62 active_connection_id_limit_; - // Sent by the server when it has previously sent a RETRY packet. - // Uses the original_connection_id transport parameter in IETF QUIC. - quiche::QuicheOptional<QuicConnectionId> original_connection_id_to_send_; - quiche::QuicheOptional<QuicConnectionId> received_original_connection_id_; + // The value of the Destination Connection ID field from the first + // Initial packet sent by the client. + // Uses the original_destination_connection_id transport parameter in + // IETF QUIC. + quiche::QuicheOptional<QuicConnectionId> + original_destination_connection_id_to_send_; + quiche::QuicheOptional<QuicConnectionId> + received_original_destination_connection_id_; + + // The value that the endpoint included in the Source Connection ID field of + // the first Initial packet it sent. + // Uses the initial_source_connection_id transport parameter in IETF QUIC. + quiche::QuicheOptional<QuicConnectionId> + initial_source_connection_id_to_send_; + quiche::QuicheOptional<QuicConnectionId> + received_initial_source_connection_id_; + + // The value that the server included in the Source Connection ID field of a + // Retry packet it sent. + // Uses the retry_source_connection_id transport parameter in IETF QUIC. + quiche::QuicheOptional<QuicConnectionId> retry_source_connection_id_to_send_; + quiche::QuicheOptional<QuicConnectionId> received_retry_source_connection_id_; // Custom transport parameters that can be sent and received in the TLS // handshake. diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_config_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_config_test.cc index 4aa10ef40b0..050a091a8d2 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_config_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_config_test.cc @@ -180,12 +180,8 @@ TEST_P(QuicConfigTest, ProcessClientHello) { 2 * kInitialStreamFlowControlWindowForTest); EXPECT_EQ(config_.ReceivedInitialSessionFlowControlWindowBytes(), 2 * kInitialSessionFlowControlWindowForTest); - if (GetQuicReloadableFlag(quic_negotiate_ack_delay_time)) { - EXPECT_TRUE(config_.HasReceivedMaxAckDelayMs()); - EXPECT_EQ(kTestMaxAckDelayMs, config_.ReceivedMaxAckDelayMs()); - } else { - EXPECT_FALSE(config_.HasReceivedMaxAckDelayMs()); - } + EXPECT_TRUE(config_.HasReceivedMaxAckDelayMs()); + EXPECT_EQ(kTestMaxAckDelayMs, config_.ReceivedMaxAckDelayMs()); // IETF QUIC stream limits should not be received in QUIC crypto messages. EXPECT_FALSE( @@ -238,12 +234,8 @@ TEST_P(QuicConfigTest, ProcessServerHello) { EXPECT_FALSE(config_.HasReceivedIPv6AlternateServerAddress()); EXPECT_TRUE(config_.HasReceivedStatelessResetToken()); EXPECT_EQ(kTestResetToken, config_.ReceivedStatelessResetToken()); - if (GetQuicReloadableFlag(quic_negotiate_ack_delay_time)) { - EXPECT_TRUE(config_.HasReceivedMaxAckDelayMs()); - EXPECT_EQ(kTestMaxAckDelayMs, config_.ReceivedMaxAckDelayMs()); - } else { - EXPECT_FALSE(config_.HasReceivedMaxAckDelayMs()); - } + EXPECT_TRUE(config_.HasReceivedMaxAckDelayMs()); + EXPECT_EQ(kTestMaxAckDelayMs, config_.ReceivedMaxAckDelayMs()); // IETF QUIC stream limits should not be received in QUIC crypto messages. EXPECT_FALSE( @@ -442,7 +434,7 @@ TEST_P(QuicConfigTest, IncomingLargeIdleTimeoutTransportParameter) { // Since the received value is above ours, we should then use ours. config_.SetIdleNetworkTimeout(quic::QuicTime::Delta::FromSeconds(60)); TransportParameters params; - params.idle_timeout_milliseconds.set_value(120000); + params.max_idle_timeout_ms.set_value(120000); std::string error_details = "foobar"; EXPECT_THAT(config_.ProcessTransportParameters( @@ -468,6 +460,10 @@ TEST_P(QuicConfigTest, FillTransportParams) { config_.SetMaxDatagramFrameSizeToSend(kMaxDatagramFrameSizeForTest); config_.SetActiveConnectionIdLimitToSend(kFakeActiveConnectionIdLimit); + config_.SetOriginalConnectionIdToSend(TestConnectionId(0x1111)); + config_.SetInitialSourceConnectionIdToSend(TestConnectionId(0x2222)); + config_.SetRetrySourceConnectionIdToSend(TestConnectionId(0x3333)); + TransportParameters params; config_.FillTransportParameters(¶ms); @@ -479,13 +475,23 @@ TEST_P(QuicConfigTest, FillTransportParams) { params.initial_max_stream_data_uni.value()); EXPECT_EQ(static_cast<uint64_t>(kMaximumIdleTimeoutSecs * 1000), - params.idle_timeout_milliseconds.value()); + params.max_idle_timeout_ms.value()); - EXPECT_EQ(kMaxPacketSizeForTest, params.max_packet_size.value()); + EXPECT_EQ(kMaxPacketSizeForTest, params.max_udp_payload_size.value()); EXPECT_EQ(kMaxDatagramFrameSizeForTest, params.max_datagram_frame_size.value()); EXPECT_EQ(kFakeActiveConnectionIdLimit, params.active_connection_id_limit.value()); + + ASSERT_TRUE(params.original_destination_connection_id.has_value()); + EXPECT_EQ(TestConnectionId(0x1111), + params.original_destination_connection_id.value()); + ASSERT_TRUE(params.initial_source_connection_id.has_value()); + EXPECT_EQ(TestConnectionId(0x2222), + params.initial_source_connection_id.value()); + ASSERT_TRUE(params.retry_source_connection_id.has_value()); + EXPECT_EQ(TestConnectionId(0x3333), + params.retry_source_connection_id.value()); } TEST_P(QuicConfigTest, ProcessTransportParametersServer) { @@ -493,7 +499,6 @@ TEST_P(QuicConfigTest, ProcessTransportParametersServer) { // TransportParameters are only used for QUIC+TLS. return; } - SetQuicReloadableFlag(quic_negotiate_ack_delay_time, true); TransportParameters params; params.initial_max_stream_data_bidi_local.set_value( @@ -502,13 +507,16 @@ TEST_P(QuicConfigTest, ProcessTransportParametersServer) { 3 * kMinimumFlowControlSendWindow); params.initial_max_stream_data_uni.set_value(4 * kMinimumFlowControlSendWindow); - params.max_packet_size.set_value(kMaxPacketSizeForTest); + params.max_udp_payload_size.set_value(kMaxPacketSizeForTest); params.max_datagram_frame_size.set_value(kMaxDatagramFrameSizeForTest); params.initial_max_streams_bidi.set_value(kDefaultMaxStreamsPerConnection); params.stateless_reset_token = CreateFakeStatelessResetToken(); params.max_ack_delay.set_value(kFakeMaxAckDelay); params.ack_delay_exponent.set_value(kFakeAckDelayExponent); params.active_connection_id_limit.set_value(kFakeActiveConnectionIdLimit); + params.original_destination_connection_id = TestConnectionId(0x1111); + params.initial_source_connection_id = TestConnectionId(0x2222); + params.retry_source_connection_id = TestConnectionId(0x3333); std::string error_details; EXPECT_THAT(config_.ProcessTransportParameters( @@ -544,11 +552,15 @@ TEST_P(QuicConfigTest, ProcessTransportParametersServer) { config_.ReceivedMaxBidirectionalStreams()); EXPECT_FALSE(config_.DisableConnectionMigration()); + EXPECT_FALSE(config_.PeerSupportsHandshakeDone()); // The following config shouldn't be processed because of resumption. EXPECT_FALSE(config_.HasReceivedStatelessResetToken()); EXPECT_FALSE(config_.HasReceivedMaxAckDelayMs()); EXPECT_FALSE(config_.HasReceivedAckDelayExponent()); + EXPECT_FALSE(config_.HasReceivedOriginalConnectionId()); + EXPECT_FALSE(config_.HasReceivedInitialSourceConnectionId()); + EXPECT_FALSE(config_.HasReceivedRetrySourceConnectionId()); // Let the config process another slightly tweaked transport paramters. // Note that the values for flow control and stream limit cannot be smaller @@ -559,11 +571,12 @@ TEST_P(QuicConfigTest, ProcessTransportParametersServer) { 4 * kMinimumFlowControlSendWindow); params.initial_max_stream_data_uni.set_value(5 * kMinimumFlowControlSendWindow); - params.max_packet_size.set_value(2 * kMaxPacketSizeForTest); + params.max_udp_payload_size.set_value(2 * kMaxPacketSizeForTest); params.max_datagram_frame_size.set_value(2 * kMaxDatagramFrameSizeForTest); params.initial_max_streams_bidi.set_value(2 * kDefaultMaxStreamsPerConnection); - params.disable_migration = true; + params.disable_active_migration = true; + params.support_handshake_done = true; EXPECT_THAT(config_.ProcessTransportParameters( params, SERVER, /* is_resumption = */ false, &error_details), @@ -598,6 +611,7 @@ TEST_P(QuicConfigTest, ProcessTransportParametersServer) { config_.ReceivedMaxBidirectionalStreams()); EXPECT_TRUE(config_.DisableConnectionMigration()); + EXPECT_TRUE(config_.PeerSupportsHandshakeDone()); ASSERT_TRUE(config_.HasReceivedStatelessResetToken()); ASSERT_TRUE(config_.HasReceivedMaxAckDelayMs()); @@ -609,6 +623,15 @@ TEST_P(QuicConfigTest, ProcessTransportParametersServer) { ASSERT_TRUE(config_.HasReceivedActiveConnectionIdLimit()); EXPECT_EQ(config_.ReceivedActiveConnectionIdLimit(), kFakeActiveConnectionIdLimit); + + ASSERT_TRUE(config_.HasReceivedOriginalConnectionId()); + EXPECT_EQ(config_.ReceivedOriginalConnectionId(), TestConnectionId(0x1111)); + ASSERT_TRUE(config_.HasReceivedInitialSourceConnectionId()); + EXPECT_EQ(config_.ReceivedInitialSourceConnectionId(), + TestConnectionId(0x2222)); + ASSERT_TRUE(config_.HasReceivedRetrySourceConnectionId()); + EXPECT_EQ(config_.ReceivedRetrySourceConnectionId(), + TestConnectionId(0x3333)); } TEST_P(QuicConfigTest, DisableMigrationTransportParameter) { @@ -617,7 +640,7 @@ TEST_P(QuicConfigTest, DisableMigrationTransportParameter) { return; } TransportParameters params; - params.disable_migration = true; + params.disable_active_migration = true; std::string error_details; EXPECT_THAT(config_.ProcessTransportParameters( params, SERVER, /* is_resumption = */ false, &error_details), diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_connection.cc b/chromium/net/third_party/quiche/src/quic/core/quic_connection.cc index 4f089a44fe9..4a21277e942 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_connection.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_connection.cc @@ -25,6 +25,7 @@ #include "net/third_party/quiche/src/quic/core/quic_connection_id.h" #include "net/third_party/quiche/src/quic/core/quic_constants.h" #include "net/third_party/quiche/src/quic/core/quic_error_codes.h" +#include "net/third_party/quiche/src/quic/core/quic_legacy_version_encapsulator.h" #include "net/third_party/quiche/src/quic/core/quic_types.h" #include "net/third_party/quiche/src/quic/core/quic_utils.h" #include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" @@ -33,6 +34,7 @@ #include "net/third_party/quiche/src/quic/platform/api/quic_exported_stats.h" #include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h" #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_hostname_utils.h" #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" #include "net/third_party/quiche/src/quic/platform/api/quic_map_util.h" #include "net/third_party/quiche/src/quic/platform/api/quic_string_utils.h" @@ -107,20 +109,6 @@ class SendAlarmDelegate : public QuicAlarm::Delegate { QuicConnection* connection_; }; -class PathDegradingAlarmDelegate : public QuicAlarm::Delegate { - public: - explicit PathDegradingAlarmDelegate(QuicConnection* connection) - : connection_(connection) {} - PathDegradingAlarmDelegate(const PathDegradingAlarmDelegate&) = delete; - PathDegradingAlarmDelegate& operator=(const PathDegradingAlarmDelegate&) = - delete; - - void OnAlarm() override { connection_->OnPathDegradingTimeout(); } - - private: - QuicConnection* connection_; -}; - class TimeoutAlarmDelegate : public QuicAlarm::Delegate { public: explicit TimeoutAlarmDelegate(QuicConnection* connection) @@ -260,7 +248,7 @@ QuicConnection::QuicConnection( send_version_negotiation_packet_with_prefixed_lengths_(false), idle_timeout_connection_close_behavior_( ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET), - close_connection_after_five_rtos_(false), + num_rtos_for_blackhole_detection_(0), uber_received_packet_manager_(&stats_), stop_waiting_count_(0), pending_retransmission_alarm_(false), @@ -327,7 +315,6 @@ QuicConnection::QuicConnection( supports_release_time_(false), release_time_into_future_(QuicTime::Delta::Zero()), drop_incoming_retry_packets_(false), - max_consecutive_ptos_(0), bytes_received_before_address_validation_(0), bytes_sent_before_address_validation_(0), address_validated_(false), @@ -335,7 +322,8 @@ QuicConnection::QuicConnection( idle_network_detector_(this, clock_->ApproximateNow(), &arena_, - alarm_factory_) { + alarm_factory_), + support_handshake_done_(version().HasHandshakeDone()) { QUIC_DLOG(INFO) << ENDPOINT << "Created connection with server connection ID " << server_connection_id << " and version: " << ParsedQuicVersionToString(version()); @@ -345,9 +333,6 @@ QuicConnection::QuicConnection( << "QuicConnection: attempted to use server connection ID " << server_connection_id << " which is invalid with version " << QuicVersionToString(transport_version()); - if (advance_ack_timeout_update_) { - QUIC_RELOADABLE_FLAG_COUNT(quic_advance_ack_timeout_update); - } framer_.set_visitor(this); stats_.connection_creation_time = clock_->ApproximateNow(); // TODO(ianswett): Supply the NetworkChangeVisitor as a constructor argument @@ -377,6 +362,9 @@ QuicConnection::QuicConnection( if (perspective_ == Perspective::IS_SERVER) { SetVersionNegotiated(); } + if (default_enable_5rto_blackhole_detection_) { + num_rtos_for_blackhole_detection_ = 5; + } } void QuicConnection::InstallInitialCrypters(QuicConnectionId connection_id) { @@ -402,50 +390,158 @@ void QuicConnection::ClearQueuedPackets() { buffered_packets_.clear(); } -void QuicConnection::SetFromConfig(const QuicConfig& config) { - if (config.negotiated()) { - // Handshake complete, set handshake timeout to Infinite. - SetNetworkTimeouts(QuicTime::Delta::Infinite(), - config.IdleNetworkTimeout()); - idle_timeout_connection_close_behavior_ = - ConnectionCloseBehavior::SILENT_CLOSE; - if (original_connection_id_.has_value()) { - DCHECK_EQ(perspective_, Perspective::IS_CLIENT); - // We received a RETRY packet, validate that the |original_connection_id| - // from the config matches the one from the RETRY. - if (!config.HasReceivedOriginalConnectionId() || - config.ReceivedOriginalConnectionId() != - original_connection_id_.value()) { +bool QuicConnection::ValidateConfigConnectionIdsOld(const QuicConfig& config) { + // This function validates connection IDs as defined in IETF draft-27 and + // earlier. + DCHECK(config.negotiated()); + DCHECK(!version().AuthenticatesHandshakeConnectionIds()); + if (original_destination_connection_id_.has_value() && + retry_source_connection_id_.has_value()) { + DCHECK_EQ(perspective_, Perspective::IS_CLIENT); + // We received a RETRY packet, validate that the original destination + // connection ID from the config matches the one from the RETRY. + if (!config.HasReceivedOriginalConnectionId() || + config.ReceivedOriginalConnectionId() != + original_destination_connection_id_.value()) { + std::string received_value; + if (config.HasReceivedOriginalConnectionId()) { + received_value = config.ReceivedOriginalConnectionId().ToString(); + } else { + received_value = "none"; + } + std::string error_details = quiche::QuicheStrCat( + "Bad original_connection_id: expected ", + original_destination_connection_id_.value().ToString(), ", received ", + received_value, ", RETRY used ", server_connection_id_.ToString()); + CloseConnection(IETF_QUIC_PROTOCOL_VIOLATION, error_details, + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); + return false; + } + } else { + // We did not receive a RETRY packet, make sure we did not receive the + // original_destination_connection_id transport parameter. + if (config.HasReceivedOriginalConnectionId()) { + std::string error_details = quiche::QuicheStrCat( + "Bad original_connection_id: did not receive RETRY but received ", + config.ReceivedOriginalConnectionId().ToString()); + CloseConnection(IETF_QUIC_PROTOCOL_VIOLATION, error_details, + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); + return false; + } + } + return true; +} + +bool QuicConnection::ValidateConfigConnectionIds(const QuicConfig& config) { + DCHECK(config.negotiated()); + if (!version().UsesTls()) { + // QUIC+TLS is required to transmit connection ID transport parameters. + return true; + } + if (!version().AuthenticatesHandshakeConnectionIds()) { + return ValidateConfigConnectionIdsOld(config); + } + // This function validates connection IDs as defined in IETF draft-28 and + // later. + + // Validate initial_source_connection_id. + QuicConnectionId expected_initial_source_connection_id; + if (perspective_ == Perspective::IS_CLIENT) { + expected_initial_source_connection_id = server_connection_id_; + } else { + expected_initial_source_connection_id = client_connection_id_; + } + if (!config.HasReceivedInitialSourceConnectionId() || + config.ReceivedInitialSourceConnectionId() != + expected_initial_source_connection_id) { + std::string received_value; + if (config.HasReceivedInitialSourceConnectionId()) { + received_value = config.ReceivedInitialSourceConnectionId().ToString(); + } else { + received_value = "none"; + } + std::string error_details = + quiche::QuicheStrCat("Bad initial_source_connection_id: expected ", + expected_initial_source_connection_id.ToString(), + ", received ", received_value); + CloseConnection(IETF_QUIC_PROTOCOL_VIOLATION, error_details, + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); + return false; + } + if (perspective_ == Perspective::IS_CLIENT) { + // Validate original_destination_connection_id. + if (!config.HasReceivedOriginalConnectionId() || + config.ReceivedOriginalConnectionId() != + GetOriginalDestinationConnectionId()) { + std::string received_value; + if (config.HasReceivedOriginalConnectionId()) { + received_value = config.ReceivedOriginalConnectionId().ToString(); + } else { + received_value = "none"; + } + std::string error_details = quiche::QuicheStrCat( + "Bad original_destination_connection_id: expected ", + GetOriginalDestinationConnectionId().ToString(), ", received ", + received_value); + CloseConnection(IETF_QUIC_PROTOCOL_VIOLATION, error_details, + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); + return false; + } + // Validate retry_source_connection_id. + if (retry_source_connection_id_.has_value()) { + // We received a RETRY packet, validate that the retry source + // connection ID from the config matches the one from the RETRY. + if (!config.HasReceivedRetrySourceConnectionId() || + config.ReceivedRetrySourceConnectionId() != + retry_source_connection_id_.value()) { std::string received_value; - if (config.HasReceivedOriginalConnectionId()) { - received_value = config.ReceivedOriginalConnectionId().ToString(); + if (config.HasReceivedRetrySourceConnectionId()) { + received_value = config.ReceivedRetrySourceConnectionId().ToString(); } else { received_value = "none"; } - std::string error_details = quiche::QuicheStrCat( - "Bad original_connection_id: expected ", - original_connection_id_.value().ToString(), ", received ", - received_value, ", RETRY used ", server_connection_id_.ToString()); + std::string error_details = + quiche::QuicheStrCat("Bad retry_source_connection_id: expected ", + retry_source_connection_id_.value().ToString(), + ", received ", received_value); CloseConnection(IETF_QUIC_PROTOCOL_VIOLATION, error_details, ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); - return; + return false; } } else { // We did not receive a RETRY packet, make sure we did not receive the - // original_connection_id transport parameter. - if (config.HasReceivedOriginalConnectionId()) { + // retry_source_connection_id transport parameter. + if (config.HasReceivedRetrySourceConnectionId()) { std::string error_details = quiche::QuicheStrCat( - "Bad original_connection_id: did not receive RETRY but received ", - config.ReceivedOriginalConnectionId().ToString()); + "Bad retry_source_connection_id: did not receive RETRY but " + "received ", + config.ReceivedRetrySourceConnectionId().ToString()); CloseConnection(IETF_QUIC_PROTOCOL_VIOLATION, error_details, ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); - return; + return false; } } + } + return true; +} + +void QuicConnection::SetFromConfig(const QuicConfig& config) { + if (config.negotiated()) { + // Handshake complete, set handshake timeout to Infinite. + SetNetworkTimeouts(QuicTime::Delta::Infinite(), + config.IdleNetworkTimeout()); + idle_timeout_connection_close_behavior_ = + ConnectionCloseBehavior::SILENT_CLOSE; + if (!ValidateConfigConnectionIds(config)) { + return; + } } else { SetNetworkTimeouts(config.max_time_before_crypto_handshake(), config.max_idle_time_before_crypto_handshake()); } + if (config.HandshakeDoneSupported()) { + support_handshake_done_ = true; + } sent_packet_manager_.SetFromConfig(config); if (config.HasReceivedBytesForConnectionId() && @@ -461,24 +557,41 @@ void QuicConnection::SetFromConfig(const QuicConfig& config) { if (config.HasClientRequestedIndependentOption(kMTUL, perspective_)) { SetMtuDiscoveryTarget(kMtuDiscoveryTargetPacketSizeLow); } + if (default_enable_5rto_blackhole_detection_) { + if (config.HasClientRequestedIndependentOption(kCBHD, perspective_)) { + QUIC_CODE_COUNT(quic_client_only_blackhole_detection); + blackhole_detection_disabled_ = true; + } + if (config.HasClientSentConnectionOption(k2RTO, perspective_)) { + QUIC_CODE_COUNT(quic_2rto_blackhole_detection); + num_rtos_for_blackhole_detection_ = 2; + } + if (config.HasClientSentConnectionOption(k3RTO, perspective_)) { + QUIC_CODE_COUNT(quic_3rto_blackhole_detection); + num_rtos_for_blackhole_detection_ = 3; + } + if (config.HasClientSentConnectionOption(k4RTO, perspective_)) { + QUIC_CODE_COUNT(quic_4rto_blackhole_detection); + num_rtos_for_blackhole_detection_ = 4; + } + if (config.HasClientSentConnectionOption(k6RTO, perspective_)) { + QUIC_CODE_COUNT(quic_6rto_blackhole_detection); + num_rtos_for_blackhole_detection_ = 6; + } + } if (debug_visitor_ != nullptr) { debug_visitor_->OnSetFromConfig(config); } uber_received_packet_manager_.SetFromConfig(config, perspective_); if (config.HasClientSentConnectionOption(k5RTO, perspective_)) { - close_connection_after_five_rtos_ = true; + num_rtos_for_blackhole_detection_ = 5; } if (sent_packet_manager_.pto_enabled()) { - if (config.HasClientSentConnectionOption(k6PTO, perspective_)) { - max_consecutive_ptos_ = 5; - QUIC_CODE_COUNT(quic_close_connection_6pto); - } - if (config.HasClientSentConnectionOption(k7PTO, perspective_)) { - max_consecutive_ptos_ = 6; - } - if (config.HasClientSentConnectionOption(k8PTO, perspective_)) { - max_consecutive_ptos_ = 7; + if (config.HasClientSentConnectionOption(k6PTO, perspective_) || + config.HasClientSentConnectionOption(k7PTO, perspective_) || + config.HasClientSentConnectionOption(k8PTO, perspective_)) { + num_rtos_for_blackhole_detection_ = 5; } } if (config.HasClientSentConnectionOption(kNSTP, perspective_)) { @@ -502,8 +615,7 @@ void QuicConnection::SetFromConfig(const QuicConfig& config) { } if (config.HasReceivedMaxPacketSize()) { peer_max_packet_size_ = config.ReceivedMaxPacketSize(); - packet_creator_.SetMaxPacketLength( - GetLimitedMaxPacketSize(packet_creator_.max_packet_length())); + MaybeUpdatePacketCreatorMaxPacketLengthAndPadding(); } if (config.HasReceivedMaxDatagramFrameSize()) { packet_creator_.SetMaxDatagramFrameSize( @@ -519,6 +631,29 @@ void QuicConnection::SetFromConfig(const QuicConfig& config) { } } +void QuicConnection::EnableLegacyVersionEncapsulation( + const std::string& server_name) { + if (perspective_ != Perspective::IS_CLIENT) { + QUIC_BUG << "Cannot enable Legacy Version Encapsulation on the server"; + return; + } + if (legacy_version_encapsulation_enabled_) { + QUIC_BUG << "Do not call EnableLegacyVersionEncapsulation twice"; + return; + } + if (!QuicHostnameUtils::IsValidSNI(server_name)) { + // Legacy Version Encapsulation is only used when SNI is transmitted. + QUIC_DLOG(INFO) + << "Refusing to use Legacy Version Encapsulation with invalid SNI \"" + << server_name << "\""; + return; + } + QUIC_DLOG(INFO) << "Enabling Legacy Version Encapsulation with SNI \"" + << server_name << "\""; + legacy_version_encapsulation_enabled_ = true; + legacy_version_encapsulation_sni_ = server_name; +} + void QuicConnection::ApplyConnectionOptions( const QuicTagVector& connection_options) { sent_packet_manager_.ApplyConnectionOptions(connection_options); @@ -605,6 +740,7 @@ void QuicConnection::OnPublicResetPacket(const QuicPublicResetPacket& packet) { // here. (Check for a bug regression.) DCHECK_EQ(server_connection_id_, packet.connection_id); DCHECK_EQ(perspective_, Perspective::IS_CLIENT); + DCHECK(!VersionHasIetfInvariantHeader(transport_version())); if (debug_visitor_ != nullptr) { debug_visitor_->OnPublicResetPacket(packet); } @@ -718,8 +854,12 @@ void QuicConnection::OnRetryPacket( << server_connection_id_ << " with " << new_connection_id << ", received token " << quiche::QuicheTextUtils::HexEncode(retry_token); - DCHECK(!original_connection_id_.has_value()); - original_connection_id_ = server_connection_id_; + if (!original_destination_connection_id_.has_value()) { + original_destination_connection_id_ = server_connection_id_; + } + DCHECK(!retry_source_connection_id_.has_value()) + << retry_source_connection_id_.value(); + retry_source_connection_id_ = new_connection_id; server_connection_id_ = new_connection_id; packet_creator_.SetServerConnectionId(server_connection_id_); packet_creator_.SetRetryToken(retry_token); @@ -738,11 +878,27 @@ bool QuicConnection::HasIncomingConnectionId(QuicConnectionId connection_id) { return false; } -void QuicConnection::AddIncomingConnectionId(QuicConnectionId connection_id) { - if (HasIncomingConnectionId(connection_id)) { - return; +void QuicConnection::SetOriginalDestinationConnectionId( + const QuicConnectionId& original_destination_connection_id) { + QUIC_DLOG(INFO) << "Setting original_destination_connection_id to " + << original_destination_connection_id + << " on connection with server_connection_id " + << server_connection_id_; + DCHECK_NE(original_destination_connection_id, server_connection_id_); + if (!HasIncomingConnectionId(original_destination_connection_id)) { + incoming_connection_ids_.push_back(original_destination_connection_id); + } + InstallInitialCrypters(original_destination_connection_id); + DCHECK(!original_destination_connection_id_.has_value()) + << original_destination_connection_id_.value(); + original_destination_connection_id_ = original_destination_connection_id; +} + +QuicConnectionId QuicConnection::GetOriginalDestinationConnectionId() { + if (original_destination_connection_id_.has_value()) { + return original_destination_connection_id_.value(); } - incoming_connection_ids_.push_back(connection_id); + return server_connection_id_; } bool QuicConnection::OnUnauthenticatedPublicHeader( @@ -841,6 +997,35 @@ void QuicConnection::OnSuccessfulVersionNegotiation() { } } +void QuicConnection::OnSuccessfulMigrationAfterProbing() { + DCHECK_EQ(perspective_, Perspective::IS_CLIENT); + if (IsPathDegrading()) { + // If path was previously degrading, and migration is successful after + // probing, restart the path degrading and blackhole detection. + OnForwardProgressMade(); + } + // TODO(b/159074035): notify SentPacketManger with RTT sample from probing and + // reset cwnd if this is a successful network migration. +} + +void QuicConnection::OnTransportParametersSent( + const TransportParameters& transport_parameters) const { + if (debug_visitor_ != nullptr) { + debug_visitor_->OnTransportParametersSent(transport_parameters); + } +} + +void QuicConnection::OnTransportParametersReceived( + const TransportParameters& transport_parameters) const { + if (debug_visitor_ != nullptr) { + debug_visitor_->OnTransportParametersReceived(transport_parameters); + } +} + +bool QuicConnection::HasPendingAcks() const { + return ack_alarm_->IsSet(); +} + void QuicConnection::OnDecryptedPacket(EncryptionLevel level) { last_decrypted_packet_level_ = level; last_packet_decrypted_ = true; @@ -849,13 +1034,10 @@ void QuicConnection::OnDecryptedPacket(EncryptionLevel level) { // Address is validated by successfully processing a HANDSHAKE packet. address_validated_ = true; } - if (extend_idle_time_on_decryptable_packets_) { - QUIC_RELOADABLE_FLAG_COUNT(quic_extend_idle_time_on_decryptable_packets); - if (use_idle_network_detector_) { - idle_network_detector_.OnPacketReceived(time_of_last_received_packet_); - } else { - time_of_last_decryptable_packet_ = time_of_last_received_packet_; - } + if (use_idle_network_detector_) { + idle_network_detector_.OnPacketReceived(time_of_last_received_packet_); + } else { + time_of_last_decryptable_packet_ = time_of_last_received_packet_; } visitor_->OnPacketDecrypted(level); @@ -923,6 +1105,9 @@ bool QuicConnection::OnPacketHeader(const QuicPacketHeader& header) { --stats_.packets_dropped; QUIC_DVLOG(1) << ENDPOINT << "Received packet header: " << header; last_header_ = header; + if (!stats_.first_decrypted_packet.IsInitialized()) { + stats_.first_decrypted_packet = last_header_.packet_number; + } // Record packet receipt to populate ack info before processing stream // frames, since the processing may result in sending a bundled ack. @@ -962,14 +1147,9 @@ bool QuicConnection::OnStreamFrame(const QuicStreamFrame& frame) { ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); return false; } - if (advance_ack_timeout_update_) { - MaybeUpdateAckTimeout(); - } + MaybeUpdateAckTimeout(); visitor_->OnStreamFrame(frame); stats_.stream_bytes_received += frame.data_length; - if (!advance_ack_timeout_update_) { - should_last_packet_instigate_acks_ = true; - } consecutive_retransmittable_on_wire_ping_count_ = 0; return connected_; } @@ -984,13 +1164,8 @@ bool QuicConnection::OnCryptoFrame(const QuicCryptoFrame& frame) { if (debug_visitor_ != nullptr) { debug_visitor_->OnCryptoFrame(frame); } - if (advance_ack_timeout_update_) { - MaybeUpdateAckTimeout(); - } + MaybeUpdateAckTimeout(); visitor_->OnCryptoFrame(frame); - if (!advance_ack_timeout_update_) { - should_last_packet_instigate_acks_ = true; - } return connected_; } @@ -1032,11 +1207,6 @@ bool QuicConnection::OnAckFrameStart(QuicPacketNumber largest_acked, ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); return false; } - - if (!GetLargestAckedPacket().IsInitialized() || - largest_acked > GetLargestAckedPacket()) { - visitor_->OnForwardProgressConfirmed(); - } processing_ack_frame_ = true; sent_packet_manager_.OnAckFrameStart(largest_acked, ack_delay_time, GetTimeOfLastReceivedPacket()); @@ -1177,11 +1347,7 @@ bool QuicConnection::OnPingFrame(const QuicPingFrame& frame) { if (debug_visitor_ != nullptr) { debug_visitor_->OnPingFrame(frame); } - if (advance_ack_timeout_update_) { - MaybeUpdateAckTimeout(); - } else { - should_last_packet_instigate_acks_ = true; - } + MaybeUpdateAckTimeout(); return true; } @@ -1223,13 +1389,8 @@ bool QuicConnection::OnRstStreamFrame(const QuicRstStreamFrame& frame) { << "RST_STREAM_FRAME received for stream: " << frame.stream_id << " with error: " << QuicRstStreamErrorCodeToString(frame.error_code); - if (advance_ack_timeout_update_) { - MaybeUpdateAckTimeout(); - } + MaybeUpdateAckTimeout(); visitor_->OnRstStream(frame); - if (!advance_ack_timeout_update_) { - should_last_packet_instigate_acks_ = true; - } return connected_; } @@ -1260,11 +1421,7 @@ bool QuicConnection::OnPathChallengeFrame(const QuicPathChallengeFrame& frame) { // response. received_path_challenge_payloads_.push_back(frame.data_buffer); - if (advance_ack_timeout_update_) { - MaybeUpdateAckTimeout(); - } else { - should_last_packet_instigate_acks_ = true; - } + MaybeUpdateAckTimeout(); return true; } @@ -1272,11 +1429,7 @@ bool QuicConnection::OnPathResponseFrame(const QuicPathResponseFrame& frame) { if (debug_visitor_ != nullptr) { debug_visitor_->OnPathResponseFrame(frame); } - if (advance_ack_timeout_update_) { - MaybeUpdateAckTimeout(); - } else { - should_last_packet_instigate_acks_ = true; - } + MaybeUpdateAckTimeout(); if (!transmitted_connectivity_probe_payload_ || *transmitted_connectivity_probe_payload_ != frame.data_buffer) { // Is not for the probe we sent, ignore it. @@ -1363,13 +1516,8 @@ bool QuicConnection::OnGoAwayFrame(const QuicGoAwayFrame& frame) { << frame.last_good_stream_id << " and error: " << QuicErrorCodeToString(frame.error_code) << " and reason: " << frame.reason_phrase; - if (advance_ack_timeout_update_) { - MaybeUpdateAckTimeout(); - } + MaybeUpdateAckTimeout(); visitor_->OnGoAway(frame); - if (!advance_ack_timeout_update_) { - should_last_packet_instigate_acks_ = true; - } return connected_; } @@ -1384,13 +1532,8 @@ bool QuicConnection::OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) { debug_visitor_->OnWindowUpdateFrame(frame, GetTimeOfLastReceivedPacket()); } QUIC_DVLOG(1) << ENDPOINT << "WINDOW_UPDATE_FRAME received " << frame; - if (advance_ack_timeout_update_) { - MaybeUpdateAckTimeout(); - } + MaybeUpdateAckTimeout(); visitor_->OnWindowUpdateFrame(frame); - if (!advance_ack_timeout_update_) { - should_last_packet_instigate_acks_ = true; - } return connected_; } @@ -1427,19 +1570,20 @@ bool QuicConnection::OnMessageFrame(const QuicMessageFrame& frame) { if (debug_visitor_ != nullptr) { debug_visitor_->OnMessageFrame(frame); } - if (advance_ack_timeout_update_) { - MaybeUpdateAckTimeout(); - } + MaybeUpdateAckTimeout(); visitor_->OnMessageReceived( quiche::QuicheStringPiece(frame.data, frame.message_length)); - if (!advance_ack_timeout_update_) { - should_last_packet_instigate_acks_ = true; - } return connected_; } bool QuicConnection::OnHandshakeDoneFrame(const QuicHandshakeDoneFrame& frame) { - DCHECK(connected_ && VersionHasIetfQuicFrames(transport_version())); + DCHECK(connected_); + if (!support_handshake_done_) { + CloseConnection(IETF_QUIC_PROTOCOL_VIOLATION, + "Handshake done frame is unsupported", + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); + return false; + } if (perspective_ == Perspective::IS_SERVER) { CloseConnection(IETF_QUIC_PROTOCOL_VIOLATION, @@ -1455,16 +1599,17 @@ bool QuicConnection::OnHandshakeDoneFrame(const QuicHandshakeDoneFrame& frame) { if (debug_visitor_ != nullptr) { debug_visitor_->OnHandshakeDoneFrame(frame); } - if (advance_ack_timeout_update_) { - MaybeUpdateAckTimeout(); - } + MaybeUpdateAckTimeout(); visitor_->OnHandshakeDoneReceived(); - if (!advance_ack_timeout_update_) { - should_last_packet_instigate_acks_ = true; - } return connected_; } +bool QuicConnection::OnAckFrequencyFrame( + const QuicAckFrequencyFrame& /*frame*/) { + // TODO(b/148614353): implement this fully. + QUIC_LOG_EVERY_N_SEC(ERROR, 120) << "Get unexpected AckFrequencyFrame."; + return false; +} bool QuicConnection::OnBlockedFrame(const QuicBlockedFrame& frame) { DCHECK(connected_); @@ -1477,14 +1622,9 @@ bool QuicConnection::OnBlockedFrame(const QuicBlockedFrame& frame) { } QUIC_DLOG(INFO) << ENDPOINT << "BLOCKED_FRAME received for stream: " << frame.stream_id; - if (advance_ack_timeout_update_) { - MaybeUpdateAckTimeout(); - } + MaybeUpdateAckTimeout(); visitor_->OnBlockedFrame(frame); stats_.blocked_frames_received++; - if (!advance_ack_timeout_update_) { - should_last_packet_instigate_acks_ = true; - } return connected_; } @@ -1556,7 +1696,7 @@ void QuicConnection::OnPacketComplete() { // For IETF QUIC, it is guaranteed that TLS will give connection the // corresponding write key before read key. In other words, connection should // never process a packet while an ACK for it cannot be encrypted. - if (!advance_ack_timeout_update_ || !should_last_packet_instigate_acks_) { + if (!should_last_packet_instigate_acks_) { uber_received_packet_manager_.MaybeUpdateAckTimeout( should_last_packet_instigate_acks_, last_decrypted_packet_level_, last_header_.packet_number, GetTimeOfLastReceivedPacket(), @@ -1576,6 +1716,14 @@ void QuicConnection::OnAuthenticatedIetfStatelessResetPacket( const QuicIetfStatelessResetPacket& /*packet*/) { // TODO(fayang): Add OnAuthenticatedIetfStatelessResetPacket to // debug_visitor_. + DCHECK(VersionHasIetfInvariantHeader(transport_version())); + DCHECK_EQ(perspective_, Perspective::IS_CLIENT); + if (!visitor_->ValidateStatelessReset(last_packet_destination_address_, + last_packet_source_address_)) { + // This packet is received on a probing path. Do not close connection. + return; + } + const std::string error_details = "Received stateless reset."; QUIC_CODE_COUNT(quic_tear_down_local_connection_on_stateless_reset); TearDownLocalConnectionState(QUIC_PUBLIC_RESET, error_details, @@ -1693,6 +1841,29 @@ void QuicConnection::SendVersionNegotiationPacket(bool ietf_quic, pending_version_negotiation_packet_ = false; } +void QuicConnection::MaybeActivateLegacyVersionEncapsulation() { + if (!legacy_version_encapsulation_enabled_) { + return; + } + DCHECK(!legacy_version_encapsulation_in_progress_); + QUIC_BUG_IF(!packet_creator_.CanSetMaxPacketLength()) + << "Cannot activate Legacy Version Encapsulation mid-packet"; + QUIC_BUG_IF(coalesced_packet_.length() != 0u) + << "Cannot activate Legacy Version Encapsulation mid-coalesced-packet"; + legacy_version_encapsulation_in_progress_ = true; + MaybeUpdatePacketCreatorMaxPacketLengthAndPadding(); +} +void QuicConnection::MaybeDisactivateLegacyVersionEncapsulation() { + if (!legacy_version_encapsulation_in_progress_) { + return; + } + // Flush any remaining packet before disactivating encapsulation. + packet_creator_.FlushCurrentPacket(); + DCHECK(legacy_version_encapsulation_enabled_); + legacy_version_encapsulation_in_progress_ = false; + MaybeUpdatePacketCreatorMaxPacketLengthAndPadding(); +} + size_t QuicConnection::SendCryptoData(EncryptionLevel level, size_t write_length, QuicStreamOffset offset) { @@ -1700,11 +1871,21 @@ size_t QuicConnection::SendCryptoData(EncryptionLevel level, QUIC_BUG << "Attempt to send empty crypto frame"; return 0; } - if (!ShouldGeneratePacket(HAS_RETRANSMITTABLE_DATA, IS_HANDSHAKE)) { + if (!GetQuicReloadableFlag(quic_fix_checking_should_generate_packet) && + !ShouldGeneratePacket(HAS_RETRANSMITTABLE_DATA, IS_HANDSHAKE)) { return 0; } - ScopedPacketFlusher flusher(this); - return packet_creator_.ConsumeCryptoData(level, write_length, offset); + if (level == ENCRYPTION_INITIAL) { + MaybeActivateLegacyVersionEncapsulation(); + } + size_t consumed_length; + { + ScopedPacketFlusher flusher(this); + consumed_length = + packet_creator_.ConsumeCryptoData(level, write_length, offset); + } // Added scope ensures packets are flushed before continuing. + MaybeDisactivateLegacyVersionEncapsulation(); + return consumed_length; } QuicConsumedData QuicConnection::SendStreamData(QuicStreamId id, @@ -1716,13 +1897,24 @@ QuicConsumedData QuicConnection::SendStreamData(QuicStreamId id, return QuicConsumedData(0, false); } - // Opportunistically bundle an ack with every outgoing packet. - // Particularly, we want to bundle with handshake packets since we don't know - // which decrypter will be used on an ack packet following a handshake - // packet (a handshake packet from client to server could result in a REJ or a - // SHLO from the server, leading to two different decrypters at the server.) - ScopedPacketFlusher flusher(this); - return packet_creator_.ConsumeData(id, write_length, offset, state); + if (packet_creator_.encryption_level() == ENCRYPTION_INITIAL && + QuicUtils::IsCryptoStreamId(transport_version(), id)) { + MaybeActivateLegacyVersionEncapsulation(); + } + QuicConsumedData consumed_data(0, false); + { + // Opportunistically bundle an ack with every outgoing packet. + // Particularly, we want to bundle with handshake packets since we don't + // know which decrypter will be used on an ack packet following a handshake + // packet (a handshake packet from client to server could result in a REJ or + // a SHLO from the server, leading to two different decrypters at the + // server.) + ScopedPacketFlusher flusher(this); + consumed_data = + packet_creator_.ConsumeData(id, write_length, offset, state); + } // Added scope ensures packets are flushed before continuing. + MaybeDisactivateLegacyVersionEncapsulation(); + return consumed_data; } bool QuicConnection::SendControlFrame(const QuicFrame& frame) { @@ -1734,8 +1926,7 @@ bool QuicConnection::SendControlFrame(const QuicFrame& frame) { // anti-amplification limit is used, client needs to send something to avoid // handshake deadlock. QUIC_DVLOG(1) << ENDPOINT << "Failed to send control frame: " << frame - << " at encryption level: " - << EncryptionLevelToString(encryption_level_); + << " at encryption level: " << encryption_level_; return false; } ScopedPacketFlusher flusher(this); @@ -1795,10 +1986,6 @@ const QuicConnectionStats& QuicConnection::GetStats() { return stats_; } -void QuicConnection::ResetHasNonAppLimitedSampleAfterHandshakeCompletion() { - stats_.has_non_app_limited_sample = false; -} - void QuicConnection::OnCoalescedPacket(const QuicEncryptedPacket& packet) { QueueCoalescedPacket(packet); } @@ -1809,39 +1996,85 @@ void QuicConnection::OnUndecryptablePacket(const QuicEncryptedPacket& packet, QUIC_DVLOG(1) << ENDPOINT << "Received undecryptable packet of length " << packet.length() << " with" << (has_decryption_key ? "" : "out") << " key at level " - << EncryptionLevelToString(decryption_level) + << decryption_level << " while connection is at encryption level " - << EncryptionLevelToString(encryption_level_); + << encryption_level_; DCHECK(EncryptionLevelIsValid(decryption_level)); if (encryption_level_ != ENCRYPTION_FORWARD_SECURE) { ++stats_.undecryptable_packets_received_before_handshake_complete; } - bool should_enqueue = true; + const bool should_enqueue = + ShouldEnqueueUnDecryptablePacket(decryption_level, has_decryption_key); + if (should_enqueue) { + QueueUndecryptablePacket(packet, decryption_level); + } + + if (debug_visitor_ != nullptr) { + debug_visitor_->OnUndecryptablePacket(decryption_level, + /*dropped=*/!should_enqueue); + } +} + +bool QuicConnection::ShouldEnqueueUnDecryptablePacket( + EncryptionLevel decryption_level, + bool has_decryption_key) const { if (encryption_level_ == ENCRYPTION_FORWARD_SECURE) { // We do not expect to install any further keys. - should_enqueue = false; - } else if (undecryptable_packets_.size() >= max_undecryptable_packets_) { + return false; + } + if (undecryptable_packets_.size() >= max_undecryptable_packets_) { // We do not queue more than max_undecryptable_packets_ packets. - should_enqueue = false; - } else if (has_decryption_key) { + return false; + } + if (has_decryption_key) { // We already have the key for this decryption level, therefore no // future keys will allow it be decrypted. - should_enqueue = false; - } else if (version().KnowsWhichDecrypterToUse() && - decryption_level <= encryption_level_) { + return false; + } + if (version().KnowsWhichDecrypterToUse() && + decryption_level <= encryption_level_) { // On versions that know which decrypter to use, we install keys in order // so we will not get newer keys for lower encryption levels. - should_enqueue = false; + return false; } + return true; +} - if (should_enqueue) { - QueueUndecryptablePacket(packet, decryption_level); +std::string QuicConnection::UndecryptablePacketsInfo() const { + std::string info = quiche::QuicheStrCat( + "num_undecryptable_packets: ", undecryptable_packets_.size(), " {"); + for (const auto& packet : undecryptable_packets_) { + info = quiche::QuicheStrCat( + info, "[", EncryptionLevelToString(packet.encryption_level), ", ", + packet.packet->length(), ", ", packet.processed, "]"); + } + info = quiche::QuicheStrCat(info, "}"); + return info; +} + +void QuicConnection::MaybeUpdatePacketCreatorMaxPacketLengthAndPadding() { + QuicByteCount max_packet_length = GetLimitedMaxPacketSize(long_term_mtu_); + if (legacy_version_encapsulation_in_progress_) { + DCHECK(legacy_version_encapsulation_enabled_); + const QuicByteCount minimum_overhead = + QuicLegacyVersionEncapsulator::GetMinimumOverhead( + legacy_version_encapsulation_sni_); + if (max_packet_length < minimum_overhead) { + QUIC_BUG << "Cannot apply Legacy Version Encapsulation overhead because " + << "max_packet_length " << max_packet_length + << " < minimum_overhead " << minimum_overhead; + legacy_version_encapsulation_in_progress_ = false; + legacy_version_encapsulation_enabled_ = false; + MaybeUpdatePacketCreatorMaxPacketLengthAndPadding(); + return; + } + max_packet_length -= minimum_overhead; } - - if (debug_visitor_ != nullptr) { - debug_visitor_->OnUndecryptablePacket(decryption_level, - /*dropped=*/!should_enqueue); + packet_creator_.SetMaxPacketLength(max_packet_length); + if (legacy_version_encapsulation_enabled_) { + packet_creator_.set_disable_padding_override( + legacy_version_encapsulation_in_progress_); } } @@ -1899,14 +2132,9 @@ void QuicConnection::ProcessUdpPacket(const QuicSocketAddress& self_address, << " too far from current time:" << clock_->ApproximateNow().ToDebuggingValue(); } - if (!extend_idle_time_on_decryptable_packets_ && use_idle_network_detector_) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_use_idle_network_detector, 1, 6); - idle_network_detector_.OnPacketReceived(packet.receipt_time()); - } else { - time_of_last_received_packet_ = packet.receipt_time(); - } + time_of_last_received_packet_ = packet.receipt_time(); QUIC_DVLOG(1) << ENDPOINT << "time of last received packet: " - << GetTimeOfLastReceivedPacket().ToDebuggingValue(); + << packet.receipt_time().ToDebuggingValue(); ScopedPacketFlusher flusher(this); if (!framer_.ProcessPacket(packet)) { @@ -2040,6 +2268,9 @@ bool QuicConnection::ProcessValidatedPacket(const QuicPacketHeader& header) { QUIC_DLOG(INFO) << ENDPOINT << "Replacing connection ID " << server_connection_id_ << " with " << header.source_connection_id; + if (!original_destination_connection_id_.has_value()) { + original_destination_connection_id_ = server_connection_id_; + } server_connection_id_ = header.source_connection_id; packet_creator_.SetServerConnectionId(server_connection_id_); } @@ -2122,12 +2353,7 @@ void QuicConnection::WriteQueuedPackets() { // TODO(wub): Reduce max packet size to a safe default, or the actual MTU. mtu_discoverer_.Disable(); mtu_discovery_alarm_->Cancel(); - if (GetQuicReloadableFlag( - quic_ignore_msg_too_big_from_buffered_packets)) { - QUIC_RELOADABLE_FLAG_COUNT( - quic_ignore_msg_too_big_from_buffered_packets); - buffered_packets_.pop_front(); - } + buffered_packets_.pop_front(); continue; } if (IsWriteError(result.status)) { @@ -2156,17 +2382,26 @@ void QuicConnection::SendProbingRetransmissions() { } } -void QuicConnection::RetransmitUnackedPackets( - TransmissionType retransmission_type) { - sent_packet_manager_.RetransmitUnackedPackets(retransmission_type); +void QuicConnection::RetransmitZeroRttPackets() { + sent_packet_manager_.RetransmitZeroRttPackets(); - WriteIfNotBlocked(); + if (!GetQuicReloadableFlag( + quic_do_not_retransmit_immediately_on_zero_rtt_reject)) { + WriteIfNotBlocked(); + } } void QuicConnection::NeuterUnencryptedPackets() { sent_packet_manager_.NeuterUnencryptedPackets(); // This may have changed the retransmission timer, so re-arm it. SetRetransmissionAlarm(); + if (default_enable_5rto_blackhole_detection_) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_default_enable_5rto_blackhole_detection2, + 1, 3); + // Consider this as forward progress since this is called when initial key + // gets discarded (or previous unencrypted data is not needed anymore). + OnForwardProgressMade(); + } if (SupportsMultiplePacketNumberSpaces()) { // Stop sending ack of initial packet number space. uber_received_packet_manager_.ResetAckStates(ENCRYPTION_INITIAL); @@ -2179,9 +2414,13 @@ void QuicConnection::NeuterUnencryptedPackets() { bool QuicConnection::ShouldGeneratePacket( HasRetransmittableData retransmittable, IsHandshake handshake) { + DCHECK(handshake != IS_HANDSHAKE || + QuicVersionUsesCryptoFrames(transport_version())) + << ENDPOINT + << "Handshake in STREAM frames should not check ShouldGeneratePacket"; // We should serialize handshake packets immediately to ensure that they // end up sent at the right encryption level. - if (handshake == IS_HANDSHAKE) { + if (!move_amplification_limit_ && handshake == IS_HANDSHAKE) { if (LimitedByAmplificationFactor()) { // Server is constrained by the amplification restriction. QUIC_DVLOG(1) << ENDPOINT << "Constrained by amplification restriction"; @@ -2209,9 +2448,8 @@ const QuicFrames QuicConnection::MaybeBundleAckOpportunistically() { QuicFrame updated_ack_frame = GetUpdatedAckFrame(); QUIC_BUG_IF(updated_ack_frame.ack_frame->packets.Empty()) << ENDPOINT << "Attempted to opportunistically bundle an empty " - << EncryptionLevelToString(encryption_level_) << " ACK, " - << (has_pending_ack ? "" : "!") << "has_pending_ack, stop_waiting_count_ " - << stop_waiting_count_; + << encryption_level_ << " ACK, " << (has_pending_ack ? "" : "!") + << "has_pending_ack, stop_waiting_count_ " << stop_waiting_count_; frames.push_back(updated_ack_frame); if (!no_stop_waiting_frames_) { @@ -2227,6 +2465,14 @@ bool QuicConnection::CanWrite(HasRetransmittableData retransmittable) { return false; } + if (move_amplification_limit_ && LimitedByAmplificationFactor()) { + // Server is constrained by the amplification restriction. + QUIC_RELOADABLE_FLAG_COUNT(quic_move_amplification_limit); + QUIC_CODE_COUNT(quic_throttled_by_amplification_limit); + QUIC_DVLOG(1) << ENDPOINT << "Constrained by amplification restriction"; + return false; + } + if (sent_packet_manager_.pending_timer_transmission_count() > 0) { // Force sending the retransmissions for HANDSHAKE, TLP, RTO, PROBING cases. return true; @@ -2305,7 +2551,7 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) { // Termination packets are encrypted and saved, so don't exit early. const bool is_termination_packet = IsTerminationPacket(*packet); QuicPacketNumber packet_number = packet->packet_number; - const QuicPacketLength encrypted_length = packet->encrypted_length; + QuicPacketLength encrypted_length = packet->encrypted_length; // Termination packets are eventually owned by TimeWaitListManager. // Others are deleted at the end of this call. if (is_termination_packet) { @@ -2320,18 +2566,21 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) { } DCHECK_LE(encrypted_length, kMaxOutgoingPacketSize); - if (!is_mtu_discovery) { - DCHECK_LE(encrypted_length, packet_creator_.max_packet_length()); - } + DCHECK(is_mtu_discovery || + encrypted_length <= packet_creator_.max_packet_length()) + << " encrypted_length=" << encrypted_length + << " > packet_creator max_packet_length=" + << packet_creator_.max_packet_length(); QUIC_DVLOG(1) << ENDPOINT << "Sending packet " << packet_number << " : " << (IsRetransmittable(*packet) == HAS_RETRANSMITTABLE_DATA ? "data bearing " : " ack only ") - << ", encryption level: " - << EncryptionLevelToString(packet->encryption_level) + << ", encryption level: " << packet->encryption_level << ", encrypted length:" << encrypted_length - << ", fate: " << SerializedPacketFateToString(fate); - QUIC_DVLOG(2) << ENDPOINT << "packet(" << packet_number << "): " << std::endl + << ", fate: " << fate; + QUIC_DVLOG(2) << ENDPOINT << packet->encryption_level << " packet number " + << packet_number << " of length " << encrypted_length << ": " + << std::endl << quiche::QuicheTextUtils::HexDump(quiche::QuicheStringPiece( packet->encrypted_buffer, encrypted_length)); @@ -2377,6 +2626,14 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) { buffered_packets_.emplace_back(*packet, self_address(), peer_address()); break; case SEND_TO_WRITER: + // At this point, packet->release_encrypted_buffer is either nullptr, + // meaning |packet->encrypted_buffer| is a stack buffer, or not-nullptr, + /// meaning it's a writer-allocated buffer. Note that connectivity probing + // packets do not use this function, so setting release_encrypted_buffer + // to nullptr will not cause probing packets to be leaked. + // + // writer_->WritePacket transfers buffer ownership back to the writer. + packet->release_encrypted_buffer = nullptr; result = writer_->WritePacket(packet->encrypted_buffer, encrypted_length, self_address().host(), peer_address(), per_packet_options_); @@ -2396,6 +2653,48 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) { // write error has been handled. QUIC_BUG_IF(!version().CanSendCoalescedPackets()); return false; + case LEGACY_VERSION_ENCAPSULATE: { + DCHECK(!is_mtu_discovery); + DCHECK_EQ(perspective_, Perspective::IS_CLIENT); + DCHECK_EQ(packet->encryption_level, ENCRYPTION_INITIAL); + DCHECK(legacy_version_encapsulation_enabled_); + DCHECK(legacy_version_encapsulation_in_progress_); + QuicPacketLength encapsulated_length = + QuicLegacyVersionEncapsulator::Encapsulate( + legacy_version_encapsulation_sni_, + quiche::QuicheStringPiece(packet->encrypted_buffer, + packet->encrypted_length), + server_connection_id_, framer_.creation_time(), + GetLimitedMaxPacketSize(long_term_mtu_), + const_cast<char*>(packet->encrypted_buffer)); + if (encapsulated_length != 0) { + stats_.sent_legacy_version_encapsulated_packets++; + packet->encrypted_length = encapsulated_length; + encrypted_length = encapsulated_length; + QUIC_DVLOG(2) + << ENDPOINT + << "Successfully performed Legacy Version Encapsulation on " + << packet->encryption_level << " packet number " << packet_number + << " of length " << encrypted_length << ": " << std::endl + << quiche::QuicheTextUtils::HexDump(quiche::QuicheStringPiece( + packet->encrypted_buffer, encrypted_length)); + } else { + QUIC_BUG << ENDPOINT + << "Failed to perform Legacy Version Encapsulation on " + << packet->encryption_level << " packet number " + << packet_number << " of length " << encrypted_length; + } + if (!buffered_packets_.empty() || HandleWriteBlocked()) { + // Buffer the packet. + buffered_packets_.emplace_back(*packet, self_address(), peer_address()); + } else { // Send the packet to the writer. + // writer_->WritePacket transfers buffer ownership back to the writer. + packet->release_encrypted_buffer = nullptr; + result = writer_->WritePacket(packet->encrypted_buffer, + encrypted_length, self_address().host(), + peer_address(), per_packet_options_); + } + } break; default: DCHECK(false); break; @@ -2499,6 +2798,11 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) { const bool in_flight = sent_packet_manager_.OnPacketSent( packet, packet_send_time, packet->transmission_type, IsRetransmittable(*packet)); + QUIC_BUG_IF(default_enable_5rto_blackhole_detection_ && + blackhole_detector_.IsDetectionInProgress() && + !sent_packet_manager_.HasInFlightPackets()) + << ENDPOINT + << "Trying to start blackhole detection without no bytes in flight"; if (in_flight || !retransmission_alarm_->IsSet()) { SetRetransmissionAlarm(); @@ -2620,11 +2924,11 @@ void QuicConnection::OnWriteError(int error_code) { } } -char* QuicConnection::GetPacketBuffer() { +QuicPacketBuffer QuicConnection::GetPacketBuffer() { if (version().CanSendCoalescedPackets() && !IsHandshakeConfirmed()) { // Do not use writer's packet buffer for coalesced packets which may contain // multiple QUIC packets. - return nullptr; + return {nullptr, nullptr}; } return writer_->GetNextWriteLocation(self_address().host(), peer_address()); } @@ -2700,6 +3004,11 @@ void QuicConnection::OnHandshakeComplete() { sent_packet_manager_.SetHandshakeConfirmed(); // This may have changed the retransmission timer, so re-arm it. SetRetransmissionAlarm(); + if (default_enable_5rto_blackhole_detection_) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_default_enable_5rto_blackhole_detection2, + 2, 3); + OnForwardProgressMade(); + } if (!SupportsMultiplePacketNumberSpaces()) { // The client should immediately ack the SHLO to confirm the handshake is // complete with the server. @@ -2753,11 +3062,6 @@ void QuicConnection::SendAck() { visitor_->OnAckNeedsRetransmittableFrame(); } -void QuicConnection::OnPathDegradingTimeout() { - is_path_degrading_ = true; - visitor_->OnPathDegrading(); -} - void QuicConnection::OnRetransmissionTimeout() { #ifndef NDEBUG if (sent_packet_manager_.unacked_packets().empty()) { @@ -2784,6 +3088,13 @@ void QuicConnection::OnRetransmissionTimeout() { debug_visitor_->OnNPacketNumbersSkipped(num_packet_numbers_to_skip); } } + if (default_enable_5rto_blackhole_detection_ && + !sent_packet_manager_.HasInFlightPackets() && + blackhole_detector_.IsDetectionInProgress()) { + // Stop detection in quiescence. + DCHECK_EQ(QuicSentPacketManager::LOSS_MODE, retransmission_mode); + blackhole_detector_.StopDetection(); + } WriteIfNotBlocked(); // A write failure can result in the connection being closed, don't attempt to @@ -2817,8 +3128,9 @@ void QuicConnection::OnRetransmissionTimeout() { if (retransmission_mode == QuicSentPacketManager::PTO_MODE) { sent_packet_manager_.AdjustPendingTimerTransmissions(); } - if (retransmission_mode != QuicSentPacketManager::LOSS_MODE) { - // When timer fires in TLP or RTO mode, ensure 1) at least one packet is + if (retransmission_mode != QuicSentPacketManager::LOSS_MODE && + retransmission_mode != QuicSentPacketManager::HANDSHAKE_MODE) { + // When timer fires in TLP/RTO/PTO mode, ensure 1) at least one packet is // created, or there is data to send and available credit (such that // packets will be sent eventually). QUIC_BUG_IF(packet_creator_.packet_number() == @@ -2859,8 +3171,7 @@ void QuicConnection::SetDiversificationNonce( void QuicConnection::SetDefaultEncryptionLevel(EncryptionLevel level) { QUIC_DVLOG(1) << ENDPOINT << "Setting default encryption level from " - << EncryptionLevelToString(encryption_level_) << " to " - << EncryptionLevelToString(level); + << encryption_level_ << " to " << level; if (level != encryption_level_ && packet_creator_.HasPendingFrames()) { // Flush all queued frames when encryption level changes. ScopedPacketFlusher flusher(this); @@ -2936,27 +3247,79 @@ void QuicConnection::MaybeProcessUndecryptablePackets() { return; } - while (connected_ && !undecryptable_packets_.empty()) { - // Making sure there is no pending frames when processing next undecrypted - // packet because the queued ack frame may change. - packet_creator_.FlushCurrentPacket(); - if (!connected_) { - return; + if (GetQuicReloadableFlag(quic_fix_undecryptable_packets)) { + QUIC_RELOADABLE_FLAG_COUNT(quic_fix_undecryptable_packets); + auto iter = undecryptable_packets_.begin(); + while (connected_ && iter != undecryptable_packets_.end()) { + // Making sure there is no pending frames when processing next undecrypted + // packet because the queued ack frame may change. + packet_creator_.FlushCurrentPacket(); + if (!connected_) { + return; + } + UndecryptablePacket* undecryptable_packet = &*iter; + ++iter; + if (undecryptable_packet->processed) { + continue; + } + QUIC_DVLOG(1) << ENDPOINT << "Attempting to process undecryptable packet"; + if (debug_visitor_ != nullptr) { + debug_visitor_->OnAttemptingToProcessUndecryptablePacket( + undecryptable_packet->encryption_level); + } + if (framer_.ProcessPacket(*undecryptable_packet->packet)) { + QUIC_DVLOG(1) << ENDPOINT << "Processed undecryptable packet!"; + undecryptable_packet->processed = true; + ++stats_.packets_processed; + continue; + } + const bool has_decryption_key = + version().KnowsWhichDecrypterToUse() && + framer_.HasDecrypterOfEncryptionLevel( + undecryptable_packet->encryption_level); + if (framer_.error() == QUIC_DECRYPTION_FAILURE && + ShouldEnqueueUnDecryptablePacket( + undecryptable_packet->encryption_level, has_decryption_key)) { + QUIC_DVLOG(1) + << ENDPOINT + << "Need to attempt to process this undecryptable packet later"; + continue; + } + undecryptable_packet->processed = true; } - QUIC_DVLOG(1) << ENDPOINT << "Attempting to process undecryptable packet"; - const auto& undecryptable_packet = undecryptable_packets_.front(); - if (debug_visitor_ != nullptr) { - debug_visitor_->OnAttemptingToProcessUndecryptablePacket( - undecryptable_packet.encryption_level); + // Remove processed packets. We cannot remove elements in the while loop + // above because currently QuicCircularDeque does not support removing + // mid elements. + while (!undecryptable_packets_.empty()) { + if (!undecryptable_packets_.front().processed) { + break; + } + undecryptable_packets_.pop_front(); } - if (!framer_.ProcessPacket(*undecryptable_packet.packet) && - framer_.error() == QUIC_DECRYPTION_FAILURE) { - QUIC_DVLOG(1) << ENDPOINT << "Unable to process undecryptable packet..."; - break; + } else { + while (connected_ && !undecryptable_packets_.empty()) { + // Making sure there is no pending frames when processing next undecrypted + // packet because the queued ack frame may change. + packet_creator_.FlushCurrentPacket(); + if (!connected_) { + return; + } + QUIC_DVLOG(1) << ENDPOINT << "Attempting to process undecryptable packet"; + const auto& undecryptable_packet = undecryptable_packets_.front(); + if (debug_visitor_ != nullptr) { + debug_visitor_->OnAttemptingToProcessUndecryptablePacket( + undecryptable_packet.encryption_level); + } + if (!framer_.ProcessPacket(*undecryptable_packet.packet) && + framer_.error() == QUIC_DECRYPTION_FAILURE) { + QUIC_DVLOG(1) << ENDPOINT + << "Unable to process undecryptable packet..."; + break; + } + QUIC_DVLOG(1) << ENDPOINT << "Processed undecryptable packet!"; + ++stats_.packets_processed; + undecryptable_packets_.pop_front(); } - QUIC_DVLOG(1) << ENDPOINT << "Processed undecryptable packet!"; - ++stats_.packets_processed; - undecryptable_packets_.pop_front(); } // Once forward secure encryption is in use, there will be no @@ -3074,8 +3437,8 @@ void QuicConnection::SendConnectionClosePacket(QuicErrorCode error, if (!framer_.HasEncrypterOfEncryptionLevel(level)) { continue; } - QUIC_DLOG(INFO) << ENDPOINT << "Sending connection close packet at level: " - << EncryptionLevelToString(level); + QUIC_DLOG(INFO) << ENDPOINT + << "Sending connection close packet at level: " << level; SetDefaultEncryptionLevel(level); // Bundle an ACK of the corresponding packet number space for debugging // purpose. @@ -3156,7 +3519,7 @@ QuicByteCount QuicConnection::max_packet_length() const { void QuicConnection::SetMaxPacketLength(QuicByteCount length) { long_term_mtu_ = length; - packet_creator_.SetMaxPacketLength(GetLimitedMaxPacketSize(length)); + MaybeUpdatePacketCreatorMaxPacketLengthAndPadding(); } bool QuicConnection::HasQueuedData() const { @@ -3164,22 +3527,6 @@ bool QuicConnection::HasQueuedData() const { packet_creator_.HasPendingFrames() || !buffered_packets_.empty(); } -bool QuicConnection::CanWriteStreamData() { - // Don't write stream data if there are negotiation or queued data packets - // to send. Otherwise, continue and bundle as many frames as possible. - if (pending_version_negotiation_packet_ || !buffered_packets_.empty()) { - return false; - } - - IsHandshake pending_handshake = - visitor_->HasPendingHandshake() ? IS_HANDSHAKE : NOT_HANDSHAKE; - // Sending queued packets may have caused the socket to become write blocked, - // or the congestion manager to prohibit sending. If we've sent everything - // we had queued and we're still not blocked, let the visitor know it can - // write more. - return ShouldGeneratePacket(HAS_RETRANSMITTABLE_DATA, pending_handshake); -} - void QuicConnection::SetNetworkTimeouts(QuicTime::Delta handshake_timeout, QuicTime::Delta idle_timeout) { QUIC_BUG_IF(idle_timeout > handshake_timeout) @@ -3868,15 +4215,7 @@ void QuicConnection::PostProcessAfterAckFrame(bool send_stop_waiting, // have a better estimate of the current rtt than when it was set. SetRetransmissionAlarm(); if (acked_new_packet) { - is_path_degrading_ = false; - if (sent_packet_manager_.HasInFlightPackets()) { - // Restart detections if forward progress has been made. - blackhole_detector_.RestartDetection(GetPathDegradingDeadline(), - GetNetworkBlackholeDeadline()); - } else { - // Stop detections in quiecense. - blackhole_detector_.StopDetection(); - } + OnForwardProgressMade(); } if (send_stop_waiting) { @@ -3963,7 +4302,7 @@ EncryptionLevel QuicConnection::GetConnectionCloseEncryptionLevel() const { // A forward secure packet has been received. QUIC_BUG_IF(encryption_level_ != ENCRYPTION_FORWARD_SECURE) << ENDPOINT << "Unexpected connection close encryption level " - << EncryptionLevelToString(encryption_level_); + << encryption_level_; return ENCRYPTION_FORWARD_SECURE; } if (framer_.HasEncrypterOfEncryptionLevel(ENCRYPTION_ZERO_RTT)) { @@ -3979,25 +4318,68 @@ EncryptionLevel QuicConnection::GetConnectionCloseEncryptionLevel() const { return ENCRYPTION_INITIAL; } +void QuicConnection::MaybeBundleCryptoDataWithAckOfSpace( + PacketNumberSpace space) { + DCHECK(SupportsMultiplePacketNumberSpaces()); + QUIC_BUG_IF(space == APPLICATION_DATA); + const QuicTime ack_timeout = + uber_received_packet_manager_.GetAckTimeout(space); + if (!ack_timeout.IsInitialized() || + (ack_timeout > clock_->ApproximateNow() && + ack_timeout > uber_received_packet_manager_.GetEarliestAckTimeout())) { + // No pending ACK of space. + return; + } + if (coalesced_packet_.length() > 0) { + // Do not bundle CRYPTO data if the ACK could be coalesced with other + // packets. + return; + } + + sent_packet_manager_.RetransmitDataOfSpaceIfAny(space); +} + void QuicConnection::SendAllPendingAcks() { DCHECK(SupportsMultiplePacketNumberSpaces()); QUIC_DVLOG(1) << ENDPOINT << "Trying to send all pending ACKs"; ack_alarm_->Cancel(); + QuicTime earliest_ack_timeout = + uber_received_packet_manager_.GetEarliestAckTimeout(); + QUIC_BUG_IF(!earliest_ack_timeout.IsInitialized()); + if (GetQuicReloadableFlag(quic_bundle_crypto_data_with_initial_ack)) { + // On the server side, sends INITIAL data with INITIAL ACK. On the client + // side, sends HANDSHAKE data (containing client Finished) with HANDSHAKE + // ACK. + PacketNumberSpace space = + perspective() == Perspective::IS_SERVER ? INITIAL_DATA : HANDSHAKE_DATA; + MaybeBundleCryptoDataWithAckOfSpace(space); + earliest_ack_timeout = + uber_received_packet_manager_.GetEarliestAckTimeout(); + if (!earliest_ack_timeout.IsInitialized()) { + QUIC_RELOADABLE_FLAG_COUNT(quic_bundle_crypto_data_with_initial_ack); + return; + } + } // Latches current encryption level. const EncryptionLevel current_encryption_level = encryption_level_; for (int8_t i = INITIAL_DATA; i <= APPLICATION_DATA; ++i) { const QuicTime ack_timeout = uber_received_packet_manager_.GetAckTimeout( static_cast<PacketNumberSpace>(i)); - if (!ack_timeout.IsInitialized() || - ack_timeout > clock_->ApproximateNow()) { + if (!ack_timeout.IsInitialized()) { continue; } - if (!framer_.HasEncrypterOfEncryptionLevel( - QuicUtils::GetEncryptionLevel(static_cast<PacketNumberSpace>(i)))) { - QUIC_BUG << ENDPOINT << "Cannot send ACKs for packet number space " - << PacketNumberSpaceToString(static_cast<PacketNumberSpace>(i)) - << " without corresponding encrypter"; - continue; + if (GetQuicReloadableFlag(quic_always_send_earliest_ack)) { + QUIC_RELOADABLE_FLAG_COUNT(quic_always_send_earliest_ack); + } + if (ack_timeout > clock_->ApproximateNow()) { + if (!GetQuicReloadableFlag(quic_always_send_earliest_ack)) { + continue; + } + if (ack_timeout > earliest_ack_timeout) { + // Always send the earliest ACK to make forward progress in case alarm + // fires early. + continue; + } } QUIC_DVLOG(1) << ENDPOINT << "Sending ACK of packet number space " << PacketNumberSpaceToString( @@ -4011,8 +4393,12 @@ void QuicConnection::SendAllPendingAcks() { const bool flushed = packet_creator_.FlushAckFrame(frames); if (!flushed) { // Connection is write blocked. - QUIC_BUG_IF(!writer_->IsWriteBlocked()) - << "Writer not blocked, but ACK not flushed for packet space:" << i; + QUIC_BUG_IF( + !writer_->IsWriteBlocked() && + (!move_amplification_limit_ || !LimitedByAmplificationFactor())) + << "Writer not blocked and not throttled by amplification factor, " + "but ACK not flushed for packet space:" + << i; break; } ResetAckStates(); @@ -4024,7 +4410,13 @@ void QuicConnection::SendAllPendingAcks() { uber_received_packet_manager_.GetEarliestAckTimeout(); if (timeout.IsInitialized()) { // If there are ACKs pending, re-arm ack alarm. - ack_alarm_->Set(timeout); + if (update_ack_alarm_in_send_all_pending_acks_) { + QUIC_RELOADABLE_FLAG_COUNT( + quic_update_ack_alarm_in_send_all_pending_acks); + ack_alarm_->Update(timeout, kAlarmGranularity); + } else { + ack_alarm_->Set(timeout); + } } // Only try to bundle retransmittable data with ACK frame if default // encryption level is forward secure. @@ -4066,13 +4458,15 @@ bool QuicConnection::FlushCoalescedPacket() { if (coalesced_packet_.length() == 0) { return true; } - QUIC_DVLOG(1) << ENDPOINT << "Sending coalesced packet"; + char buffer[kMaxOutgoingPacketSize]; const size_t length = packet_creator_.SerializeCoalescedPacket( coalesced_packet_, buffer, coalesced_packet_.max_packet_length()); if (length == 0) { return false; } + QUIC_DVLOG(1) << ENDPOINT << "Sending coalesced packet " + << coalesced_packet_.ToString(length); if (!buffered_packets_.empty() || HandleWriteBlocked()) { QUIC_DVLOG(1) << ENDPOINT @@ -4158,6 +4552,26 @@ void QuicConnection::SetLargestReceivedPacketWithAck( } } +void QuicConnection::OnForwardProgressMade() { + if (is_path_degrading_) { + visitor_->OnForwardProgressMadeAfterPathDegrading(); + is_path_degrading_ = false; + } + if (sent_packet_manager_.HasInFlightPackets()) { + // Restart detections if forward progress has been made. + blackhole_detector_.RestartDetection(GetPathDegradingDeadline(), + GetNetworkBlackholeDeadline()); + } else { + // Stop detections in quiecense. + blackhole_detector_.StopDetection(); + } + QUIC_BUG_IF(default_enable_5rto_blackhole_detection_ && + blackhole_detector_.IsDetectionInProgress() && + !sent_packet_manager_.HasInFlightPackets()) + << ENDPOINT + << "Trying to start blackhole detection without no bytes in flight"; +} + QuicPacketNumber QuicConnection::GetLargestReceivedPacketWithAck() const { if (SupportsMultiplePacketNumberSpaces()) { return largest_seen_packets_with_ack_[QuicUtils::GetPacketNumberSpace( @@ -4187,21 +4601,28 @@ bool QuicConnection::EnforceAntiAmplificationLimit() const { bool QuicConnection::LimitedByAmplificationFactor() const { return EnforceAntiAmplificationLimit() && bytes_sent_before_address_validation_ >= - GetQuicFlag(FLAGS_quic_anti_amplification_factor) * + anti_amplification_factor_ * bytes_received_before_address_validation_; } SerializedPacketFate QuicConnection::DeterminePacketFate( bool is_mtu_discovery) { - if (version().CanSendCoalescedPackets() && !IsHandshakeConfirmed() && - !is_mtu_discovery) { - // Before receiving ACK for any 1-RTT packets, always try to coalesce - // packet (except MTU discovery packet). - return COALESCE; + if (legacy_version_encapsulation_in_progress_) { + DCHECK(!is_mtu_discovery); + return LEGACY_VERSION_ENCAPSULATE; } - // Packet cannot be coalesced, flush existing coalesced packet. - if (version().CanSendCoalescedPackets() && !FlushCoalescedPacket()) { - return FAILED_TO_WRITE_COALESCED_PACKET; + if (version().CanSendCoalescedPackets()) { + // Disable coalescing when Legacy Version Encapsulation is in use to avoid + // having to reframe encapsulated packets. + if (!IsHandshakeConfirmed() && !is_mtu_discovery) { + // Before receiving ACK for any 1-RTT packets, always try to coalesce + // packet (except MTU discovery packet). + return COALESCE; + } + // Packet cannot be coalesced, flush existing coalesced packet. + if (!FlushCoalescedPacket()) { + return FAILED_TO_WRITE_COALESCED_PACKET; + } } if (!buffered_packets_.empty() || HandleWriteBlocked()) { return BUFFER; @@ -4269,6 +4690,11 @@ void QuicConnection::OnPathDegradingDetected() { } void QuicConnection::OnBlackholeDetected() { + QUIC_BUG_IF(default_enable_5rto_blackhole_detection_ && + !sent_packet_manager_.HasInFlightPackets()) + << ENDPOINT + << "Closing connection because of blackhole, but there is no bytes in " + "flight"; CloseConnection(QUIC_TOO_MANY_RTOS, "Network blackhole detected.", ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); } @@ -4278,10 +4704,14 @@ void QuicConnection::OnHandshakeTimeout() { DCHECK(use_idle_network_detector_); const QuicTime::Delta duration = clock_->ApproximateNow() - stats_.connection_creation_time; - const std::string error_details = quiche::QuicheStrCat( + std::string error_details = quiche::QuicheStrCat( "Handshake timeout expired after ", duration.ToDebuggingValue(), ". Timeout:", idle_network_detector_.handshake_timeout().ToDebuggingValue()); + if (perspective() == Perspective::IS_CLIENT && version().UsesTls()) { + error_details = + quiche::QuicheStrCat(error_details, UndecryptablePacketsInfo()); + } QUIC_DVLOG(1) << ENDPOINT << error_details; CloseConnection(QUIC_HANDSHAKE_TIMEOUT, error_details, ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); @@ -4311,7 +4741,6 @@ void QuicConnection::OnIdleNetworkDetected() { } void QuicConnection::MaybeUpdateAckTimeout() { - DCHECK(advance_ack_timeout_update_); if (should_last_packet_instigate_acks_) { return; } @@ -4345,20 +4774,27 @@ QuicTime QuicConnection::GetNetworkBlackholeDeadline() const { if (!ShouldDetectBlackhole()) { return QuicTime::Zero(); } + DCHECK_LT(0u, num_rtos_for_blackhole_detection_); return clock_->ApproximateNow() + - sent_packet_manager_.GetNetworkBlackholeDelay(); + sent_packet_manager_.GetNetworkBlackholeDelay( + num_rtos_for_blackhole_detection_); } bool QuicConnection::ShouldDetectBlackhole() const { - if (!connected_) { + if (!connected_ || blackhole_detection_disabled_) { return false; } // No blackhole detection before handshake completes. + if (default_enable_5rto_blackhole_detection_) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_default_enable_5rto_blackhole_detection2, + 3, 3); + return IsHandshakeComplete(); + } + if (!GetHandshakeTimeout().IsInfinite()) { return false; } - return close_connection_after_five_rtos_ || - (sent_packet_manager_.pto_enabled() && max_consecutive_ptos_ > 0); + return num_rtos_for_blackhole_detection_ > 0; } QuicTime::Delta QuicConnection::GetHandshakeTimeout() const { @@ -4372,12 +4808,9 @@ QuicTime QuicConnection::GetTimeOfLastReceivedPacket() const { if (use_idle_network_detector_) { return idle_network_detector_.time_of_last_received_packet(); } - if (extend_idle_time_on_decryptable_packets_) { - DCHECK(time_of_last_decryptable_packet_ == time_of_last_received_packet_ || - !last_packet_decrypted_); - return time_of_last_decryptable_packet_; - } - return time_of_last_received_packet_; + DCHECK(time_of_last_decryptable_packet_ == time_of_last_received_packet_ || + !last_packet_decrypted_); + return time_of_last_decryptable_packet_; } #undef ENDPOINT // undef for jumbo builds diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_connection.h b/chromium/net/third_party/quiche/src/quic/core/quic_connection.h index 6586fb2870a..c0f722dd0c8 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_connection.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_connection.h @@ -26,6 +26,7 @@ #include "net/third_party/quiche/src/quic/core/crypto/quic_decrypter.h" #include "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h" +#include "net/third_party/quiche/src/quic/core/crypto/transport_parameters.h" #include "net/third_party/quiche/src/quic/core/frames/quic_max_streams_frame.h" #include "net/third_party/quiche/src/quic/core/proto/cached_network_parameters_proto.h" #include "net/third_party/quiche/src/quic/core/quic_alarm.h" @@ -130,6 +131,12 @@ class QUIC_EXPORT_PRIVATE QuicConnectionVisitorInterface { // bandwidth. Returns true if data was sent, false otherwise. virtual bool SendProbingData() = 0; + // Called when stateless reset packet is received. Returns true if the + // connection needs to be closed. + virtual bool ValidateStatelessReset( + const quic::QuicSocketAddress& self_address, + const quic::QuicSocketAddress& peer_address) = 0; + // Called when the connection experiences a change in congestion window. virtual void OnCongestionWindowChange(QuicTime now) = 0; @@ -139,6 +146,9 @@ class QUIC_EXPORT_PRIVATE QuicConnectionVisitorInterface { // Called when the peer seems unreachable over the current path. virtual void OnPathDegrading() = 0; + // Called when forward progress made after path degrading. + virtual void OnForwardProgressMadeAfterPathDegrading() = 0; + // Called when the connection sends ack after // max_consecutive_num_packets_with_no_retransmittable_frames_ consecutive not // retransmittable packets sent. To instigate an ack from peer, a @@ -155,9 +165,6 @@ class QUIC_EXPORT_PRIVATE QuicConnectionVisitorInterface { // or yielded to other connections. virtual bool WillingAndAbleToWrite() const = 0; - // Called to ask if any handshake messages are pending in this visitor. - virtual bool HasPendingHandshake() const = 0; - // Called to ask if the connection should be kept alive and prevented // from timing out, for example if there are outstanding application // transactions expecting a response. @@ -170,10 +177,6 @@ class QUIC_EXPORT_PRIVATE QuicConnectionVisitorInterface { // Called to get current handshake state. virtual HandshakeState GetHandshakeState() const = 0; - // Called when an ACK is received with a larger |largest_acked| than - // previously observed. - virtual void OnForwardProgressConfirmed() = 0; - // Called when a STOP_SENDING frame has been received. virtual void OnStopSendingFrame(const QuicStopSendingFrame& frame) = 0; @@ -341,6 +344,14 @@ class QUIC_EXPORT_PRIVATE QuicConnectionDebugVisitor // Called when |count| packet numbers have been skipped. virtual void OnNPacketNumbersSkipped(QuicPacketCount /*count*/) {} + + // Called for QUIC+TLS versions when we send transport parameters. + virtual void OnTransportParametersSent( + const TransportParameters& /*transport_parameters*/) {} + + // Called for QUIC+TLS versions when we receive transport parameters. + virtual void OnTransportParametersReceived( + const TransportParameters& /*transport_parameters*/) {} }; class QUIC_EXPORT_PRIVATE QuicConnectionHelperInterface { @@ -458,11 +469,6 @@ class QUIC_EXPORT_PRIVATE QuicConnection // Returns statistics tracked for this connection. const QuicConnectionStats& GetStats(); - // Mark stats_.has_non_app_limited_sample as false. - // TODO(b/151166631) Remove this once the proper fix in b/151166631 is rolled - // out. - void ResetHasNonAppLimitedSampleAfterHandshakeCompletion(); - // Processes an incoming UDP packet (consisting of a QuicEncryptedPacket) from // the peer. // In a client, the packet may be "stray" and have a different connection ID @@ -578,6 +584,7 @@ class QUIC_EXPORT_PRIVATE QuicConnection bool OnNewTokenFrame(const QuicNewTokenFrame& frame) override; bool OnMessageFrame(const QuicMessageFrame& frame) override; bool OnHandshakeDoneFrame(const QuicHandshakeDoneFrame& frame) override; + bool OnAckFrequencyFrame(const QuicAckFrequencyFrame& frame) override; void OnPacketComplete() override; bool IsValidStatelessResetToken(QuicUint128 token) const override; void OnAuthenticatedIetfStatelessResetPacket( @@ -587,7 +594,7 @@ class QUIC_EXPORT_PRIVATE QuicConnection bool ShouldGeneratePacket(HasRetransmittableData retransmittable, IsHandshake handshake) override; const QuicFrames MaybeBundleAckOpportunistically() override; - char* GetPacketBuffer() override; + QuicPacketBuffer GetPacketBuffer() override; void OnSerializedPacket(SerializedPacket packet) override; void OnUnrecoverableError(QuicErrorCode error, const std::string& error_details) override; @@ -669,14 +676,10 @@ class QUIC_EXPORT_PRIVATE QuicConnection return server_supported_versions_; } - // Testing only. + bool HasQueuedPackets() const { return !buffered_packets_.empty(); } + // Testing only. TODO(ianswett): Use a peer instead. size_t NumQueuedPackets() const { return buffered_packets_.size(); } - // Returns true if the underlying UDP socket is writable, there is - // no queued data and the connection is not congestion-control - // blocked. - bool CanWriteStreamData(); - // Returns true if the connection has queued packets or frames. bool HasQueuedData() const; @@ -695,19 +698,13 @@ class QUIC_EXPORT_PRIVATE QuicConnection // Sets up a packet with an QuicAckFrame and sends it out. void SendAck(); - // Called when the path degrading alarm fires. - void OnPathDegradingTimeout(); - // Called when an RTO fires. Resets the retransmission alarm if there are // remaining unacked packets. void OnRetransmissionTimeout(); - // Retransmits all unacked packets with retransmittable frames if - // |retransmission_type| is ALL_UNACKED_PACKETS, otherwise retransmits only - // initially encrypted packets. Used when the negotiated protocol version is - // different from what was initially assumed and when the initial encryption - // changes. - void RetransmitUnackedPackets(TransmissionType retransmission_type); + // Retransmits all sent 0-RTT encrypted packets. Called when new 0-RTT or + // 1-RTT key is available. + void RetransmitZeroRttPackets(); // Calls |sent_packet_manager_|'s NeuterUnencryptedPackets. Used when the // connection becomes forward secure and hasn't received acks for all packets. @@ -942,9 +939,13 @@ class QUIC_EXPORT_PRIVATE QuicConnection // Returns the largest received packet number sent by peer. QuicPacketNumber GetLargestReceivedPacket() const; - // Adds the connection ID to a set of connection IDs that are accepted as - // destination on incoming packets. - void AddIncomingConnectionId(QuicConnectionId connection_id); + // Sets the original destination connection ID on the connection. + // This is called by QuicDispatcher when it has replaced the connection ID. + void SetOriginalDestinationConnectionId( + const QuicConnectionId& original_destination_connection_id); + + // Returns the original destination connection ID used for this connection. + QuicConnectionId GetOriginalDestinationConnectionId(); // Called when ACK alarm goes off. Sends ACKs of those packet number spaces // which have expired ACK timeout. Only used when this connection supports @@ -965,6 +966,30 @@ class QUIC_EXPORT_PRIVATE QuicConnection // Called when version is considered negotiated. void OnSuccessfulVersionNegotiation(); + // Called when self migration succeeds after probing. + void OnSuccessfulMigrationAfterProbing(); + + // Called for QUIC+TLS versions when we send transport parameters. + void OnTransportParametersSent( + const TransportParameters& transport_parameters) const; + + // Called for QUIC+TLS versions when we receive transport parameters. + void OnTransportParametersReceived( + const TransportParameters& transport_parameters) const; + + // Returns true if ack_alarm_ is set. + bool HasPendingAcks() const; + + size_t anti_amplification_factor() const { + return anti_amplification_factor_; + } + + void OnUserAgentIdKnown() { sent_packet_manager_.OnUserAgentIdKnown(); } + + // Enables Legacy Version Encapsulation using |server_name| as SNI. + // Can only be set if this is a client connection. + void EnableLegacyVersionEncapsulation(const std::string& server_name); + protected: // Calls cancel() on all the alarms owned by this connection. void CancelAllAlarms(); @@ -1075,12 +1100,16 @@ class QUIC_EXPORT_PRIVATE QuicConnection struct QUIC_EXPORT_PRIVATE UndecryptablePacket { UndecryptablePacket(const QuicEncryptedPacket& packet, EncryptionLevel encryption_level) - : packet(packet.Clone()), encryption_level(encryption_level) {} + : packet(packet.Clone()), + encryption_level(encryption_level), + processed(false) {} std::unique_ptr<QuicEncryptedPacket> packet; - // Currently, |encryption_level| is only used for logging and does not - // affect processing of the packet. EncryptionLevel encryption_level; + // This gets set to true if 1) connection sucessfully processed the packet + // or 2) connection failed to process the packet and will not try to process + // it later. + bool processed; }; // Notifies the visitor of the close and marks the connection as disconnected. @@ -1237,6 +1266,10 @@ class QUIC_EXPORT_PRIVATE QuicConnection // received packet number which contains an ACK frame. void SetLargestReceivedPacketWithAck(QuicPacketNumber new_value); + // Called when new packets have been acknowledged or old keys have been + // discarded. + void OnForwardProgressMade(); + // Returns largest received packet number which contains an ACK frame. QuicPacketNumber GetLargestReceivedPacketWithAck() const; @@ -1285,6 +1318,30 @@ class QUIC_EXPORT_PRIVATE QuicConnection QuicTime::Delta GetHandshakeTimeout() const; QuicTime GetTimeOfLastReceivedPacket() const; + // Validate connection IDs used during the handshake. Closes the connection + // on validation failure. + bool ValidateConfigConnectionIds(const QuicConfig& config); + bool ValidateConfigConnectionIdsOld(const QuicConfig& config); + + // Called when ACK alarm goes off. Try to bundle crypto data with the ACK of + // |space|. + void MaybeBundleCryptoDataWithAckOfSpace(PacketNumberSpace space); + + // Returns true if an undecryptable packet of |decryption_level| should be + // buffered (such that connection can try to decrypt it later). + bool ShouldEnqueueUnDecryptablePacket(EncryptionLevel decryption_level, + bool has_decryption_key) const; + + // Returns string which contains undecryptable packets information. + std::string UndecryptablePacketsInfo() const; + + // Sets the max packet length on the packet creator if needed. + void MaybeUpdatePacketCreatorMaxPacketLengthAndPadding(); + + // Sets internal state to enable or disable Legacy Version Encapsulation. + void MaybeActivateLegacyVersionEncapsulation(); + void MaybeDisactivateLegacyVersionEncapsulation(); + QuicFramer framer_; // Contents received in the current packet, especially used to identify @@ -1394,9 +1451,8 @@ class QUIC_EXPORT_PRIVATE QuicConnection // a connection close packet is sent, but not after. ConnectionCloseBehavior idle_timeout_connection_close_behavior_; - // When true, close the QUIC connection after 5 RTOs. Due to the min rto of - // 200ms, this is over 5 seconds. - bool close_connection_after_five_rtos_; + // When > 0, close the QUIC connection after this number of RTOs. + size_t num_rtos_for_blackhole_detection_; UberReceivedPacketManager uber_received_packet_manager_; @@ -1601,18 +1657,19 @@ class QUIC_EXPORT_PRIVATE QuicConnection // vector to improve performance since it is expected to be very small. std::vector<QuicConnectionId> incoming_connection_ids_; - // When we receive a RETRY packet, we replace |server_connection_id_| with the - // value from the RETRY packet and save off the original value of - // |server_connection_id_| into |original_connection_id_| for validation. - quiche::QuicheOptional<QuicConnectionId> original_connection_id_; + // When we receive a RETRY packet or some INITIAL packets, we replace + // |server_connection_id_| with the value from that packet and save off the + // original value of |server_connection_id_| into + // |original_destination_connection_id_| for validation. + quiche::QuicheOptional<QuicConnectionId> original_destination_connection_id_; + + // After we receive a RETRY packet, |retry_source_connection_id_| contains + // the source connection ID from that packet. + quiche::QuicheOptional<QuicConnectionId> retry_source_connection_id_; // Indicates whether received RETRY packets should be dropped. bool drop_incoming_retry_packets_; - // If max_consecutive_ptos_ > 0, close connection if consecutive PTOs is - // greater than max_consecutive_ptos. - size_t max_consecutive_ptos_; - // Bytes received before address validation. Only used when // EnforceAntiAmplificationLimit returns true. size_t bytes_received_before_address_validation_; @@ -1644,14 +1701,40 @@ class QUIC_EXPORT_PRIVATE QuicConnection QuicIdleNetworkDetector idle_network_detector_; + bool blackhole_detection_disabled_ = false; + + // True if this connection supports handshake done frame. + bool support_handshake_done_; + const bool use_idle_network_detector_ = GetQuicReloadableFlag(quic_use_idle_network_detector); - const bool extend_idle_time_on_decryptable_packets_ = - GetQuicReloadableFlag(quic_extend_idle_time_on_decryptable_packets); - - const bool advance_ack_timeout_update_ = - GetQuicReloadableFlag(quic_advance_ack_timeout_update); + const bool update_ack_alarm_in_send_all_pending_acks_ = + GetQuicReloadableFlag(quic_update_ack_alarm_in_send_all_pending_acks); + + const bool move_amplification_limit_ = + GetQuicReloadableFlag(quic_move_amplification_limit); + + // TODO(fayang): Change the default value of quic_anti_amplification_factor to + // 5 when deprecating quic_move_amplification_limit. + // TODO(b/153892665): Change the default value of + // quic_anti_amplification_factor back to 3 when cert compression is + // supported. + const size_t anti_amplification_factor_ = + move_amplification_limit_ + ? 5 + : GetQuicFlag(FLAGS_quic_anti_amplification_factor); + + const bool default_enable_5rto_blackhole_detection_ = + GetQuicReloadableFlag(quic_default_enable_5rto_blackhole_detection2); + + // Whether the Legacy Version Encapsulation feature is enabled. + bool legacy_version_encapsulation_enabled_ = false; + // Whether we are in the middle of sending a packet using Legacy Version + // Encapsulation. + bool legacy_version_encapsulation_in_progress_ = false; + // SNI to send when using Legacy Version Encapsulation. + std::string legacy_version_encapsulation_sni_; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.cc b/chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.cc index 89f7e546d88..191918c9887 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.cc @@ -53,6 +53,8 @@ std::ostream& operator<<(std::ostream& os, const QuicConnectionStats& s) { os << " num_coalesced_packets_processed: " << s.num_coalesced_packets_processed; os << " num_ack_aggregation_epochs: " << s.num_ack_aggregation_epochs; + os << " sent_legacy_version_encapsulated_packets: " + << s.sent_legacy_version_encapsulated_packets; os << " }"; return os; diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.h b/chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.h index 3b0c85d2228..3579be0f6f4 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_connection_stats.h @@ -47,9 +47,21 @@ struct QUIC_EXPORT_PRIVATE QuicConnectionStats { QuicPacketCount packets_lost = 0; QuicPacketCount packet_spuriously_detected_lost = 0; - // The sum of the detection time of all lost packets. The detection time of a - // lost packet is defined as: T(detection) - T(send). - QuicTime::Delta total_loss_detection_time = QuicTime::Delta::Zero(); + // The sum of loss detection response times of all lost packets, in number of + // round trips. + // Given a packet detected as lost: + // T(S) T(1Rtt) T(D) + // |_________________________________|_______| + // Where + // T(S) is the time when the packet is sent. + // T(1Rtt) is one rtt after T(S), using the rtt at the time of detection. + // T(D) is the time of detection, i.e. when the packet is declared as lost. + // The loss detection response time is defined as + // (T(D) - T(S)) / (T(1Rtt) - T(S)) + // + // The average loss detection response time is this number divided by + // |packets_lost|. Smaller result means detection is faster. + float total_loss_detection_response_time = 0.0; // Number of times this connection went through the slow start phase. uint32_t slowstart_count = 0; @@ -90,6 +102,7 @@ struct QUIC_EXPORT_PRIVATE QuicConnectionStats { int64_t min_rtt_us = 0; // Minimum RTT in microseconds. int64_t srtt_us = 0; // Smoothed RTT in microseconds. + int64_t cwnd_bootstrapping_rtt_us = 0; // RTT used in cwnd_bootstrapping. QuicByteCount max_packet_size = 0; QuicByteCount max_received_packet_size = 0; QuicBandwidth estimated_bandwidth = QuicBandwidth::Zero(); @@ -104,6 +117,9 @@ struct QUIC_EXPORT_PRIVATE QuicConnectionStats { // Maximum sequence reordering observed from acked packets. QuicPacketCount sent_packets_max_sequence_reordering = 0; + // Number of times that a packet is not detected as lost per reordering_shift, + // but would have been if the reordering_shift increases by one. + QuicPacketCount sent_packets_num_borderline_time_reorderings = 0; // The following stats are used only in TcpCubicSender. // The number of loss events from TCP's perspective. Each loss event includes @@ -136,6 +152,16 @@ struct QUIC_EXPORT_PRIVATE QuicConnectionStats { // Whether there is any non app-limited bandwidth sample. bool has_non_app_limited_sample = false; + + // Packet number of first decrypted packet. + QuicPacketNumber first_decrypted_packet; + + // Max consecutive retransmission timeout before making forward progress. + size_t max_consecutive_rto_with_forward_progress = 0; + + // Number of sent packets that were encapsulated using Legacy Version + // Encapsulation. + QuicPacketCount sent_legacy_version_encapsulated_packets = 0; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_connection_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_connection_test.cc index 24f233ef233..7fc45caefb3 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_connection_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_connection_test.cc @@ -18,6 +18,7 @@ #include "net/third_party/quiche/src/quic/core/crypto/quic_decrypter.h" #include "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h" #include "net/third_party/quiche/src/quic/core/quic_connection_id.h" +#include "net/third_party/quiche/src/quic/core/quic_constants.h" #include "net/third_party/quiche/src/quic/core/quic_packets.h" #include "net/third_party/quiche/src/quic/core/quic_simple_buffer_allocator.h" #include "net/third_party/quiche/src/quic/core/quic_types.h" @@ -28,6 +29,7 @@ #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" #include "net/third_party/quiche/src/quic/platform/api/quic_reference_counted.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" #include "net/third_party/quiche/src/quic/test_tools/mock_clock.h" #include "net/third_party/quiche/src/quic/test_tools/mock_random.h" @@ -48,7 +50,6 @@ using testing::_; using testing::AnyNumber; using testing::AtLeast; using testing::DoAll; -using testing::Exactly; using testing::Ge; using testing::IgnoreResult; using testing::InSequence; @@ -336,6 +337,11 @@ class TestAlarmFactory : public QuicAlarmFactory { }; class TestPacketWriter : public QuicPacketWriter { + struct PacketBuffer { + QUIC_CACHELINE_ALIGNED char buffer[1500]; + bool in_use = false; + }; + public: TestPacketWriter(ParsedQuicVersion version, MockClock* clock) : version_(version), @@ -344,16 +350,40 @@ class TestPacketWriter : public QuicPacketWriter { QuicFramerPeer::SetLastSerializedServerConnectionId(framer_.framer(), TestConnectionId()); framer_.framer()->SetInitialObfuscators(TestConnectionId()); + + for (int i = 0; i < 128; ++i) { + PacketBuffer* p = new PacketBuffer(); + packet_buffer_pool_.push_back(p); + packet_buffer_pool_index_[p->buffer] = p; + packet_buffer_free_list_.push_back(p); + } } TestPacketWriter(const TestPacketWriter&) = delete; TestPacketWriter& operator=(const TestPacketWriter&) = delete; + ~TestPacketWriter() override { + EXPECT_EQ(packet_buffer_pool_.size(), packet_buffer_free_list_.size()) + << packet_buffer_pool_.size() - packet_buffer_free_list_.size() + << " out of " << packet_buffer_pool_.size() + << " packet buffers have been leaked."; + for (auto p : packet_buffer_pool_) { + delete p; + } + } + // QuicPacketWriter interface WriteResult WritePacket(const char* buffer, size_t buf_len, const QuicIpAddress& /*self_address*/, const QuicSocketAddress& /*peer_address*/, PerPacketOptions* /*options*/) override { + // If the buffer is allocated from the pool, return it back to the pool. + // Note the buffer content doesn't change. + if (packet_buffer_pool_index_.find(const_cast<char*>(buffer)) != + packet_buffer_pool_index_.end()) { + FreePacketBuffer(buffer); + } + QuicEncryptedPacket packet(buffer, buf_len); ++packets_write_attempts_; @@ -440,10 +470,15 @@ class TestPacketWriter : public QuicPacketWriter { bool IsBatchMode() const override { return is_batch_mode_; } - char* GetNextWriteLocation( + QuicPacketBuffer GetNextWriteLocation( const QuicIpAddress& /*self_address*/, const QuicSocketAddress& /*peer_address*/) override { - return nullptr; + if (GetQuicReloadableFlag(quic_avoid_leak_writer_buffer)) { + return {AllocPacketBuffer(), + [this](const char* p) { FreePacketBuffer(p); }}; + } + // Do not use writer buffer for serializing packets. + return {nullptr, nullptr}; } WriteResult Flush() override { @@ -591,6 +626,23 @@ class TestPacketWriter : public QuicPacketWriter { SimpleQuicFramer* framer() { return &framer_; } private: + char* AllocPacketBuffer() { + PacketBuffer* p = packet_buffer_free_list_.front(); + EXPECT_FALSE(p->in_use); + p->in_use = true; + packet_buffer_free_list_.pop_front(); + return p->buffer; + } + + void FreePacketBuffer(const char* buffer) { + auto iter = packet_buffer_pool_index_.find(const_cast<char*>(buffer)); + ASSERT_TRUE(iter != packet_buffer_pool_index_.end()); + PacketBuffer* p = iter->second; + ASSERT_TRUE(p->in_use); + p->in_use = false; + packet_buffer_free_list_.push_back(p); + } + ParsedQuicVersion version_; SimpleQuicFramer framer_; size_t last_packet_size_ = 0; @@ -619,6 +671,12 @@ class TestPacketWriter : public QuicPacketWriter { QuicTime::Delta write_pause_time_delta_ = QuicTime::Delta::Zero(); QuicByteCount max_packet_size_ = kMaxOutgoingPacketSize; bool supports_release_time_ = false; + // Used to verify writer-allocated packet buffers are properly released. + std::vector<PacketBuffer*> packet_buffer_pool_; + // Buffer address => Address of the owning PacketBuffer. + QuicHashMap<char*, PacketBuffer*> packet_buffer_pool_index_; + // Indices in packet_buffer_pool_ that are not allocated. + std::list<PacketBuffer*> packet_buffer_free_list_; }; class TestConnection : public QuicConnection { @@ -739,7 +797,7 @@ class TestConnection : public QuicConnection { // Ensures the connection can write stream data before writing. QuicConsumedData EnsureWritableAndSendStreamData5() { - EXPECT_TRUE(CanWriteStreamData()); + EXPECT_TRUE(CanWrite(HAS_RETRANSMITTABLE_DATA)); return SendStreamData5(); } @@ -1091,14 +1149,12 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> { EXPECT_CALL(*send_algorithm_, OnApplicationLimited(_)).Times(AnyNumber()); EXPECT_CALL(visitor_, WillingAndAbleToWrite()).Times(AnyNumber()); EXPECT_CALL(visitor_, OnPacketDecrypted(_)).Times(AnyNumber()); - EXPECT_CALL(visitor_, HasPendingHandshake()).Times(AnyNumber()); EXPECT_CALL(visitor_, OnCanWrite()) .WillRepeatedly(Invoke(¬ifier_, &SimpleSessionNotifier::OnCanWrite)); EXPECT_CALL(visitor_, ShouldKeepConnectionAlive()) .WillRepeatedly(Return(false)); EXPECT_CALL(visitor_, OnCongestionWindowChange(_)).Times(AnyNumber()); EXPECT_CALL(visitor_, OnPacketReceived(_, _, _)).Times(AnyNumber()); - EXPECT_CALL(visitor_, OnForwardProgressConfirmed()).Times(AnyNumber()); EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)).Times(AnyNumber()); EXPECT_CALL(visitor_, OnOneRttPacketAcknowledged()) .Times(testing::AtMost(1)); @@ -1317,9 +1373,8 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> { level); } - size_t ProcessCryptoPacketAtLevel(uint64_t number, - EncryptionLevel /*level*/) { - QuicPacketHeader header = ConstructPacketHeader(number, ENCRYPTION_INITIAL); + size_t ProcessCryptoPacketAtLevel(uint64_t number, EncryptionLevel level) { + QuicPacketHeader header = ConstructPacketHeader(number, level); QuicFrames frames; if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { frames.push_back(QuicFrame(&crypto_frame_)); @@ -1329,10 +1384,10 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> { frames.push_back(QuicFrame(QuicPaddingFrame(-1))); std::unique_ptr<QuicPacket> packet = ConstructPacket(header, frames); char buffer[kMaxOutgoingPacketSize]; - peer_creator_.set_encryption_level(ENCRYPTION_INITIAL); - size_t encrypted_length = peer_framer_.EncryptPayload( - ENCRYPTION_INITIAL, QuicPacketNumber(number), *packet, buffer, - kMaxOutgoingPacketSize); + peer_creator_.set_encryption_level(level); + size_t encrypted_length = + peer_framer_.EncryptPayload(level, QuicPacketNumber(number), *packet, + buffer, kMaxOutgoingPacketSize); connection_.ProcessUdpPacket( kSelfAddress, kPeerAddress, QuicReceivedPacket(buffer, encrypted_length, clock_.Now(), false)); @@ -1694,6 +1749,9 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> { void MtuDiscoveryTestInit() { set_perspective(Perspective::IS_SERVER); QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false); + if (version().SupportsAntiAmplificationLimit()) { + QuicConnectionPeer::SetAddressValidated(&connection_); + } connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); peer_creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE); // QuicFramer::GetMaxPlaintextSize uses the smallest max plaintext size @@ -1712,9 +1770,21 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> { EXPECT_TRUE(connection_.connected()); } + void PathProbeTestInit(Perspective perspective) { + set_perspective(perspective); + EXPECT_EQ(connection_.perspective(), perspective); + if (perspective == Perspective::IS_SERVER) { + QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false); + } + connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); + peer_creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE); + } + void TestClientRetryHandling(bool invalid_retry_tag, - bool missing_id_in_config, - bool wrong_id_in_config); + bool missing_original_id_in_config, + bool wrong_original_id_in_config, + bool missing_retry_id_in_config, + bool wrong_retry_id_in_config); QuicConnectionId connection_id_; QuicFramer framer_; @@ -1941,6 +2011,9 @@ TEST_P(QuicConnectionTest, EffectivePeerAddressChangeAtServer) { set_perspective(Perspective::IS_SERVER); QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false); EXPECT_EQ(Perspective::IS_SERVER, connection_.perspective()); + if (version().SupportsAntiAmplificationLimit()) { + QuicConnectionPeer::SetAddressValidated(&connection_); + } // Clear direct_peer_address. QuicConnectionPeer::SetDirectPeerAddress(&connection_, QuicSocketAddress()); @@ -2022,9 +2095,7 @@ TEST_P(QuicConnectionTest, EffectivePeerAddressChangeAtServer) { } TEST_P(QuicConnectionTest, ReceivePathProbeWithNoAddressChangeAtServer) { - set_perspective(Perspective::IS_SERVER); - QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false); - EXPECT_EQ(Perspective::IS_SERVER, connection_.perspective()); + PathProbeTestInit(Perspective::IS_SERVER); // Clear direct_peer_address. QuicConnectionPeer::SetDirectPeerAddress(&connection_, QuicSocketAddress()); @@ -2068,9 +2139,6 @@ TEST_P(QuicConnectionTest, ReceivePathProbeWithNoAddressChangeAtServer) { // Regression test for b/150161358. TEST_P(QuicConnectionTest, BufferedMtuPacketTooBig) { - if (!GetQuicReloadableFlag(quic_ignore_msg_too_big_from_buffered_packets)) { - return; - } EXPECT_CALL(visitor_, OnWriteBlocked()).Times(1); writer_->SetWriteBlocked(); @@ -2138,9 +2206,7 @@ TEST_P(QuicConnectionTest, DiscardQueuedPacketsAfterConnectionClose) { // in IETF version: receive a packet contains PATH CHALLENGE with peer address // change. TEST_P(QuicConnectionTest, ReceivePathProbingAtServer) { - set_perspective(Perspective::IS_SERVER); - QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false); - EXPECT_EQ(Perspective::IS_SERVER, connection_.perspective()); + PathProbeTestInit(Perspective::IS_SERVER); // Clear direct_peer_address. QuicConnectionPeer::SetDirectPeerAddress(&connection_, QuicSocketAddress()); @@ -2278,9 +2344,7 @@ TEST_P(QuicConnectionTest, ReceivePaddedPingWithPortChangeAtServer) { } TEST_P(QuicConnectionTest, ReceiveReorderedPathProbingAtServer) { - set_perspective(Perspective::IS_SERVER); - QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false); - EXPECT_EQ(Perspective::IS_SERVER, connection_.perspective()); + PathProbeTestInit(Perspective::IS_SERVER); // Clear direct_peer_address. QuicConnectionPeer::SetDirectPeerAddress(&connection_, QuicSocketAddress()); @@ -2336,9 +2400,7 @@ TEST_P(QuicConnectionTest, ReceiveReorderedPathProbingAtServer) { } TEST_P(QuicConnectionTest, MigrateAfterProbingAtServer) { - set_perspective(Perspective::IS_SERVER); - QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false); - EXPECT_EQ(Perspective::IS_SERVER, connection_.perspective()); + PathProbeTestInit(Perspective::IS_SERVER); // Clear direct_peer_address. QuicConnectionPeer::SetDirectPeerAddress(&connection_, QuicSocketAddress()); @@ -2393,8 +2455,7 @@ TEST_P(QuicConnectionTest, MigrateAfterProbingAtServer) { TEST_P(QuicConnectionTest, ReceivePaddedPingAtClient) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - set_perspective(Perspective::IS_CLIENT); - EXPECT_EQ(Perspective::IS_CLIENT, connection_.perspective()); + PathProbeTestInit(Perspective::IS_CLIENT); // Clear direct_peer_address. QuicConnectionPeer::SetDirectPeerAddress(&connection_, QuicSocketAddress()); @@ -2442,8 +2503,7 @@ TEST_P(QuicConnectionTest, ReceiveConnectivityProbingResponseAtClient) { return; } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - set_perspective(Perspective::IS_CLIENT); - EXPECT_EQ(Perspective::IS_CLIENT, connection_.perspective()); + PathProbeTestInit(Perspective::IS_CLIENT); // Clear direct_peer_address. QuicConnectionPeer::SetDirectPeerAddress(&connection_, QuicSocketAddress()); @@ -3129,9 +3189,12 @@ TEST_P(QuicConnectionTest, BasicSending) { if (connection_.SupportsMultiplePacketNumberSpaces()) { return; } + const QuicConnectionStats& stats = connection_.GetStats(); + EXPECT_FALSE(stats.first_decrypted_packet.IsInitialized()); EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); ProcessDataPacket(1); + EXPECT_EQ(QuicPacketNumber(1), stats.first_decrypted_packet); QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 2); QuicPacketNumber last_packet; SendStreamDataToPeer(1, "foo", 0, NO_FIN, &last_packet); // Packet 1 @@ -3215,6 +3278,7 @@ TEST_P(QuicConnectionTest, BasicSending) { } else { EXPECT_EQ(QuicPacketNumber(7u), least_unacked()); } + EXPECT_EQ(QuicPacketNumber(1), stats.first_decrypted_packet); } // QuicConnection should record the packet sent-time prior to sending the @@ -3480,8 +3544,7 @@ TEST_P(QuicConnectionTest, LargeSendWithPendingAck) { // Processs a PING frame. ProcessFramePacket(QuicFrame(QuicPingFrame())); // Ensure that this has caused the ACK alarm to be set. - QuicAlarm* ack_alarm = QuicConnectionPeer::GetAckAlarm(&connection_); - EXPECT_TRUE(ack_alarm->IsSet()); + EXPECT_TRUE(connection_.HasPendingAcks()); // Send data and ensure the ack is bundled. EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(8); @@ -3506,7 +3569,7 @@ TEST_P(QuicConnectionTest, LargeSendWithPendingAck) { writer_->stream_frames()[0]->stream_id); EXPECT_TRUE(writer_->stream_frames()[0]->fin); // Ensure the ack alarm was cancelled when the ack was sent. - EXPECT_FALSE(ack_alarm->IsSet()); + EXPECT_FALSE(connection_.HasPendingAcks()); } TEST_P(QuicConnectionTest, OnCanWrite) { @@ -4241,6 +4304,12 @@ TEST_P(QuicConnectionTest, TailLossProbeDelayForNonStreamDataInTLPR) { options.push_back(kTLPR); config.SetConnectionOptionsToSend(options); QuicConfigPeer::SetNegotiated(&config, true); + if (connection_.version().AuthenticatesHandshakeConnectionIds()) { + QuicConfigPeer::SetReceivedOriginalConnectionId( + &config, connection_.connection_id()); + QuicConfigPeer::SetReceivedInitialSourceConnectionId( + &config, connection_.connection_id()); + } connection_.SetFromConfig(config); connection_.SetMaxTailLossProbes(1); @@ -4414,47 +4483,6 @@ TEST_P(QuicConnectionTest, RtoWithNoDataToRetransmit) { } } -TEST_P(QuicConnectionTest, RetransmitWithSameEncryptionLevel) { - use_tagging_decrypter(); - - // A TaggingEncrypter puts kTagSize copies of the given byte (0x01 here) at - // the end of the packet. We can test this to check which encrypter was used. - connection_.SetEncrypter(ENCRYPTION_INITIAL, - std::make_unique<TaggingEncrypter>(0x01)); - QuicByteCount packet_size; - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)) - .WillOnce(SaveArg<3>(&packet_size)); - connection_.SendCryptoDataWithString("foo", 0); - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AnyNumber()); - EXPECT_EQ(0x01010101u, writer_->final_bytes_of_last_packet()); - - connection_.SetEncrypter(ENCRYPTION_ZERO_RTT, - std::make_unique<TaggingEncrypter>(0x02)); - connection_.SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT); - SendStreamDataToPeer(3, "foo", 0, NO_FIN, nullptr); - EXPECT_EQ(0x02020202u, writer_->final_bytes_of_last_packet()); - - { - InSequence s; - EXPECT_CALL(*send_algorithm_, - OnPacketSent(_, _, QuicPacketNumber(3), _, _)); - EXPECT_CALL(*send_algorithm_, - OnPacketSent(_, _, QuicPacketNumber(4), _, _)); - } - - // Manually mark both packets for retransmission. - connection_.RetransmitUnackedPackets(ALL_UNACKED_RETRANSMISSION); - if (!connection_.version().CanSendCoalescedPackets()) { - // Packet should have been sent with ENCRYPTION_INITIAL. - // If connection can send coalesced packet, both retransmissions will be - // coalesced in the same UDP datagram. - EXPECT_EQ(0x01010101u, writer_->final_bytes_of_previous_packet()); - } - - // Packet should have been sent with ENCRYPTION_ZERO_RTT. - EXPECT_EQ(0x02020202u, writer_->final_bytes_of_last_packet()); -} - TEST_P(QuicConnectionTest, SendHandshakeMessages) { use_tagging_decrypter(); // A TaggingEncrypter puts kTagSize copies of the given byte (0x01 here) at @@ -4514,6 +4542,8 @@ TEST_P(QuicConnectionTest, } TEST_P(QuicConnectionTest, RetransmitPacketsWithInitialEncryption) { + SetQuicReloadableFlag(quic_do_not_retransmit_immediately_on_zero_rtt_reject, + true); use_tagging_decrypter(); connection_.SetEncrypter(ENCRYPTION_INITIAL, std::make_unique<TaggingEncrypter>(0x01)); @@ -4526,9 +4556,9 @@ TEST_P(QuicConnectionTest, RetransmitPacketsWithInitialEncryption) { connection_.SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT); SendStreamDataToPeer(2, "bar", 0, NO_FIN, nullptr); - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); - - connection_.RetransmitUnackedPackets(ALL_INITIAL_RETRANSMISSION); + EXPECT_FALSE(notifier_.HasLostStreamData()); + connection_.RetransmitZeroRttPackets(); + EXPECT_TRUE(notifier_.HasLostStreamData()); } TEST_P(QuicConnectionTest, BufferNonDecryptablePackets) { @@ -4739,7 +4769,7 @@ TEST_P(QuicConnectionTest, InitialTimeout) { EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet()); EXPECT_FALSE(connection_.connected()); - EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + EXPECT_FALSE(connection_.HasPendingAcks()); EXPECT_FALSE(connection_.GetPingAlarm()->IsSet()); EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet()); EXPECT_FALSE(connection_.GetSendAlarm()->IsSet()); @@ -4794,7 +4824,7 @@ TEST_P(QuicConnectionTest, IdleTimeoutAfterFirstSentPacket) { EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet()); EXPECT_FALSE(connection_.connected()); - EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + EXPECT_FALSE(connection_.HasPendingAcks()); EXPECT_FALSE(connection_.GetPingAlarm()->IsSet()); EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet()); EXPECT_FALSE(connection_.GetSendAlarm()->IsSet()); @@ -4838,7 +4868,7 @@ TEST_P(QuicConnectionTest, IdleTimeoutAfterSendTwoPackets) { EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet()); EXPECT_FALSE(connection_.connected()); - EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + EXPECT_FALSE(connection_.HasPendingAcks()); EXPECT_FALSE(connection_.GetPingAlarm()->IsSet()); EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet()); EXPECT_FALSE(connection_.GetSendAlarm()->IsSet()); @@ -4885,7 +4915,7 @@ TEST_P(QuicConnectionTest, HandshakeTimeout) { EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet()); EXPECT_FALSE(connection_.connected()); - EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + EXPECT_FALSE(connection_.HasPendingAcks()); EXPECT_FALSE(connection_.GetPingAlarm()->IsSet()); EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet()); EXPECT_FALSE(connection_.GetSendAlarm()->IsSet()); @@ -5764,6 +5794,12 @@ TEST_P(QuicConnectionTest, TimeoutAfterSendAfterHandshake) { config.ProcessPeerHello(msg, CLIENT, &error_details); EXPECT_THAT(error, IsQuicNoError()); + if (connection_.version().AuthenticatesHandshakeConnectionIds()) { + QuicConfigPeer::SetReceivedOriginalConnectionId( + &config, connection_.connection_id()); + QuicConfigPeer::SetReceivedInitialSourceConnectionId( + &config, connection_.connection_id()); + } connection_.SetFromConfig(config); const QuicTime::Delta default_idle_timeout = @@ -5910,6 +5946,12 @@ TEST_P(QuicConnectionTest, TimeoutAfterSendSilentCloseWithOpenStreams) { config.ProcessPeerHello(msg, CLIENT, &error_details); EXPECT_THAT(error, IsQuicNoError()); + if (connection_.version().AuthenticatesHandshakeConnectionIds()) { + QuicConfigPeer::SetReceivedOriginalConnectionId( + &config, connection_.connection_id()); + QuicConfigPeer::SetReceivedInitialSourceConnectionId( + &config, connection_.connection_id()); + } connection_.SetFromConfig(config); const QuicTime::Delta default_idle_timeout = @@ -6074,6 +6116,16 @@ TEST_P(QuicConnectionTest, TimeoutAfter5ClientRTOs) { connection_options.push_back(k5RTO); config.SetConnectionOptionsToSend(connection_options); QuicConfigPeer::SetNegotiated(&config, true); + if (GetQuicReloadableFlag(quic_default_enable_5rto_blackhole_detection2)) { + EXPECT_CALL(visitor_, GetHandshakeState()) + .WillRepeatedly(Return(HANDSHAKE_COMPLETE)); + } + if (connection_.version().AuthenticatesHandshakeConnectionIds()) { + QuicConfigPeer::SetReceivedOriginalConnectionId( + &config, connection_.connection_id()); + QuicConfigPeer::SetReceivedInitialSourceConnectionId( + &config, connection_.connection_id()); + } connection_.SetFromConfig(config); // Send stream data. @@ -6212,7 +6264,7 @@ TEST_P(QuicConnectionTest, LoopThroughSendingPacketsWithTruncation) { TEST_P(QuicConnectionTest, SendDelayedAck) { QuicTime ack_time = clock_.ApproximateNow() + DefaultDelayedAckTime(); EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + EXPECT_FALSE(connection_.HasPendingAcks()); const uint8_t tag = 0x07; SetDecrypter(ENCRYPTION_ZERO_RTT, std::make_unique<StrictTaggingDecrypter>(tag)); @@ -6227,7 +6279,7 @@ TEST_P(QuicConnectionTest, SendDelayedAck) { ProcessDataPacketAtLevel(1, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); // Check if delayed ack timer is running for the expected interval. - EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); + EXPECT_TRUE(connection_.HasPendingAcks()); EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline()); // Simulate delayed ack alarm firing. clock_.AdvanceTime(DefaultDelayedAckTime()); @@ -6242,7 +6294,7 @@ TEST_P(QuicConnectionTest, SendDelayedAck) { EXPECT_FALSE(writer_->stop_waiting_frames().empty()); } EXPECT_FALSE(writer_->ack_frames().empty()); - EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + EXPECT_FALSE(connection_.HasPendingAcks()); } TEST_P(QuicConnectionTest, SendDelayedAfterQuiescence) { @@ -6251,7 +6303,7 @@ TEST_P(QuicConnectionTest, SendDelayedAfterQuiescence) { // The beginning of the connection counts as quiescence. QuicTime ack_time = clock_.ApproximateNow() + kAlarmGranularity; EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + EXPECT_FALSE(connection_.HasPendingAcks()); const uint8_t tag = 0x07; SetDecrypter(ENCRYPTION_ZERO_RTT, std::make_unique<StrictTaggingDecrypter>(tag)); @@ -6266,7 +6318,7 @@ TEST_P(QuicConnectionTest, SendDelayedAfterQuiescence) { ProcessDataPacketAtLevel(1, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); // Check if delayed ack timer is running for the expected interval. - EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); + EXPECT_TRUE(connection_.HasPendingAcks()); EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline()); // Simulate delayed ack alarm firing. clock_.AdvanceTime(DefaultDelayedAckTime()); @@ -6281,7 +6333,7 @@ TEST_P(QuicConnectionTest, SendDelayedAfterQuiescence) { EXPECT_FALSE(writer_->stop_waiting_frames().empty()); } EXPECT_FALSE(writer_->ack_frames().empty()); - EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + EXPECT_FALSE(connection_.HasPendingAcks()); // Process another packet immedately after sending the ack and expect the // ack alarm to be set delayed ack time in the future. @@ -6290,7 +6342,7 @@ TEST_P(QuicConnectionTest, SendDelayedAfterQuiescence) { ProcessDataPacketAtLevel(2, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); // Check if delayed ack timer is running for the expected interval. - EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); + EXPECT_TRUE(connection_.HasPendingAcks()); EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline()); // Simulate delayed ack alarm firing. clock_.AdvanceTime(DefaultDelayedAckTime()); @@ -6305,7 +6357,7 @@ TEST_P(QuicConnectionTest, SendDelayedAfterQuiescence) { EXPECT_FALSE(writer_->stop_waiting_frames().empty()); } EXPECT_FALSE(writer_->ack_frames().empty()); - EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + EXPECT_FALSE(connection_.HasPendingAcks()); // Wait 1 second and ensure the ack alarm is set to 1ms in the future. clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1)); @@ -6314,7 +6366,7 @@ TEST_P(QuicConnectionTest, SendDelayedAfterQuiescence) { ProcessDataPacketAtLevel(3, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); // Check if delayed ack timer is running for the expected interval. - EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); + EXPECT_TRUE(connection_.HasPendingAcks()); EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline()); } @@ -6331,7 +6383,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimation) { QuicTime ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(kMinRttMs / 4); EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + EXPECT_FALSE(connection_.HasPendingAcks()); const uint8_t tag = 0x07; SetDecrypter(ENCRYPTION_ZERO_RTT, std::make_unique<StrictTaggingDecrypter>(tag)); @@ -6346,7 +6398,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimation) { EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); } - EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + EXPECT_FALSE(connection_.HasPendingAcks()); // The same as ProcessPacket(1) except that ENCRYPTION_ZERO_RTT is used // instead of ENCRYPTION_INITIAL. EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); @@ -6354,12 +6406,12 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimation) { ENCRYPTION_ZERO_RTT); // Check if delayed ack timer is running for the expected interval. - EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); + EXPECT_TRUE(connection_.HasPendingAcks()); EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline()); // The 10th received packet causes an ack to be sent. for (int i = 0; i < 9; ++i) { - EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); + EXPECT_TRUE(connection_.HasPendingAcks()); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); ProcessDataPacketAtLevel(kFirstDecimatedPacket + 1 + i, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); @@ -6374,7 +6426,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimation) { EXPECT_FALSE(writer_->stop_waiting_frames().empty()); } EXPECT_FALSE(writer_->ack_frames().empty()); - EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + EXPECT_FALSE(connection_.HasPendingAcks()); } TEST_P(QuicConnectionTest, SendDelayedAckAckDecimationAfterQuiescence) { @@ -6391,7 +6443,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckAckDecimationAfterQuiescence) { QuicTime ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(1); EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + EXPECT_FALSE(connection_.HasPendingAcks()); const uint8_t tag = 0x07; SetDecrypter(ENCRYPTION_ZERO_RTT, std::make_unique<StrictTaggingDecrypter>(tag)); @@ -6406,7 +6458,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckAckDecimationAfterQuiescence) { ProcessDataPacketAtLevel(1, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); // Check if delayed ack timer is running for the expected interval. - EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); + EXPECT_TRUE(connection_.HasPendingAcks()); EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline()); // Simulate delayed ack alarm firing. clock_.AdvanceTime(DefaultDelayedAckTime()); @@ -6421,7 +6473,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckAckDecimationAfterQuiescence) { EXPECT_FALSE(writer_->stop_waiting_frames().empty()); } EXPECT_FALSE(writer_->ack_frames().empty()); - EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + EXPECT_FALSE(connection_.HasPendingAcks()); // Process another packet immedately after sending the ack and expect the // ack alarm to be set delayed ack time in the future. @@ -6430,7 +6482,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckAckDecimationAfterQuiescence) { ProcessDataPacketAtLevel(2, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); // Check if delayed ack timer is running for the expected interval. - EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); + EXPECT_TRUE(connection_.HasPendingAcks()); EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline()); // Simulate delayed ack alarm firing. clock_.AdvanceTime(DefaultDelayedAckTime()); @@ -6445,7 +6497,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckAckDecimationAfterQuiescence) { EXPECT_FALSE(writer_->stop_waiting_frames().empty()); } EXPECT_FALSE(writer_->ack_frames().empty()); - EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + EXPECT_FALSE(connection_.HasPendingAcks()); // Wait 1 second and enesure the ack alarm is set to 1ms in the future. clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1)); @@ -6454,7 +6506,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckAckDecimationAfterQuiescence) { ProcessDataPacketAtLevel(3, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); // Check if delayed ack timer is running for the expected interval. - EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); + EXPECT_TRUE(connection_.HasPendingAcks()); EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline()); // Process enough packets to get into ack decimation behavior. @@ -6467,7 +6519,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckAckDecimationAfterQuiescence) { EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); ProcessDataPacketAtLevel(4 + i, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); } - EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + EXPECT_FALSE(connection_.HasPendingAcks()); // The same as ProcessPacket(1) except that ENCRYPTION_ZERO_RTT is used // instead of ENCRYPTION_INITIAL. EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); @@ -6475,12 +6527,12 @@ TEST_P(QuicConnectionTest, SendDelayedAckAckDecimationAfterQuiescence) { ENCRYPTION_ZERO_RTT); // Check if delayed ack timer is running for the expected interval. - EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); + EXPECT_TRUE(connection_.HasPendingAcks()); EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline()); // The 10th received packet causes an ack to be sent. for (int i = 0; i < 9; ++i) { - EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); + EXPECT_TRUE(connection_.HasPendingAcks()); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); ProcessDataPacketAtLevel(kFirstDecimatedPacket + 1 + i, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); @@ -6495,7 +6547,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckAckDecimationAfterQuiescence) { EXPECT_FALSE(writer_->stop_waiting_frames().empty()); } EXPECT_FALSE(writer_->ack_frames().empty()); - EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + EXPECT_FALSE(connection_.HasPendingAcks()); // Wait 1 second and enesure the ack alarm is set to 1ms in the future. clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1)); @@ -6505,7 +6557,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckAckDecimationAfterQuiescence) { ENCRYPTION_ZERO_RTT); // Check if delayed ack timer is running for the expected interval. - EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); + EXPECT_TRUE(connection_.HasPendingAcks()); EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline()); } @@ -6529,7 +6581,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationUnlimitedAggregation) { QuicTime ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(kMinRttMs / 4); EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + EXPECT_FALSE(connection_.HasPendingAcks()); const uint8_t tag = 0x07; SetDecrypter(ENCRYPTION_ZERO_RTT, std::make_unique<StrictTaggingDecrypter>(tag)); @@ -6544,7 +6596,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationUnlimitedAggregation) { EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); } - EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + EXPECT_FALSE(connection_.HasPendingAcks()); // The same as ProcessPacket(1) except that ENCRYPTION_ZERO_RTT is used // instead of ENCRYPTION_INITIAL. EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); @@ -6552,19 +6604,19 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationUnlimitedAggregation) { ENCRYPTION_ZERO_RTT); // Check if delayed ack timer is running for the expected interval. - EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); + EXPECT_TRUE(connection_.HasPendingAcks()); EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline()); // 18 packets will not cause an ack to be sent. 19 will because when // stop waiting frames are in use, we ack every 20 packets no matter what. for (int i = 0; i < 18; ++i) { - EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); + EXPECT_TRUE(connection_.HasPendingAcks()); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); ProcessDataPacketAtLevel(kFirstDecimatedPacket + 1 + i, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); } // The delayed ack timer should still be set to the expected deadline. - EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); + EXPECT_TRUE(connection_.HasPendingAcks()); EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline()); } @@ -6582,7 +6634,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationEighthRtt) { QuicTime ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(kMinRttMs / 8); EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + EXPECT_FALSE(connection_.HasPendingAcks()); const uint8_t tag = 0x07; SetDecrypter(ENCRYPTION_ZERO_RTT, std::make_unique<StrictTaggingDecrypter>(tag)); @@ -6597,7 +6649,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationEighthRtt) { EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); } - EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + EXPECT_FALSE(connection_.HasPendingAcks()); // The same as ProcessPacket(1) except that ENCRYPTION_ZERO_RTT is used // instead of ENCRYPTION_INITIAL. EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); @@ -6605,12 +6657,12 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationEighthRtt) { ENCRYPTION_ZERO_RTT); // Check if delayed ack timer is running for the expected interval. - EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); + EXPECT_TRUE(connection_.HasPendingAcks()); EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline()); // The 10th received packet causes an ack to be sent. for (int i = 0; i < 9; ++i) { - EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); + EXPECT_TRUE(connection_.HasPendingAcks()); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); ProcessDataPacketAtLevel(kFirstDecimatedPacket + 1 + i, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); @@ -6625,7 +6677,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationEighthRtt) { EXPECT_FALSE(writer_->stop_waiting_frames().empty()); } EXPECT_FALSE(writer_->ack_frames().empty()); - EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + EXPECT_FALSE(connection_.HasPendingAcks()); } TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithReordering) { @@ -6641,7 +6693,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithReordering) { QuicTime ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(kMinRttMs / 4); EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + EXPECT_FALSE(connection_.HasPendingAcks()); const uint8_t tag = 0x07; SetDecrypter(ENCRYPTION_ZERO_RTT, std::make_unique<StrictTaggingDecrypter>(tag)); @@ -6656,7 +6708,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithReordering) { EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); } - EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + EXPECT_FALSE(connection_.HasPendingAcks()); // Receive one packet out of order and then the rest in order. // The loop leaves a one packet gap between acks sent to simulate some loss. @@ -6666,13 +6718,13 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithReordering) { ProcessDataPacketAtLevel(kFirstDecimatedPacket + 9 + (j * 11), !kHasStopWaiting, ENCRYPTION_ZERO_RTT); ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(5); - EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); + EXPECT_TRUE(connection_.HasPendingAcks()); EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline()); // The 10th received packet causes an ack to be sent. writer_->Reset(); for (int i = 0; i < 9; ++i) { - EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); + EXPECT_TRUE(connection_.HasPendingAcks()); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); // The ACK shouldn't be sent until the 10th packet is processed. EXPECT_TRUE(writer_->ack_frames().empty()); @@ -6689,7 +6741,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithReordering) { EXPECT_FALSE(writer_->stop_waiting_frames().empty()); } EXPECT_FALSE(writer_->ack_frames().empty()); - EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + EXPECT_FALSE(connection_.HasPendingAcks()); } } @@ -6706,7 +6758,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithLargeReordering) { QuicTime ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(kMinRttMs / 4); EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + EXPECT_FALSE(connection_.HasPendingAcks()); const uint8_t tag = 0x07; SetDecrypter(ENCRYPTION_ZERO_RTT, std::make_unique<StrictTaggingDecrypter>(tag)); @@ -6721,7 +6773,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithLargeReordering) { EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); } - EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + EXPECT_FALSE(connection_.HasPendingAcks()); // The same as ProcessPacket(1) except that ENCRYPTION_ZERO_RTT is used // instead of ENCRYPTION_INITIAL. EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); @@ -6729,7 +6781,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithLargeReordering) { ENCRYPTION_ZERO_RTT); // Check if delayed ack timer is running for the expected interval. - EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); + EXPECT_TRUE(connection_.HasPendingAcks()); EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline()); // Process packet 10 first and ensure the alarm is one eighth min_rtt. @@ -6737,12 +6789,12 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithLargeReordering) { ProcessDataPacketAtLevel(kFirstDecimatedPacket + 19, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(5); - EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); + EXPECT_TRUE(connection_.HasPendingAcks()); EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline()); // The 10th received packet causes an ack to be sent. for (int i = 0; i < 8; ++i) { - EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); + EXPECT_TRUE(connection_.HasPendingAcks()); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); ProcessDataPacketAtLevel(kFirstDecimatedPacket + 1 + i, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); @@ -6756,11 +6808,11 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithLargeReordering) { EXPECT_FALSE(writer_->stop_waiting_frames().empty()); } EXPECT_FALSE(writer_->ack_frames().empty()); - EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + EXPECT_FALSE(connection_.HasPendingAcks()); // The next packet received in order will cause an immediate ack, // because it fills a hole. - EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + EXPECT_FALSE(connection_.HasPendingAcks()); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); ProcessDataPacketAtLevel(kFirstDecimatedPacket + 10, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); @@ -6773,7 +6825,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithLargeReordering) { EXPECT_FALSE(writer_->stop_waiting_frames().empty()); } EXPECT_FALSE(writer_->ack_frames().empty()); - EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + EXPECT_FALSE(connection_.HasPendingAcks()); } TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithReorderingEighthRtt) { @@ -6790,7 +6842,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithReorderingEighthRtt) { QuicTime ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(kMinRttMs / 8); EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + EXPECT_FALSE(connection_.HasPendingAcks()); const uint8_t tag = 0x07; SetDecrypter(ENCRYPTION_ZERO_RTT, std::make_unique<StrictTaggingDecrypter>(tag)); @@ -6805,7 +6857,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithReorderingEighthRtt) { EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); } - EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + EXPECT_FALSE(connection_.HasPendingAcks()); // The same as ProcessPacket(1) except that ENCRYPTION_ZERO_RTT is used // instead of ENCRYPTION_INITIAL. EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); @@ -6813,7 +6865,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithReorderingEighthRtt) { ENCRYPTION_ZERO_RTT); // Check if delayed ack timer is running for the expected interval. - EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); + EXPECT_TRUE(connection_.HasPendingAcks()); EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline()); // Process packet 10 first and ensure the alarm is one eighth min_rtt. @@ -6821,12 +6873,12 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithReorderingEighthRtt) { ProcessDataPacketAtLevel(kFirstDecimatedPacket + 9, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(5); - EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); + EXPECT_TRUE(connection_.HasPendingAcks()); EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline()); // The 10th received packet causes an ack to be sent. for (int i = 0; i < 8; ++i) { - EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); + EXPECT_TRUE(connection_.HasPendingAcks()); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); ProcessDataPacketAtLevel(kFirstDecimatedPacket + 1 + i, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); @@ -6841,7 +6893,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithReorderingEighthRtt) { EXPECT_FALSE(writer_->stop_waiting_frames().empty()); } EXPECT_FALSE(writer_->ack_frames().empty()); - EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + EXPECT_FALSE(connection_.HasPendingAcks()); } TEST_P(QuicConnectionTest, @@ -6859,7 +6911,7 @@ TEST_P(QuicConnectionTest, QuicTime ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(kMinRttMs / 8); EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + EXPECT_FALSE(connection_.HasPendingAcks()); const uint8_t tag = 0x07; SetDecrypter(ENCRYPTION_ZERO_RTT, std::make_unique<StrictTaggingDecrypter>(tag)); @@ -6874,7 +6926,7 @@ TEST_P(QuicConnectionTest, EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); } - EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + EXPECT_FALSE(connection_.HasPendingAcks()); // The same as ProcessPacket(1) except that ENCRYPTION_ZERO_RTT is used // instead of ENCRYPTION_INITIAL. EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); @@ -6882,7 +6934,7 @@ TEST_P(QuicConnectionTest, ENCRYPTION_ZERO_RTT); // Check if delayed ack timer is running for the expected interval. - EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); + EXPECT_TRUE(connection_.HasPendingAcks()); EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline()); // Process packet 10 first and ensure the alarm is one eighth min_rtt. @@ -6890,12 +6942,12 @@ TEST_P(QuicConnectionTest, ProcessDataPacketAtLevel(kFirstDecimatedPacket + 19, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(5); - EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); + EXPECT_TRUE(connection_.HasPendingAcks()); EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline()); // The 10th received packet causes an ack to be sent. for (int i = 0; i < 8; ++i) { - EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); + EXPECT_TRUE(connection_.HasPendingAcks()); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); ProcessDataPacketAtLevel(kFirstDecimatedPacket + 1 + i, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); @@ -6909,11 +6961,11 @@ TEST_P(QuicConnectionTest, EXPECT_FALSE(writer_->stop_waiting_frames().empty()); } EXPECT_FALSE(writer_->ack_frames().empty()); - EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + EXPECT_FALSE(connection_.HasPendingAcks()); // The next packet received in order will cause an immediate ack, // because it fills a hole. - EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + EXPECT_FALSE(connection_.HasPendingAcks()); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); ProcessDataPacketAtLevel(kFirstDecimatedPacket + 10, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); @@ -6926,27 +6978,27 @@ TEST_P(QuicConnectionTest, EXPECT_FALSE(writer_->stop_waiting_frames().empty()); } EXPECT_FALSE(writer_->ack_frames().empty()); - EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + EXPECT_FALSE(connection_.HasPendingAcks()); } TEST_P(QuicConnectionTest, SendDelayedAckOnHandshakeConfirmed) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); ProcessPacket(1); // Check that ack is sent and that delayed ack alarm is set. - EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); + EXPECT_TRUE(connection_.HasPendingAcks()); QuicTime ack_time = clock_.ApproximateNow() + DefaultDelayedAckTime(); EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline()); // Completing the handshake as the server does nothing. QuicConnectionPeer::SetPerspective(&connection_, Perspective::IS_SERVER); connection_.OnHandshakeComplete(); - EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); + EXPECT_TRUE(connection_.HasPendingAcks()); EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline()); // Complete the handshake as the client decreases the delayed ack time to 0ms. QuicConnectionPeer::SetPerspective(&connection_, Perspective::IS_CLIENT); connection_.OnHandshakeComplete(); - EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); + EXPECT_TRUE(connection_.HasPendingAcks()); if (connection_.SupportsMultiplePacketNumberSpaces()) { EXPECT_EQ(clock_.ApproximateNow() + DefaultDelayedAckTime(), connection_.GetAckAlarm()->deadline()); @@ -6969,7 +7021,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckOnSecondPacket) { EXPECT_FALSE(writer_->stop_waiting_frames().empty()); } EXPECT_FALSE(writer_->ack_frames().empty()); - EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + EXPECT_FALSE(connection_.HasPendingAcks()); } TEST_P(QuicConnectionTest, NoAckOnOldNacks) { @@ -7001,7 +7053,7 @@ TEST_P(QuicConnectionTest, NoAckOnOldNacks) { ProcessPacket(6); padding_frame_count = writer_->padding_frames().size(); EXPECT_EQ(padding_frame_count, writer_->frame_count()); - EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); + EXPECT_TRUE(connection_.HasPendingAcks()); } TEST_P(QuicConnectionTest, SendDelayedAckOnOutgoingPacket) { @@ -7025,7 +7077,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckOnOutgoingPacket) { EXPECT_FALSE(writer_->stop_waiting_frames().empty()); } EXPECT_FALSE(writer_->ack_frames().empty()); - EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + EXPECT_FALSE(connection_.HasPendingAcks()); } TEST_P(QuicConnectionTest, SendDelayedAckOnOutgoingCryptoPacket) { @@ -7045,7 +7097,7 @@ TEST_P(QuicConnectionTest, SendDelayedAckOnOutgoingCryptoPacket) { EXPECT_EQ(4u, writer_->frame_count()); EXPECT_FALSE(writer_->stop_waiting_frames().empty()); } - EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + EXPECT_FALSE(connection_.HasPendingAcks()); } TEST_P(QuicConnectionTest, BlockAndBufferOnFirstCHLOPacketOfTwo) { @@ -7053,17 +7105,29 @@ TEST_P(QuicConnectionTest, BlockAndBufferOnFirstCHLOPacketOfTwo) { ProcessPacket(1); BlockOnNextWrite(); writer_->set_is_write_blocked_data_buffered(true); + if (GetQuicReloadableFlag(quic_move_amplification_limit) && + QuicVersionUsesCryptoFrames(connection_.transport_version())) { + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); + } else { + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2); + } connection_.SendCryptoDataWithString("foo", 0); EXPECT_TRUE(writer_->IsWriteBlocked()); EXPECT_FALSE(connection_.HasQueuedData()); connection_.SendCryptoDataWithString("bar", 3); EXPECT_TRUE(writer_->IsWriteBlocked()); - EXPECT_TRUE(connection_.HasQueuedData()); + if (GetQuicReloadableFlag(quic_move_amplification_limit) && + QuicVersionUsesCryptoFrames(connection_.transport_version())) { + // CRYPTO frames are not flushed when writer is blocked. + EXPECT_FALSE(connection_.HasQueuedData()); + } else { + EXPECT_TRUE(connection_.HasQueuedData()); + } } TEST_P(QuicConnectionTest, BundleAckForSecondCHLO) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + EXPECT_FALSE(connection_.HasPendingAcks()); EXPECT_CALL(visitor_, OnCanWrite()) .WillOnce(IgnoreResult(InvokeWithoutArgs( &connection_, &TestConnection::SendCryptoStreamData))); @@ -7092,12 +7156,12 @@ TEST_P(QuicConnectionTest, BundleAckForSecondCHLO) { EXPECT_EQ(1u, writer_->padding_frames().size()); ASSERT_FALSE(writer_->ack_frames().empty()); EXPECT_EQ(QuicPacketNumber(2u), LargestAcked(writer_->ack_frames().front())); - EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + EXPECT_FALSE(connection_.HasPendingAcks()); } TEST_P(QuicConnectionTest, BundleAckForSecondCHLOTwoPacketReject) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + EXPECT_FALSE(connection_.HasPendingAcks()); // Process two packets from the crypto stream, which is frame1_'s default, // simulating a 2 packet reject. @@ -7136,7 +7200,7 @@ TEST_P(QuicConnectionTest, BundleAckForSecondCHLOTwoPacketReject) { EXPECT_EQ(1u, writer_->padding_frames().size()); ASSERT_FALSE(writer_->ack_frames().empty()); EXPECT_EQ(QuicPacketNumber(2u), LargestAcked(writer_->ack_frames().front())); - EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + EXPECT_FALSE(connection_.HasPendingAcks()); } TEST_P(QuicConnectionTest, BundleAckWithDataOnIncomingAck) { @@ -7171,7 +7235,7 @@ TEST_P(QuicConnectionTest, BundleAckWithDataOnIncomingAck) { // Check that no packet is sent and the ack alarm isn't set. EXPECT_EQ(0u, writer_->frame_count()); - EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + EXPECT_FALSE(connection_.HasPendingAcks()); writer_->Reset(); // Send the same ack, but send both data and an ack together. @@ -7199,7 +7263,7 @@ TEST_P(QuicConnectionTest, BundleAckWithDataOnIncomingAck) { LargestAcked(writer_->ack_frames().front())); } EXPECT_EQ(1u, writer_->stream_frames().size()); - EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + EXPECT_FALSE(connection_.HasPendingAcks()); } TEST_P(QuicConnectionTest, NoAckSentForClose) { @@ -7221,7 +7285,7 @@ TEST_P(QuicConnectionTest, SendWhenDisconnected) { connection_.CloseConnection(QUIC_PEER_GOING_AWAY, "no reason", ConnectionCloseBehavior::SILENT_CLOSE); EXPECT_FALSE(connection_.connected()); - EXPECT_FALSE(connection_.CanWriteStreamData()); + EXPECT_FALSE(connection_.CanWrite(HAS_RETRANSMITTABLE_DATA)); std::unique_ptr<QuicPacket> packet = ConstructDataPacket(1, !kHasStopWaiting, ENCRYPTION_INITIAL); EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(1), _, _)) @@ -7245,7 +7309,7 @@ TEST_P(QuicConnectionTest, SendConnectivityProbingWhenDisconnected) { connection_.CloseConnection(QUIC_PEER_GOING_AWAY, "no reason", ConnectionCloseBehavior::SILENT_CLOSE); EXPECT_FALSE(connection_.connected()); - EXPECT_FALSE(connection_.CanWriteStreamData()); + EXPECT_FALSE(connection_.CanWrite(HAS_RETRANSMITTABLE_DATA)); EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(1), _, _)) .Times(0); @@ -7260,7 +7324,7 @@ TEST_P(QuicConnectionTest, SendConnectivityProbingWhenDisconnected) { } TEST_P(QuicConnectionTest, WriteBlockedAfterClientSendsConnectivityProbe) { - EXPECT_EQ(Perspective::IS_CLIENT, connection_.perspective()); + PathProbeTestInit(Perspective::IS_CLIENT); TestPacketWriter probing_writer(version(), &clock_); // Block next write so that sending connectivity probe will encounter a // blocked write when send a connectivity probe to the peer. @@ -7276,8 +7340,7 @@ TEST_P(QuicConnectionTest, WriteBlockedAfterClientSendsConnectivityProbe) { } TEST_P(QuicConnectionTest, WriterBlockedAfterServerSendsConnectivityProbe) { - set_perspective(Perspective::IS_SERVER); - QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false); + PathProbeTestInit(Perspective::IS_SERVER); // Block next write so that sending connectivity probe will encounter a // blocked write when send a connectivity probe to the peer. @@ -7293,7 +7356,7 @@ TEST_P(QuicConnectionTest, WriterBlockedAfterServerSendsConnectivityProbe) { } TEST_P(QuicConnectionTest, WriterErrorWhenClientSendsConnectivityProbe) { - EXPECT_EQ(Perspective::IS_CLIENT, connection_.perspective()); + PathProbeTestInit(Perspective::IS_CLIENT); TestPacketWriter probing_writer(version(), &clock_); probing_writer.SetShouldWriteFail(); @@ -7308,8 +7371,7 @@ TEST_P(QuicConnectionTest, WriterErrorWhenClientSendsConnectivityProbe) { } TEST_P(QuicConnectionTest, WriterErrorWhenServerSendsConnectivityProbe) { - set_perspective(Perspective::IS_SERVER); - QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false); + PathProbeTestInit(Perspective::IS_SERVER); writer_->SetShouldWriteFail(); // Connection should not be closed if a connectivity probe is failed to be @@ -7356,6 +7418,7 @@ TEST_P(QuicConnectionTest, IetfStatelessReset) { kTestStatelessResetToken)); std::unique_ptr<QuicReceivedPacket> received( ConstructReceivedPacket(*packet, QuicTime::Zero())); + EXPECT_CALL(visitor_, ValidateStatelessReset(_, _)).WillOnce(Return(true)); EXPECT_CALL(visitor_, OnConnectionClosed(_, ConnectionCloseSource::FROM_PEER)) .WillOnce(Invoke(this, &QuicConnectionTest::SaveConnectionCloseFrame)); connection_.ProcessUdpPacket(kSelfAddress, kPeerAddress, *received); @@ -7629,6 +7692,7 @@ TEST_P(QuicConnectionTest, ConnectionCloseWhenWriteBlocked) { } TEST_P(QuicConnectionTest, OnPacketSentDebugVisitor) { + PathProbeTestInit(Perspective::IS_CLIENT); MockQuicConnectionDebugVisitor debug_visitor; connection_.set_debug_visitor(&debug_visitor); @@ -7681,8 +7745,7 @@ TEST_P(QuicConnectionTest, WindowUpdateInstigateAcks) { ProcessFramePacket(QuicFrame(window_update)); // Ensure that this has caused the ACK alarm to be set. - QuicAlarm* ack_alarm = QuicConnectionPeer::GetAckAlarm(&connection_); - EXPECT_TRUE(ack_alarm->IsSet()); + EXPECT_TRUE(connection_.HasPendingAcks()); } TEST_P(QuicConnectionTest, BlockedFrameInstigateAcks) { @@ -7695,8 +7758,7 @@ TEST_P(QuicConnectionTest, BlockedFrameInstigateAcks) { ProcessFramePacket(QuicFrame(blocked)); // Ensure that this has caused the ACK alarm to be set. - QuicAlarm* ack_alarm = QuicConnectionPeer::GetAckAlarm(&connection_); - EXPECT_TRUE(ack_alarm->IsSet()); + EXPECT_TRUE(connection_.HasPendingAcks()); } TEST_P(QuicConnectionTest, ReevaluateTimeUntilSendOnAck) { @@ -7838,32 +7900,8 @@ TEST_P(QuicConnectionTest, SetRetransmissionAlarmForCryptoPacket) { connection_.GetRetransmissionAlarm()->Fire(); } -TEST_P(QuicConnectionTest, PathDegradingAlarmForCryptoPacket) { - EXPECT_TRUE(connection_.connected()); - EXPECT_FALSE(connection_.PathDegradingDetectionInProgress()); - EXPECT_FALSE(connection_.IsPathDegrading()); - - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); - connection_.SendCryptoStreamData(); - - EXPECT_TRUE(connection_.PathDegradingDetectionInProgress()); - EXPECT_FALSE(connection_.IsPathDegrading()); - QuicTime::Delta delay = QuicConnectionPeer::GetSentPacketManager(&connection_) - ->GetPathDegradingDelay(); - EXPECT_EQ(delay, connection_.GetBlackholeDetectorAlarm()->deadline() - - clock_.ApproximateNow()); - - // Fire the path degrading alarm, path degrading signal should be sent to - // the visitor. - EXPECT_CALL(visitor_, OnPathDegrading()); - clock_.AdvanceTime(delay); - connection_.PathDegradingTimeout(); - EXPECT_TRUE(connection_.IsPathDegrading()); - EXPECT_FALSE(connection_.PathDegradingDetectionInProgress()); -} - // Includes regression test for b/69979024. -TEST_P(QuicConnectionTest, PathDegradingAlarmForNonCryptoPackets) { +TEST_P(QuicConnectionTest, PathDegradingDetectionForNonCryptoPackets) { EXPECT_TRUE(connection_.connected()); EXPECT_FALSE(connection_.PathDegradingDetectionInProgress()); EXPECT_FALSE(connection_.IsPathDegrading()); @@ -7874,21 +7912,21 @@ TEST_P(QuicConnectionTest, PathDegradingAlarmForNonCryptoPackets) { for (int i = 0; i < 2; ++i) { // Send a packet. Now there's a retransmittable packet on the wire, so the - // path degrading alarm should be set. + // path degrading detection should be set. connection_.SendStreamDataWithString( GetNthClientInitiatedStreamId(1, connection_.transport_version()), data, offset, NO_FIN); offset += data_size; EXPECT_TRUE(connection_.PathDegradingDetectionInProgress()); - // Check the deadline of the path degrading alarm. + // Check the deadline of the path degrading detection. QuicTime::Delta delay = QuicConnectionPeer::GetSentPacketManager(&connection_) ->GetPathDegradingDelay(); EXPECT_EQ(delay, connection_.GetBlackholeDetectorAlarm()->deadline() - clock_.ApproximateNow()); - // Send a second packet. The path degrading alarm's deadline should remain - // the same. + // Send a second packet. The path degrading detection's deadline should + // remain the same. // Regression test for b/69979024. clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); QuicTime prev_deadline = @@ -7902,7 +7940,7 @@ TEST_P(QuicConnectionTest, PathDegradingAlarmForNonCryptoPackets) { connection_.GetBlackholeDetectorAlarm()->deadline()); // Now receive an ACK of the first packet. This should advance the path - // degrading alarm's deadline since forward progress has been made. + // degrading detection's deadline since forward progress has been made. clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); if (i == 0) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); @@ -7912,7 +7950,7 @@ TEST_P(QuicConnectionTest, PathDegradingAlarmForNonCryptoPackets) { {{QuicPacketNumber(1u + 2u * i), QuicPacketNumber(2u + 2u * i)}}); ProcessAckPacket(&frame); EXPECT_TRUE(connection_.PathDegradingDetectionInProgress()); - // Check the deadline of the path degrading alarm. + // Check the deadline of the path degrading detection. delay = QuicConnectionPeer::GetSentPacketManager(&connection_) ->GetPathDegradingDelay(); EXPECT_EQ(delay, connection_.GetBlackholeDetectorAlarm()->deadline() - @@ -7921,7 +7959,7 @@ TEST_P(QuicConnectionTest, PathDegradingAlarmForNonCryptoPackets) { if (i == 0) { // Now receive an ACK of the second packet. Since there are no more // retransmittable packets on the wire, this should cancel the path - // degrading alarm. + // degrading detection. clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _)); frame = InitAckFrame({{QuicPacketNumber(2), QuicPacketNumber(3)}}); @@ -8010,7 +8048,7 @@ TEST_P(QuicConnectionTest, RetransmittableOnWireSetsPingAlarm) { // This test verifies that the connection marks path as degrading and does not // spin timer to detect path degrading when a new packet is sent on the // degraded path. -TEST_P(QuicConnectionTest, NoPathDegradingAlarmIfPathIsDegrading) { +TEST_P(QuicConnectionTest, NoPathDegradingDetectionIfPathIsDegrading) { EXPECT_TRUE(connection_.connected()); EXPECT_FALSE(connection_.PathDegradingDetectionInProgress()); EXPECT_FALSE(connection_.IsPathDegrading()); @@ -8024,13 +8062,13 @@ TEST_P(QuicConnectionTest, NoPathDegradingAlarmIfPathIsDegrading) { connection_.SendStreamDataWithString(1, data, offset, NO_FIN); offset += data_size; EXPECT_TRUE(connection_.PathDegradingDetectionInProgress()); - // Check the deadline of the path degrading alarm. + // Check the deadline of the path degrading detection. QuicTime::Delta delay = QuicConnectionPeer::GetSentPacketManager(&connection_) ->GetPathDegradingDelay(); EXPECT_EQ(delay, connection_.GetBlackholeDetectorAlarm()->deadline() - clock_.ApproximateNow()); - // Send a second packet. The path degrading alarm's deadline should remain + // Send a second packet. The path degrading detection's deadline should remain // the same. clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); QuicTime prev_deadline = connection_.GetBlackholeDetectorAlarm()->deadline(); @@ -8040,7 +8078,7 @@ TEST_P(QuicConnectionTest, NoPathDegradingAlarmIfPathIsDegrading) { EXPECT_EQ(prev_deadline, connection_.GetBlackholeDetectorAlarm()->deadline()); // Now receive an ACK of the first packet. This should advance the path - // degrading alarm's deadline since forward progress has been made. + // degrading detection's deadline since forward progress has been made. clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _)); @@ -8054,8 +8092,8 @@ TEST_P(QuicConnectionTest, NoPathDegradingAlarmIfPathIsDegrading) { EXPECT_EQ(delay, connection_.GetBlackholeDetectorAlarm()->deadline() - clock_.ApproximateNow()); - // Advance time to the path degrading alarm's deadline and simulate - // firing the path degrading alarm. This path will be considered as + // Advance time to the path degrading detection's deadline and simulate + // firing the path degrading detection. This path will be considered as // degrading. clock_.AdvanceTime(delay); EXPECT_CALL(visitor_, OnPathDegrading()).Times(1); @@ -8065,7 +8103,7 @@ TEST_P(QuicConnectionTest, NoPathDegradingAlarmIfPathIsDegrading) { clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); EXPECT_FALSE(connection_.PathDegradingDetectionInProgress()); - // Send a third packet. The path degrading alarm is no longer set but path + // Send a third packet. The path degrading detection is no longer set but path // should still be marked as degrading. connection_.SendStreamDataWithString(1, data, offset, NO_FIN); offset += data_size; @@ -8141,6 +8179,7 @@ TEST_P(QuicConnectionTest, UnmarkPathDegradingOnForwardProgress) { // degrading. And will set a timer to detect new path degrading. clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _)); + EXPECT_CALL(visitor_, OnForwardProgressMadeAfterPathDegrading()).Times(1); frame = InitAckFrame({{QuicPacketNumber(2), QuicPacketNumber(3)}}); ProcessAckPacket(&frame); EXPECT_FALSE(connection_.IsPathDegrading()); @@ -8382,8 +8421,7 @@ TEST_P(QuicConnectionTest, DoNotForceSendingAckOnPacketTooLarge) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); // Send an ack by simulating delayed ack alarm firing. ProcessPacket(1); - QuicAlarm* ack_alarm = QuicConnectionPeer::GetAckAlarm(&connection_); - EXPECT_TRUE(ack_alarm->IsSet()); + EXPECT_TRUE(connection_.HasPendingAcks()); connection_.GetAckAlarm()->Fire(); // Simulate data packet causes write error. EXPECT_CALL(visitor_, OnConnectionClosed(_, _)); @@ -8973,45 +9011,6 @@ TEST_P(QuicConnectionTest, ResetBackOffRetransmitableOnWireTimeout) { connection_.GetPingAlarm()->deadline() - clock_.ApproximateNow()); } -TEST_P(QuicConnectionTest, OnForwardProgressConfirmed) { - EXPECT_CALL(visitor_, OnForwardProgressConfirmed()).Times(Exactly(0)); - EXPECT_TRUE(connection_.connected()); - - const char data[] = "data"; - size_t data_size = strlen(data); - QuicStreamOffset offset = 0; - - // Send two packets. - connection_.SendStreamDataWithString(1, data, offset, NO_FIN); - offset += data_size; - connection_.SendStreamDataWithString(1, data, offset, NO_FIN); - offset += data_size; - - // Ack packet 1. This increases the largest_acked to 1, so - // OnForwardProgressConfirmed() should be called - clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); - EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _)); - EXPECT_CALL(visitor_, OnForwardProgressConfirmed()); - QuicAckFrame frame = - InitAckFrame({{QuicPacketNumber(1), QuicPacketNumber(2)}}); - ProcessAckPacket(&frame); - - // Ack packet 1 again. largest_acked remains at 1, so - // OnForwardProgressConfirmed() should not be called. - clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); - frame = InitAckFrame({{QuicPacketNumber(1), QuicPacketNumber(2)}}); - ProcessAckPacket(&frame); - - // Ack packet 2. This increases the largest_acked to 2, so - // OnForwardProgressConfirmed() should be called. - clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); - EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _)); - EXPECT_CALL(visitor_, OnForwardProgressConfirmed()); - frame = InitAckFrame({{QuicPacketNumber(2), QuicPacketNumber(3)}}); - ProcessAckPacket(&frame); -} - TEST_P(QuicConnectionTest, ValidStatelessResetToken) { const QuicUint128 kTestToken = 1010101; const QuicUint128 kWrongTestToken = 1010100; @@ -9231,6 +9230,102 @@ TEST_P(QuicConnectionTest, PathChallengeResponse) { sizeof(challenge_data))); } +TEST_P(QuicConnectionTest, + RestartPathDegradingDetectionAfterMigrationWithProbe) { + // TODO(b/150095484): add test coverage for IETF to verify that client takes + // PATH RESPONSE with peer address change as correct validation on the new + // path. + if (GetParam().version.HasIetfQuicFrames()) { + return; + } + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); + PathProbeTestInit(Perspective::IS_CLIENT); + + // Clear direct_peer_address and effective_peer_address. + QuicConnectionPeer::SetDirectPeerAddress(&connection_, QuicSocketAddress()); + QuicConnectionPeer::SetEffectivePeerAddress(&connection_, + QuicSocketAddress()); + EXPECT_FALSE(connection_.effective_peer_address().IsInitialized()); + + EXPECT_TRUE(connection_.connected()); + EXPECT_CALL(visitor_, ShouldKeepConnectionAlive()) + .WillRepeatedly(Return(true)); + EXPECT_FALSE(connection_.PathDegradingDetectionInProgress()); + EXPECT_FALSE(connection_.IsPathDegrading()); + EXPECT_FALSE(connection_.GetPingAlarm()->IsSet()); + + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber()); + } else { + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); + } + ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress, + kPeerAddress); + EXPECT_EQ(kPeerAddress, connection_.peer_address()); + EXPECT_EQ(kPeerAddress, connection_.effective_peer_address()); + + // Send data and verify the path degrading detection is set. + const char data[] = "data"; + size_t data_size = strlen(data); + QuicStreamOffset offset = 0; + connection_.SendStreamDataWithString(1, data, offset, NO_FIN); + offset += data_size; + + // Verify the path degrading detection is in progress. + EXPECT_TRUE(connection_.PathDegradingDetectionInProgress()); + EXPECT_FALSE(connection_.IsPathDegrading()); + QuicTime ddl = connection_.GetBlackholeDetectorAlarm()->deadline(); + + // Simulate the firing of path degrading. + clock_.AdvanceTime(ddl - clock_.ApproximateNow()); + EXPECT_CALL(visitor_, OnPathDegrading()).Times(1); + connection_.PathDegradingTimeout(); + EXPECT_TRUE(connection_.IsPathDegrading()); + EXPECT_FALSE(connection_.PathDegradingDetectionInProgress()); + + // Simulate path degrading handling by sending a probe on an alternet path. + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); + TestPacketWriter probing_writer(version(), &clock_); + connection_.SendConnectivityProbingPacket(&probing_writer, + connection_.peer_address()); + // Verify that path degrading detection is not reset. + EXPECT_FALSE(connection_.PathDegradingDetectionInProgress()); + + // Simulate successful path degrading handling by receiving probe response. + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(20)); + + if (!GetParam().version.HasIetfQuicFrames()) { + EXPECT_CALL(visitor_, + OnPacketReceived(_, _, /*is_connectivity_probe=*/true)) + .Times(1); + } else { + EXPECT_CALL(visitor_, OnPacketReceived(_, _, _)).Times(0); + } + const QuicSocketAddress kNewSelfAddress = + QuicSocketAddress(QuicIpAddress::Loopback6(), /*port=*/23456); + + std::unique_ptr<SerializedPacket> probing_packet = ConstructProbingPacket(); + std::unique_ptr<QuicReceivedPacket> received(ConstructReceivedPacket( + QuicEncryptedPacket(probing_packet->encrypted_buffer, + probing_packet->encrypted_length), + clock_.Now())); + uint64_t num_probing_received = + connection_.GetStats().num_connectivity_probing_received; + ProcessReceivedPacket(kNewSelfAddress, kPeerAddress, *received); + + EXPECT_EQ(num_probing_received + 1, + connection_.GetStats().num_connectivity_probing_received); + EXPECT_EQ(kPeerAddress, connection_.peer_address()); + EXPECT_EQ(kPeerAddress, connection_.effective_peer_address()); + EXPECT_TRUE(connection_.IsPathDegrading()); + + // Verify new path degrading detection is activated. + EXPECT_CALL(visitor_, OnForwardProgressMadeAfterPathDegrading()).Times(1); + connection_.OnSuccessfulMigrationAfterProbing(); + EXPECT_FALSE(connection_.IsPathDegrading()); + EXPECT_TRUE(connection_.PathDegradingDetectionInProgress()); +} + // Regression test for b/110259444 TEST_P(QuicConnectionTest, DoNotScheduleSpuriousAckAlarm) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); @@ -9238,9 +9333,8 @@ TEST_P(QuicConnectionTest, DoNotScheduleSpuriousAckAlarm) { writer_->SetWriteBlocked(); ProcessPacket(1); - QuicAlarm* ack_alarm = QuicConnectionPeer::GetAckAlarm(&connection_); // Verify ack alarm is set. - EXPECT_TRUE(ack_alarm->IsSet()); + EXPECT_TRUE(connection_.HasPendingAcks()); // Fire the ack alarm, verify no packet is sent because the writer is blocked. EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0); connection_.GetAckAlarm()->Fire(); @@ -9249,7 +9343,7 @@ TEST_P(QuicConnectionTest, DoNotScheduleSpuriousAckAlarm) { EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); ProcessPacket(2); // Verify ack alarm is not set. - EXPECT_FALSE(ack_alarm->IsSet()); + EXPECT_FALSE(connection_.HasPendingAcks()); } TEST_P(QuicConnectionTest, DisablePacingOffloadConnectionOptions) { @@ -9428,7 +9522,7 @@ TEST_P(QuicConnectionTest, MultiplePacketNumberSpacesBasicReceiving) { use_tagging_decrypter(); // Receives packet 1000 in initial data. ProcessCryptoPacketAtLevel(1000, ENCRYPTION_INITIAL); - EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); + EXPECT_TRUE(connection_.HasPendingAcks()); peer_framer_.SetEncrypter(ENCRYPTION_ZERO_RTT, std::make_unique<TaggingEncrypter>(0x02)); SetDecrypter(ENCRYPTION_ZERO_RTT, @@ -9437,13 +9531,13 @@ TEST_P(QuicConnectionTest, MultiplePacketNumberSpacesBasicReceiving) { std::make_unique<TaggingEncrypter>(0x02)); // Receives packet 1000 in application data. ProcessDataPacketAtLevel(1000, false, ENCRYPTION_ZERO_RTT); - EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); + EXPECT_TRUE(connection_.HasPendingAcks()); connection_.SendApplicationDataAtLevel(ENCRYPTION_ZERO_RTT, 5, "data", 0, NO_FIN); // Verify application data ACK gets bundled with outgoing data. EXPECT_EQ(2u, writer_->frame_count()); // Make sure ACK alarm is still set because initial data is not ACKed. - EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); + EXPECT_TRUE(connection_.HasPendingAcks()); // Receive packet 1001 in application data. ProcessDataPacketAtLevel(1001, false, ENCRYPTION_ZERO_RTT); clock_.AdvanceTime(DefaultRetransmissionTime()); @@ -9452,10 +9546,10 @@ TEST_P(QuicConnectionTest, MultiplePacketNumberSpacesBasicReceiving) { connection_.SetEncrypter(ENCRYPTION_FORWARD_SECURE, std::make_unique<TaggingEncrypter>(0x02)); connection_.GetAckAlarm()->Fire(); - EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + EXPECT_FALSE(connection_.HasPendingAcks()); // Receives more packets in application data. ProcessDataPacketAtLevel(1002, false, ENCRYPTION_ZERO_RTT); - EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); + EXPECT_TRUE(connection_.HasPendingAcks()); peer_framer_.SetEncrypter(ENCRYPTION_FORWARD_SECURE, std::make_unique<TaggingEncrypter>(0x02)); @@ -9464,7 +9558,7 @@ TEST_P(QuicConnectionTest, MultiplePacketNumberSpacesBasicReceiving) { // Verify zero rtt and forward secure packets get acked in the same packet. EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); ProcessDataPacket(1003); - EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + EXPECT_FALSE(connection_.HasPendingAcks()); } TEST_P(QuicConnectionTest, CancelAckAlarmOnWriteBlocked) { @@ -9479,7 +9573,7 @@ TEST_P(QuicConnectionTest, CancelAckAlarmOnWriteBlocked) { use_tagging_decrypter(); // Receives packet 1000 in initial data. ProcessCryptoPacketAtLevel(1000, ENCRYPTION_INITIAL); - EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); + EXPECT_TRUE(connection_.HasPendingAcks()); peer_framer_.SetEncrypter(ENCRYPTION_ZERO_RTT, std::make_unique<TaggingEncrypter>(0x02)); SetDecrypter(ENCRYPTION_ZERO_RTT, @@ -9488,7 +9582,7 @@ TEST_P(QuicConnectionTest, CancelAckAlarmOnWriteBlocked) { std::make_unique<TaggingEncrypter>(0x02)); // Receives packet 1000 in application data. ProcessDataPacketAtLevel(1000, false, ENCRYPTION_ZERO_RTT); - EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); + EXPECT_TRUE(connection_.HasPendingAcks()); writer_->SetWriteBlocked(); EXPECT_CALL(visitor_, OnWriteBlocked()).Times(AnyNumber()); @@ -9500,13 +9594,13 @@ TEST_P(QuicConnectionTest, CancelAckAlarmOnWriteBlocked) { std::make_unique<TaggingEncrypter>(0x02)); connection_.GetAckAlarm()->Fire(); // Verify ACK alarm is not set. - EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + EXPECT_FALSE(connection_.HasPendingAcks()); writer_->SetWritable(); // Verify 2 ACKs are sent when connection gets unblocked. EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2); connection_.OnCanWrite(); - EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + EXPECT_FALSE(connection_.HasPendingAcks()); } // Make sure a packet received with the right client connection ID is processed. @@ -9618,12 +9712,11 @@ TEST_P(QuicConnectionTest, CheckConnectedBeforeFlush) { } ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress, kPeerAddress); - QuicAlarm* ack_alarm = QuicConnectionPeer::GetAckAlarm(&connection_); - EXPECT_TRUE(ack_alarm->IsSet()); + EXPECT_TRUE(connection_.HasPendingAcks()); ProcessFramePacketWithAddresses(QuicFrame(connection_close_frame.release()), kSelfAddress, kPeerAddress); // Verify ack alarm is not set. - EXPECT_FALSE(ack_alarm->IsSet()); + EXPECT_FALSE(connection_.HasPendingAcks()); } // Verify that a packet containing three coalesced packets is parsed correctly. @@ -9861,8 +9954,18 @@ TEST_P(QuicConnectionTest, CloseConnectionAfter6ClientPTOs) { connection_options.push_back(k6PTO); config.SetConnectionOptionsToSend(connection_options); QuicConfigPeer::SetNegotiated(&config, true); + if (connection_.version().AuthenticatesHandshakeConnectionIds()) { + QuicConfigPeer::SetReceivedOriginalConnectionId( + &config, connection_.connection_id()); + QuicConfigPeer::SetReceivedInitialSourceConnectionId( + &config, connection_.connection_id()); + } EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); connection_.SetFromConfig(config); + if (GetQuicReloadableFlag(quic_default_enable_5rto_blackhole_detection2)) { + EXPECT_CALL(visitor_, GetHandshakeState()) + .WillRepeatedly(Return(HANDSHAKE_COMPLETE)); + } EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet()); // Send stream data. @@ -9902,8 +10005,18 @@ TEST_P(QuicConnectionTest, CloseConnectionAfter7ClientPTOs) { connection_options.push_back(k7PTO); config.SetConnectionOptionsToSend(connection_options); QuicConfigPeer::SetNegotiated(&config, true); + if (connection_.version().AuthenticatesHandshakeConnectionIds()) { + QuicConfigPeer::SetReceivedOriginalConnectionId( + &config, connection_.connection_id()); + QuicConfigPeer::SetReceivedInitialSourceConnectionId( + &config, connection_.connection_id()); + } EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); connection_.SetFromConfig(config); + if (GetQuicReloadableFlag(quic_default_enable_5rto_blackhole_detection2)) { + EXPECT_CALL(visitor_, GetHandshakeState()) + .WillRepeatedly(Return(HANDSHAKE_COMPLETE)); + } EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet()); // Send stream data. @@ -9941,9 +10054,19 @@ TEST_P(QuicConnectionTest, CloseConnectionAfter8ClientPTOs) { connection_options.push_back(k2PTO); connection_options.push_back(k8PTO); QuicConfigPeer::SetNegotiated(&config, true); + if (connection_.version().AuthenticatesHandshakeConnectionIds()) { + QuicConfigPeer::SetReceivedOriginalConnectionId( + &config, connection_.connection_id()); + QuicConfigPeer::SetReceivedInitialSourceConnectionId( + &config, connection_.connection_id()); + } config.SetConnectionOptionsToSend(connection_options); EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); connection_.SetFromConfig(config); + if (GetQuicReloadableFlag(quic_default_enable_5rto_blackhole_detection2)) { + EXPECT_CALL(visitor_, GetHandshakeState()) + .WillRepeatedly(Return(HANDSHAKE_COMPLETE)); + } EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet()); // Send stream data. @@ -10009,7 +10132,7 @@ TEST_P(QuicConnectionTest, DeprecateHandshakeMode) { EXPECT_CALL(visitor_, SendPing()).WillOnce(Invoke([this]() { SendPing(); })); connection_.GetRetransmissionAlarm()->Fire(); EXPECT_EQ(1u, connection_.GetStats().pto_count); - EXPECT_EQ(0u, connection_.GetStats().crypto_retransmit_count); + EXPECT_EQ(1u, connection_.GetStats().crypto_retransmit_count); EXPECT_EQ(1u, writer_->ping_frames().size()); } @@ -10023,13 +10146,17 @@ TEST_P(QuicConnectionTest, AntiAmplificationLimit) { // Verify no data can be sent at the beginning because bytes received is 0. EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0); connection_.SendCryptoDataWithString("foo", 0); + if (GetQuicReloadableFlag(quic_move_amplification_limit)) { + EXPECT_FALSE(connection_.CanWrite(HAS_RETRANSMITTABLE_DATA)); + EXPECT_FALSE(connection_.CanWrite(NO_RETRANSMITTABLE_DATA)); + } EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet()); // Receives packet 1. ProcessCryptoPacketAtLevel(1, ENCRYPTION_INITIAL); const size_t anti_amplification_factor = - GetQuicFlag(FLAGS_quic_anti_amplification_factor); + connection_.anti_amplification_factor(); // Verify now packets can be sent. for (size_t i = 0; i < anti_amplification_factor; ++i) { EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); @@ -10064,6 +10191,48 @@ TEST_P(QuicConnectionTest, AntiAmplificationLimit) { } } +TEST_P(QuicConnectionTest, AckPendingWithAmplificationLimited) { + if (!connection_.version().SupportsAntiAmplificationLimit() || + !GetQuicReloadableFlag(quic_move_amplification_limit)) { + return; + } + EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber()); + EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(AnyNumber()); + set_perspective(Perspective::IS_SERVER); + use_tagging_decrypter(); + connection_.SetEncrypter(ENCRYPTION_INITIAL, + std::make_unique<TaggingEncrypter>(0x01)); + connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL); + // Receives packet 1. + ProcessCryptoPacketAtLevel(1, ENCRYPTION_INITIAL); + connection_.SetEncrypter(ENCRYPTION_HANDSHAKE, + std::make_unique<TaggingEncrypter>(0x02)); + connection_.SetDefaultEncryptionLevel(ENCRYPTION_HANDSHAKE); + EXPECT_TRUE(connection_.HasPendingAcks()); + // Send response in different encryption level and cause amplification factor + // throttled. + size_t i = 0; + while (connection_.CanWrite(HAS_RETRANSMITTABLE_DATA)) { + connection_.SendCryptoDataWithString(std::string(1024, 'a'), i * 1024, + ENCRYPTION_HANDSHAKE); + ++i; + } + // Verify ACK is still pending. + EXPECT_TRUE(connection_.HasPendingAcks()); + + // Fire ACK alarm and verify ACK cannot be sent due to amplification factor. + clock_.AdvanceTime(connection_.GetAckAlarm()->deadline() - clock_.Now()); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0); + connection_.GetAckAlarm()->Fire(); + // Verify ACK alarm is cancelled. + EXPECT_FALSE(connection_.HasPendingAcks()); + + // Receives packet 2 and verify ACK gets flushed. + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); + ProcessCryptoPacketAtLevel(2, ENCRYPTION_INITIAL); + EXPECT_FALSE(writer_->ack_frames().empty()); +} + TEST_P(QuicConnectionTest, ConnectionCloseFrameType) { if (!VersionHasIetfQuicFrames(version().transport_version)) { // Test relevent only for IETF QUIC. @@ -10202,6 +10371,49 @@ TEST_P(QuicConnectionTest, SendCoalescedPackets) { EXPECT_NE(nullptr, writer_->coalesced_packet()); } +TEST_P(QuicConnectionTest, LegacyVersionEncapsulation) { + connection_.EnableLegacyVersionEncapsulation("test.example.org"); + + MockQuicConnectionDebugVisitor debug_visitor; + connection_.set_debug_visitor(&debug_visitor); + EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _)).Times(1); + + // Our TestPacketWriter normally parses the sent packet using the version + // from the connection, so here we need to tell it to use the encapsulation + // version, and reset the initial decrypter for that version. + writer_->framer()->SetSupportedVersions( + SupportedVersions(LegacyVersionForEncapsulation())); + writer_->framer()->framer()->SetInitialObfuscators( + connection_.connection_id()); + + { + QuicConnection::ScopedPacketFlusher flusher(&connection_); + connection_.SendCryptoDataWithString("TEST_CRYPTO_DATA", /*offset=*/0); + } + + EXPECT_EQ(1u, writer_->packets_write_attempts()); + // Verify that the packet is fully padded. + EXPECT_EQ(connection_.max_packet_length(), writer_->last_packet_size()); + + // Check that the connection stats show Legacy Version Encapsulation was used. + EXPECT_GT(connection_.GetStats().sent_legacy_version_encapsulated_packets, + 0u); + + // Verify that the sent packet was in fact encapsulated, and check header. + const QuicPacketHeader& encapsulated_header = writer_->last_packet_header(); + EXPECT_TRUE(encapsulated_header.version_flag); + EXPECT_EQ(encapsulated_header.version, LegacyVersionForEncapsulation()); + EXPECT_EQ(encapsulated_header.destination_connection_id, + connection_.connection_id()); + + // Encapsulated packet should contain a stream frame for the crypto stream, + // optionally padding, and nothing else. + EXPECT_EQ(0u, writer_->crypto_frames().size()); + EXPECT_EQ(1u, writer_->stream_frames().size()); + EXPECT_EQ(writer_->frame_count(), writer_->framer()->padding_frames().size() + + writer_->stream_frames().size()); +} + TEST_P(QuicConnectionTest, ClientReceivedHandshakeDone) { if (!connection_.version().HasHandshakeDone()) { return; @@ -10299,14 +10511,20 @@ TEST_P(QuicConnectionTest, MultiplePacketNumberSpacePto) { EXPECT_EQ(0x01010101u, writer_->final_bytes_of_last_packet()); } -void QuicConnectionTest::TestClientRetryHandling(bool invalid_retry_tag, - bool missing_id_in_config, - bool wrong_id_in_config) { +void QuicConnectionTest::TestClientRetryHandling( + bool invalid_retry_tag, + bool missing_original_id_in_config, + bool wrong_original_id_in_config, + bool missing_retry_id_in_config, + bool wrong_retry_id_in_config) { if (invalid_retry_tag) { - ASSERT_FALSE(missing_id_in_config); - ASSERT_FALSE(wrong_id_in_config); + ASSERT_FALSE(missing_original_id_in_config); + ASSERT_FALSE(wrong_original_id_in_config); + ASSERT_FALSE(missing_retry_id_in_config); + ASSERT_FALSE(wrong_retry_id_in_config); } else { - ASSERT_FALSE(missing_id_in_config && wrong_id_in_config); + ASSERT_FALSE(missing_original_id_in_config && wrong_original_id_in_config); + ASSERT_FALSE(missing_retry_id_in_config && wrong_retry_id_in_config); } if (!version().HasRetryIntegrityTag()) { return; @@ -10321,15 +10539,20 @@ void QuicConnectionTest::TestClientRetryHandling(bool invalid_retry_tag, 0xff, 0xff, 0x00, 0x00, 0x1b, 0x00, 0x08, 0xf0, 0x67, 0xa5, 0x50, 0x2a, 0x42, 0x62, 0xb5, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0xa5, 0x23, 0xcb, 0x5b, 0xa5, 0x24, 0x69, 0x5f, 0x65, 0x69, 0xf2, 0x93, 0xa1, 0x35, 0x9d, 0x8e}; + char retry_packet29[] = { + 0xff, 0xff, 0x00, 0x00, 0x1d, 0x00, 0x08, 0xf0, 0x67, 0xa5, 0x50, 0x2a, + 0x42, 0x62, 0xb5, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0xd1, 0x69, 0x26, 0xd8, + 0x1f, 0x6f, 0x9c, 0xa2, 0x95, 0x3a, 0x8a, 0xa4, 0x57, 0x5e, 0x1e, 0x49}; char* retry_packet; size_t retry_packet_length; - if (version() == - ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_27)) { + if (version() == ParsedQuicVersion::Draft29()) { + retry_packet = retry_packet29; + retry_packet_length = QUICHE_ARRAYSIZE(retry_packet29); + } else if (version() == ParsedQuicVersion::Draft27()) { retry_packet = retry_packet27; retry_packet_length = QUICHE_ARRAYSIZE(retry_packet27); - } else if (version() == - ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_25)) { + } else if (version() == ParsedQuicVersion::Draft25()) { retry_packet = retry_packet25; retry_packet_length = QUICHE_ARRAYSIZE(retry_packet25); } else { @@ -10360,11 +10583,17 @@ void QuicConnectionTest::TestClientRetryHandling(bool invalid_retry_tag, } QuicConnectionId config_original_connection_id = original_connection_id; - if (wrong_id_in_config) { + if (wrong_original_id_in_config) { // Flip the first bit of the connection ID. ASSERT_FALSE(config_original_connection_id.IsEmpty()); config_original_connection_id.mutable_data()[0] ^= 0x80; } + QuicConnectionId config_retry_source_connection_id = new_connection_id; + if (wrong_retry_id_in_config) { + // Flip the first bit of the connection ID. + ASSERT_FALSE(config_retry_source_connection_id.IsEmpty()); + config_retry_source_connection_id.mutable_data()[0] ^= 0x80; + } // Make sure the connection uses the connection ID from the test vectors, QuicConnectionPeer::SetServerConnectionId(&connection_, @@ -10397,11 +10626,21 @@ void QuicConnectionTest::TestClientRetryHandling(bool invalid_retry_tag, // Test validating the original_connection_id from the config. QuicConfig received_config; QuicConfigPeer::SetNegotiated(&received_config, true); - if (!missing_id_in_config) { + if (connection_.version().AuthenticatesHandshakeConnectionIds()) { + QuicConfigPeer::SetReceivedInitialSourceConnectionId( + &received_config, connection_.connection_id()); + if (!missing_retry_id_in_config) { + QuicConfigPeer::SetReceivedRetrySourceConnectionId( + &received_config, config_retry_source_connection_id); + } + } + if (!missing_original_id_in_config) { QuicConfigPeer::SetReceivedOriginalConnectionId( &received_config, config_original_connection_id); } - if (missing_id_in_config || wrong_id_in_config) { + + if (missing_original_id_in_config || wrong_original_id_in_config || + missing_retry_id_in_config || wrong_retry_id_in_config) { EXPECT_CALL(visitor_, OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF)) .Times(1); @@ -10412,8 +10651,9 @@ void QuicConnectionTest::TestClientRetryHandling(bool invalid_retry_tag, } EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)).Times(AnyNumber()); connection_.SetFromConfig(received_config); - if (missing_id_in_config || wrong_id_in_config) { - EXPECT_FALSE(connection_.connected()); + if (missing_original_id_in_config || wrong_original_id_in_config || + missing_retry_id_in_config || wrong_retry_id_in_config) { + ASSERT_FALSE(connection_.connected()); TestConnectionCloseQuicErrorCode(IETF_QUIC_PROTOCOL_VIOLATION); } else { EXPECT_TRUE(connection_.connected()); @@ -10422,31 +10662,74 @@ void QuicConnectionTest::TestClientRetryHandling(bool invalid_retry_tag, TEST_P(QuicConnectionTest, ClientParsesRetry) { TestClientRetryHandling(/*invalid_retry_tag=*/false, - /*missing_id_in_config=*/false, - /*wrong_id_in_config=*/false); + /*missing_original_id_in_config=*/false, + /*wrong_original_id_in_config=*/false, + /*missing_retry_id_in_config=*/false, + /*wrong_retry_id_in_config=*/false); } -TEST_P(QuicConnectionTest, ClientParsesInvalidRetry) { +TEST_P(QuicConnectionTest, ClientParsesRetryInvalidTag) { TestClientRetryHandling(/*invalid_retry_tag=*/true, - /*missing_id_in_config=*/false, - /*wrong_id_in_config=*/false); + /*missing_original_id_in_config=*/false, + /*wrong_original_id_in_config=*/false, + /*missing_retry_id_in_config=*/false, + /*wrong_retry_id_in_config=*/false); } -TEST_P(QuicConnectionTest, ClientParsesRetryMissingId) { +TEST_P(QuicConnectionTest, ClientParsesRetryMissingOriginalId) { TestClientRetryHandling(/*invalid_retry_tag=*/false, - /*missing_id_in_config=*/true, - /*wrong_id_in_config=*/false); + /*missing_original_id_in_config=*/true, + /*wrong_original_id_in_config=*/false, + /*missing_retry_id_in_config=*/false, + /*wrong_retry_id_in_config=*/false); } -TEST_P(QuicConnectionTest, ClientParsesRetryWrongId) { +TEST_P(QuicConnectionTest, ClientParsesRetryWrongOriginalId) { TestClientRetryHandling(/*invalid_retry_tag=*/false, - /*missing_id_in_config=*/false, - /*wrong_id_in_config=*/true); + /*missing_original_id_in_config=*/false, + /*wrong_original_id_in_config=*/true, + /*missing_retry_id_in_config=*/false, + /*wrong_retry_id_in_config=*/false); +} + +TEST_P(QuicConnectionTest, ClientParsesRetryMissingRetryId) { + if (!connection_.version().AuthenticatesHandshakeConnectionIds()) { + // Versions that do not authenticate connection IDs never send the + // retry_source_connection_id transport parameter. + return; + } + TestClientRetryHandling(/*invalid_retry_tag=*/false, + /*missing_original_id_in_config=*/false, + /*wrong_original_id_in_config=*/false, + /*missing_retry_id_in_config=*/true, + /*wrong_retry_id_in_config=*/false); +} + +TEST_P(QuicConnectionTest, ClientParsesRetryWrongRetryId) { + if (!connection_.version().AuthenticatesHandshakeConnectionIds()) { + // Versions that do not authenticate connection IDs never send the + // retry_source_connection_id transport parameter. + return; + } + TestClientRetryHandling(/*invalid_retry_tag=*/false, + /*missing_original_id_in_config=*/false, + /*wrong_original_id_in_config=*/false, + /*missing_retry_id_in_config=*/false, + /*wrong_retry_id_in_config=*/true); } TEST_P(QuicConnectionTest, ClientReceivesOriginalConnectionIdWithoutRetry) { - // Make sure that receiving the original_connection_id transport parameter - // fails the handshake when no RETRY packet was received before it. + if (!connection_.version().UsesTls()) { + // QUIC+TLS is required to transmit connection ID transport parameters. + return; + } + if (connection_.version().AuthenticatesHandshakeConnectionIds()) { + // Versions that authenticate connection IDs always send the + // original_destination_connection_id transport parameter. + return; + } + // Make sure that receiving the original_destination_connection_id transport + // parameter fails the handshake when no RETRY packet was received before it. QuicConfig received_config; QuicConfigPeer::SetNegotiated(&received_config, true); QuicConfigPeer::SetReceivedOriginalConnectionId(&received_config, @@ -10459,6 +10742,26 @@ TEST_P(QuicConnectionTest, ClientReceivesOriginalConnectionIdWithoutRetry) { TestConnectionCloseQuicErrorCode(IETF_QUIC_PROTOCOL_VIOLATION); } +TEST_P(QuicConnectionTest, ClientReceivesRetrySourceConnectionIdWithoutRetry) { + if (!connection_.version().AuthenticatesHandshakeConnectionIds()) { + // Versions that do not authenticate connection IDs never send the + // retry_source_connection_id transport parameter. + return; + } + // Make sure that receiving the retry_source_connection_id transport parameter + // fails the handshake when no RETRY packet was received before it. + QuicConfig received_config; + QuicConfigPeer::SetNegotiated(&received_config, true); + QuicConfigPeer::SetReceivedRetrySourceConnectionId(&received_config, + TestConnectionId(0x12345)); + EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)).Times(AnyNumber()); + EXPECT_CALL(visitor_, OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF)) + .Times(1); + connection_.SetFromConfig(received_config); + EXPECT_FALSE(connection_.connected()); + TestConnectionCloseQuicErrorCode(IETF_QUIC_PROTOCOL_VIOLATION); +} + // Regression test for http://crbug/1047977 TEST_P(QuicConnectionTest, MaxStreamsFrameCausesConnectionClose) { if (!VersionHasIetfQuicFrames(connection_.transport_version())) { @@ -10640,28 +10943,14 @@ TEST_P(QuicConnectionTest, DonotExtendIdleTimeOnUndecryptablePackets) { peer_framer_.SetEncrypter(ENCRYPTION_FORWARD_SECURE, std::make_unique<TaggingEncrypter>(tag)); ProcessDataPacketAtLevel(1, !kHasStopWaiting, ENCRYPTION_FORWARD_SECURE); - if (GetQuicReloadableFlag(quic_extend_idle_time_on_decryptable_packets)) { - // Verify deadline does not get extended. - EXPECT_EQ(initial_deadline, connection_.GetTimeoutAlarm()->deadline()); - } - if (GetQuicReloadableFlag(quic_extend_idle_time_on_decryptable_packets)) { - EXPECT_CALL(visitor_, OnConnectionClosed(_, _)).Times(1); - } else { - EXPECT_CALL(visitor_, OnConnectionClosed(_, _)).Times(0); - } + // Verify deadline does not get extended. + EXPECT_EQ(initial_deadline, connection_.GetTimeoutAlarm()->deadline()); + EXPECT_CALL(visitor_, OnConnectionClosed(_, _)).Times(1); QuicTime::Delta delay = initial_deadline - clock_.ApproximateNow(); clock_.AdvanceTime(delay); - if (GetQuicReloadableFlag(quic_extend_idle_time_on_decryptable_packets)) { - connection_.GetTimeoutAlarm()->Fire(); - } - if (GetQuicReloadableFlag(quic_extend_idle_time_on_decryptable_packets)) { - // Verify connection gets closed. - EXPECT_FALSE(connection_.connected()); - } else { - // Verify the timeout alarm deadline is updated. - EXPECT_TRUE(connection_.connected()); - EXPECT_TRUE(connection_.GetTimeoutAlarm()->IsSet()); - } + connection_.GetTimeoutAlarm()->Fire(); + // Verify connection gets closed. + EXPECT_FALSE(connection_.connected()); } TEST_P(QuicConnectionTest, BundleAckWithImmediateResponse) { @@ -10673,15 +10962,440 @@ TEST_P(QuicConnectionTest, BundleAckWithImmediateResponse) { })); EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); ProcessDataPacket(1); - QuicAlarm* ack_alarm = QuicConnectionPeer::GetAckAlarm(&connection_); - if (GetQuicReloadableFlag(quic_advance_ack_timeout_update)) { - // Verify ACK is bundled with WINDOW_UPDATE. - EXPECT_FALSE(writer_->ack_frames().empty()); - EXPECT_FALSE(ack_alarm->IsSet()); + // Verify ACK is bundled with WINDOW_UPDATE. + EXPECT_FALSE(writer_->ack_frames().empty()); + EXPECT_FALSE(connection_.HasPendingAcks()); +} + +TEST_P(QuicConnectionTest, AckAlarmFiresEarly) { + if (!connection_.SupportsMultiplePacketNumberSpaces()) { + return; + } + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber()); + } + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); + use_tagging_decrypter(); + // Receives packet 1000 in initial data. + ProcessCryptoPacketAtLevel(1000, ENCRYPTION_INITIAL); + EXPECT_TRUE(connection_.HasPendingAcks()); + + peer_framer_.SetEncrypter(ENCRYPTION_ZERO_RTT, + std::make_unique<TaggingEncrypter>(0x02)); + SetDecrypter(ENCRYPTION_ZERO_RTT, + std::make_unique<StrictTaggingDecrypter>(0x02)); + connection_.SetEncrypter(ENCRYPTION_INITIAL, + std::make_unique<TaggingEncrypter>(0x02)); + // Receives packet 1000 in application data. + ProcessDataPacketAtLevel(1000, false, ENCRYPTION_ZERO_RTT); + EXPECT_TRUE(connection_.HasPendingAcks()); + // Verify ACK deadline does not change. + EXPECT_EQ(clock_.ApproximateNow() + kAlarmGranularity, + connection_.GetAckAlarm()->deadline()); + + // Ack alarm fires early. + if (GetQuicReloadableFlag(quic_always_send_earliest_ack)) { + // Verify the earliest ACK is flushed. + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); } else { - // ACK is pending. - EXPECT_TRUE(writer_->ack_frames().empty()); - EXPECT_TRUE(ack_alarm->IsSet()); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0); + } + connection_.GetAckAlarm()->Fire(); + EXPECT_TRUE(connection_.HasPendingAcks()); + if (GetQuicReloadableFlag(quic_always_send_earliest_ack)) { + EXPECT_EQ(clock_.ApproximateNow() + DefaultDelayedAckTime(), + connection_.GetAckAlarm()->deadline()); + } else { + // No forward progress has been made. + EXPECT_EQ(clock_.ApproximateNow() + kAlarmGranularity, + connection_.GetAckAlarm()->deadline()); + } +} + +TEST_P(QuicConnectionTest, ClientOnlyBlackholeDetectionClient) { + if (!GetQuicReloadableFlag(quic_default_enable_5rto_blackhole_detection2)) { + return; + } + QuicConfig config; + QuicTagVector connection_options; + connection_options.push_back(kCBHD); + config.SetConnectionOptionsToSend(connection_options); + EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); + connection_.SetFromConfig(config); + EXPECT_CALL(visitor_, GetHandshakeState()) + .WillRepeatedly(Return(HANDSHAKE_COMPLETE)); + EXPECT_FALSE(connection_.GetBlackholeDetectorAlarm()->IsSet()); + // Send stream data. + SendStreamDataToPeer( + GetNthClientInitiatedStreamId(1, connection_.transport_version()), "foo", + 0, FIN, nullptr); + // Verify blackhole detection is in progress. + EXPECT_TRUE(connection_.GetBlackholeDetectorAlarm()->IsSet()); +} + +TEST_P(QuicConnectionTest, ClientOnlyBlackholeDetectionServer) { + if (!GetQuicReloadableFlag(quic_default_enable_5rto_blackhole_detection2)) { + return; + } + set_perspective(Perspective::IS_SERVER); + QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false); + if (version().SupportsAntiAmplificationLimit()) { + QuicConnectionPeer::SetAddressValidated(&connection_); + } + QuicConfig config; + QuicTagVector connection_options; + connection_options.push_back(kCBHD); + config.SetInitialReceivedConnectionOptions(connection_options); + EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); + connection_.SetFromConfig(config); + EXPECT_CALL(visitor_, GetHandshakeState()) + .WillRepeatedly(Return(HANDSHAKE_COMPLETE)); + EXPECT_FALSE(connection_.GetBlackholeDetectorAlarm()->IsSet()); + // Send stream data. + SendStreamDataToPeer( + GetNthClientInitiatedStreamId(1, connection_.transport_version()), "foo", + 0, FIN, nullptr); + // Verify blackhole detection is disabled. + EXPECT_FALSE(connection_.GetBlackholeDetectorAlarm()->IsSet()); +} + +TEST_P(QuicConnectionTest, 2RtoBlackholeDetection) { + if (!GetQuicReloadableFlag(quic_default_enable_5rto_blackhole_detection2)) { + return; + } + QuicConfig config; + QuicTagVector connection_options; + connection_options.push_back(k2RTO); + config.SetConnectionOptionsToSend(connection_options); + EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); + connection_.SetFromConfig(config); + const size_t kMinRttMs = 40; + RttStats* rtt_stats = const_cast<RttStats*>(manager_->GetRttStats()); + rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kMinRttMs), + QuicTime::Delta::Zero(), QuicTime::Zero()); + EXPECT_CALL(visitor_, GetHandshakeState()) + .WillRepeatedly(Return(HANDSHAKE_COMPLETE)); + EXPECT_FALSE(connection_.GetBlackholeDetectorAlarm()->IsSet()); + // Send stream data. + SendStreamDataToPeer( + GetNthClientInitiatedStreamId(1, connection_.transport_version()), "foo", + 0, FIN, nullptr); + // Verify blackhole delay is expected. + EXPECT_EQ(clock_.Now() + + connection_.sent_packet_manager().GetNetworkBlackholeDelay(2), + QuicConnectionPeer::GetBlackholeDetectionDeadline(&connection_)); +} + +TEST_P(QuicConnectionTest, 3RtoBlackholeDetection) { + if (!GetQuicReloadableFlag(quic_default_enable_5rto_blackhole_detection2)) { + return; + } + QuicConfig config; + QuicTagVector connection_options; + connection_options.push_back(k3RTO); + config.SetConnectionOptionsToSend(connection_options); + EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); + connection_.SetFromConfig(config); + const size_t kMinRttMs = 40; + RttStats* rtt_stats = const_cast<RttStats*>(manager_->GetRttStats()); + rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kMinRttMs), + QuicTime::Delta::Zero(), QuicTime::Zero()); + EXPECT_CALL(visitor_, GetHandshakeState()) + .WillRepeatedly(Return(HANDSHAKE_COMPLETE)); + EXPECT_FALSE(connection_.GetBlackholeDetectorAlarm()->IsSet()); + // Send stream data. + SendStreamDataToPeer( + GetNthClientInitiatedStreamId(1, connection_.transport_version()), "foo", + 0, FIN, nullptr); + // Verify blackhole delay is expected. + EXPECT_EQ(clock_.Now() + + connection_.sent_packet_manager().GetNetworkBlackholeDelay(3), + QuicConnectionPeer::GetBlackholeDetectionDeadline(&connection_)); +} + +TEST_P(QuicConnectionTest, 4RtoBlackholeDetection) { + if (!GetQuicReloadableFlag(quic_default_enable_5rto_blackhole_detection2)) { + return; + } + QuicConfig config; + QuicTagVector connection_options; + connection_options.push_back(k4RTO); + config.SetConnectionOptionsToSend(connection_options); + EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); + connection_.SetFromConfig(config); + const size_t kMinRttMs = 40; + RttStats* rtt_stats = const_cast<RttStats*>(manager_->GetRttStats()); + rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kMinRttMs), + QuicTime::Delta::Zero(), QuicTime::Zero()); + EXPECT_CALL(visitor_, GetHandshakeState()) + .WillRepeatedly(Return(HANDSHAKE_COMPLETE)); + EXPECT_FALSE(connection_.GetBlackholeDetectorAlarm()->IsSet()); + // Send stream data. + SendStreamDataToPeer( + GetNthClientInitiatedStreamId(1, connection_.transport_version()), "foo", + 0, FIN, nullptr); + // Verify blackhole delay is expected. + EXPECT_EQ(clock_.Now() + + connection_.sent_packet_manager().GetNetworkBlackholeDelay(4), + QuicConnectionPeer::GetBlackholeDetectionDeadline(&connection_)); +} + +TEST_P(QuicConnectionTest, 6RtoBlackholeDetection) { + if (!GetQuicReloadableFlag(quic_default_enable_5rto_blackhole_detection2)) { + return; + } + QuicConfig config; + QuicTagVector connection_options; + connection_options.push_back(k6RTO); + config.SetConnectionOptionsToSend(connection_options); + EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); + connection_.SetFromConfig(config); + const size_t kMinRttMs = 40; + RttStats* rtt_stats = const_cast<RttStats*>(manager_->GetRttStats()); + rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kMinRttMs), + QuicTime::Delta::Zero(), QuicTime::Zero()); + EXPECT_CALL(visitor_, GetHandshakeState()) + .WillRepeatedly(Return(HANDSHAKE_COMPLETE)); + EXPECT_FALSE(connection_.GetBlackholeDetectorAlarm()->IsSet()); + // Send stream data. + SendStreamDataToPeer( + GetNthClientInitiatedStreamId(1, connection_.transport_version()), "foo", + 0, FIN, nullptr); + // Verify blackhole delay is expected. + EXPECT_EQ(clock_.Now() + + connection_.sent_packet_manager().GetNetworkBlackholeDelay(6), + QuicConnectionPeer::GetBlackholeDetectionDeadline(&connection_)); +} + +// Regresstion test for b/158491591. +TEST_P(QuicConnectionTest, MadeForwardProgressOnDiscardingKeys) { + if (!connection_.SupportsMultiplePacketNumberSpaces()) { + return; + } + use_tagging_decrypter(); + // Send handshake packet. + connection_.SetEncrypter(ENCRYPTION_HANDSHAKE, + std::make_unique<TaggingEncrypter>(0x02)); + connection_.SetDefaultEncryptionLevel(ENCRYPTION_HANDSHAKE); + EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(1); + QuicConfig config; + QuicTagVector connection_options; + connection_options.push_back(k5RTO); + config.SetConnectionOptionsToSend(connection_options); + QuicConfigPeer::SetNegotiated(&config, true); + if (GetQuicReloadableFlag(quic_default_enable_5rto_blackhole_detection2)) { + EXPECT_CALL(visitor_, GetHandshakeState()) + .WillRepeatedly(Return(HANDSHAKE_COMPLETE)); + } + if (connection_.version().AuthenticatesHandshakeConnectionIds()) { + QuicConfigPeer::SetReceivedOriginalConnectionId( + &config, connection_.connection_id()); + QuicConfigPeer::SetReceivedInitialSourceConnectionId( + &config, connection_.connection_id()); + } + EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); + connection_.SetFromConfig(config); + + connection_.SendCryptoDataWithString("foo", 0, ENCRYPTION_HANDSHAKE); + EXPECT_TRUE(connection_.BlackholeDetectionInProgress()); + // Discard handshake keys. + connection_.OnHandshakeComplete(); + if (GetQuicReloadableFlag(quic_default_enable_5rto_blackhole_detection2)) { + // Verify blackhole detection stops. + EXPECT_FALSE(connection_.BlackholeDetectionInProgress()); + } else { + // Problematic: although there is nothing in flight, blackhole detection is + // still in progress. + EXPECT_TRUE(connection_.BlackholeDetectionInProgress()); + } +} + +TEST_P(QuicConnectionTest, ProcessUndecryptablePacketsBasedOnEncryptionLevel) { + if (!connection_.SupportsMultiplePacketNumberSpaces()) { + return; + } + // SetFromConfig is always called after construction from InitializeSession. + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); + EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); + EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(AnyNumber()); + QuicConfig config; + connection_.SetFromConfig(config); + connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL); + connection_.RemoveDecrypter(ENCRYPTION_FORWARD_SECURE); + use_tagging_decrypter(); + + peer_framer_.SetEncrypter(ENCRYPTION_HANDSHAKE, + std::make_unique<TaggingEncrypter>(0x01)); + peer_framer_.SetEncrypter(ENCRYPTION_FORWARD_SECURE, + std::make_unique<TaggingEncrypter>(0x02)); + + for (uint64_t i = 1; i <= 3; ++i) { + ProcessDataPacketAtLevel(i, !kHasStopWaiting, ENCRYPTION_HANDSHAKE); + } + ProcessDataPacketAtLevel(4, !kHasStopWaiting, ENCRYPTION_FORWARD_SECURE); + for (uint64_t j = 5; j <= 7; ++j) { + ProcessDataPacketAtLevel(j, !kHasStopWaiting, ENCRYPTION_HANDSHAKE); + } + EXPECT_EQ(7u, QuicConnectionPeer::NumUndecryptablePackets(&connection_)); + EXPECT_FALSE(connection_.GetProcessUndecryptablePacketsAlarm()->IsSet()); + SetDecrypter(ENCRYPTION_HANDSHAKE, + std::make_unique<StrictTaggingDecrypter>(0x01)); + EXPECT_TRUE(connection_.GetProcessUndecryptablePacketsAlarm()->IsSet()); + connection_.SetDefaultEncryptionLevel(ENCRYPTION_HANDSHAKE); + connection_.SetEncrypter(ENCRYPTION_HANDSHAKE, + std::make_unique<TaggingEncrypter>(0x01)); + if (GetQuicReloadableFlag(quic_fix_undecryptable_packets)) { + // Verify all ENCRYPTION_HANDSHAKE packets get processed. + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(6); + } else { + // Verify packets before 4 get processed. + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(3); + } + connection_.GetProcessUndecryptablePacketsAlarm()->Fire(); + EXPECT_EQ(4u, QuicConnectionPeer::NumUndecryptablePackets(&connection_)); + + SetDecrypter(ENCRYPTION_FORWARD_SECURE, + std::make_unique<StrictTaggingDecrypter>(0x02)); + EXPECT_TRUE(connection_.GetProcessUndecryptablePacketsAlarm()->IsSet()); + connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); + connection_.SetEncrypter(ENCRYPTION_FORWARD_SECURE, + std::make_unique<TaggingEncrypter>(0x02)); + if (GetQuicReloadableFlag(quic_fix_undecryptable_packets)) { + // Verify the 1-RTT packet gets processed. + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); + } else { + // Verify all packets get processed. + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(4); + } + connection_.GetProcessUndecryptablePacketsAlarm()->Fire(); + EXPECT_EQ(0u, QuicConnectionPeer::NumUndecryptablePackets(&connection_)); +} + +TEST_P(QuicConnectionTest, ServerBundlesInitialDataWithInitialAck) { + if (!connection_.SupportsMultiplePacketNumberSpaces()) { + return; + } + set_perspective(Perspective::IS_SERVER); + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber()); + } + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); + use_tagging_decrypter(); + // Receives packet 1000 in initial data. + ProcessCryptoPacketAtLevel(1000, ENCRYPTION_INITIAL); + EXPECT_TRUE(connection_.HasPendingAcks()); + + connection_.SetEncrypter(ENCRYPTION_INITIAL, + std::make_unique<TaggingEncrypter>(0x01)); + connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL); + connection_.SendCryptoDataWithString("foo", 0, ENCRYPTION_INITIAL); + QuicTime expected_pto_time = + connection_.sent_packet_manager().GetRetransmissionTime(); + + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); + connection_.SetEncrypter(ENCRYPTION_HANDSHAKE, + std::make_unique<TaggingEncrypter>(0x02)); + connection_.SetDefaultEncryptionLevel(ENCRYPTION_HANDSHAKE); + EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(1); + connection_.SendCryptoDataWithString("foo", 0, ENCRYPTION_HANDSHAKE); + // Verify PTO time does not change. + EXPECT_EQ(expected_pto_time, + connection_.sent_packet_manager().GetRetransmissionTime()); + + // Receives packet 1001 in initial data. + ProcessCryptoPacketAtLevel(1001, ENCRYPTION_INITIAL); + EXPECT_TRUE(connection_.HasPendingAcks()); + // Receives packet 1002 in initial data. + ProcessCryptoPacketAtLevel(1002, ENCRYPTION_INITIAL); + EXPECT_FALSE(writer_->ack_frames().empty()); + if (GetQuicReloadableFlag(quic_bundle_crypto_data_with_initial_ack)) { + // Verify CRYPTO frame is bundled with INITIAL ACK. + EXPECT_FALSE(writer_->crypto_frames().empty()); + // Verify PTO time changes. + EXPECT_NE(expected_pto_time, + connection_.sent_packet_manager().GetRetransmissionTime()); + } else { + EXPECT_TRUE(writer_->crypto_frames().empty()); + // Verify PTO time does not change. + EXPECT_EQ(expected_pto_time, + connection_.sent_packet_manager().GetRetransmissionTime()); + } +} + +TEST_P(QuicConnectionTest, ClientBundlesHandshakeDataWithHandshakeAck) { + if (!connection_.SupportsMultiplePacketNumberSpaces()) { + return; + } + EXPECT_EQ(Perspective::IS_CLIENT, connection_.perspective()); + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber()); + } + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); + use_tagging_decrypter(); + connection_.SetEncrypter(ENCRYPTION_HANDSHAKE, + std::make_unique<TaggingEncrypter>(0x02)); + connection_.SetDefaultEncryptionLevel(ENCRYPTION_HANDSHAKE); + SetDecrypter(ENCRYPTION_HANDSHAKE, + std::make_unique<StrictTaggingDecrypter>(0x02)); + peer_framer_.SetEncrypter(ENCRYPTION_HANDSHAKE, + std::make_unique<TaggingEncrypter>(0x02)); + // Receives packet 1000 in handshake data. + ProcessCryptoPacketAtLevel(1000, ENCRYPTION_HANDSHAKE); + EXPECT_TRUE(connection_.HasPendingAcks()); + + EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(2); + connection_.SendCryptoDataWithString("foo", 0, ENCRYPTION_HANDSHAKE); + + // Receives packet 1001 in handshake data. + ProcessCryptoPacketAtLevel(1001, ENCRYPTION_HANDSHAKE); + EXPECT_TRUE(connection_.HasPendingAcks()); + // Receives packet 1002 in handshake data. + ProcessCryptoPacketAtLevel(1002, ENCRYPTION_HANDSHAKE); + EXPECT_FALSE(writer_->ack_frames().empty()); + if (GetQuicReloadableFlag(quic_bundle_crypto_data_with_initial_ack)) { + // Verify CRYPTO frame is bundled with HANDSHAKE ACK. + EXPECT_FALSE(writer_->crypto_frames().empty()); + } else { + EXPECT_TRUE(writer_->crypto_frames().empty()); + } +} + +// Regresstion test for b/156232673. +TEST_P(QuicConnectionTest, CoalescePacketOfLowerEncryptionLevel) { + if (!connection_.version().CanSendCoalescedPackets()) { + return; + } + if (GetQuicReloadableFlag(quic_fix_min_crypto_frame_size)) { + EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(1); + } else { + EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(0); + } + { + QuicConnection::ScopedPacketFlusher flusher(&connection_); + use_tagging_decrypter(); + connection_.SetEncrypter(ENCRYPTION_HANDSHAKE, + std::make_unique<TaggingEncrypter>(0x01)); + connection_.SetEncrypter(ENCRYPTION_FORWARD_SECURE, + std::make_unique<TaggingEncrypter>(0x02)); + connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); + SendStreamDataToPeer(2, std::string(1286, 'a'), 0, NO_FIN, nullptr); + connection_.SetDefaultEncryptionLevel(ENCRYPTION_HANDSHAKE); + // Try to coalesce a HANDSHAKE packet after 1-RTT packet. + if (GetQuicReloadableFlag(quic_fix_min_crypto_frame_size)) { + // Verify soft max packet length gets resumed and handshake packet gets + // successfully sent. + connection_.SendCryptoDataWithString("a", 0, ENCRYPTION_HANDSHAKE); + } else { + // Problematic: creator thinks there is space to consume 1-byte, however, + // extra paddings make the serialization fail because of + // MinPlaintextPacketSize. + EXPECT_CALL(visitor_, + OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF)); + EXPECT_QUIC_BUG( + connection_.SendCryptoDataWithString("a", 0, ENCRYPTION_HANDSHAKE), + "AppendPaddingFrame of 3 failed"); + } } } diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.cc b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.cc index e93fd071c07..a769da9cd60 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.cc @@ -171,6 +171,12 @@ size_t QuicCryptoClientHandshaker::BufferSizeLimitForLevel( return QuicCryptoHandshaker::BufferSizeLimitForLevel(level); } +void QuicCryptoClientHandshaker::OnConnectionClosed( + QuicErrorCode /*error*/, + ConnectionCloseSource /*source*/) { + next_state_ = STATE_CONNECTION_CLOSED; +} + void QuicCryptoClientHandshaker::HandleServerConfigUpdateMessage( const CryptoHandshakeMessage& server_config_update) { DCHECK(server_config_update.tag() == kSCUP); @@ -236,6 +242,9 @@ void QuicCryptoClientHandshaker::DoHandshakeLoop( break; case STATE_NONE: QUIC_NOTREACHED(); + return; + case STATE_CONNECTION_CLOSED: + rv = QUIC_FAILURE; return; // We are done. } } while (rv != QUIC_PENDING && next_state_ != STATE_NONE); @@ -281,7 +290,9 @@ void QuicCryptoClientHandshaker::DoSendCHLO( // inchoate or subsequent hello. session()->config()->ToHandshakeMessage(&out, session()->transport_version()); - if (!cached->IsComplete(session()->connection()->clock()->WallNow())) { + if (!cached->IsComplete(session()->connection()->clock()->WallNow()) || + session()->config()->HasClientRequestedIndependentOption( + kQNZR, session()->perspective())) { crypto_config_->FillInchoateClientHello( server_id_, session()->supported_versions().front(), cached, session()->connection()->random_generator(), diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.h b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.h index 5ba93f24848..90f011dd053 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.h @@ -53,9 +53,9 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientHandshaker void OnOneRttPacketAcknowledged() override {} void OnHandshakePacketSent() override {} void OnConnectionClosed(QuicErrorCode /*error*/, - ConnectionCloseSource /*source*/) override {} + ConnectionCloseSource /*source*/) override; void OnHandshakeDoneReceived() override; - void OnApplicationState( + void SetServerApplicationStateForResumption( std::unique_ptr<ApplicationState> /*application_state*/) override { QUICHE_NOTREACHED(); } @@ -103,6 +103,7 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientHandshaker STATE_RECV_SHLO, STATE_INITIALIZE_SCUP, STATE_NONE, + STATE_CONNECTION_CLOSED, }; // Handles new server config and optional source-address token provided by the diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.cc b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.cc index 36dc4cdb4c3..62a261d1fc1 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.cc @@ -126,9 +126,10 @@ void QuicCryptoClientStream::OnHandshakeDoneReceived() { handshaker_->OnHandshakeDoneReceived(); } -void QuicCryptoClientStream::OnApplicationState( +void QuicCryptoClientStream::SetServerApplicationStateForResumption( std::unique_ptr<ApplicationState> application_state) { - handshaker_->OnApplicationState(std::move(application_state)); + handshaker_->SetServerApplicationStateForResumption( + std::move(application_state)); } } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.h b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.h index 23f83c7e390..be99fb2b949 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.h @@ -63,9 +63,6 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientStreamBase : public QuicCryptoStream { // client. Does not count update messages that were received prior // to handshake confirmation. virtual int num_scup_messages_received() const = 0; - - virtual void OnApplicationState( - std::unique_ptr<ApplicationState> application_state) = 0; }; class QUIC_EXPORT_PRIVATE QuicCryptoClientStream @@ -167,7 +164,7 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientStream virtual void OnHandshakeDoneReceived() = 0; // Called when application state is received. - virtual void OnApplicationState( + virtual void SetServerApplicationStateForResumption( std::unique_ptr<ApplicationState> application_state) = 0; }; @@ -223,10 +220,9 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientStream ConnectionCloseSource source) override; void OnHandshakeDoneReceived() override; HandshakeState GetHandshakeState() const override; - size_t BufferSizeLimitForLevel(EncryptionLevel level) const override; - - void OnApplicationState( + void SetServerApplicationStateForResumption( std::unique_ptr<ApplicationState> application_state) override; + size_t BufferSizeLimitForLevel(EncryptionLevel level) const override; std::string chlo_hash() const; diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream_test.cc index 6542382d670..7f6d7770eb6 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream_test.cc @@ -162,6 +162,25 @@ TEST_F(QuicCryptoClientStreamTest, ExpiredServerConfig) { EXPECT_EQ(ENCRYPTION_INITIAL, connection_->encryption_level()); } +TEST_F(QuicCryptoClientStreamTest, ClientTurnedOffZeroRtt) { + // Seed the config with a cached server config. + CompleteCryptoHandshake(); + + // Recreate connection with the new config. + CreateConnection(); + + // Set connection option. + QuicTagVector options; + options.push_back(kQNZR); + session_->config()->SetClientConnectionOptions(options); + + EXPECT_CALL(*session_, OnProofValid(testing::_)); + stream()->CryptoConnect(); + // Check that a client hello was sent. + ASSERT_EQ(1u, connection_->encrypted_packets_.size()); + EXPECT_EQ(ENCRYPTION_INITIAL, connection_->encryption_level()); +} + TEST_F(QuicCryptoClientStreamTest, ClockSkew) { // Test that if the client's clock is skewed with respect to the server, // the handshake succeeds. In the past, the client would get the server @@ -299,7 +318,6 @@ TEST_F(QuicCryptoClientStreamTest, ServerConfigUpdateWithCert) { // Recreate connection with the new config and verify a 0-RTT attempt. CreateConnection(); - EXPECT_CALL(*connection_, OnCanWrite()); EXPECT_CALL(*session_, OnProofValid(testing::_)); EXPECT_CALL(*session_, OnProofVerifyDetailsAvailable(testing::_)) .Times(testing::AnyNumber()); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.cc b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.cc index 66f82298476..6c840671daf 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.cc @@ -8,6 +8,7 @@ #include <string> #include "third_party/boringssl/src/include/openssl/sha.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h" #include "net/third_party/quiche/src/common/platform/api/quiche_arraysize.h" #include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" #include "net/third_party/quiche/src/common/platform/api/quiche_text_utils.h" @@ -298,6 +299,11 @@ bool QuicCryptoServerStream::IsZeroRtt() const { num_handshake_messages_with_server_nonces_ == 0; } +bool QuicCryptoServerStream::IsResumption() const { + // QUIC Crypto doesn't have a non-0-RTT resumption mode. + return IsZeroRtt(); +} + int QuicCryptoServerStream::NumServerConfigUpdateMessagesSent() const { return num_server_config_update_messages_sent_; } @@ -307,7 +313,7 @@ QuicCryptoServerStream::PreviousCachedNetworkParams() const { return previous_cached_network_params_.get(); } -bool QuicCryptoServerStream::ZeroRttAttempted() const { +bool QuicCryptoServerStream::ResumptionAttempted() const { return zero_rtt_attempted_; } @@ -370,6 +376,12 @@ HandshakeState QuicCryptoServerStream::GetHandshakeState() const { return one_rtt_packet_decrypted_ ? HANDSHAKE_COMPLETE : HANDSHAKE_START; } +void QuicCryptoServerStream::SetServerApplicationStateForResumption( + std::unique_ptr<ApplicationState> /*state*/) { + // QUIC Crypto doesn't need to remember any application state as part of doing + // 0-RTT resumption, so this function is a no-op. +} + size_t QuicCryptoServerStream::BufferSizeLimitForLevel( EncryptionLevel level) const { return QuicCryptoHandshaker::BufferSizeLimitForLevel(level); @@ -389,6 +401,17 @@ void QuicCryptoServerStream::ProcessClientHello( nullptr); return; } + + if (GetQuicReloadableFlag(quic_save_user_agent_in_quic_session)) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_save_user_agent_in_quic_session, 1, 3); + quiche::QuicheStringPiece user_agent_id; + message.GetStringPiece(quic::kUAID, &user_agent_id); + if (!session()->user_agent_id().has_value()) { + std::string uaid = user_agent_id.empty() ? "" : user_agent_id.data(); + session()->SetUserAgentId(std::move(uaid)); + } + } + if (!result->info.server_nonce.empty()) { ++num_handshake_messages_with_server_nonces_; } diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.h b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.h index 52d4874994d..9ed7764a078 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.h @@ -35,9 +35,10 @@ class QUIC_EXPORT_PRIVATE QuicCryptoServerStream void SendServerConfigUpdate( const CachedNetworkParameters* cached_network_params) override; bool IsZeroRtt() const override; + bool IsResumption() const override; + bool ResumptionAttempted() const override; int NumServerConfigUpdateMessagesSent() const override; const CachedNetworkParameters* PreviousCachedNetworkParams() const override; - bool ZeroRttAttempted() const override; void SetPreviousCachedNetworkParams( CachedNetworkParameters cached_network_params) override; void OnPacketDecrypted(EncryptionLevel level) override; @@ -55,6 +56,8 @@ class QUIC_EXPORT_PRIVATE QuicCryptoServerStream const override; CryptoMessageParser* crypto_message_parser() override; HandshakeState GetHandshakeState() const override; + void SetServerApplicationStateForResumption( + std::unique_ptr<ApplicationState> state) override; size_t BufferSizeLimitForLevel(EncryptionLevel level) const override; // From QuicCryptoHandshaker diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream_base.h b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream_base.h index cdf12a3143d..540b7a42174 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream_base.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream_base.h @@ -62,8 +62,17 @@ class QUIC_EXPORT_PRIVATE QuicCryptoServerStreamBase : public QuicCryptoStream { virtual void SendServerConfigUpdate( const CachedNetworkParameters* cached_network_params) = 0; + // Returns true if the connection was a successful 0-RTT resumption. virtual bool IsZeroRtt() const = 0; - virtual bool ZeroRttAttempted() const = 0; + + // Returns true if the connection was the result of a resumption handshake, + // whether 0-RTT or not. + virtual bool IsResumption() const = 0; + + // Returns true if the client attempted a resumption handshake, whether or not + // the resumption actually occurred. + virtual bool ResumptionAttempted() const = 0; + virtual const CachedNetworkParameters* PreviousCachedNetworkParams() const = 0; virtual void SetPreviousCachedNetworkParams( diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream_test.cc index debfc3b0f52..9ff7dc05d47 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream_test.cc @@ -226,7 +226,7 @@ TEST_F(QuicCryptoServerStreamTest, ZeroRTT) { // Do a first handshake in order to prime the client config with the server's // information. AdvanceHandshakeWithFakeClient(); - EXPECT_FALSE(server_stream()->ZeroRttAttempted()); + EXPECT_FALSE(server_stream()->ResumptionAttempted()); // Now do another handshake, hopefully in 0-RTT. QUIC_LOG(INFO) << "Resetting for 0-RTT handshake attempt"; @@ -247,7 +247,7 @@ TEST_F(QuicCryptoServerStreamTest, ZeroRTT) { client_connection_, client_stream(), server_connection_, server_stream()); EXPECT_EQ(1, client_stream()->num_sent_client_hellos()); - EXPECT_TRUE(server_stream()->ZeroRttAttempted()); + EXPECT_TRUE(server_stream()->ResumptionAttempted()); } TEST_F(QuicCryptoServerStreamTest, FailByPolicy) { diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream.cc b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream.cc index 20704fb627a..59a012224e8 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream.cc @@ -268,6 +268,12 @@ void QuicCryptoStream::WritePendingCryptoRetransmission() { level, pending.length, pending.offset, HANDSHAKE_RETRANSMISSION); send_buffer->OnStreamDataRetransmitted(pending.offset, bytes_consumed); if (bytes_consumed < pending.length) { + if (GetQuicReloadableFlag( + quic_fix_write_pending_crypto_retransmission)) { + QUIC_RELOADABLE_FLAG_COUNT( + quic_fix_write_pending_crypto_retransmission); + return; + } break; } } diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream.h b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream.h index 49d37042390..54d1b2525c2 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream.h @@ -100,6 +100,21 @@ class QUIC_EXPORT_PRIVATE QuicCryptoStream : public QuicStream { // Returns current handshake state. virtual HandshakeState GetHandshakeState() const = 0; + // Called to provide the server-side application state that must be checked + // when performing a 0-RTT TLS resumption. + // + // On a client, this may be called at any time; 0-RTT tickets will not be + // cached until this function is called. When a 0-RTT resumption is attempted, + // QuicSession::SetApplicationState will be called with the state provided by + // a call to this function on a previous connection. + // + // On a server, this function must be called before commencing the handshake, + // otherwise 0-RTT tickets will not be issued. On subsequent connections, + // 0-RTT will be rejected if the data passed into this function does not match + // the data passed in on the connection where the 0-RTT ticket was issued. + virtual void SetServerApplicationStateForResumption( + std::unique_ptr<ApplicationState> state) = 0; + // Returns the maximum number of bytes that can be buffered at a particular // encryption level |level|. virtual size_t BufferSizeLimitForLevel(EncryptionLevel level) const; diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream_test.cc index 5f414e6a98a..f763d2d4782 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream_test.cc @@ -61,6 +61,8 @@ class MockQuicCryptoStream : public QuicCryptoStream, void OnHandshakePacketSent() override {} void OnHandshakeDoneReceived() override {} HandshakeState GetHandshakeState() const override { return HANDSHAKE_START; } + void SetServerApplicationStateForResumption( + std::unique_ptr<ApplicationState> /*application_state*/) override {} private: QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params_; @@ -419,7 +421,7 @@ TEST_F(QuicCryptoStreamTest, RetransmitStreamData) { .WillOnce(InvokeWithoutArgs([this]() { return session_.ConsumeData( QuicUtils::GetCryptoStreamId(connection_->transport_version()), 150, - 1350, NO_FIN, HANDSHAKE_RETRANSMISSION, QuicheNullOpt); + 1350, NO_FIN, HANDSHAKE_RETRANSMISSION, QUICHE_NULLOPT); })); EXPECT_FALSE(stream_->RetransmitStreamData(1350, 1350, false, diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_default_packet_writer.cc b/chromium/net/third_party/quiche/src/quic/core/quic_default_packet_writer.cc index 42220050885..b34bed49fcf 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_default_packet_writer.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_default_packet_writer.cc @@ -54,10 +54,10 @@ bool QuicDefaultPacketWriter::IsBatchMode() const { return false; } -char* QuicDefaultPacketWriter::GetNextWriteLocation( +QuicPacketBuffer QuicDefaultPacketWriter::GetNextWriteLocation( const QuicIpAddress& /*self_address*/, const QuicSocketAddress& /*peer_address*/) { - return nullptr; + return {nullptr, nullptr}; } WriteResult QuicDefaultPacketWriter::Flush() { diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_default_packet_writer.h b/chromium/net/third_party/quiche/src/quic/core/quic_default_packet_writer.h index 36d4d8aa267..5388cae2314 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_default_packet_writer.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_default_packet_writer.h @@ -35,8 +35,9 @@ class QUIC_EXPORT_PRIVATE QuicDefaultPacketWriter : public QuicPacketWriter { const QuicSocketAddress& peer_address) const override; bool SupportsReleaseTime() const override; bool IsBatchMode() const override; - char* GetNextWriteLocation(const QuicIpAddress& self_address, - const QuicSocketAddress& peer_address) override; + QuicPacketBuffer GetNextWriteLocation( + const QuicIpAddress& self_address, + const QuicSocketAddress& peer_address) override; WriteResult Flush() override; void set_fd(int fd) { fd_ = fd; } diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.cc b/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.cc index c0d39700f41..afdec636120 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.cc @@ -68,9 +68,9 @@ class PacketCollector : public QuicPacketCreator::DelegateInterface, serialized_packet.encrypted_length, true)); } - char* GetPacketBuffer() override { + QuicPacketBuffer GetPacketBuffer() override { // Let QuicPacketCreator to serialize packets on stack buffer. - return nullptr; + return {nullptr, nullptr}; } void OnUnrecoverableError(QuicErrorCode /*error*/, @@ -181,21 +181,113 @@ class StatelessConnectionTerminator { // Class which extracts the ALPN from a QUIC_CRYPTO CHLO packet. class ChloAlpnExtractor : public ChloExtractor::Delegate { public: - void OnChlo(QuicTransportVersion /*version*/, + void OnChlo(QuicTransportVersion version, QuicConnectionId /*server_connection_id*/, const CryptoHandshakeMessage& chlo) override { quiche::QuicheStringPiece alpn_value; if (chlo.GetStringPiece(kALPN, &alpn_value)) { alpn_ = std::string(alpn_value); } + if (GetQuicReloadableFlag(quic_dispatcher_legacy_version_encapsulation)) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_dispatcher_legacy_version_encapsulation, + 1, 3); + if (version == LegacyVersionForEncapsulation().transport_version) { + quiche::QuicheStringPiece qlve_value; + if (chlo.GetStringPiece(kQLVE, &qlve_value)) { + legacy_version_encapsulation_inner_packet_ = std::string(qlve_value); + } + } + } } std::string&& ConsumeAlpn() { return std::move(alpn_); } + std::string&& ConsumeLegacyVersionEncapsulationInnerPacket() { + DCHECK(GetQuicReloadableFlag(quic_dispatcher_legacy_version_encapsulation)); + return std::move(legacy_version_encapsulation_inner_packet_); + } + private: std::string alpn_; + std::string legacy_version_encapsulation_inner_packet_; }; +bool MaybeHandleLegacyVersionEncapsulation( + QuicDispatcher* dispatcher, + ChloAlpnExtractor* alpn_extractor, + const ReceivedPacketInfo& packet_info) { + DCHECK(GetQuicReloadableFlag(quic_dispatcher_legacy_version_encapsulation)); + std::string legacy_version_encapsulation_inner_packet = + alpn_extractor->ConsumeLegacyVersionEncapsulationInnerPacket(); + if (legacy_version_encapsulation_inner_packet.empty()) { + // This CHLO did not contain the Legacy Version Encapsulation tag. + return false; + } + PacketHeaderFormat format; + QuicLongHeaderType long_packet_type; + bool version_present; + bool has_length_prefix; + QuicVersionLabel version_label; + ParsedQuicVersion parsed_version = ParsedQuicVersion::Unsupported(); + QuicConnectionId destination_connection_id, source_connection_id; + bool retry_token_present; + quiche::QuicheStringPiece retry_token; + std::string detailed_error; + const QuicErrorCode error = QuicFramer::ParsePublicHeaderDispatcher( + QuicEncryptedPacket(legacy_version_encapsulation_inner_packet.data(), + legacy_version_encapsulation_inner_packet.length()), + kQuicDefaultConnectionIdLength, &format, &long_packet_type, + &version_present, &has_length_prefix, &version_label, &parsed_version, + &destination_connection_id, &source_connection_id, &retry_token_present, + &retry_token, &detailed_error); + if (error != QUIC_NO_ERROR) { + QUIC_DLOG(ERROR) + << "Failed to parse Legacy Version Encapsulation inner packet:" + << detailed_error; + return false; + } + if (destination_connection_id != packet_info.destination_connection_id) { + // We enforce that the inner and outer connection IDs match to make sure + // this never impacts routing of packets. + QUIC_DLOG(ERROR) << "Ignoring Legacy Version Encapsulation packet " + "with mismatched connection ID " + << destination_connection_id << " vs " + << packet_info.destination_connection_id; + return false; + } + if (legacy_version_encapsulation_inner_packet.length() >= + packet_info.packet.length()) { + QUIC_BUG << "Inner packet cannot be larger than outer " + << legacy_version_encapsulation_inner_packet.length() << " vs " + << packet_info.packet.length(); + return false; + } + + QUIC_DVLOG(1) << "Extracted a Legacy Version Encapsulation " + << legacy_version_encapsulation_inner_packet.length() + << " byte packet of version " << parsed_version; + + // Append zeroes to the end of the packet. This will ensure that + // we use the right number of bytes for calculating anti-amplification + // limits. Note that this only works for long headers of versions that carry + // long header lengths, since they'll ignore any trailing zeroes. We still + // do this for all packets to ensure version negotiation works. + legacy_version_encapsulation_inner_packet.append( + packet_info.packet.length() - + legacy_version_encapsulation_inner_packet.length(), + 0x00); + + // Process the inner packet as if it had been received by itself. + QuicReceivedPacket received_encapsulated_packet( + legacy_version_encapsulation_inner_packet.data(), + legacy_version_encapsulation_inner_packet.length(), + packet_info.packet.receipt_time()); + dispatcher->ProcessPacket(packet_info.self_address, packet_info.peer_address, + received_encapsulated_packet); + QUIC_CODE_COUNT(quic_legacy_version_encapsulation_decapsulated); + return true; +} + } // namespace QuicDispatcher::QuicDispatcher( @@ -307,30 +399,54 @@ void QuicDispatcher::ProcessPacket(const QuicSocketAddress& self_address, } QuicConnectionId QuicDispatcher::MaybeReplaceServerConnectionId( - QuicConnectionId server_connection_id, - ParsedQuicVersion version) const { - if (server_connection_id.length() == expected_server_connection_id_length_) { + const QuicConnectionId& server_connection_id, + const ParsedQuicVersion& version) const { + const uint8_t server_connection_id_length = server_connection_id.length(); + if (server_connection_id_length == expected_server_connection_id_length_) { return server_connection_id; } DCHECK(version.AllowsVariableLengthConnectionIds()); - - QuicConnectionId new_connection_id = - GenerateNewServerConnectionId(version, server_connection_id); + QuicConnectionId new_connection_id; + if (server_connection_id_length < expected_server_connection_id_length_) { + new_connection_id = ReplaceShortServerConnectionId( + version, server_connection_id, expected_server_connection_id_length_); + // Verify that ReplaceShortServerConnectionId is deterministic. + DCHECK_EQ(new_connection_id, ReplaceShortServerConnectionId( + version, server_connection_id, + expected_server_connection_id_length_)); + } else { + new_connection_id = ReplaceLongServerConnectionId( + version, server_connection_id, expected_server_connection_id_length_); + // Verify that ReplaceLongServerConnectionId is deterministic. + DCHECK_EQ(new_connection_id, ReplaceLongServerConnectionId( + version, server_connection_id, + expected_server_connection_id_length_)); + } DCHECK_EQ(expected_server_connection_id_length_, new_connection_id.length()); - // Verify that GenerateNewServerConnectionId is deterministic. - DCHECK_EQ(new_connection_id, - GenerateNewServerConnectionId(version, server_connection_id)); - QUIC_DLOG(INFO) << "Replacing incoming connection ID " << server_connection_id << " with " << new_connection_id; return new_connection_id; } -QuicConnectionId QuicDispatcher::GenerateNewServerConnectionId( - ParsedQuicVersion /*version*/, - QuicConnectionId connection_id) const { - return QuicUtils::CreateReplacementConnectionId(connection_id); +QuicConnectionId QuicDispatcher::ReplaceShortServerConnectionId( + const ParsedQuicVersion& /*version*/, + const QuicConnectionId& server_connection_id, + uint8_t expected_server_connection_id_length) const { + DCHECK_LT(server_connection_id.length(), + expected_server_connection_id_length); + return QuicUtils::CreateReplacementConnectionId( + server_connection_id, expected_server_connection_id_length); +} + +QuicConnectionId QuicDispatcher::ReplaceLongServerConnectionId( + const ParsedQuicVersion& /*version*/, + const QuicConnectionId& server_connection_id, + uint8_t expected_server_connection_id_length) const { + DCHECK_GT(server_connection_id.length(), + expected_server_connection_id_length); + return QuicUtils::CreateReplacementConnectionId( + server_connection_id, expected_server_connection_id_length); } bool QuicDispatcher::MaybeDispatchPacket( @@ -367,6 +483,26 @@ bool QuicDispatcher::MaybeDispatchPacket( auto it = session_map_.find(server_connection_id); if (it != session_map_.end()) { DCHECK(!buffered_packets_.HasBufferedPackets(server_connection_id)); + if (GetQuicReloadableFlag(quic_dispatcher_legacy_version_encapsulation)) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_dispatcher_legacy_version_encapsulation, + 2, 3); + if (packet_info.version_flag && + packet_info.version != it->second->version() && + packet_info.version == LegacyVersionForEncapsulation()) { + // This packet is using the Legacy Version Encapsulation version but the + // corresponding session isn't, attempt extraction of inner packet. + ChloAlpnExtractor alpn_extractor; + if (ChloExtractor::Extract(packet_info.packet, packet_info.version, + config_->create_session_tag_indicators(), + &alpn_extractor, + server_connection_id.length())) { + if (MaybeHandleLegacyVersionEncapsulation(this, &alpn_extractor, + packet_info)) { + return true; + } + } + } + } it->second->ProcessUdpPacket(packet_info.self_address, packet_info.peer_address, packet_info.packet); return true; @@ -521,6 +657,29 @@ void QuicDispatcher::ProcessHeader(ReceivedPacketInfo* packet_info) { BufferEarlyPacket(*packet_info); break; } + if (GetQuicReloadableFlag(quic_dont_pad_chlo)) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_dont_pad_chlo, 2, 2); + // We only apply this check for versions that do not use the IETF + // invariant header because those versions are already checked in + // QuicDispatcher::MaybeDispatchPacket. + if (packet_info->version_flag && + !packet_info->version.HasIetfInvariantHeader() && + crypto_config()->validate_chlo_size() && + packet_info->packet.length() < kMinClientInitialPacketLength) { + QUIC_DVLOG(1) << "Dropping CHLO packet which is too short, length: " + << packet_info->packet.length(); + QUIC_CODE_COUNT(quic_drop_small_chlo_packets); + break; + } + } + if (GetQuicReloadableFlag(quic_dispatcher_legacy_version_encapsulation)) { + QUIC_RELOADABLE_FLAG_COUNT_N( + quic_dispatcher_legacy_version_encapsulation, 3, 3); + if (MaybeHandleLegacyVersionEncapsulation(this, &alpn_extractor, + *packet_info)) { + break; + } + } ProcessChlo({alpn_extractor.ConsumeAlpn()}, packet_info); } break; case kFateTimeWait: @@ -568,36 +727,6 @@ std::string QuicDispatcher::SelectAlpn(const std::vector<std::string>& alpns) { QuicDispatcher::QuicPacketFate QuicDispatcher::ValidityChecks( const ReceivedPacketInfo& packet_info) { if (!packet_info.version_flag) { - // The Android network conformance test contains a UDP test that sends a - // 12-byte packet with the following format: - // - 0x0c (public flags: 8-byte connection ID, 1-byte packet number) - // - randomized 8-byte connection ID - // - 0x01 (1-byte packet number) - // - 0x00 (private flags) - // - 0x07 (PING frame). - // That packet is invalid and we would normally drop it but in order to - // unblock this conformance testing we have the following workaround that - // will be removed once the fixed test is deployed. - // TODO(b/139691956) Remove this workaround once fixed test is deployed. - if (!GetQuicReloadableFlag( - quic_remove_android_conformance_test_workaround) && - packet_info.packet.length() == 12 && - packet_info.packet.data()[0] == 0x0c && - packet_info.packet.data()[9] == 0x01 && - packet_info.packet.data()[10] == 0x00 && - packet_info.packet.data()[11] == 0x07) { - QUIC_DLOG(INFO) << "Received Android UDP network conformance test " - "packet with connection ID " - << packet_info.destination_connection_id; - // Respond with a public reset that the test will know how to parse - // then return kFateDrop to stop processing of this packet. - time_wait_list_manager()->SendPublicReset( - packet_info.self_address, packet_info.peer_address, - packet_info.destination_connection_id, - /*ietf_quic=*/false, GetPerPacketContext()); - return kFateDrop; - } - QUIC_DLOG(INFO) << "Packet without version arrived for unknown connection ID " << packet_info.destination_connection_id; @@ -884,8 +1013,8 @@ void QuicDispatcher::ProcessBufferedChlos(size_t max_connections_to_create) { CreateQuicSession(server_connection_id, packets.front().peer_address, alpn, packet_list.version); if (original_connection_id != server_connection_id) { - session->connection()->AddIncomingConnectionId(original_connection_id); - session->connection()->InstallInitialCrypters(original_connection_id); + session->connection()->SetOriginalDestinationConnectionId( + original_connection_id); } QUIC_DLOG(INFO) << "Created new session for " << server_connection_id; @@ -976,10 +1105,16 @@ void QuicDispatcher::ProcessChlo(const std::vector<std::string>& alpns, std::unique_ptr<QuicSession> session = CreateQuicSession(packet_info->destination_connection_id, packet_info->peer_address, alpn, packet_info->version); - DCHECK(session); + if (QUIC_PREDICT_FALSE(session == nullptr)) { + QUIC_BUG << "CreateQuicSession returned nullptr for " + << packet_info->destination_connection_id << " from " + << packet_info->peer_address << " ALPN \"" << alpn << "\" version " + << packet_info->version; + return; + } if (original_connection_id != packet_info->destination_connection_id) { - session->connection()->AddIncomingConnectionId(original_connection_id); - session->connection()->InstallInitialCrypters(original_connection_id); + session->connection()->SetOriginalDestinationConnectionId( + original_connection_id); } QUIC_DLOG(INFO) << "Created new session for " << packet_info->destination_connection_id; diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.h b/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.h index 73ab3ec4fd0..f0c35eae152 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.h @@ -103,30 +103,17 @@ class QUIC_NO_EXPORT QuicDispatcher void OnConnectionAddedToTimeWaitList( QuicConnectionId server_connection_id) override; - using SessionMap = QuicUnorderedMap<QuicConnectionId, - std::unique_ptr<QuicSession>, - QuicConnectionIdHash>; + using SessionMap = QuicHashMap<QuicConnectionId, + std::unique_ptr<QuicSession>, + QuicConnectionIdHash>; const SessionMap& session_map() const { return session_map_; } // Deletes all sessions on the closed session list and clears the list. virtual void DeleteSessions(); - using ConnectionIdMap = QuicUnorderedMap<QuicConnectionId, - QuicConnectionId, - QuicConnectionIdHash>; - - // The largest packet number we expect to receive with a connection - // ID for a connection that is not established yet. The current design will - // send a handshake and then up to 50 or so data packets, and then it may - // resend the handshake packet up to 10 times. (Retransmitted packets are - // sent with unique packet numbers.) - static const uint64_t kMaxReasonableInitialPacketNumber = 100; - static_assert(kMaxReasonableInitialPacketNumber >= - kInitialCongestionWindow + 10, - "kMaxReasonableInitialPacketNumber is unreasonably small " - "relative to kInitialCongestionWindow."); - + using ConnectionIdMap = + QuicHashMap<QuicConnectionId, QuicConnectionId, QuicConnectionIdHash>; // QuicBufferedPacketStore::VisitorInterface implementation. void OnExpiredPackets(QuicConnectionId server_connection_id, @@ -162,11 +149,29 @@ class QUIC_NO_EXPORT QuicDispatcher virtual bool MaybeDispatchPacket(const ReceivedPacketInfo& packet_info); // Generate a connection ID with a length that is expected by the dispatcher. + // Called only when |server_connection_id| is shorter than + // |expected_connection_id_length|. // Note that this MUST produce a deterministic result (calling this method // with two connection IDs that are equal must produce the same result). - virtual QuicConnectionId GenerateNewServerConnectionId( - ParsedQuicVersion version, - QuicConnectionId connection_id) const; + // Note that this is not used in general operation because our default + // |expected_server_connection_id_length| is 8, and the IETF specification + // requires clients to use an initial length of at least 8. However, we + // allow disabling that requirement via + // |allow_short_initial_server_connection_ids_|. + virtual QuicConnectionId ReplaceShortServerConnectionId( + const ParsedQuicVersion& version, + const QuicConnectionId& server_connection_id, + uint8_t expected_server_connection_id_length) const; + + // Generate a connection ID with a length that is expected by the dispatcher. + // Called only when |server_connection_id| is longer than + // |expected_connection_id_length|. + // Note that this MUST produce a deterministic result (calling this method + // with two connection IDs that are equal must produce the same result). + virtual QuicConnectionId ReplaceLongServerConnectionId( + const ParsedQuicVersion& version, + const QuicConnectionId& server_connection_id, + uint8_t expected_server_connection_id_length) const; // Values to be returned by ValidityChecks() to indicate what should be done // with a packet. Fates with greater values are considered to be higher @@ -308,11 +313,12 @@ class QUIC_NO_EXPORT QuicDispatcher std::string SelectAlpn(const std::vector<std::string>& alpns); // If the connection ID length is different from what the dispatcher expects, - // replace the connection ID with a random one of the right length, - // and save it to make sure the mapping is persistent. + // replace the connection ID with one of the right length. + // Note that this MUST produce a deterministic result (calling this method + // with two connection IDs that are equal must produce the same result). QuicConnectionId MaybeReplaceServerConnectionId( - QuicConnectionId server_connection_id, - ParsedQuicVersion version) const; + const QuicConnectionId& server_connection_id, + const ParsedQuicVersion& version) const; private: friend class test::QuicDispatcherPeer; diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher_test.cc index 814462e9d01..ef4190d470a 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher_test.cc @@ -580,6 +580,73 @@ TEST_P(QuicDispatcherTestAllVersions, TlsMultiPacketClientHelloWithReordering) { TestTlsMultiPacketClientHello(/*add_reordering=*/true); } +TEST_P(QuicDispatcherTestAllVersions, LegacyVersionEncapsulation) { + if (!version_.HasLongHeaderLengths()) { + // Decapsulating Legacy Version Encapsulation packets from these versions + // is not currently supported in QuicDispatcher. + return; + } + SetQuicReloadableFlag(quic_dont_pad_chlo, true); + SetQuicReloadableFlag(quic_dispatcher_legacy_version_encapsulation, true); + QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); + QuicConnectionId server_connection_id = TestConnectionId(); + QuicConfig client_config = DefaultQuicConfig(); + client_config.SetClientConnectionOptions(QuicTagVector{kQLVE}); + std::vector<std::unique_ptr<QuicReceivedPacket>> packets = + GetFirstFlightOfPackets(version_, client_config, server_connection_id); + ASSERT_EQ(packets.size(), 1u); + + // Validate that Legacy Version Encapsulation is actually being used by + // checking the version of the packet before processing it. + PacketHeaderFormat format = IETF_QUIC_LONG_HEADER_PACKET; + QuicLongHeaderType long_packet_type; + bool version_present; + bool has_length_prefix; + QuicVersionLabel version_label; + ParsedQuicVersion parsed_version = ParsedQuicVersion::Unsupported(); + QuicConnectionId destination_connection_id, source_connection_id; + bool retry_token_present; + quiche::QuicheStringPiece retry_token; + std::string detailed_error; + const QuicErrorCode error = QuicFramer::ParsePublicHeaderDispatcher( + QuicEncryptedPacket(packets[0]->data(), packets[0]->length()), + kQuicDefaultConnectionIdLength, &format, &long_packet_type, + &version_present, &has_length_prefix, &version_label, &parsed_version, + &destination_connection_id, &source_connection_id, &retry_token_present, + &retry_token, &detailed_error); + ASSERT_THAT(error, IsQuicNoError()) << detailed_error; + EXPECT_EQ(format, GOOGLE_QUIC_PACKET); + EXPECT_TRUE(version_present); + EXPECT_FALSE(has_length_prefix); + EXPECT_EQ(parsed_version, LegacyVersionForEncapsulation()); + EXPECT_EQ(destination_connection_id, server_connection_id); + EXPECT_EQ(source_connection_id, EmptyQuicConnectionId()); + EXPECT_FALSE(retry_token_present); + EXPECT_TRUE(detailed_error.empty()); + + // Processing the packet should create a new session. + EXPECT_CALL(*dispatcher_, + CreateQuicSession(server_connection_id, client_address, + Eq(ExpectedAlpn()), _)) + .WillOnce(Return(ByMove(CreateSession( + dispatcher_.get(), config_, server_connection_id, client_address, + &mock_helper_, &mock_alarm_factory_, &crypto_config_, + QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)))); + EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()), + ProcessUdpPacket(_, _, _)) + .Times(2); + + ProcessReceivedPacket(packets[0]->Clone(), client_address, version_, + server_connection_id); + EXPECT_EQ(dispatcher_->session_map().size(), 1u); + + // Processing the same packet a second time should also be routed by the + // dispatcher to the right connection (we expect ProcessUdpPacket to be + // called twice, see the EXPECT_CALL above). + ProcessReceivedPacket(std::move(packets[0]), client_address, version_, + server_connection_id); +} + TEST_P(QuicDispatcherTestAllVersions, ProcessPackets) { QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); @@ -1010,57 +1077,20 @@ TEST_P(QuicDispatcherTestAllVersions, ProcessFirstFlight(client_address, EmptyQuicConnectionId()); } -TEST_P(QuicDispatcherTestAllVersions, OKSeqNoPacketProcessed) { - if (version_.UsesTls()) { - // QUIC+TLS allows clients to start with any packet number. - return; - } - QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); - QuicConnectionId connection_id = TestConnectionId(1); - - EXPECT_CALL(*dispatcher_, - CreateQuicSession(TestConnectionId(1), client_address, - Eq(ExpectedAlpn()), _)) - .WillOnce(Return(ByMove(CreateSession( - dispatcher_.get(), config_, TestConnectionId(1), client_address, - &mock_helper_, &mock_alarm_factory_, &crypto_config_, - QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)))); - EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()), - ProcessUdpPacket(_, _, _)) - .WillOnce(WithArg<2>(Invoke([this](const QuicEncryptedPacket& packet) { - ValidatePacket(TestConnectionId(1), packet); - }))); - - // A packet whose packet number is the largest that is allowed to start a - // connection. - EXPECT_CALL(*dispatcher_, - ShouldCreateOrBufferPacketForConnection( - ReceivedPacketInfoConnectionIdEquals(connection_id))); - ProcessPacket(client_address, connection_id, true, SerializeCHLO(), - CONNECTION_ID_PRESENT, PACKET_4BYTE_PACKET_NUMBER, - QuicDispatcher::kMaxReasonableInitialPacketNumber); -} - TEST_P(QuicDispatcherTestOneVersion, VersionsChangeInFlight) { VerifyVersionNotSupported(QuicVersionReservedForNegotiation()); for (ParsedQuicVersion version : CurrentSupportedVersions()) { VerifyVersionSupported(version); + QuicDisableVersion(version); + VerifyVersionNotSupported(version); + QuicEnableVersion(version); + VerifyVersionSupported(version); } - - // Turn off version Q050. - SetQuicReloadableFlag(quic_disable_version_q050, true); - VerifyVersionNotSupported( - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50)); - - // Turn on version Q050. - SetQuicReloadableFlag(quic_disable_version_q050, false); - VerifyVersionSupported( - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50)); } TEST_P(QuicDispatcherTestOneVersion, RejectDeprecatedVersionsWithVersionNegotiation) { - static_assert(quic::SupportedVersions().size() == 8u, + static_assert(quic::SupportedVersions().size() == 9u, "Please add deprecated versions to this test"); QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); CreateTimeWaitListManager(); @@ -1275,55 +1305,6 @@ TEST_P(QuicDispatcherTestOneVersion, VersionNegotiationProbeEndToEnd) { destination_connection_id_bytes, sizeof(destination_connection_id_bytes)); } -TEST_P(QuicDispatcherTestOneVersion, AndroidConformanceTestOld) { - if (GetQuicReloadableFlag(quic_remove_android_conformance_test_workaround)) { - // TODO(b/139691956) Remove this test once the flag is deprecated. - return; - } - SavingWriter* saving_writer = new SavingWriter(); - // dispatcher_ takes ownership of saving_writer. - QuicDispatcherPeer::UseWriter(dispatcher_.get(), saving_writer); - - QuicTimeWaitListManager* time_wait_list_manager = new QuicTimeWaitListManager( - saving_writer, dispatcher_.get(), mock_helper_.GetClock(), - &mock_alarm_factory_); - // dispatcher_ takes ownership of time_wait_list_manager. - QuicDispatcherPeer::SetTimeWaitListManager(dispatcher_.get(), - time_wait_list_manager); - // clang-format off - static const unsigned char packet[] = { - // Android UDP network conformance test packet as it was before this change: - // https://android-review.googlesource.com/c/platform/cts/+/1104285 - 0x0c, // public flags: 8-byte connection ID, 1-byte packet number - 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, // 8-byte connection ID - 0x01, // 1-byte packet number - 0x00, // private flags - 0x07, // PING frame - }; - // clang-format on - - QuicEncryptedPacket encrypted(reinterpret_cast<const char*>(packet), - sizeof(packet), false); - std::unique_ptr<QuicReceivedPacket> received_packet( - ConstructReceivedPacket(encrypted, mock_helper_.GetClock()->Now())); - EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, _, _)).Times(0); - - QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); - dispatcher_->ProcessPacket(server_address_, client_address, *received_packet); - ASSERT_EQ(1u, saving_writer->packets()->size()); - - // The Android UDP network conformance test directly checks that bytes 1-9 - // of the response match the connection ID that was sent. - static const char connection_id_bytes[] = {0x71, 0x72, 0x73, 0x74, - 0x75, 0x76, 0x77, 0x78}; - ASSERT_GE((*(saving_writer->packets()))[0]->length(), - 1u + sizeof(connection_id_bytes)); - quiche::test::CompareCharArraysWithHexError( - "response connection ID", &(*(saving_writer->packets()))[0]->data()[1], - sizeof(connection_id_bytes), connection_id_bytes, - sizeof(connection_id_bytes)); -} - TEST_P(QuicDispatcherTestOneVersion, AndroidConformanceTest) { // WARNING: do not remove or modify this test without making sure that we // still have adequate coverage for the Android conformance test. @@ -1373,8 +1354,12 @@ TEST_P(QuicDispatcherTestOneVersion, AndroidConformanceTest) { } TEST_P(QuicDispatcherTestAllVersions, DoNotProcessSmallPacket) { - if (!version_.HasIetfInvariantHeader()) { - // We only drop small packets when using IETF_QUIC_LONG_HEADER_PACKET. + if (!version_.HasIetfInvariantHeader() && + !GetQuicReloadableFlag(quic_dont_pad_chlo)) { + // When quic_dont_pad_chlo is false, we only drop small packets when using + // IETF_QUIC_LONG_HEADER_PACKET. When quic_dont_pad_chlo is true, we drop + // small packets for all versions. + // TODO(dschinazi) remove this early return when we deprecate the flag. return; } CreateTimeWaitListManager(); @@ -2340,7 +2325,8 @@ TEST_P(BufferedPacketStoreTest, ReceiveCHLOForBufferedConnection) { // Regression test for b/117874922. TEST_P(BufferedPacketStoreTest, ProcessBufferedChloWithDifferentVersion) { // Ensure the preferred version is not supported by the server. - SetQuicReloadableFlag(quic_enable_version_draft_27, false); + QuicDisableVersion(AllSupportedVersions().front()); + uint64_t last_connection_id = kMaxNumSessionsToCreate + 5; ParsedQuicVersionVector supported_versions = CurrentSupportedVersions(); for (uint64_t conn_id = 1; conn_id <= last_connection_id; ++conn_id) { diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_error_codes.cc b/chromium/net/third_party/quiche/src/quic/core/quic_error_codes.cc index 6afccfece10..1c0984aae17 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_error_codes.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_error_codes.cc @@ -203,6 +203,8 @@ const char* QuicErrorCodeToString(QuicErrorCode error) { RETURN_STRING_LITERAL(QUIC_HTTP_DUPLICATE_SETTING_IDENTIFIER); RETURN_STRING_LITERAL(QUIC_HTTP_INVALID_MAX_PUSH_ID); RETURN_STRING_LITERAL(QUIC_HTTP_STREAM_LIMIT_TOO_LOW); + RETURN_STRING_LITERAL(QUIC_HTTP_ZERO_RTT_RESUMPTION_SETTINGS_MISMATCH); + RETURN_STRING_LITERAL(QUIC_HTTP_ZERO_RTT_REJECTION_SETTINGS_MISMATCH); RETURN_STRING_LITERAL(QUIC_HPACK_INDEX_VARINT_ERROR); RETURN_STRING_LITERAL(QUIC_HPACK_NAME_LENGTH_VARINT_ERROR); RETURN_STRING_LITERAL(QUIC_HPACK_VALUE_LENGTH_VARINT_ERROR); @@ -221,6 +223,9 @@ const char* QuicErrorCodeToString(QuicErrorCode error) { RETURN_STRING_LITERAL(QUIC_HPACK_TRUNCATED_BLOCK); RETURN_STRING_LITERAL(QUIC_HPACK_FRAGMENT_TOO_LONG); RETURN_STRING_LITERAL(QUIC_HPACK_COMPRESSED_HEADER_SIZE_EXCEEDS_LIMIT); + RETURN_STRING_LITERAL(QUIC_ZERO_RTT_UNRETRANSMITTABLE); + RETURN_STRING_LITERAL(QUIC_ZERO_RTT_REJECTION_LIMIT_REDUCED); + RETURN_STRING_LITERAL(QUIC_ZERO_RTT_RESUMPTION_LIMIT_REDUCED); RETURN_STRING_LITERAL(QUIC_LAST_ERROR); // Intentionally have no default case, so we'll break the build @@ -567,6 +572,10 @@ QuicErrorCodeToIetfMapping QuicErrorCodeToTransportErrorCode( case QUIC_HTTP_STREAM_LIMIT_TOO_LOW: return {false, static_cast<uint64_t>( QuicHttp3ErrorCode::GENERAL_PROTOCOL_ERROR)}; + case QUIC_HTTP_ZERO_RTT_RESUMPTION_SETTINGS_MISMATCH: + return {false, static_cast<uint64_t>(QuicHttp3ErrorCode::SETTINGS_ERROR)}; + case QUIC_HTTP_ZERO_RTT_REJECTION_SETTINGS_MISMATCH: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; case QUIC_HPACK_INDEX_VARINT_ERROR: return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; case QUIC_HPACK_NAME_LENGTH_VARINT_ERROR: @@ -599,6 +608,12 @@ QuicErrorCodeToIetfMapping QuicErrorCodeToTransportErrorCode( return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; case QUIC_HPACK_COMPRESSED_HEADER_SIZE_EXCEEDS_LIMIT: return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_ZERO_RTT_UNRETRANSMITTABLE: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_ZERO_RTT_REJECTION_LIMIT_REDUCED: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; + case QUIC_ZERO_RTT_RESUMPTION_LIMIT_REDUCED: + return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; case QUIC_LAST_ERROR: return {false, static_cast<uint64_t>(QUIC_LAST_ERROR)}; } diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_error_codes.h b/chromium/net/third_party/quiche/src/quic/core/quic_error_codes.h index f057fea1028..4c13f2c8382 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_error_codes.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_error_codes.h @@ -431,6 +431,12 @@ enum QuicErrorCode { QUIC_HTTP_INVALID_MAX_PUSH_ID = 159, // Received unidirectional stream limit is lower than required by HTTP/3. QUIC_HTTP_STREAM_LIMIT_TOO_LOW = 160, + // Received mismatched SETTINGS frame from HTTP/3 connection where early data + // is accepted. Server violated the HTTP/3 spec. + QUIC_HTTP_ZERO_RTT_RESUMPTION_SETTINGS_MISMATCH = 164, + // Received mismatched SETTINGS frame from HTTP/3 connection where early data + // is rejected. Our implementation currently doesn't support it. + QUIC_HTTP_ZERO_RTT_REJECTION_SETTINGS_MISMATCH = 165, // HPACK header block decoding errors. // Index varint beyond implementation limit. @@ -466,8 +472,20 @@ enum QuicErrorCode { // Total compressed HPACK data size exceeds limit. QUIC_HPACK_COMPRESSED_HEADER_SIZE_EXCEEDS_LIMIT = 150, + // Stream/flow control limit from 1-RTT handshake is too low to retransmit + // 0-RTT data. This is our implentation error. We could in theory keep the + // connection alive but chose not to for simplicity. + QUIC_ZERO_RTT_UNRETRANSMITTABLE = 161, + // Stream/flow control limit from 0-RTT rejection reduces cached limit. + // This is our implentation error. We could in theory keep the connection + // alive but chose not to for simplicity. + QUIC_ZERO_RTT_REJECTION_LIMIT_REDUCED = 162, + // Stream/flow control limit from 0-RTT resumption reduces cached limit. + // This is the peer violating QUIC spec. + QUIC_ZERO_RTT_RESUMPTION_LIMIT_REDUCED = 163, + // No error. Used as bound while iterating. - QUIC_LAST_ERROR = 161, + QUIC_LAST_ERROR = 166, }; // QuicErrorCodes is encoded as four octets on-the-wire when doing Google QUIC, // or a varint62 when doing IETF QUIC. Ensure that its value does not exceed diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_flow_controller.h b/chromium/net/third_party/quiche/src/quic/core/quic_flow_controller.h index 29c3c02d1a3..daad3d9d560 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_flow_controller.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_flow_controller.h @@ -91,6 +91,8 @@ class QUIC_EXPORT_PRIVATE QuicFlowController QuicByteCount bytes_consumed() const { return bytes_consumed_; } + QuicByteCount bytes_sent() const { return bytes_sent_; } + QuicStreamOffset send_window_offset() const { return send_window_offset_; } QuicStreamOffset highest_received_byte_offset() const { diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_framer.cc b/chromium/net/third_party/quiche/src/quic/core/quic_framer.cc index b05b4576d8e..139896560d6 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_framer.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_framer.cc @@ -6,6 +6,7 @@ #include <cstddef> #include <cstdint> +#include <limits> #include <memory> #include <string> #include <utility> @@ -20,6 +21,7 @@ #include "net/third_party/quiche/src/quic/core/crypto/quic_decrypter.h" #include "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h" #include "net/third_party/quiche/src/quic/core/crypto/quic_random.h" +#include "net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.h" #include "net/third_party/quiche/src/quic/core/quic_connection_id.h" #include "net/third_party/quiche/src/quic/core/quic_constants.h" #include "net/third_party/quiche/src/quic/core/quic_data_reader.h" @@ -28,6 +30,7 @@ #include "net/third_party/quiche/src/quic/core/quic_packets.h" #include "net/third_party/quiche/src/quic/core/quic_socket_address_coder.h" #include "net/third_party/quiche/src/quic/core/quic_stream_frame_data_producer.h" +#include "net/third_party/quiche/src/quic/core/quic_time.h" #include "net/third_party/quiche/src/quic/core/quic_types.h" #include "net/third_party/quiche/src/quic/core/quic_utils.h" #include "net/third_party/quiche/src/quic/core/quic_versions.h" @@ -622,6 +625,17 @@ size_t QuicFramer::GetStopSendingFrameSize(const QuicStopSendingFrame& frame) { } // static +size_t QuicFramer::GetAckFrequencyFrameSize( + const QuicAckFrequencyFrame& frame) { + return QuicDataWriter::GetVarInt62Len(IETF_ACK_FREQUENCY) + + QuicDataWriter::GetVarInt62Len(frame.sequence_number) + + QuicDataWriter::GetVarInt62Len(frame.packet_tolerance) + + QuicDataWriter::GetVarInt62Len(frame.max_ack_delay.ToMicroseconds()) + + // One byte for encoding boolean + 1; +} + +// static size_t QuicFramer::GetPathChallengeFrameSize( const QuicPathChallengeFrame& frame) { return kQuicFrameTypeSize + sizeof(frame.data_buffer); @@ -675,7 +689,8 @@ size_t QuicFramer::GetRetransmittableControlFrameSize( case HANDSHAKE_DONE_FRAME: // HANDSHAKE_DONE has no payload. return kQuicFrameTypeSize; - + case ACK_FREQUENCY_FRAME: + return GetAckFrequencyFrameSize(*frame.ack_frequency_frame); case STREAM_FRAME: case ACK_FRAME: case STOP_WAITING_FRAME: @@ -1013,6 +1028,9 @@ size_t QuicFramer::BuildDataPacket(const QuicPacketHeader& header, return 0; } break; + case HANDSHAKE_DONE_FRAME: + // HANDSHAKE_DONE has no payload. + break; default: RaiseError(QUIC_INVALID_FRAME_DATA); QUIC_BUG << "QUIC_INVALID_FRAME_DATA"; @@ -1034,8 +1052,8 @@ size_t QuicFramer::AppendIetfFrames(const QuicFrames& frames, for (const QuicFrame& frame : frames) { // Determine if we should write stream frame length in header. const bool last_frame_in_packet = i == frames.size() - 1; - if (!AppendIetfTypeByte(frame, last_frame_in_packet, writer)) { - QUIC_BUG << "AppendIetfTypeByte failed: " << detailed_error(); + if (!AppendIetfFrameType(frame, last_frame_in_packet, writer)) { + QUIC_BUG << "AppendIetfFrameType failed: " << detailed_error(); return 0; } @@ -1182,6 +1200,12 @@ size_t QuicFramer::AppendIetfFrames(const QuicFrames& frames, case HANDSHAKE_DONE_FRAME: // HANDSHAKE_DONE has no payload. break; + case ACK_FREQUENCY_FRAME: + if (!AppendAckFrequencyFrame(*frame.ack_frequency_frame, writer)) { + QUIC_BUG << "AppendAckFrequencyFrame failed: " << detailed_error(); + return 0; + } + break; default: set_detailed_error("Tried to append unknown frame type."); RaiseError(QUIC_INVALID_FRAME_DATA); @@ -2004,6 +2028,10 @@ bool QuicFramer::HasEncrypterOfEncryptionLevel(EncryptionLevel level) const { return encrypter_[level] != nullptr; } +bool QuicFramer::HasDecrypterOfEncryptionLevel(EncryptionLevel level) const { + return decrypter_[level] != nullptr; +} + bool QuicFramer::AppendPacketHeader(const QuicPacketHeader& header, QuicDataWriter* writer, size_t* length_field_offset) { @@ -2986,6 +3014,19 @@ bool QuicFramer::ProcessFrameData(QuicDataReader* reader, } break; } + case HANDSHAKE_DONE_FRAME: { + // HANDSHAKE_DONE has no payload. + QuicHandshakeDoneFrame handshake_done_frame; + QUIC_DVLOG(2) << ENDPOINT << "Processing handshake done frame " + << handshake_done_frame; + if (!visitor_->OnHandshakeDoneFrame(handshake_done_frame)) { + QUIC_DVLOG(1) << ENDPOINT + << "Visitor asked to stop further processing."; + // Returning true since there was no parsing error. + return true; + } + break; + } default: set_detailed_error("Illegal frame type."); @@ -3329,7 +3370,20 @@ bool QuicFramer::ProcessIetfFrameData(QuicDataReader* reader, << handshake_done_frame; break; } - + case IETF_ACK_FREQUENCY: { + QuicAckFrequencyFrame frame; + if (!ProcessAckFrequencyFrame(reader, &frame)) { + return RaiseError(QUIC_INVALID_FRAME_DATA); + } + QUIC_DVLOG(2) << ENDPOINT << "Processing IETF ack frequency frame " + << frame; + if (!visitor_->OnAckFrequencyFrame(frame)) { + QUIC_DVLOG(1) << "Visitor asked to stop further processing."; + // Returning true since there was no parsing error. + return true; + } + break; + } default: set_detailed_error("Illegal frame type."); QUIC_DLOG(WARNING) @@ -3509,6 +3563,47 @@ bool QuicFramer::ProcessCryptoFrame(QuicDataReader* reader, return true; } +bool QuicFramer::ProcessAckFrequencyFrame(QuicDataReader* reader, + QuicAckFrequencyFrame* frame) { + if (!reader->ReadVarInt62(&frame->sequence_number)) { + set_detailed_error("Unable to read sequence number."); + return false; + } + + if (!reader->ReadVarInt62(&frame->packet_tolerance)) { + set_detailed_error("Unable to read packet tolerance."); + return false; + } + if (frame->packet_tolerance == 0) { + set_detailed_error("Invalid packet tolerance."); + return false; + } + uint64_t max_ack_delay_us; + if (!reader->ReadVarInt62(&max_ack_delay_us)) { + set_detailed_error("Unable to read max_ack_delay_us."); + return false; + } + constexpr uint64_t kMaxAckDelayUsBound = 1u << 24; + if (max_ack_delay_us > kMaxAckDelayUsBound) { + set_detailed_error("Invalid max_ack_delay_us."); + return false; + } + frame->max_ack_delay = QuicTime::Delta::FromMicroseconds(max_ack_delay_us); + + uint8_t ignore_order; + if (!reader->ReadUInt8(&ignore_order)) { + set_detailed_error("Unable to read ignore_order."); + return false; + } + if (ignore_order > 1) { + set_detailed_error("Invalid ignore_order."); + return false; + } + frame->ignore_order = ignore_order; + + return true; +} + bool QuicFramer::ProcessAckFrame(QuicDataReader* reader, uint8_t frame_type) { const bool has_ack_blocks = ExtractBit(frame_type, kQuicHasMultipleAckBlocksOffset); @@ -4097,8 +4192,7 @@ void QuicFramer::SetDecrypter(EncryptionLevel level, DCHECK_GE(level, decrypter_level_); DCHECK(!version_.KnowsWhichDecrypterToUse()); QUIC_DVLOG(1) << ENDPOINT << "Setting decrypter from level " - << EncryptionLevelToString(decrypter_level_) << " to " - << EncryptionLevelToString(level); + << decrypter_level_ << " to " << level; decrypter_[decrypter_level_] = nullptr; decrypter_[level] = std::move(decrypter); decrypter_level_ = level; @@ -4111,8 +4205,7 @@ void QuicFramer::SetAlternativeDecrypter( DCHECK_NE(level, decrypter_level_); DCHECK(!version_.KnowsWhichDecrypterToUse()); QUIC_DVLOG(1) << ENDPOINT << "Setting alternative decrypter from level " - << EncryptionLevelToString(alternative_decrypter_level_) - << " to " << EncryptionLevelToString(level); + << alternative_decrypter_level_ << " to " << level; if (alternative_decrypter_level_ != NUM_ENCRYPTION_LEVELS) { decrypter_[alternative_decrypter_level_] = nullptr; } @@ -4124,15 +4217,13 @@ void QuicFramer::SetAlternativeDecrypter( void QuicFramer::InstallDecrypter(EncryptionLevel level, std::unique_ptr<QuicDecrypter> decrypter) { DCHECK(version_.KnowsWhichDecrypterToUse()); - QUIC_DVLOG(1) << ENDPOINT << "Installing decrypter at level " - << EncryptionLevelToString(level); + QUIC_DVLOG(1) << ENDPOINT << "Installing decrypter at level " << level; decrypter_[level] = std::move(decrypter); } void QuicFramer::RemoveDecrypter(EncryptionLevel level) { DCHECK(version_.KnowsWhichDecrypterToUse()); - QUIC_DVLOG(1) << ENDPOINT << "Removing decrypter at level " - << EncryptionLevelToString(level); + QUIC_DVLOG(1) << ENDPOINT << "Removing decrypter at level " << level; decrypter_[level] = nullptr; } @@ -4156,14 +4247,12 @@ void QuicFramer::SetEncrypter(EncryptionLevel level, std::unique_ptr<QuicEncrypter> encrypter) { DCHECK_GE(level, 0); DCHECK_LT(level, NUM_ENCRYPTION_LEVELS); - QUIC_DVLOG(1) << ENDPOINT << "Setting encrypter at level " - << EncryptionLevelToString(level); + QUIC_DVLOG(1) << ENDPOINT << "Setting encrypter at level " << level; encrypter_[level] = std::move(encrypter); } void QuicFramer::RemoveEncrypter(EncryptionLevel level) { - QUIC_DVLOG(1) << ENDPOINT << "Removing encrypter of " - << EncryptionLevelToString(level); + QUIC_DVLOG(1) << ENDPOINT << "Removing encrypter of " << level; encrypter_[level] = nullptr; } @@ -4185,7 +4274,7 @@ size_t QuicFramer::EncryptInPlace(EncryptionLevel level, if (encrypter_[level] == nullptr) { QUIC_BUG << ENDPOINT << "Attempted to encrypt in place without encrypter at level " - << EncryptionLevelToString(level); + << level; RaiseError(QUIC_ENCRYPTION_FAILURE); return 0; } @@ -4248,7 +4337,7 @@ bool QuicFramer::ApplyHeaderProtection(EncryptionLevel level, QUIC_BUG << ENDPOINT << "Attempted to apply header protection without encrypter at level " - << EncryptionLevelToString(level) << " using " << version_; + << level << " using " << version_; return false; } @@ -4318,7 +4407,7 @@ bool QuicFramer::RemoveHeaderProtection(QuicDataReader* reader, QUIC_DVLOG(1) << ENDPOINT << "No decrypter available for removing header protection at level " - << EncryptionLevelToString(expected_decryption_level); + << expected_decryption_level; return false; } @@ -4439,7 +4528,7 @@ size_t QuicFramer::EncryptPayload(EncryptionLevel level, DCHECK(packet_number.IsInitialized()); if (encrypter_[level] == nullptr) { QUIC_BUG << ENDPOINT << "Attempted to encrypt without encrypter at level " - << EncryptionLevelToString(level); + << level; RaiseError(QUIC_ENCRYPTION_FAILURE); return 0; } @@ -4449,6 +4538,14 @@ size_t QuicFramer::EncryptPayload(EncryptionLevel level, // Copy in the header, because the encrypter only populates the encrypted // plaintext content. const size_t ad_len = associated_data.length(); + if (packet.length() < ad_len) { + QUIC_BUG << ENDPOINT + << "packet is shorter than associated data length. version:" + << version() << ", packet length:" << packet.length() + << ", associated data length:" << ad_len; + RaiseError(QUIC_ENCRYPTION_FAILURE); + return 0; + } memmove(buffer, associated_data.data(), ad_len); // Encrypt the plaintext into the buffer. size_t output_length = 0; @@ -4474,7 +4571,7 @@ size_t QuicFramer::GetCiphertextSize(EncryptionLevel level, if (encrypter_[level] == nullptr) { QUIC_BUG << ENDPOINT << "Attempted to get ciphertext size without encrypter at level " - << EncryptionLevelToString(level) << " using " << version_; + << level << " using " << version_; return plaintext_size; } return encrypter_[level]->GetCiphertextSize(plaintext_size); @@ -4729,7 +4826,7 @@ bool QuicFramer::AppendTypeByte(const QuicFrame& frame, bool last_frame_in_packet, QuicDataWriter* writer) { if (VersionHasIetfQuicFrames(version_.transport_version)) { - return AppendIetfTypeByte(frame, last_frame_in_packet, writer); + return AppendIetfFrameType(frame, last_frame_in_packet, writer); } uint8_t type_byte = 0; switch (frame.type) { @@ -4785,9 +4882,9 @@ bool QuicFramer::AppendTypeByte(const QuicFrame& frame, return writer->WriteUInt8(type_byte); } -bool QuicFramer::AppendIetfTypeByte(const QuicFrame& frame, - bool last_frame_in_packet, - QuicDataWriter* writer) { +bool QuicFramer::AppendIetfFrameType(const QuicFrame& frame, + bool last_frame_in_packet, + QuicDataWriter* writer) { uint8_t type_byte = 0; switch (frame.type) { case PADDING_FRAME: @@ -4805,7 +4902,9 @@ bool QuicFramer::AppendIetfTypeByte(const QuicFrame& frame, type_byte = IETF_CONNECTION_CLOSE; break; default: - set_detailed_error("Invalid QuicConnectionCloseFrame type."); + set_detailed_error(quiche::QuicheStrCat( + "Invalid QuicConnectionCloseFrame type: ", + static_cast<int>(frame.connection_close_frame->close_type))); return RaiseError(QUIC_INTERNAL_ERROR); } break; @@ -4890,12 +4989,15 @@ bool QuicFramer::AppendIetfTypeByte(const QuicFrame& frame, case HANDSHAKE_DONE_FRAME: type_byte = IETF_HANDSHAKE_DONE; break; + case ACK_FREQUENCY_FRAME: + type_byte = IETF_ACK_FREQUENCY; + break; default: QUIC_BUG << "Attempt to generate a frame type for an unsupported value: " << frame.type; return false; } - return writer->WriteUInt8(type_byte); + return writer->WriteVarInt62(type_byte); } // static @@ -5107,6 +5209,29 @@ bool QuicFramer::AppendCryptoFrame(const QuicCryptoFrame& frame, return true; } +bool QuicFramer::AppendAckFrequencyFrame(const QuicAckFrequencyFrame& frame, + QuicDataWriter* writer) { + if (!writer->WriteVarInt62(frame.sequence_number)) { + set_detailed_error("Writing sequence number failed."); + return false; + } + if (!writer->WriteVarInt62(frame.packet_tolerance)) { + set_detailed_error("Writing packet tolerance failed."); + return false; + } + if (!writer->WriteVarInt62( + static_cast<uint64_t>(frame.max_ack_delay.ToMicroseconds()))) { + set_detailed_error("Writing max_ack_delay_us failed."); + return false; + } + if (!writer->WriteUInt8(static_cast<uint8_t>(frame.ignore_order))) { + set_detailed_error("Writing ignore_order failed."); + return false; + } + + return true; +} + void QuicFramer::set_version(const ParsedQuicVersion version) { DCHECK(IsSupportedVersion(version)) << ParsedQuicVersionToString(version); version_ = version; @@ -5365,7 +5490,7 @@ bool QuicFramer::AppendIetfAckFrameAndTypeByte(const QuicAckFrame& frame, QuicDataWriter::GetVarInt62Len(frame.ecn_ce_count)); } - if (!writer->WriteUInt8(type)) { + if (!writer->WriteVarInt62(type)) { set_detailed_error("No room for frame-type"); return false; } diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_framer.h b/chromium/net/third_party/quiche/src/quic/core/quic_framer.h index 8ace715d285..8e63fc25722 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_framer.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_framer.h @@ -218,6 +218,9 @@ class QUIC_EXPORT_PRIVATE QuicFramerVisitorInterface { // Called when a handshake done frame has been parsed. virtual bool OnHandshakeDoneFrame(const QuicHandshakeDoneFrame& frame) = 0; + // Called when an AckFrequencyFrame has been parsed. + virtual bool OnAckFrequencyFrame(const QuicAckFrequencyFrame& frame) = 0; + // Called when a packet has been completely processed. virtual void OnPacketComplete() = 0; @@ -321,6 +324,8 @@ class QUIC_EXPORT_PRIVATE QuicFramer { // Size in bytes of all reset stream frame fields. static size_t GetRstStreamFrameSize(QuicTransportVersion version, const QuicRstStreamFrame& frame); + // Size in bytes of all ack frenquency frame fields. + static size_t GetAckFrequencyFrameSize(const QuicAckFrequencyFrame& frame); // Size in bytes of all connection close frame fields, including the error // details. static size_t GetConnectionCloseFrameSize( @@ -481,14 +486,16 @@ class QUIC_EXPORT_PRIVATE QuicFramer { bool AppendTypeByte(const QuicFrame& frame, bool last_frame_in_packet, QuicDataWriter* writer); - bool AppendIetfTypeByte(const QuicFrame& frame, - bool last_frame_in_packet, - QuicDataWriter* writer); + bool AppendIetfFrameType(const QuicFrame& frame, + bool last_frame_in_packet, + QuicDataWriter* writer); size_t AppendIetfFrames(const QuicFrames& frames, QuicDataWriter* writer); bool AppendStreamFrame(const QuicStreamFrame& frame, bool last_frame_in_packet, QuicDataWriter* writer); bool AppendCryptoFrame(const QuicCryptoFrame& frame, QuicDataWriter* writer); + bool AppendAckFrequencyFrame(const QuicAckFrequencyFrame& frame, + QuicDataWriter* writer); // SetDecrypter sets the primary decrypter, replacing any that already exists. // If an alternative decrypter is in place then the function DCHECKs. This is @@ -571,6 +578,8 @@ class QUIC_EXPORT_PRIVATE QuicFramer { // Returns true if encrypter of |level| is available. bool HasEncrypterOfEncryptionLevel(EncryptionLevel level) const; + // Returns true if decrypter of |level| is available. + bool HasDecrypterOfEncryptionLevel(EncryptionLevel level) const; void set_validate_flags(bool value) { validate_flags_ = value; } @@ -915,7 +924,8 @@ class QUIC_EXPORT_PRIVATE QuicFramer { bool ProcessCryptoFrame(QuicDataReader* reader, EncryptionLevel encryption_level, QuicCryptoFrame* frame); - + bool ProcessAckFrequencyFrame(QuicDataReader* reader, + QuicAckFrequencyFrame* frame); // IETF frame appending methods. All methods append the type byte as well. bool AppendIetfStreamFrame(const QuicStreamFrame& frame, bool last_frame_in_packet, diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_framer_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_framer_test.cc index fb9c2eb87bc..5a5a8fa1a8a 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_framer_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_framer_test.cc @@ -406,6 +406,15 @@ class TestQuicVisitor : public QuicFramerVisitorInterface { return true; } + bool OnAckFrequencyFrame(const QuicAckFrequencyFrame& frame) override { + ++frame_count_; + ack_frequency_frames_.emplace_back( + std::make_unique<QuicAckFrequencyFrame>(frame)); + DCHECK(VersionHasIetfQuicFrames(transport_version_)); + EXPECT_EQ(IETF_ACK_FREQUENCY, framer_->current_received_frame_type()); + return true; + } + void OnPacketComplete() override { ++complete_packets_; } bool OnRstStreamFrame(const QuicRstStreamFrame& frame) override { @@ -574,6 +583,7 @@ class TestQuicVisitor : public QuicFramerVisitorInterface { std::vector<std::unique_ptr<QuicPingFrame>> ping_frames_; std::vector<std::unique_ptr<QuicMessageFrame>> message_frames_; std::vector<std::unique_ptr<QuicHandshakeDoneFrame>> handshake_done_frames_; + std::vector<std::unique_ptr<QuicAckFrequencyFrame>> ack_frequency_frames_; std::vector<std::unique_ptr<QuicEncryptedPacket>> coalesced_packets_; std::vector<std::unique_ptr<QuicEncryptedPacket>> undecryptable_packets_; std::vector<EncryptionLevel> undecryptable_decryption_levels_; @@ -5159,6 +5169,52 @@ TEST_P(QuicFramerTest, HandshakeDoneFrame) { EXPECT_EQ(1u, visitor_.handshake_done_frames_.size()); } +TEST_P(QuicFramerTest, ParseAckFrequencyFrame) { + SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE); + // clang-format off + unsigned char packet[] = { + // type (short header, 4 byte packet number) + 0x43, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x12, 0x34, 0x56, 0x78, + + // ack frequency frame type (which needs two bytes as it is > 0x3F) + 0x40, 0xAF, + // sequence_number + 0x11, + // packet_tolerance + 0x02, + // max_ack_delay_us = 2'5000 us + 0x80, 0x00, 0x61, 0xA8, + // ignore_order + 0x01 + }; + // clang-format on + + if (!VersionHasIetfQuicFrames(framer_.transport_version())) { + return; + } + + QuicEncryptedPacket encrypted(AsChars(packet), QUICHE_ARRAYSIZE(packet), + false); + EXPECT_TRUE(framer_.ProcessPacket(encrypted)); + + EXPECT_THAT(framer_.error(), IsQuicNoError()); + ASSERT_TRUE(visitor_.header_.get()); + EXPECT_TRUE(CheckDecryption( + encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, + PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); + + ASSERT_EQ(1u, visitor_.ack_frequency_frames_.size()); + const auto& frame = visitor_.ack_frequency_frames_.front(); + EXPECT_EQ(17u, frame->sequence_number); + EXPECT_EQ(2u, frame->packet_tolerance); + EXPECT_EQ(2'5000u, frame->max_ack_delay.ToMicroseconds()); + EXPECT_EQ(true, frame->ignore_order); +} + TEST_P(QuicFramerTest, MessageFrame) { if (!VersionSupportsMessageFrames(framer_.transport_version())) { return; @@ -8607,6 +8663,53 @@ TEST_P(QuicFramerTest, BuildHandshakeDonePacket) { QUICHE_ARRAYSIZE(packet)); } +TEST_P(QuicFramerTest, BuildAckFrequencyPacket) { + QuicPacketHeader header; + header.destination_connection_id = FramerTestConnectionId(); + header.reset_flag = false; + header.version_flag = false; + header.packet_number = kPacketNumber; + + QuicAckFrequencyFrame ack_frequency_frame; + ack_frequency_frame.sequence_number = 3; + ack_frequency_frame.packet_tolerance = 5; + ack_frequency_frame.max_ack_delay = QuicTime::Delta::FromMicroseconds(0x3fff); + ack_frequency_frame.ignore_order = false; + QuicFrames frames = {QuicFrame(&ack_frequency_frame)}; + + // clang-format off + unsigned char packet[] = { + // type (short header, 4 byte packet number) + 0x43, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x12, 0x34, 0x56, 0x78, + + // frame type (Ack Frequency frame) + 0x40, 0xaf, + // sequence number + 0x03, + // packet tolerance + 0x05, + // max_ack_delay_us + 0x7f, 0xff, + // ignore_oder + 0x00 + }; + // clang-format on + if (!VersionHasIetfQuicFrames(framer_.transport_version())) { + return; + } + + std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); + ASSERT_TRUE(data != nullptr); + + quiche::test::CompareCharArraysWithHexError( + "constructed packet", data->data(), data->length(), AsChars(packet), + QUICHE_ARRAYSIZE(packet)); +} + TEST_P(QuicFramerTest, BuildMessagePacket) { if (!VersionSupportsMessageFrames(framer_.transport_version())) { return; @@ -9013,6 +9116,24 @@ TEST_P(QuicFramerTest, EncryptPacket) { EXPECT_TRUE(CheckEncryption(packet_number, raw.get())); } +// Regression test for b/158014497. +TEST_P(QuicFramerTest, EncryptEmptyPacket) { + auto packet = std::make_unique<QuicPacket>( + new char[100], 0, true, PACKET_8BYTE_CONNECTION_ID, + PACKET_0BYTE_CONNECTION_ID, + /*includes_version=*/true, + /*includes_diversification_nonce=*/true, PACKET_1BYTE_PACKET_NUMBER, + VARIABLE_LENGTH_INTEGER_LENGTH_0, + /*retry_token_length=*/0, VARIABLE_LENGTH_INTEGER_LENGTH_0); + char buffer[kMaxOutgoingPacketSize]; + size_t encrypted_length = 1; + EXPECT_QUIC_BUG(encrypted_length = framer_.EncryptPayload( + ENCRYPTION_INITIAL, kPacketNumber, *packet, buffer, + kMaxOutgoingPacketSize), + "packet is shorter than associated data length"); + EXPECT_EQ(0u, encrypted_length); +} + TEST_P(QuicFramerTest, EncryptPacketWithVersionFlag) { QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); QuicPacketNumber packet_number = kPacketNumber; diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_legacy_version_encapsulator.cc b/chromium/net/third_party/quiche/src/quic/core/quic_legacy_version_encapsulator.cc new file mode 100644 index 00000000000..816b8c79c50 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/quic_legacy_version_encapsulator.cc @@ -0,0 +1,145 @@ +// Copyright (c) 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/third_party/quiche/src/quic/core/quic_legacy_version_encapsulator.h" +#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.h" +#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h" +#include "net/third_party/quiche/src/quic/core/quic_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_text_utils.h" + +namespace quic { + +QuicLegacyVersionEncapsulator::QuicLegacyVersionEncapsulator( + QuicPacketBuffer packet_buffer) + : packet_buffer_(packet_buffer) {} + +QuicLegacyVersionEncapsulator::~QuicLegacyVersionEncapsulator() {} + +// static +QuicByteCount QuicLegacyVersionEncapsulator::GetMinimumOverhead( + quiche::QuicheStringPiece sni) { + // The number 52 is the sum of: + // - Flags (1 byte) + // - Server Connection ID (8 bytes) + // - Version (4 bytes) + // - Packet Number (1 byte) + // - Message Authentication Hash (12 bytes) + // - Frame Type (1 byte) + // - Stream ID (1 byte) + // - ClientHello tag (4 bytes) + // - ClientHello num tags (2 bytes) + // - Padding (2 bytes) + // - SNI tag (4 bytes) + // - SNI end offset (4 bytes) + // - QLVE tag (4 bytes) + // - QLVE end offset (4 bytes) + return 52 + sni.length(); +} + +QuicPacketBuffer QuicLegacyVersionEncapsulator::GetPacketBuffer() { + return packet_buffer_; +} + +void QuicLegacyVersionEncapsulator::OnSerializedPacket( + SerializedPacket serialized_packet) { + if (encrypted_length_ != 0) { + unrecoverable_failure_encountered_ = true; + QUIC_BUG << "OnSerializedPacket called twice"; + return; + } + if (serialized_packet.encrypted_length == 0) { + unrecoverable_failure_encountered_ = true; + QUIC_BUG << "OnSerializedPacket called with empty packet"; + return; + } + encrypted_length_ = serialized_packet.encrypted_length; +} + +void QuicLegacyVersionEncapsulator::OnUnrecoverableError( + QuicErrorCode error, + const std::string& error_details) { + unrecoverable_failure_encountered_ = true; + QUIC_BUG << "QuicLegacyVersionEncapsulator received error " << error << ": " + << error_details; +} + +bool QuicLegacyVersionEncapsulator::ShouldGeneratePacket( + HasRetransmittableData /*retransmittable*/, + IsHandshake /*handshake*/) { + return true; +} + +const QuicFrames +QuicLegacyVersionEncapsulator::MaybeBundleAckOpportunistically() { + // We do not want to ever include any ACKs here, return an empty array. + return QuicFrames(); +} + +// static +QuicPacketLength QuicLegacyVersionEncapsulator::Encapsulate( + quiche::QuicheStringPiece sni, + quiche::QuicheStringPiece inner_packet, + const QuicConnectionId& server_connection_id, + QuicTime creation_time, + QuicByteCount outer_max_packet_length, + char* out) { + if (outer_max_packet_length > kMaxOutgoingPacketSize) { + outer_max_packet_length = kMaxOutgoingPacketSize; + } + CryptoHandshakeMessage outer_chlo; + outer_chlo.set_tag(kCHLO); + outer_chlo.SetStringPiece(kSNI, sni); + outer_chlo.SetStringPiece(kQLVE, inner_packet); + const QuicData& serialized_outer_chlo = outer_chlo.GetSerialized(); + DCHECK(!LegacyVersionForEncapsulation().UsesCryptoFrames()); + DCHECK(LegacyVersionForEncapsulation().UsesQuicCrypto()); + QuicStreamFrame outer_stream_frame( + QuicUtils::GetCryptoStreamId( + LegacyVersionForEncapsulation().transport_version), + /*fin=*/false, + /*offset=*/0, serialized_outer_chlo.AsStringPiece()); + QuicFramer outer_framer( + ParsedQuicVersionVector{LegacyVersionForEncapsulation()}, creation_time, + Perspective::IS_CLIENT, kQuicDefaultConnectionIdLength); + outer_framer.SetInitialObfuscators(server_connection_id); + char outer_encrypted_packet[kMaxOutgoingPacketSize]; + QuicPacketBuffer outer_packet_buffer(outer_encrypted_packet, nullptr); + QuicLegacyVersionEncapsulator creator_delegate(outer_packet_buffer); + QuicPacketCreator outer_creator(server_connection_id, &outer_framer, + &creator_delegate); + outer_creator.SetMaxPacketLength(outer_max_packet_length); + outer_creator.set_encryption_level(ENCRYPTION_INITIAL); + outer_creator.SetTransmissionType(NOT_RETRANSMISSION); + if (!outer_creator.AddPaddedSavedFrame(QuicFrame(outer_stream_frame), + NOT_RETRANSMISSION)) { + QUIC_BUG << "Failed to add Legacy Version Encapsulation stream frame " + "(max packet length is " + << outer_creator.max_packet_length() << ") " << outer_stream_frame; + return 0; + } + outer_creator.FlushCurrentPacket(); + const QuicPacketLength encrypted_length = creator_delegate.encrypted_length_; + if (creator_delegate.unrecoverable_failure_encountered_ || + encrypted_length == 0) { + QUIC_BUG << "Failed to perform Legacy Version Encapsulation of " + << inner_packet.length() << " bytes"; + return 0; + } + if (encrypted_length > kMaxOutgoingPacketSize) { + QUIC_BUG << "Legacy Version Encapsulation outer creator generated a " + "packet with unexpected length " + << encrypted_length; + return 0; + } + + QUIC_DLOG(INFO) << "Successfully performed Legacy Version Encapsulation from " + << inner_packet.length() << " bytes to " << encrypted_length; + + // Replace our current packet with the encapsulated one. + memcpy(out, outer_encrypted_packet, encrypted_length); + return encrypted_length; +} + +} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_legacy_version_encapsulator.h b/chromium/net/third_party/quiche/src/quic/core/quic_legacy_version_encapsulator.h new file mode 100644 index 00000000000..3d9c1564506 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/quic_legacy_version_encapsulator.h @@ -0,0 +1,71 @@ +// Copyright (c) 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_QUIC_LEGACY_VERSION_ENCAPSULATOR_H_ +#define QUICHE_QUIC_CORE_QUIC_LEGACY_VERSION_ENCAPSULATOR_H_ + +#include "net/third_party/quiche/src/quic/core/quic_packet_creator.h" +#include "net/third_party/quiche/src/quic/core/quic_packets.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" + +namespace quic { + +// QuicLegacyVersionEncapsulator is responsible for encapsulation of packets +// using Legacy Version Encapsulation. + +class QUIC_EXPORT_PRIVATE QuicLegacyVersionEncapsulator + : public QuicPacketCreator::DelegateInterface { + public: + // Encapsulates |inner_packet| into a new encapsulated packet that uses a + // CHLO of version LegacyVersionForEncapsulation() with server name |sni| + // exposed and using |server_connection_id|. The packet will be padded up to + // |outer_max_packet_length| bytes if necessary. On failure, returns 0. On + // success, returns the length of the outer encapsulated packet, and copies + // the contents of the encapsulated packet to |out|. |out| must point to a + // valid memory buffer capable of holding kMaxOutgoingPacketSize bytes. + static QuicPacketLength Encapsulate( + quiche::QuicheStringPiece sni, + quiche::QuicheStringPiece inner_packet, + const QuicConnectionId& server_connection_id, + QuicTime creation_time, + QuicByteCount outer_max_packet_length, + char* out); + + // Returns the number of bytes of minimum overhead caused by Legacy Version + // Encapsulation, based on the length of the provided server name |sni|. + // The overhead may be higher due to extra padding added. + static QuicByteCount GetMinimumOverhead(quiche::QuicheStringPiece sni); + + // Overrides for QuicPacketCreator::DelegateInterface. + QuicPacketBuffer GetPacketBuffer() override; + void OnSerializedPacket(SerializedPacket serialized_packet) override; + void OnUnrecoverableError(QuicErrorCode error, + const std::string& error_details) override; + bool ShouldGeneratePacket(HasRetransmittableData retransmittable, + IsHandshake handshake) override; + const QuicFrames MaybeBundleAckOpportunistically() override; + + ~QuicLegacyVersionEncapsulator() override; + + private: + explicit QuicLegacyVersionEncapsulator(QuicPacketBuffer packet_buffer); + + // Disallow copy, move and assignment. + QuicLegacyVersionEncapsulator(const QuicLegacyVersionEncapsulator&) = delete; + QuicLegacyVersionEncapsulator(QuicLegacyVersionEncapsulator&&) = delete; + QuicLegacyVersionEncapsulator& operator=( + const QuicLegacyVersionEncapsulator&) = delete; + QuicLegacyVersionEncapsulator& operator=(QuicLegacyVersionEncapsulator&&) = + delete; + + QuicPacketBuffer packet_buffer_; + QuicPacketLength encrypted_length_ = 0; + bool unrecoverable_failure_encountered_ = false; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_QUIC_LEGACY_VERSION_ENCAPSULATOR_H_ diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_legacy_version_encapsulator_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_legacy_version_encapsulator_test.cc new file mode 100644 index 00000000000..a71b2f44eb5 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/quic_legacy_version_encapsulator_test.cc @@ -0,0 +1,109 @@ +// Copyright (c) 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/third_party/quiche/src/quic/core/quic_legacy_version_encapsulator.h" + +#include "net/third_party/quiche/src/quic/core/quic_versions.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_text_utils.h" + +namespace quic { +namespace test { +namespace { + +class QuicLegacyVersionEncapsulatorTest + : public QuicTestWithParam<ParsedQuicVersion> { + protected: + QuicLegacyVersionEncapsulatorTest() + : version_(GetParam()), + sni_("test.example.org"), + server_connection_id_(TestConnectionId()), + outer_max_packet_length_(kMaxOutgoingPacketSize), + encapsulated_length_(0) {} + + void Encapsulate(const std::string& inner_packet) { + encapsulated_length_ = QuicLegacyVersionEncapsulator::Encapsulate( + sni_, inner_packet, server_connection_id_, QuicTime::Zero(), + outer_max_packet_length_, outer_buffer_); + } + + void CheckEncapsulation() { + ASSERT_NE(encapsulated_length_, 0u); + ASSERT_EQ(encapsulated_length_, outer_max_packet_length_); + // Verify that the encapsulated packet parses as encapsulated. + PacketHeaderFormat format = IETF_QUIC_LONG_HEADER_PACKET; + QuicLongHeaderType long_packet_type; + bool version_present; + bool has_length_prefix; + QuicVersionLabel version_label; + ParsedQuicVersion parsed_version = ParsedQuicVersion::Unsupported(); + QuicConnectionId destination_connection_id, source_connection_id; + bool retry_token_present; + quiche::QuicheStringPiece retry_token; + std::string detailed_error; + const QuicErrorCode error = QuicFramer::ParsePublicHeaderDispatcher( + QuicEncryptedPacket(outer_buffer_, encapsulated_length_), + kQuicDefaultConnectionIdLength, &format, &long_packet_type, + &version_present, &has_length_prefix, &version_label, &parsed_version, + &destination_connection_id, &source_connection_id, &retry_token_present, + &retry_token, &detailed_error); + ASSERT_THAT(error, IsQuicNoError()) << detailed_error; + EXPECT_EQ(format, GOOGLE_QUIC_PACKET); + EXPECT_TRUE(version_present); + EXPECT_FALSE(has_length_prefix); + EXPECT_EQ(parsed_version, LegacyVersionForEncapsulation()); + EXPECT_EQ(destination_connection_id, server_connection_id_); + EXPECT_EQ(source_connection_id, EmptyQuicConnectionId()); + EXPECT_FALSE(retry_token_present); + EXPECT_TRUE(detailed_error.empty()); + } + + QuicByteCount Overhead() { + return QuicLegacyVersionEncapsulator::GetMinimumOverhead(sni_); + } + + ParsedQuicVersion version_; + std::string sni_; + QuicConnectionId server_connection_id_; + QuicByteCount outer_max_packet_length_; + char outer_buffer_[kMaxOutgoingPacketSize]; + QuicPacketLength encapsulated_length_; +}; + +INSTANTIATE_TEST_SUITE_P(QuicLegacyVersionEncapsulatorTests, + QuicLegacyVersionEncapsulatorTest, + ::testing::ValuesIn(AllSupportedVersions()), + ::testing::PrintToStringParamName()); + +TEST_P(QuicLegacyVersionEncapsulatorTest, Simple) { + Encapsulate("TEST_INNER_PACKET"); + CheckEncapsulation(); +} + +TEST_P(QuicLegacyVersionEncapsulatorTest, TooBig) { + std::string inner_packet(kMaxOutgoingPacketSize, '?'); + EXPECT_QUIC_BUG(Encapsulate(inner_packet), "Legacy Version Encapsulation"); + ASSERT_EQ(encapsulated_length_, 0u); +} + +TEST_P(QuicLegacyVersionEncapsulatorTest, BarelyFits) { + QuicByteCount inner_size = kMaxOutgoingPacketSize - Overhead(); + std::string inner_packet(inner_size, '?'); + Encapsulate(inner_packet); + CheckEncapsulation(); +} + +TEST_P(QuicLegacyVersionEncapsulatorTest, DoesNotQuiteFit) { + QuicByteCount inner_size = 1 + kMaxOutgoingPacketSize - Overhead(); + std::string inner_packet(inner_size, '?'); + EXPECT_QUIC_BUG(Encapsulate(inner_packet), "Legacy Version Encapsulation"); + ASSERT_EQ(encapsulated_length_, 0u); +} + +} // namespace +} // namespace test +} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_linux_socket_utils.cc b/chromium/net/third_party/quiche/src/quic/core/quic_linux_socket_utils.cc new file mode 100644 index 00000000000..6dd74c3b19c --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/quic_linux_socket_utils.cc @@ -0,0 +1,314 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/third_party/quiche/src/quic/core/quic_linux_socket_utils.h" + +#include <linux/net_tstamp.h> +#include <netinet/in.h> +#include <cstdint> + +#include "net/third_party/quiche/src/quic/core/quic_syscall_wrapper.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_ip_address.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h" + +namespace quic { + +QuicMsgHdr::QuicMsgHdr(const char* buffer, + size_t buf_len, + const QuicSocketAddress& peer_address, + char* cbuf, + size_t cbuf_size) + : iov_{const_cast<char*>(buffer), buf_len}, + cbuf_(cbuf), + cbuf_size_(cbuf_size), + cmsg_(nullptr) { + // Only support unconnected sockets. + DCHECK(peer_address.IsInitialized()); + + raw_peer_address_ = peer_address.generic_address(); + hdr_.msg_name = &raw_peer_address_; + hdr_.msg_namelen = raw_peer_address_.ss_family == AF_INET + ? sizeof(sockaddr_in) + : sizeof(sockaddr_in6); + + hdr_.msg_iov = &iov_; + hdr_.msg_iovlen = 1; + hdr_.msg_flags = 0; + + hdr_.msg_control = nullptr; + hdr_.msg_controllen = 0; +} + +void QuicMsgHdr::SetIpInNextCmsg(const QuicIpAddress& self_address) { + if (!self_address.IsInitialized()) { + return; + } + + if (self_address.IsIPv4()) { + QuicLinuxSocketUtils::SetIpInfoInCmsgData( + self_address, GetNextCmsgData<in_pktinfo>(IPPROTO_IP, IP_PKTINFO)); + } else { + QuicLinuxSocketUtils::SetIpInfoInCmsgData( + self_address, GetNextCmsgData<in6_pktinfo>(IPPROTO_IPV6, IPV6_PKTINFO)); + } +} + +void* QuicMsgHdr::GetNextCmsgDataInternal(int cmsg_level, + int cmsg_type, + size_t data_size) { + // msg_controllen needs to be increased first, otherwise CMSG_NXTHDR will + // return nullptr. + hdr_.msg_controllen += CMSG_SPACE(data_size); + DCHECK_LE(hdr_.msg_controllen, cbuf_size_); + + if (cmsg_ == nullptr) { + DCHECK_EQ(nullptr, hdr_.msg_control); + memset(cbuf_, 0, cbuf_size_); + hdr_.msg_control = cbuf_; + cmsg_ = CMSG_FIRSTHDR(&hdr_); + } else { + DCHECK_NE(nullptr, hdr_.msg_control); + cmsg_ = CMSG_NXTHDR(&hdr_, cmsg_); + } + + DCHECK_NE(nullptr, cmsg_) << "Insufficient control buffer space"; + + cmsg_->cmsg_len = CMSG_LEN(data_size); + cmsg_->cmsg_level = cmsg_level; + cmsg_->cmsg_type = cmsg_type; + + return CMSG_DATA(cmsg_); +} + +void QuicMMsgHdr::InitOneHeader(int i, const BufferedWrite& buffered_write) { + mmsghdr* mhdr = GetMMsgHdr(i); + msghdr* hdr = &mhdr->msg_hdr; + iovec* iov = GetIov(i); + + iov->iov_base = const_cast<char*>(buffered_write.buffer); + iov->iov_len = buffered_write.buf_len; + hdr->msg_iov = iov; + hdr->msg_iovlen = 1; + hdr->msg_control = nullptr; + hdr->msg_controllen = 0; + + // Only support unconnected sockets. + DCHECK(buffered_write.peer_address.IsInitialized()); + + sockaddr_storage* peer_address_storage = GetPeerAddressStorage(i); + *peer_address_storage = buffered_write.peer_address.generic_address(); + hdr->msg_name = peer_address_storage; + hdr->msg_namelen = peer_address_storage->ss_family == AF_INET + ? sizeof(sockaddr_in) + : sizeof(sockaddr_in6); +} + +void QuicMMsgHdr::SetIpInNextCmsg(int i, const QuicIpAddress& self_address) { + if (!self_address.IsInitialized()) { + return; + } + + if (self_address.IsIPv4()) { + QuicLinuxSocketUtils::SetIpInfoInCmsgData( + self_address, GetNextCmsgData<in_pktinfo>(i, IPPROTO_IP, IP_PKTINFO)); + } else { + QuicLinuxSocketUtils::SetIpInfoInCmsgData( + self_address, + GetNextCmsgData<in6_pktinfo>(i, IPPROTO_IPV6, IPV6_PKTINFO)); + } +} + +void* QuicMMsgHdr::GetNextCmsgDataInternal(int i, + int cmsg_level, + int cmsg_type, + size_t data_size) { + mmsghdr* mhdr = GetMMsgHdr(i); + msghdr* hdr = &mhdr->msg_hdr; + cmsghdr*& cmsg = *GetCmsgHdr(i); + + // msg_controllen needs to be increased first, otherwise CMSG_NXTHDR will + // return nullptr. + hdr->msg_controllen += CMSG_SPACE(data_size); + DCHECK_LE(hdr->msg_controllen, cbuf_size_); + + if (cmsg == nullptr) { + DCHECK_EQ(nullptr, hdr->msg_control); + hdr->msg_control = GetCbuf(i); + cmsg = CMSG_FIRSTHDR(hdr); + } else { + DCHECK_NE(nullptr, hdr->msg_control); + cmsg = CMSG_NXTHDR(hdr, cmsg); + } + + DCHECK_NE(nullptr, cmsg) << "Insufficient control buffer space"; + + cmsg->cmsg_len = CMSG_LEN(data_size); + cmsg->cmsg_level = cmsg_level; + cmsg->cmsg_type = cmsg_type; + + return CMSG_DATA(cmsg); +} + +int QuicMMsgHdr::num_bytes_sent(int num_packets_sent) { + DCHECK_LE(0, num_packets_sent); + DCHECK_LE(num_packets_sent, num_msgs_); + + int bytes_sent = 0; + iovec* iov = GetIov(0); + for (int i = 0; i < num_packets_sent; ++i) { + bytes_sent += iov[i].iov_len; + } + return bytes_sent; +} + +// static +int QuicLinuxSocketUtils::GetUDPSegmentSize(int fd) { + int optval; + socklen_t optlen = sizeof(optval); + int rc = getsockopt(fd, SOL_UDP, UDP_SEGMENT, &optval, &optlen); + if (rc < 0) { + QUIC_LOG_EVERY_N_SEC(INFO, 10) + << "getsockopt(UDP_SEGMENT) failed: " << strerror(errno); + return -1; + } + QUIC_LOG_EVERY_N_SEC(INFO, 10) + << "getsockopt(UDP_SEGMENT) returned segment size: " << optval; + return optval; +} + +// static +bool QuicLinuxSocketUtils::EnableReleaseTime(int fd, clockid_t clockid) { + // TODO(wub): Change to sock_txtime once it is available in linux/net_tstamp.h + struct LinuxSockTxTime { + clockid_t clockid; /* reference clockid */ + uint32_t flags; /* flags defined by enum txtime_flags */ + }; + + LinuxSockTxTime so_txtime_val{clockid, 0}; + + if (setsockopt(fd, SOL_SOCKET, SO_TXTIME, &so_txtime_val, + sizeof(so_txtime_val)) != 0) { + QUIC_LOG_EVERY_N_SEC(INFO, 10) + << "setsockopt(SOL_SOCKET,SO_TXTIME) failed: " << strerror(errno); + return false; + } + + return true; +} + +// static +bool QuicLinuxSocketUtils::GetTtlFromMsghdr(struct msghdr* hdr, int* ttl) { + if (hdr->msg_controllen > 0) { + struct cmsghdr* cmsg; + for (cmsg = CMSG_FIRSTHDR(hdr); cmsg != nullptr; + cmsg = CMSG_NXTHDR(hdr, cmsg)) { + if ((cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_TTL) || + (cmsg->cmsg_level == IPPROTO_IPV6 && + cmsg->cmsg_type == IPV6_HOPLIMIT)) { + *ttl = *(reinterpret_cast<int*>(CMSG_DATA(cmsg))); + return true; + } + } + } + return false; +} + +// static +void QuicLinuxSocketUtils::SetIpInfoInCmsgData( + const QuicIpAddress& self_address, + void* cmsg_data) { + DCHECK(self_address.IsInitialized()); + const std::string& address_str = self_address.ToPackedString(); + if (self_address.IsIPv4()) { + in_pktinfo* pktinfo = static_cast<in_pktinfo*>(cmsg_data); + pktinfo->ipi_ifindex = 0; + memcpy(&pktinfo->ipi_spec_dst, address_str.c_str(), address_str.length()); + } else if (self_address.IsIPv6()) { + in6_pktinfo* pktinfo = static_cast<in6_pktinfo*>(cmsg_data); + memcpy(&pktinfo->ipi6_addr, address_str.c_str(), address_str.length()); + } else { + QUIC_BUG << "Unrecognized IPAddress"; + } +} + +// static +size_t QuicLinuxSocketUtils::SetIpInfoInCmsg(const QuicIpAddress& self_address, + cmsghdr* cmsg) { + std::string address_string; + if (self_address.IsIPv4()) { + cmsg->cmsg_len = CMSG_LEN(sizeof(in_pktinfo)); + cmsg->cmsg_level = IPPROTO_IP; + cmsg->cmsg_type = IP_PKTINFO; + in_pktinfo* pktinfo = reinterpret_cast<in_pktinfo*>(CMSG_DATA(cmsg)); + memset(pktinfo, 0, sizeof(in_pktinfo)); + pktinfo->ipi_ifindex = 0; + address_string = self_address.ToPackedString(); + memcpy(&pktinfo->ipi_spec_dst, address_string.c_str(), + address_string.length()); + return sizeof(in_pktinfo); + } else if (self_address.IsIPv6()) { + cmsg->cmsg_len = CMSG_LEN(sizeof(in6_pktinfo)); + cmsg->cmsg_level = IPPROTO_IPV6; + cmsg->cmsg_type = IPV6_PKTINFO; + in6_pktinfo* pktinfo = reinterpret_cast<in6_pktinfo*>(CMSG_DATA(cmsg)); + memset(pktinfo, 0, sizeof(in6_pktinfo)); + address_string = self_address.ToPackedString(); + memcpy(&pktinfo->ipi6_addr, address_string.c_str(), + address_string.length()); + return sizeof(in6_pktinfo); + } else { + QUIC_BUG << "Unrecognized IPAddress"; + return 0; + } +} + +// static +WriteResult QuicLinuxSocketUtils::WritePacket(int fd, const QuicMsgHdr& hdr) { + int rc; + do { + rc = GetGlobalSyscallWrapper()->Sendmsg(fd, hdr.hdr(), 0); + } while (rc < 0 && errno == EINTR); + if (rc >= 0) { + return WriteResult(WRITE_STATUS_OK, rc); + } + return WriteResult((errno == EAGAIN || errno == EWOULDBLOCK) + ? WRITE_STATUS_BLOCKED + : WRITE_STATUS_ERROR, + errno); +} + +// static +WriteResult QuicLinuxSocketUtils::WriteMultiplePackets(int fd, + QuicMMsgHdr* mhdr, + int* num_packets_sent) { + *num_packets_sent = 0; + + if (mhdr->num_msgs() <= 0) { + return WriteResult(WRITE_STATUS_ERROR, EINVAL); + } + + int rc; + do { + rc = GetGlobalSyscallWrapper()->Sendmmsg(fd, mhdr->mhdr(), mhdr->num_msgs(), + 0); + } while (rc < 0 && errno == EINTR); + + if (rc > 0) { + *num_packets_sent = rc; + + return WriteResult(WRITE_STATUS_OK, mhdr->num_bytes_sent(rc)); + } else if (rc == 0) { + QUIC_BUG << "sendmmsg returned 0, returning WRITE_STATUS_ERROR. errno: " + << errno; + errno = EIO; + } + + return WriteResult((errno == EAGAIN || errno == EWOULDBLOCK) + ? WRITE_STATUS_BLOCKED + : WRITE_STATUS_ERROR, + errno); +} + +} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_linux_socket_utils.h b/chromium/net/third_party/quiche/src/quic/core/quic_linux_socket_utils.h new file mode 100644 index 00000000000..40916579fad --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/quic_linux_socket_utils.h @@ -0,0 +1,298 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_PLATFORM_IMPL_QUIC_LINUX_SOCKET_UTILS_H_ +#define QUICHE_QUIC_PLATFORM_IMPL_QUIC_LINUX_SOCKET_UTILS_H_ + +#include <errno.h> +#include <stddef.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/uio.h> +#include <deque> +#include <functional> +#include <iterator> +#include <memory> +#include <type_traits> +#include <utility> + +#include "net/third_party/quiche/src/quic/core/quic_packet_writer.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_ip_address.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h" + +#ifndef SOL_UDP +#define SOL_UDP 17 +#endif + +#ifndef UDP_SEGMENT +#define UDP_SEGMENT 103 +#endif + +#ifndef UDP_MAX_SEGMENTS +#define UDP_MAX_SEGMENTS (1 << 6UL) +#endif + +#ifndef SO_TXTIME +#define SO_TXTIME 61 +#endif + +namespace quic { + +const int kCmsgSpaceForIpv4 = CMSG_SPACE(sizeof(in_pktinfo)); +const int kCmsgSpaceForIpv6 = CMSG_SPACE(sizeof(in6_pktinfo)); +// kCmsgSpaceForIp should be big enough to hold both IPv4 and IPv6 packet info. +const int kCmsgSpaceForIp = (kCmsgSpaceForIpv4 < kCmsgSpaceForIpv6) + ? kCmsgSpaceForIpv6 + : kCmsgSpaceForIpv4; + +const int kCmsgSpaceForSegmentSize = CMSG_SPACE(sizeof(uint16_t)); + +const int kCmsgSpaceForTxTime = CMSG_SPACE(sizeof(uint64_t)); + +const int kCmsgSpaceForTTL = CMSG_SPACE(sizeof(int)); + +// QuicMsgHdr is used to build msghdr objects that can be used send packets via +// ::sendmsg. +// +// Example: +// // cbuf holds control messages(cmsgs). The size is determined from what +// // cmsgs will be set for this msghdr. +// char cbuf[kCmsgSpaceForIp + kCmsgSpaceForSegmentSize]; +// QuicMsgHdr hdr(packet_buf, packet_buf_len, peer_addr, cbuf, sizeof(cbuf)); +// +// // Set IP in cmsgs. +// hdr.SetIpInNextCmsg(self_addr); +// +// // Set GSO size in cmsgs. +// *hdr.GetNextCmsgData<uint16_t>(SOL_UDP, UDP_SEGMENT) = 1200; +// +// QuicLinuxSocketUtils::WritePacket(fd, hdr); +class QUIC_EXPORT_PRIVATE QuicMsgHdr { + public: + QuicMsgHdr(const char* buffer, + size_t buf_len, + const QuicSocketAddress& peer_address, + char* cbuf, + size_t cbuf_size); + + // Set IP info in the next cmsg. Both IPv4 and IPv6 are supported. + void SetIpInNextCmsg(const QuicIpAddress& self_address); + + template <typename DataType> + DataType* GetNextCmsgData(int cmsg_level, int cmsg_type) { + return reinterpret_cast<DataType*>( + GetNextCmsgDataInternal(cmsg_level, cmsg_type, sizeof(DataType))); + } + + const msghdr* hdr() const { return &hdr_; } + + protected: + void* GetNextCmsgDataInternal(int cmsg_level, + int cmsg_type, + size_t data_size); + + msghdr hdr_; + iovec iov_; + sockaddr_storage raw_peer_address_; + char* cbuf_; + const size_t cbuf_size_; + // The last cmsg populated so far. nullptr means nothing has been populated. + cmsghdr* cmsg_; +}; + +// BufferedWrite holds all information needed to send a packet. +struct QUIC_EXPORT_PRIVATE BufferedWrite { + BufferedWrite(const char* buffer, + size_t buf_len, + const QuicIpAddress& self_address, + const QuicSocketAddress& peer_address) + : BufferedWrite(buffer, + buf_len, + self_address, + peer_address, + std::unique_ptr<PerPacketOptions>(), + /*release_time=*/0) {} + + BufferedWrite(const char* buffer, + size_t buf_len, + const QuicIpAddress& self_address, + const QuicSocketAddress& peer_address, + std::unique_ptr<PerPacketOptions> options, + uint64_t release_time) + : buffer(buffer), + buf_len(buf_len), + self_address(self_address), + peer_address(peer_address), + options(std::move(options)), + release_time(release_time) {} + + const char* buffer; // Not owned. + size_t buf_len; + QuicIpAddress self_address; + QuicSocketAddress peer_address; + std::unique_ptr<PerPacketOptions> options; + + // The release time according to the owning packet writer's clock, which is + // often not a QuicClock. Calculated from packet writer's Now() and the + // release time delay in |options|. + // 0 means it can be sent at the same time as the previous packet in a batch, + // or can be sent Now() if this is the first packet of a batch. + uint64_t release_time; +}; + +// QuicMMsgHdr is used to build mmsghdr objects that can be used to send +// multiple packets at once via ::sendmmsg. +// +// Example: +// QuicCircularDeque<BufferedWrite> buffered_writes; +// ... (Populate buffered_writes) ... +// +// QuicMMsgHdr mhdr( +// buffered_writes.begin(), buffered_writes.end(), kCmsgSpaceForIp, +// [](QuicMMsgHdr* mhdr, int i, const BufferedWrite& buffered_write) { +// mhdr->SetIpInNextCmsg(i, buffered_write.self_address); +// }); +// +// int num_packets_sent; +// QuicSocketUtils::WriteMultiplePackets(fd, &mhdr, &num_packets_sent); +class QUIC_EXPORT_PRIVATE QuicMMsgHdr { + public: + typedef std::function< + void(QuicMMsgHdr* mhdr, int i, const BufferedWrite& buffered_write)> + ControlBufferInitializer; + template <typename IteratorT> + QuicMMsgHdr(const IteratorT& first, + const IteratorT& last, + size_t cbuf_size, + ControlBufferInitializer cbuf_initializer) + : num_msgs_(std::distance(first, last)), cbuf_size_(cbuf_size) { + static_assert( + std::is_same<typename std::iterator_traits<IteratorT>::value_type, + BufferedWrite>::value, + "Must iterate over a collection of BufferedWrite."); + + DCHECK_LE(0, num_msgs_); + if (num_msgs_ == 0) { + return; + } + + storage_.reset(new char[StorageSize()]); + memset(&storage_[0], 0, StorageSize()); + + int i = -1; + for (auto it = first; it != last; ++it) { + ++i; + + InitOneHeader(i, *it); + if (cbuf_initializer) { + cbuf_initializer(this, i, *it); + } + } + } + + void SetIpInNextCmsg(int i, const QuicIpAddress& self_address); + + template <typename DataType> + DataType* GetNextCmsgData(int i, int cmsg_level, int cmsg_type) { + return reinterpret_cast<DataType*>( + GetNextCmsgDataInternal(i, cmsg_level, cmsg_type, sizeof(DataType))); + } + + mmsghdr* mhdr() { return GetMMsgHdr(0); } + + int num_msgs() const { return num_msgs_; } + + // Get the total number of bytes in the first |num_packets_sent| packets. + int num_bytes_sent(int num_packets_sent); + + protected: + void InitOneHeader(int i, const BufferedWrite& buffered_write); + + void* GetNextCmsgDataInternal(int i, + int cmsg_level, + int cmsg_type, + size_t data_size); + + size_t StorageSize() const { + return num_msgs_ * + (sizeof(mmsghdr) + sizeof(iovec) + sizeof(sockaddr_storage) + + sizeof(cmsghdr*) + cbuf_size_); + } + + mmsghdr* GetMMsgHdr(int i) { + auto* first = reinterpret_cast<mmsghdr*>(&storage_[0]); + return &first[i]; + } + + iovec* GetIov(int i) { + auto* first = reinterpret_cast<iovec*>(GetMMsgHdr(num_msgs_)); + return &first[i]; + } + + sockaddr_storage* GetPeerAddressStorage(int i) { + auto* first = reinterpret_cast<sockaddr_storage*>(GetIov(num_msgs_)); + return &first[i]; + } + + cmsghdr** GetCmsgHdr(int i) { + auto* first = reinterpret_cast<cmsghdr**>(GetPeerAddressStorage(num_msgs_)); + return &first[i]; + } + + char* GetCbuf(int i) { + auto* first = reinterpret_cast<char*>(GetCmsgHdr(num_msgs_)); + return &first[i * cbuf_size_]; + } + + const int num_msgs_; + // Size of cmsg buffer for each message. + const size_t cbuf_size_; + // storage_ holds the memory of + // |num_msgs_| mmsghdr + // |num_msgs_| iovec + // |num_msgs_| sockaddr_storage, for peer addresses + // |num_msgs_| cmsghdr* + // |num_msgs_| cbuf, each of size cbuf_size + std::unique_ptr<char[]> storage_; +}; + +class QUIC_EXPORT_PRIVATE QuicLinuxSocketUtils { + public: + // Return the UDP segment size of |fd|, 0 means segment size has not been set + // on this socket. If GSO is not supported, return -1. + static int GetUDPSegmentSize(int fd); + + // Enable release time on |fd|. + static bool EnableReleaseTime(int fd, clockid_t clockid); + + // If the msghdr contains an IP_TTL entry, this will set ttl to the correct + // value and return true. Otherwise it will return false. + static bool GetTtlFromMsghdr(struct msghdr* hdr, int* ttl); + + // Set IP(self_address) in |cmsg_data|. Does not touch other fields in the + // containing cmsghdr. + static void SetIpInfoInCmsgData(const QuicIpAddress& self_address, + void* cmsg_data); + + // A helper for WritePacket which fills in the cmsg with the supplied self + // address. + // Returns the length of the packet info structure used. + static size_t SetIpInfoInCmsg(const QuicIpAddress& self_address, + cmsghdr* cmsg); + + // Writes the packet in |hdr| to the socket, using ::sendmsg. + static WriteResult WritePacket(int fd, const QuicMsgHdr& hdr); + + // Writes the packets in |mhdr| to the socket, using ::sendmmsg if available. + static WriteResult WriteMultiplePackets(int fd, + QuicMMsgHdr* mhdr, + int* num_packets_sent); +}; + +} // namespace quic + +#endif // QUICHE_QUIC_PLATFORM_IMPL_QUIC_LINUX_SOCKET_UTILS_H_ diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_linux_socket_utils_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_linux_socket_utils_test.cc new file mode 100644 index 00000000000..32ad12f1473 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/quic_linux_socket_utils_test.cc @@ -0,0 +1,329 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/third_party/quiche/src/quic/core/quic_linux_socket_utils.h" + +#include <netinet/in.h> +#include <stdint.h> +#include <cstddef> +#include <sstream> +#include <vector> + +#include <string> + +#include "net/third_party/quiche/src/quic/core/quic_circular_deque.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_mock_syscall_wrapper.h" + +using testing::_; +using testing::InSequence; +using testing::Invoke; + +namespace quic { +namespace test { +namespace { + +class QuicLinuxSocketUtilsTest : public QuicTest { + protected: + WriteResult TestWriteMultiplePackets( + int fd, + const QuicCircularDeque<BufferedWrite>::const_iterator& first, + const QuicCircularDeque<BufferedWrite>::const_iterator& last, + int* num_packets_sent) { + QuicMMsgHdr mhdr( + first, last, kCmsgSpaceForIp, + [](QuicMMsgHdr* mhdr, int i, const BufferedWrite& buffered_write) { + mhdr->SetIpInNextCmsg(i, buffered_write.self_address); + }); + + WriteResult res = + QuicLinuxSocketUtils::WriteMultiplePackets(fd, &mhdr, num_packets_sent); + return res; + } + + MockQuicSyscallWrapper mock_syscalls_; + ScopedGlobalSyscallWrapperOverride syscall_override_{&mock_syscalls_}; +}; + +void CheckIpAndTtlInCbuf(msghdr* hdr, + const void* cbuf, + const QuicIpAddress& self_addr, + int ttl) { + const bool is_ipv4 = self_addr.IsIPv4(); + const size_t ip_cmsg_space = is_ipv4 ? kCmsgSpaceForIpv4 : kCmsgSpaceForIpv6; + + EXPECT_EQ(cbuf, hdr->msg_control); + EXPECT_EQ(ip_cmsg_space + CMSG_SPACE(sizeof(uint16_t)), hdr->msg_controllen); + + cmsghdr* cmsg = CMSG_FIRSTHDR(hdr); + EXPECT_EQ(cmsg->cmsg_len, is_ipv4 ? CMSG_LEN(sizeof(in_pktinfo)) + : CMSG_LEN(sizeof(in6_pktinfo))); + EXPECT_EQ(cmsg->cmsg_level, is_ipv4 ? IPPROTO_IP : IPPROTO_IPV6); + EXPECT_EQ(cmsg->cmsg_type, is_ipv4 ? IP_PKTINFO : IPV6_PKTINFO); + + const std::string& self_addr_str = self_addr.ToPackedString(); + if (is_ipv4) { + in_pktinfo* pktinfo = reinterpret_cast<in_pktinfo*>(CMSG_DATA(cmsg)); + EXPECT_EQ(0, memcmp(&pktinfo->ipi_spec_dst, self_addr_str.c_str(), + self_addr_str.length())); + } else { + in6_pktinfo* pktinfo = reinterpret_cast<in6_pktinfo*>(CMSG_DATA(cmsg)); + EXPECT_EQ(0, memcmp(&pktinfo->ipi6_addr, self_addr_str.c_str(), + self_addr_str.length())); + } + + cmsg = CMSG_NXTHDR(hdr, cmsg); + EXPECT_EQ(cmsg->cmsg_len, CMSG_LEN(sizeof(int))); + EXPECT_EQ(cmsg->cmsg_level, is_ipv4 ? IPPROTO_IP : IPPROTO_IPV6); + EXPECT_EQ(cmsg->cmsg_type, is_ipv4 ? IP_TTL : IPV6_HOPLIMIT); + EXPECT_EQ(ttl, *reinterpret_cast<int*>(CMSG_DATA(cmsg))); + + EXPECT_EQ(nullptr, CMSG_NXTHDR(hdr, cmsg)); +} + +void CheckMsghdrWithoutCbuf(const msghdr* hdr, + const void* buffer, + size_t buf_len, + const QuicSocketAddress& peer_addr) { + EXPECT_EQ( + peer_addr.host().IsIPv4() ? sizeof(sockaddr_in) : sizeof(sockaddr_in6), + hdr->msg_namelen); + sockaddr_storage peer_generic_addr = peer_addr.generic_address(); + EXPECT_EQ(0, memcmp(hdr->msg_name, &peer_generic_addr, hdr->msg_namelen)); + EXPECT_EQ(1u, hdr->msg_iovlen); + EXPECT_EQ(buffer, hdr->msg_iov->iov_base); + EXPECT_EQ(buf_len, hdr->msg_iov->iov_len); + EXPECT_EQ(0, hdr->msg_flags); + EXPECT_EQ(nullptr, hdr->msg_control); + EXPECT_EQ(0u, hdr->msg_controllen); +} + +void CheckIpAndGsoSizeInCbuf(msghdr* hdr, + const void* cbuf, + const QuicIpAddress& self_addr, + uint16_t gso_size) { + const bool is_ipv4 = self_addr.IsIPv4(); + const size_t ip_cmsg_space = is_ipv4 ? kCmsgSpaceForIpv4 : kCmsgSpaceForIpv6; + + EXPECT_EQ(cbuf, hdr->msg_control); + EXPECT_EQ(ip_cmsg_space + CMSG_SPACE(sizeof(uint16_t)), hdr->msg_controllen); + + cmsghdr* cmsg = CMSG_FIRSTHDR(hdr); + EXPECT_EQ(cmsg->cmsg_len, is_ipv4 ? CMSG_LEN(sizeof(in_pktinfo)) + : CMSG_LEN(sizeof(in6_pktinfo))); + EXPECT_EQ(cmsg->cmsg_level, is_ipv4 ? IPPROTO_IP : IPPROTO_IPV6); + EXPECT_EQ(cmsg->cmsg_type, is_ipv4 ? IP_PKTINFO : IPV6_PKTINFO); + + const std::string& self_addr_str = self_addr.ToPackedString(); + if (is_ipv4) { + in_pktinfo* pktinfo = reinterpret_cast<in_pktinfo*>(CMSG_DATA(cmsg)); + EXPECT_EQ(0, memcmp(&pktinfo->ipi_spec_dst, self_addr_str.c_str(), + self_addr_str.length())); + } else { + in6_pktinfo* pktinfo = reinterpret_cast<in6_pktinfo*>(CMSG_DATA(cmsg)); + EXPECT_EQ(0, memcmp(&pktinfo->ipi6_addr, self_addr_str.c_str(), + self_addr_str.length())); + } + + cmsg = CMSG_NXTHDR(hdr, cmsg); + EXPECT_EQ(cmsg->cmsg_len, CMSG_LEN(sizeof(uint16_t))); + EXPECT_EQ(cmsg->cmsg_level, SOL_UDP); + EXPECT_EQ(cmsg->cmsg_type, UDP_SEGMENT); + EXPECT_EQ(gso_size, *reinterpret_cast<uint16_t*>(CMSG_DATA(cmsg))); + + EXPECT_EQ(nullptr, CMSG_NXTHDR(hdr, cmsg)); +} + +TEST_F(QuicLinuxSocketUtilsTest, QuicMsgHdr) { + QuicSocketAddress peer_addr(QuicIpAddress::Loopback4(), 1234); + char packet_buf[1024]; + + QuicMsgHdr quic_hdr(packet_buf, sizeof(packet_buf), peer_addr, nullptr, 0); + CheckMsghdrWithoutCbuf(quic_hdr.hdr(), packet_buf, sizeof(packet_buf), + peer_addr); + + for (bool is_ipv4 : {true, false}) { + QuicIpAddress self_addr = + is_ipv4 ? QuicIpAddress::Loopback4() : QuicIpAddress::Loopback6(); + char cbuf[kCmsgSpaceForIp + kCmsgSpaceForTTL]; + QuicMsgHdr quic_hdr(packet_buf, sizeof(packet_buf), peer_addr, cbuf, + sizeof(cbuf)); + msghdr* hdr = const_cast<msghdr*>(quic_hdr.hdr()); + + EXPECT_EQ(nullptr, hdr->msg_control); + EXPECT_EQ(0u, hdr->msg_controllen); + + quic_hdr.SetIpInNextCmsg(self_addr); + EXPECT_EQ(cbuf, hdr->msg_control); + const size_t ip_cmsg_space = + is_ipv4 ? kCmsgSpaceForIpv4 : kCmsgSpaceForIpv6; + EXPECT_EQ(ip_cmsg_space, hdr->msg_controllen); + + if (is_ipv4) { + *quic_hdr.GetNextCmsgData<int>(IPPROTO_IP, IP_TTL) = 32; + } else { + *quic_hdr.GetNextCmsgData<int>(IPPROTO_IPV6, IPV6_HOPLIMIT) = 32; + } + + CheckIpAndTtlInCbuf(hdr, cbuf, self_addr, 32); + } +} + +TEST_F(QuicLinuxSocketUtilsTest, QuicMMsgHdr) { + QuicCircularDeque<BufferedWrite> buffered_writes; + char packet_buf1[1024]; + char packet_buf2[512]; + buffered_writes.emplace_back( + packet_buf1, sizeof(packet_buf1), QuicIpAddress::Loopback4(), + QuicSocketAddress(QuicIpAddress::Loopback4(), 4)); + buffered_writes.emplace_back( + packet_buf2, sizeof(packet_buf2), QuicIpAddress::Loopback6(), + QuicSocketAddress(QuicIpAddress::Loopback6(), 6)); + + QuicMMsgHdr quic_mhdr_without_cbuf(buffered_writes.begin(), + buffered_writes.end(), 0, nullptr); + for (size_t i = 0; i < buffered_writes.size(); ++i) { + const BufferedWrite& bw = buffered_writes[i]; + CheckMsghdrWithoutCbuf(&quic_mhdr_without_cbuf.mhdr()[i].msg_hdr, bw.buffer, + bw.buf_len, bw.peer_address); + } + + QuicMMsgHdr quic_mhdr_with_cbuf( + buffered_writes.begin(), buffered_writes.end(), + kCmsgSpaceForIp + kCmsgSpaceForSegmentSize, + [](QuicMMsgHdr* mhdr, int i, const BufferedWrite& buffered_write) { + mhdr->SetIpInNextCmsg(i, buffered_write.self_address); + *mhdr->GetNextCmsgData<uint16_t>(i, SOL_UDP, UDP_SEGMENT) = 1300; + }); + for (size_t i = 0; i < buffered_writes.size(); ++i) { + const BufferedWrite& bw = buffered_writes[i]; + msghdr* hdr = &quic_mhdr_with_cbuf.mhdr()[i].msg_hdr; + CheckIpAndGsoSizeInCbuf(hdr, hdr->msg_control, bw.self_address, 1300); + } +} + +TEST_F(QuicLinuxSocketUtilsTest, WriteMultiplePackets_NoPacketsToSend) { + int num_packets_sent; + QuicCircularDeque<BufferedWrite> buffered_writes; + + EXPECT_CALL(mock_syscalls_, Sendmmsg(_, _, _, _)).Times(0); + + EXPECT_EQ(WriteResult(WRITE_STATUS_ERROR, EINVAL), + TestWriteMultiplePackets(1, buffered_writes.begin(), + buffered_writes.end(), &num_packets_sent)); +} + +TEST_F(QuicLinuxSocketUtilsTest, WriteMultiplePackets_WriteBlocked) { + int num_packets_sent; + QuicCircularDeque<BufferedWrite> buffered_writes; + buffered_writes.emplace_back(nullptr, 0, QuicIpAddress(), + QuicSocketAddress(QuicIpAddress::Any4(), 0)); + + EXPECT_CALL(mock_syscalls_, Sendmmsg(_, _, _, _)) + .WillOnce(Invoke([](int /*fd*/, mmsghdr* /*msgvec*/, + unsigned int /*vlen*/, int /*flags*/) { + errno = EWOULDBLOCK; + return -1; + })); + + EXPECT_EQ(WriteResult(WRITE_STATUS_BLOCKED, EWOULDBLOCK), + TestWriteMultiplePackets(1, buffered_writes.begin(), + buffered_writes.end(), &num_packets_sent)); + EXPECT_EQ(0, num_packets_sent); +} + +TEST_F(QuicLinuxSocketUtilsTest, WriteMultiplePackets_WriteError) { + int num_packets_sent; + QuicCircularDeque<BufferedWrite> buffered_writes; + buffered_writes.emplace_back(nullptr, 0, QuicIpAddress(), + QuicSocketAddress(QuicIpAddress::Any4(), 0)); + + EXPECT_CALL(mock_syscalls_, Sendmmsg(_, _, _, _)) + .WillOnce(Invoke([](int /*fd*/, mmsghdr* /*msgvec*/, + unsigned int /*vlen*/, int /*flags*/) { + errno = EPERM; + return -1; + })); + + EXPECT_EQ(WriteResult(WRITE_STATUS_ERROR, EPERM), + TestWriteMultiplePackets(1, buffered_writes.begin(), + buffered_writes.end(), &num_packets_sent)); + EXPECT_EQ(0, num_packets_sent); +} + +TEST_F(QuicLinuxSocketUtilsTest, WriteMultiplePackets_WriteSuccess) { + int num_packets_sent; + QuicCircularDeque<BufferedWrite> buffered_writes; + const int kNumBufferedWrites = 10; + static_assert(kNumBufferedWrites < 256, "Must be less than 256"); + std::vector<std::string> buffer_holder; + for (int i = 0; i < kNumBufferedWrites; ++i) { + size_t buf_len = (i + 1) * 2; + std::ostringstream buffer_ostream; + while (buffer_ostream.str().length() < buf_len) { + buffer_ostream << i; + } + buffer_holder.push_back(buffer_ostream.str().substr(0, buf_len - 1) + '$'); + + buffered_writes.emplace_back(buffer_holder.back().data(), buf_len, + QuicIpAddress(), + QuicSocketAddress(QuicIpAddress::Any4(), 0)); + + // Leave the first self_address uninitialized. + if (i != 0) { + ASSERT_TRUE(buffered_writes.back().self_address.FromString("127.0.0.1")); + } + + std::ostringstream peer_ip_ostream; + QuicIpAddress peer_ip_address; + peer_ip_ostream << "127.0.1." << i + 1; + ASSERT_TRUE(peer_ip_address.FromString(peer_ip_ostream.str())); + buffered_writes.back().peer_address = + QuicSocketAddress(peer_ip_address, i + 1); + } + + InSequence s; + + for (int expected_num_packets_sent : {1, 2, 3, 10}) { + SCOPED_TRACE(testing::Message() + << "expected_num_packets_sent=" << expected_num_packets_sent); + EXPECT_CALL(mock_syscalls_, Sendmmsg(_, _, _, _)) + .WillOnce(Invoke( + [&](int /*fd*/, mmsghdr* msgvec, unsigned int vlen, int /*flags*/) { + EXPECT_LE(static_cast<unsigned int>(expected_num_packets_sent), + vlen); + for (unsigned int i = 0; i < vlen; ++i) { + const BufferedWrite& buffered_write = buffered_writes[i]; + const msghdr& hdr = msgvec[i].msg_hdr; + EXPECT_EQ(1u, hdr.msg_iovlen); + EXPECT_EQ(buffered_write.buffer, hdr.msg_iov->iov_base); + EXPECT_EQ(buffered_write.buf_len, hdr.msg_iov->iov_len); + sockaddr_storage expected_peer_address = + buffered_write.peer_address.generic_address(); + EXPECT_EQ(0, memcmp(&expected_peer_address, hdr.msg_name, + sizeof(sockaddr_storage))); + EXPECT_EQ(buffered_write.self_address.IsInitialized(), + hdr.msg_control != nullptr); + } + return expected_num_packets_sent; + })) + .RetiresOnSaturation(); + + int expected_bytes_written = 0; + for (auto it = buffered_writes.cbegin(); + it != buffered_writes.cbegin() + expected_num_packets_sent; ++it) { + expected_bytes_written += it->buf_len; + } + + EXPECT_EQ( + WriteResult(WRITE_STATUS_OK, expected_bytes_written), + TestWriteMultiplePackets(1, buffered_writes.cbegin(), + buffered_writes.cend(), &num_packets_sent)); + EXPECT_EQ(expected_num_packets_sent, num_packets_sent); + } +} + +} // namespace +} // namespace test +} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.cc b/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.cc index 0ae78d22fa6..c1f8982f705 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.cc @@ -47,10 +47,10 @@ QuicLongHeaderType EncryptionlevelToLongHeaderType(EncryptionLevel level) { case ENCRYPTION_FORWARD_SECURE: QUIC_BUG << "Try to derive long header type for packet with encryption level: " - << EncryptionLevelToString(level); + << level; return INVALID_PACKET_TYPE; default: - QUIC_BUG << EncryptionLevelToString(level); + QUIC_BUG << level; return INVALID_PACKET_TYPE; } } @@ -165,6 +165,8 @@ void QuicPacketCreator::SetMaxPacketLength(QuicByteCount length) { if (length == max_packet_length_) { return; } + QUIC_DVLOG(1) << "Updating packet creator max packet length from " + << max_packet_length_ << " to " << length; max_packet_length_ = length; max_plaintext_size_ = framer_->GetMaxPlaintextSize(max_packet_length_); @@ -198,6 +200,8 @@ void QuicPacketCreator::SetSoftMaxPacketLength(QuicByteCount length) { } if (framer_->GetMaxPlaintextSize(length) < PacketHeaderSize() + MinPlaintextPacketSize(framer_->version())) { + // Please note: this would not guarantee to fit next packet if the size of + // packet header increases (e.g., encryption level changes). QUIC_DLOG(INFO) << length << " is too small to fit packet header"; return; } @@ -281,6 +285,10 @@ bool QuicPacketCreator::ConsumeCryptoDataToFillCurrentPacket( bool needs_full_padding, TransmissionType transmission_type, QuicFrame* frame) { + QUIC_DVLOG(2) << "ConsumeCryptoDataToFillCurrentPacket " << level + << " write_length " << write_length << " offset " << offset + << (needs_full_padding ? " needs_full_padding" : "") << " " + << transmission_type; if (!CreateCryptoFrame(level, write_length, offset, frame)) { return false; } @@ -423,8 +431,17 @@ bool QuicPacketCreator::CreateCryptoFrame(EncryptionLevel level, QuicFrame* frame) { size_t min_frame_size = QuicFramer::GetMinCryptoFrameSize(write_length, offset); - if (BytesFree() <= min_frame_size && - (!RemoveSoftMaxPacketLength() || BytesFree() <= min_frame_size)) { + size_t min_plaintext_bytes = min_frame_size; + if (fix_min_crypto_frame_size_ && queued_frames_.empty()) { + // TODO(fayang): to make this more general, we need to move the checking + // when trying to add a frame when GetSerializedFrameLength. Remove soft + // limit if current packet needs extra padding and the space is too small. + QUIC_RELOADABLE_FLAG_COUNT(quic_fix_min_crypto_frame_size); + min_plaintext_bytes = + std::max(min_frame_size, MinPlaintextPacketSize(framer_->version())); + } + if (BytesFree() <= min_plaintext_bytes && + (!RemoveSoftMaxPacketLength() || BytesFree() <= min_plaintext_bytes)) { return false; } size_t max_write_length = BytesFree() - min_frame_size; @@ -439,12 +456,23 @@ void QuicPacketCreator::FlushCurrentPacket() { } QUIC_CACHELINE_ALIGNED char stack_buffer[kMaxOutgoingPacketSize]; - char* serialized_packet_buffer = delegate_->GetPacketBuffer(); - if (serialized_packet_buffer == nullptr) { - serialized_packet_buffer = stack_buffer; + QuicOwnedPacketBuffer external_buffer(delegate_->GetPacketBuffer()); + + if (!avoid_leak_writer_buffer_ && external_buffer.release_buffer != nullptr) { + // This is not a flag count because it is incremented when flag is false. + QUIC_CODE_COUNT(quic_avoid_leak_writer_buffer_flag_false_noop_1); + + // Setting it to nullptr to keep the behavior unchanged when flag is false. + external_buffer.release_buffer = nullptr; + } + + if (external_buffer.buffer == nullptr) { + external_buffer.buffer = stack_buffer; + external_buffer.release_buffer = nullptr; } - SerializePacket(serialized_packet_buffer, kMaxOutgoingPacketSize); + DCHECK_EQ(nullptr, packet_.encrypted_buffer); + SerializePacket(std::move(external_buffer), kMaxOutgoingPacketSize); OnSerializedPacket(); } @@ -471,6 +499,12 @@ void QuicPacketCreator::ClearPacket() { packet_.transmission_type = NOT_RETRANSMISSION; packet_.encrypted_buffer = nullptr; packet_.encrypted_length = 0; + if (avoid_leak_writer_buffer_) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_avoid_leak_writer_buffer, 2, 3); + QUIC_BUG_IF(packet_.release_encrypted_buffer != nullptr) + << "packet_.release_encrypted_buffer should be empty"; + packet_.release_encrypted_buffer = nullptr; + } DCHECK(packet_.retransmittable_frames.empty()); DCHECK(packet_.nonretransmittable_frames.empty()); packet_.largest_acked.Clear(); @@ -514,7 +548,7 @@ size_t QuicPacketCreator::ReserializeInitialPacketInCoalescedPacket( return 0; } } - SerializePacket(buffer, buffer_len); + SerializePacket(QuicOwnedPacketBuffer(buffer, nullptr), buffer_len); const size_t encrypted_length = packet_.encrypted_length; // Clear frames in packet_. No need to DeleteFrames since frames are owned by // initial_packet. @@ -533,16 +567,29 @@ void QuicPacketCreator::CreateAndSerializeStreamFrame( TransmissionType transmission_type, size_t* num_bytes_consumed) { DCHECK(queued_frames_.empty()); + DCHECK(!QuicUtils::IsCryptoStreamId(transport_version(), id)); // Write out the packet header QuicPacketHeader header; FillPacketHeader(&header); QUIC_CACHELINE_ALIGNED char stack_buffer[kMaxOutgoingPacketSize]; - char* encrypted_buffer = delegate_->GetPacketBuffer(); - if (encrypted_buffer == nullptr) { - encrypted_buffer = stack_buffer; + QuicOwnedPacketBuffer packet_buffer(delegate_->GetPacketBuffer()); + + if (!avoid_leak_writer_buffer_ && packet_buffer.release_buffer != nullptr) { + // This is not a flag count because it is incremented when flag is false. + QUIC_CODE_COUNT(quic_avoid_leak_writer_buffer_flag_false_noop_2); + + // Setting it to nullptr to keep the behavior unchanged when flag is false. + packet_buffer.release_buffer = nullptr; } + if (packet_buffer.buffer == nullptr) { + packet_buffer.buffer = stack_buffer; + packet_buffer.release_buffer = nullptr; + } + + char* encrypted_buffer = packet_buffer.buffer; + QuicDataWriter writer(kMaxOutgoingPacketSize, encrypted_buffer); size_t length_field_offset = 0; if (!framer_->AppendPacketHeader(header, &writer, &length_field_offset)) { @@ -609,6 +656,9 @@ void QuicPacketCreator::CreateAndSerializeStreamFrame( packet_.transmission_type = transmission_type; + DCHECK(packet_.encryption_level == ENCRYPTION_FORWARD_SECURE || + packet_.encryption_level == ENCRYPTION_ZERO_RTT) + << packet_.encryption_level; size_t encrypted_length = framer_->EncryptInPlace( packet_.encryption_level, packet_.packet_number, GetStartOfEncryptedData(framer_->transport_version(), header), @@ -623,6 +673,14 @@ void QuicPacketCreator::CreateAndSerializeStreamFrame( packet_size_ = 0; packet_.encrypted_buffer = encrypted_buffer; packet_.encrypted_length = encrypted_length; + if (avoid_leak_writer_buffer_) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_avoid_leak_writer_buffer, 3, 3); + packet_.release_encrypted_buffer = std::move(packet_buffer).release_buffer; + } else { + // If flag --quic_avoid_leak_writer_buffer is false, the release function + // should be empty. + DCHECK(packet_buffer.release_buffer == nullptr); + } packet_.retransmittable_frames.push_back(QuicFrame(frame)); OnSerializedPacket(); } @@ -674,6 +732,9 @@ size_t QuicPacketCreator::BytesFree() { } size_t QuicPacketCreator::PacketSize() { + if (update_packet_size_) { + return queued_frames_.empty() ? PacketHeaderSize() : packet_size_; + } if (!queued_frames_.empty()) { return packet_size_; } @@ -691,7 +752,7 @@ bool QuicPacketCreator::AddPaddedSavedFrame( return false; } -void QuicPacketCreator::SerializePacket(char* encrypted_buffer, +void QuicPacketCreator::SerializePacket(QuicOwnedPacketBuffer encrypted_buffer, size_t encrypted_buffer_len) { DCHECK_LT(0u, encrypted_buffer_len); QUIC_BUG_IF(queued_frames_.empty() && pending_padding_bytes_ == 0) @@ -704,14 +765,13 @@ void QuicPacketCreator::SerializePacket(char* encrypted_buffer, QUIC_DVLOG(2) << ENDPOINT << "Serializing packet " << header << QuicFramesToString(queued_frames_) << " at encryption_level " - << EncryptionLevelToString(packet_.encryption_level); + << packet_.encryption_level; if (!framer_->HasEncrypterOfEncryptionLevel(packet_.encryption_level)) { QUIC_BUG << ENDPOINT << "Attempting to serialize " << header << QuicFramesToString(queued_frames_) - << " at missing encryption_level " - << EncryptionLevelToString(packet_.encryption_level) << " using " - << framer_->version(); + << " at missing encryption_level " << packet_.encryption_level + << " using " << framer_->version(); return; } @@ -719,10 +779,18 @@ void QuicPacketCreator::SerializePacket(char* encrypted_buffer, // Use the packet_size_ instead of the buffer size to ensure smaller // packet sizes are properly used. size_t length = - framer_->BuildDataPacket(header, queued_frames_, encrypted_buffer, + framer_->BuildDataPacket(header, queued_frames_, encrypted_buffer.buffer, packet_size_, packet_.encryption_level); if (length == 0) { - QUIC_BUG << "Failed to serialize " << queued_frames_.size() << " frames."; + QUIC_BUG << "Failed to serialize " << QuicFramesToString(queued_frames_) + << " at encryption_level: " << packet_.encryption_level + << ", needs_full_padding_: " << needs_full_padding_ + << ", packet_.num_padding_bytes: " << packet_.num_padding_bytes + << ", pending_padding_bytes_: " << pending_padding_bytes_ + << ", latched_hard_max_packet_length_: " + << latched_hard_max_packet_length_ + << ", max_packet_length_: " << max_packet_length_ + << ", header: " << header; return; } @@ -741,7 +809,7 @@ void QuicPacketCreator::SerializePacket(char* encrypted_buffer, const size_t encrypted_length = framer_->EncryptInPlace( packet_.encryption_level, packet_.packet_number, GetStartOfEncryptedData(framer_->transport_version(), header), length, - encrypted_buffer_len, encrypted_buffer); + encrypted_buffer_len, encrypted_buffer.buffer); if (encrypted_length == 0) { QUIC_BUG << "Failed to encrypt packet number " << packet_.packet_number; return; @@ -749,8 +817,17 @@ void QuicPacketCreator::SerializePacket(char* encrypted_buffer, packet_size_ = 0; queued_frames_.clear(); - packet_.encrypted_buffer = encrypted_buffer; + packet_.encrypted_buffer = encrypted_buffer.buffer; packet_.encrypted_length = encrypted_length; + if (avoid_leak_writer_buffer_) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_avoid_leak_writer_buffer, 1, 3); + packet_.release_encrypted_buffer = + std::move(encrypted_buffer).release_buffer; + } else { + // If flag --quic_avoid_leak_writer_buffer is false, the release function + // should be empty. + DCHECK(encrypted_buffer.release_buffer == nullptr); + } } std::unique_ptr<QuicEncryptedPacket> @@ -785,6 +862,7 @@ QuicPacketCreator::SerializeConnectivityProbingPacket() { header, buffer.get(), max_plaintext_size_, packet_.encryption_level); DCHECK(length); + DCHECK_EQ(packet_.encryption_level, ENCRYPTION_FORWARD_SECURE); const size_t encrypted_length = framer_->EncryptInPlace( packet_.encryption_level, packet_.packet_number, GetStartOfEncryptedData(framer_->transport_version(), header), length, @@ -824,6 +902,7 @@ QuicPacketCreator::SerializePathChallengeConnectivityProbingPacket( packet_.encryption_level); DCHECK(length); + DCHECK_EQ(packet_.encryption_level, ENCRYPTION_FORWARD_SECURE); const size_t encrypted_length = framer_->EncryptInPlace( packet_.encryption_level, packet_.packet_number, GetStartOfEncryptedData(framer_->transport_version(), header), length, @@ -865,6 +944,7 @@ QuicPacketCreator::SerializePathResponseConnectivityProbingPacket( payloads, is_padded, packet_.encryption_level); DCHECK(length); + DCHECK_EQ(packet_.encryption_level, ENCRYPTION_FORWARD_SECURE); const size_t encrypted_length = framer_->EncryptInPlace( packet_.encryption_level, packet_.packet_number, GetStartOfEncryptedData(framer_->transport_version(), header), length, @@ -1180,9 +1260,9 @@ QuicConsumedData QuicPacketCreator::ConsumeData(QuicStreamId id, write_length - total_bytes_consumed > kMaxOutgoingPacketSize && latched_hard_max_packet_length_ == 0; - while (!run_fast_path && delegate_->ShouldGeneratePacket( - HAS_RETRANSMITTABLE_DATA, - has_handshake ? IS_HANDSHAKE : NOT_HANDSHAKE)) { + while (!run_fast_path && + (has_handshake || delegate_->ShouldGeneratePacket( + HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE))) { QuicFrame frame; bool needs_full_padding = has_handshake && fully_pad_crypto_handshake_packets_; @@ -1268,6 +1348,8 @@ QuicConsumedData QuicPacketCreator::ConsumeDataFastPath( size_t QuicPacketCreator::ConsumeCryptoData(EncryptionLevel level, size_t write_length, QuicStreamOffset offset) { + QUIC_DVLOG(2) << "ConsumeCryptoData " << level << " write_length " + << write_length << " offset " << offset; QUIC_BUG_IF(!flusher_attached_) << "Packet flusher is not attached when " "generator tries to write crypto data."; MaybeBundleAckOpportunistically(); @@ -1282,7 +1364,13 @@ size_t QuicPacketCreator::ConsumeCryptoData(EncryptionLevel level, size_t total_bytes_consumed = 0; - while (total_bytes_consumed < write_length) { + while (total_bytes_consumed < write_length && + (!GetQuicReloadableFlag(quic_fix_checking_should_generate_packet) || + delegate_->ShouldGeneratePacket(HAS_RETRANSMITTABLE_DATA, + IS_HANDSHAKE))) { + if (GetQuicReloadableFlag(quic_fix_checking_should_generate_packet)) { + QUIC_RELOADABLE_FLAG_COUNT(quic_fix_checking_should_generate_packet); + } QuicFrame frame; if (!ConsumeCryptoDataToFillCurrentPacket( level, write_length - total_bytes_consumed, @@ -1484,7 +1572,7 @@ void QuicPacketCreator::FillPacketHeader(QuicPacketHeader* header) { bool QuicPacketCreator::AddFrame(const QuicFrame& frame, TransmissionType transmission_type) { QUIC_DVLOG(1) << ENDPOINT << "Adding frame with transmission type " - << TransmissionTypeToString(transmission_type) << ": " << frame; + << transmission_type << ": " << frame; if (frame.type == STREAM_FRAME && !QuicUtils::IsCryptoStreamId(framer_->transport_version(), frame.stream_frame.stream_id) && @@ -1518,10 +1606,15 @@ bool QuicPacketCreator::AddFrame(const QuicFrame& frame, /* last_frame_in_packet= */ true, GetPacketNumberLength()); } if (frame_len == 0) { - // Current open packet is full. + QUIC_DVLOG(1) << "Flushing because current open packet is full when adding " + << frame; FlushCurrentPacket(); return false; } + if (update_packet_size_ && queued_frames_.empty()) { + QUIC_RELOADABLE_FLAG_COUNT(quic_update_packet_size); + packet_size_ = PacketHeaderSize(); + } DCHECK_LT(0u, packet_size_); packet_size_ += ExpansionOnNewFrame() + frame_len; @@ -1641,6 +1734,10 @@ void QuicPacketCreator::MaybeAddPadding() { } } + if (disable_padding_override_) { + needs_full_padding_ = false; + } + // Header protection requires a minimum plaintext packet size. size_t extra_padding_bytes = 0; if (framer_->version().HasHeaderProtection()) { @@ -1675,8 +1772,7 @@ void QuicPacketCreator::MaybeAddPadding() { bool success = AddFrame(QuicFrame(QuicPaddingFrame(padding_bytes)), packet_.transmission_type); QUIC_BUG_IF(!success) << "Failed to add padding_bytes: " << padding_bytes - << " transmission_type: " - << TransmissionTypeToString(packet_.transmission_type); + << " transmission_type: " << packet_.transmission_type; } bool QuicPacketCreator::IncludeNonceInPublicHeader() const { diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.h b/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.h index 7695587f9f5..76d65574e51 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.h @@ -41,9 +41,9 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { public: virtual ~DelegateInterface() {} // Get a buffer of kMaxOutgoingPacketSize bytes to serialize the next - // packet. If return nullptr, QuicPacketCreator will serialize on a stack - // buffer. - virtual char* GetPacketBuffer() = 0; + // packet. If the return value's buffer is nullptr, QuicPacketCreator will + // serialize on a stack buffer. + virtual QuicPacketBuffer GetPacketBuffer() = 0; // Called when a packet is serialized. Delegate take the ownership of // |serialized_packet|. virtual void OnSerializedPacket(SerializedPacket serialized_packet) = 0; @@ -142,12 +142,14 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { // Returns true if current open packet can accommodate more stream frames of // stream |id| at |offset| and data length |data_size|, false otherwise. + // TODO(fayang): mark this const when deprecating quic_update_packet_size. bool HasRoomForStreamFrame(QuicStreamId id, QuicStreamOffset offset, size_t data_size); // Returns true if current open packet can accommodate a message frame of // |length|. + // TODO(fayang): mark this const when deprecating quic_update_packet_size. bool HasRoomForMessageFrame(QuicByteCount length); // Serializes all added frames into a single packet and invokes the delegate_ @@ -179,6 +181,7 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { // frames in the packet. Since stream frames are slightly smaller when they // are the last frame in a packet, this method will return a different // value than max_packet_size - PacketSize(), in this case. + // TODO(fayang): mark this const when deprecating quic_update_packet_size. size_t BytesFree(); // Returns the number of bytes that the packet will expand by if a new frame @@ -191,6 +194,7 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { // if serialized with the current frames. Adding a frame to the packet // may change the serialized length of existing frames, as per the comment // in BytesFree. + // TODO(fayang): mark this const when deprecating quic_update_packet_size. size_t PacketSize(); // Tries to add |frame| to the packet creator's list of frames to be @@ -255,6 +259,7 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { void set_encryption_level(EncryptionLevel level) { packet_.encryption_level = level; } + EncryptionLevel encryption_level() { return packet_.encryption_level; } // packet number of the last created packet, or 0 if no packets have been // created. @@ -429,6 +434,10 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { char* buffer, size_t buffer_len); + void set_disable_padding_override(bool should_disable_padding) { + disable_padding_override_ = should_disable_padding; + } + private: friend class test::QuicPacketCreatorPeer; @@ -459,7 +468,8 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { // retransmitted to packet_.retransmittable_frames. All frames must fit into // a single packet. // Fails if |encrypted_buffer_len| isn't long enough for the encrypted packet. - void SerializePacket(char* encrypted_buffer, size_t encrypted_buffer_len); + void SerializePacket(QuicOwnedPacketBuffer encrypted_buffer, + size_t encrypted_buffer_len); // Called after a new SerialiedPacket is created to call the delegate's // OnSerializedPacket and reset state. @@ -551,7 +561,8 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { // Frames to be added to the next SerializedPacket QuicFrames queued_frames_; - // packet_size should never be read directly, use PacketSize() instead. + // Serialization size of header + frames. If there is no queued frames, + // packet_size_ is 0. // TODO(ianswett): Move packet_size_ into SerializedPacket once // QuicEncryptedPacket has been flattened into SerializedPacket. size_t packet_size_; @@ -597,6 +608,17 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { // accept. There is no limit for QUIC_CRYPTO connections, but QUIC+TLS // negotiates this during the handshake. QuicByteCount max_datagram_frame_size_; + + const bool avoid_leak_writer_buffer_ = + GetQuicReloadableFlag(quic_avoid_leak_writer_buffer); + + const bool fix_min_crypto_frame_size_ = + GetQuicReloadableFlag(quic_fix_min_crypto_frame_size); + + // When true, this will override the padding generation code to disable it. + bool disable_padding_override_ = false; + + bool update_packet_size_ = GetQuicReloadableFlag(quic_update_packet_size); }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator_test.cc index d1beea7c01d..394b82ec364 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator_test.cc @@ -162,7 +162,8 @@ class QuicPacketCreatorTest : public QuicTestWithParam<TestParams> { connection_id_.length()), data_("foo"), creator_(connection_id_, &client_framer_, &delegate_, &producer_) { - EXPECT_CALL(delegate_, GetPacketBuffer()).WillRepeatedly(Return(nullptr)); + EXPECT_CALL(delegate_, GetPacketBuffer()) + .WillRepeatedly(Return(QuicPacketBuffer())); creator_.SetEncrypter(ENCRYPTION_INITIAL, std::make_unique<NullEncrypter>( Perspective::IS_CLIENT)); creator_.SetEncrypter(ENCRYPTION_HANDSHAKE, std::make_unique<NullEncrypter>( @@ -930,40 +931,36 @@ TEST_P(QuicPacketCreatorTest, BuildPathResponsePacket3ResponsesPadded) { } TEST_P(QuicPacketCreatorTest, SerializeConnectivityProbingPacket) { - for (int i = ENCRYPTION_INITIAL; i < NUM_ENCRYPTION_LEVELS; ++i) { - EncryptionLevel level = static_cast<EncryptionLevel>(i); - - creator_.set_encryption_level(level); + creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE); - std::unique_ptr<SerializedPacket> encrypted; + std::unique_ptr<SerializedPacket> encrypted; + if (VersionHasIetfQuicFrames(creator_.transport_version())) { + QuicPathFrameBuffer payload = { + {0xde, 0xad, 0xbe, 0xef, 0xba, 0xdc, 0x0f, 0xfe}}; + encrypted = + creator_.SerializePathChallengeConnectivityProbingPacket(&payload); + } else { + encrypted = creator_.SerializeConnectivityProbingPacket(); + } + { + InSequence s; + EXPECT_CALL(framer_visitor_, OnPacket()); + EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_)); + EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_)); + EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_)); + EXPECT_CALL(framer_visitor_, OnPacketHeader(_)); if (VersionHasIetfQuicFrames(creator_.transport_version())) { - QuicPathFrameBuffer payload = { - {0xde, 0xad, 0xbe, 0xef, 0xba, 0xdc, 0x0f, 0xfe}}; - encrypted = - creator_.SerializePathChallengeConnectivityProbingPacket(&payload); + EXPECT_CALL(framer_visitor_, OnPathChallengeFrame(_)); + EXPECT_CALL(framer_visitor_, OnPaddingFrame(_)); } else { - encrypted = creator_.SerializeConnectivityProbingPacket(); - } - { - InSequence s; - EXPECT_CALL(framer_visitor_, OnPacket()); - EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_)); - EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_)); - EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_)); - EXPECT_CALL(framer_visitor_, OnPacketHeader(_)); - if (VersionHasIetfQuicFrames(creator_.transport_version())) { - EXPECT_CALL(framer_visitor_, OnPathChallengeFrame(_)); - EXPECT_CALL(framer_visitor_, OnPaddingFrame(_)); - } else { - EXPECT_CALL(framer_visitor_, OnPingFrame(_)); - EXPECT_CALL(framer_visitor_, OnPaddingFrame(_)); - } - EXPECT_CALL(framer_visitor_, OnPacketComplete()); + EXPECT_CALL(framer_visitor_, OnPingFrame(_)); + EXPECT_CALL(framer_visitor_, OnPaddingFrame(_)); } - // QuicFramerPeer::SetPerspective(&client_framer_, Perspective::IS_SERVER); - server_framer_.ProcessPacket(QuicEncryptedPacket( - encrypted->encrypted_buffer, encrypted->encrypted_length)); + EXPECT_CALL(framer_visitor_, OnPacketComplete()); } + // QuicFramerPeer::SetPerspective(&client_framer_, Perspective::IS_SERVER); + server_framer_.ProcessPacket(QuicEncryptedPacket( + encrypted->encrypted_buffer, encrypted->encrypted_length)); } TEST_P(QuicPacketCreatorTest, SerializePathChallengeProbePacket) { @@ -973,28 +970,24 @@ TEST_P(QuicPacketCreatorTest, SerializePathChallengeProbePacket) { QuicPathFrameBuffer payload = { {0xde, 0xad, 0xbe, 0xef, 0xba, 0xdc, 0x0f, 0xee}}; - for (int i = ENCRYPTION_INITIAL; i < NUM_ENCRYPTION_LEVELS; ++i) { - EncryptionLevel level = static_cast<EncryptionLevel>(i); - - creator_.set_encryption_level(level); + creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE); - std::unique_ptr<SerializedPacket> encrypted( - creator_.SerializePathChallengeConnectivityProbingPacket(&payload)); - { - InSequence s; - EXPECT_CALL(framer_visitor_, OnPacket()); - EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_)); - EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_)); - EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_)); - EXPECT_CALL(framer_visitor_, OnPacketHeader(_)); - EXPECT_CALL(framer_visitor_, OnPathChallengeFrame(_)); - EXPECT_CALL(framer_visitor_, OnPaddingFrame(_)); - EXPECT_CALL(framer_visitor_, OnPacketComplete()); - } - // QuicFramerPeer::SetPerspective(&client_framer_, Perspective::IS_SERVER); - server_framer_.ProcessPacket(QuicEncryptedPacket( - encrypted->encrypted_buffer, encrypted->encrypted_length)); + std::unique_ptr<SerializedPacket> encrypted( + creator_.SerializePathChallengeConnectivityProbingPacket(&payload)); + { + InSequence s; + EXPECT_CALL(framer_visitor_, OnPacket()); + EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_)); + EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_)); + EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_)); + EXPECT_CALL(framer_visitor_, OnPacketHeader(_)); + EXPECT_CALL(framer_visitor_, OnPathChallengeFrame(_)); + EXPECT_CALL(framer_visitor_, OnPaddingFrame(_)); + EXPECT_CALL(framer_visitor_, OnPacketComplete()); } + // QuicFramerPeer::SetPerspective(&client_framer_, Perspective::IS_SERVER); + server_framer_.ProcessPacket(QuicEncryptedPacket( + encrypted->encrypted_buffer, encrypted->encrypted_length)); } TEST_P(QuicPacketCreatorTest, SerializePathResponseProbePacket1PayloadPadded) { @@ -1004,30 +997,26 @@ TEST_P(QuicPacketCreatorTest, SerializePathResponseProbePacket1PayloadPadded) { QuicPathFrameBuffer payload0 = { {0xde, 0xad, 0xbe, 0xef, 0xba, 0xdc, 0x0f, 0xee}}; - for (int i = ENCRYPTION_INITIAL; i < NUM_ENCRYPTION_LEVELS; ++i) { - EncryptionLevel level = static_cast<EncryptionLevel>(i); - creator_.set_encryption_level(level); + creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE); - QuicCircularDeque<QuicPathFrameBuffer> payloads; - payloads.push_back(payload0); + QuicCircularDeque<QuicPathFrameBuffer> payloads; + payloads.push_back(payload0); - std::unique_ptr<SerializedPacket> encrypted( - creator_.SerializePathResponseConnectivityProbingPacket(payloads, - true)); - { - InSequence s; - EXPECT_CALL(framer_visitor_, OnPacket()); - EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_)); - EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_)); - EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_)); - EXPECT_CALL(framer_visitor_, OnPacketHeader(_)); - EXPECT_CALL(framer_visitor_, OnPathResponseFrame(_)); - EXPECT_CALL(framer_visitor_, OnPaddingFrame(_)); - EXPECT_CALL(framer_visitor_, OnPacketComplete()); - } - server_framer_.ProcessPacket(QuicEncryptedPacket( - encrypted->encrypted_buffer, encrypted->encrypted_length)); + std::unique_ptr<SerializedPacket> encrypted( + creator_.SerializePathResponseConnectivityProbingPacket(payloads, true)); + { + InSequence s; + EXPECT_CALL(framer_visitor_, OnPacket()); + EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_)); + EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_)); + EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_)); + EXPECT_CALL(framer_visitor_, OnPacketHeader(_)); + EXPECT_CALL(framer_visitor_, OnPathResponseFrame(_)); + EXPECT_CALL(framer_visitor_, OnPaddingFrame(_)); + EXPECT_CALL(framer_visitor_, OnPacketComplete()); } + server_framer_.ProcessPacket(QuicEncryptedPacket( + encrypted->encrypted_buffer, encrypted->encrypted_length)); } TEST_P(QuicPacketCreatorTest, @@ -1038,29 +1027,25 @@ TEST_P(QuicPacketCreatorTest, QuicPathFrameBuffer payload0 = { {0xde, 0xad, 0xbe, 0xef, 0xba, 0xdc, 0x0f, 0xee}}; - for (int i = ENCRYPTION_INITIAL; i < NUM_ENCRYPTION_LEVELS; ++i) { - EncryptionLevel level = static_cast<EncryptionLevel>(i); - creator_.set_encryption_level(level); + creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE); - QuicCircularDeque<QuicPathFrameBuffer> payloads; - payloads.push_back(payload0); + QuicCircularDeque<QuicPathFrameBuffer> payloads; + payloads.push_back(payload0); - std::unique_ptr<SerializedPacket> encrypted( - creator_.SerializePathResponseConnectivityProbingPacket(payloads, - false)); - { - InSequence s; - EXPECT_CALL(framer_visitor_, OnPacket()); - EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_)); - EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_)); - EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_)); - EXPECT_CALL(framer_visitor_, OnPacketHeader(_)); - EXPECT_CALL(framer_visitor_, OnPathResponseFrame(_)); - EXPECT_CALL(framer_visitor_, OnPacketComplete()); - } - server_framer_.ProcessPacket(QuicEncryptedPacket( - encrypted->encrypted_buffer, encrypted->encrypted_length)); + std::unique_ptr<SerializedPacket> encrypted( + creator_.SerializePathResponseConnectivityProbingPacket(payloads, false)); + { + InSequence s; + EXPECT_CALL(framer_visitor_, OnPacket()); + EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_)); + EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_)); + EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_)); + EXPECT_CALL(framer_visitor_, OnPacketHeader(_)); + EXPECT_CALL(framer_visitor_, OnPathResponseFrame(_)); + EXPECT_CALL(framer_visitor_, OnPacketComplete()); } + server_framer_.ProcessPacket(QuicEncryptedPacket( + encrypted->encrypted_buffer, encrypted->encrypted_length)); } TEST_P(QuicPacketCreatorTest, SerializePathResponseProbePacket2PayloadsPadded) { @@ -1072,31 +1057,27 @@ TEST_P(QuicPacketCreatorTest, SerializePathResponseProbePacket2PayloadsPadded) { QuicPathFrameBuffer payload1 = { {0xad, 0xbe, 0xef, 0xba, 0xdc, 0x0f, 0xee, 0xde}}; - for (int i = ENCRYPTION_INITIAL; i < NUM_ENCRYPTION_LEVELS; ++i) { - EncryptionLevel level = static_cast<EncryptionLevel>(i); - creator_.set_encryption_level(level); + creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE); - QuicCircularDeque<QuicPathFrameBuffer> payloads; - payloads.push_back(payload0); - payloads.push_back(payload1); + QuicCircularDeque<QuicPathFrameBuffer> payloads; + payloads.push_back(payload0); + payloads.push_back(payload1); - std::unique_ptr<SerializedPacket> encrypted( - creator_.SerializePathResponseConnectivityProbingPacket(payloads, - true)); - { - InSequence s; - EXPECT_CALL(framer_visitor_, OnPacket()); - EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_)); - EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_)); - EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_)); - EXPECT_CALL(framer_visitor_, OnPacketHeader(_)); - EXPECT_CALL(framer_visitor_, OnPathResponseFrame(_)).Times(2); - EXPECT_CALL(framer_visitor_, OnPaddingFrame(_)); - EXPECT_CALL(framer_visitor_, OnPacketComplete()); - } - server_framer_.ProcessPacket(QuicEncryptedPacket( - encrypted->encrypted_buffer, encrypted->encrypted_length)); + std::unique_ptr<SerializedPacket> encrypted( + creator_.SerializePathResponseConnectivityProbingPacket(payloads, true)); + { + InSequence s; + EXPECT_CALL(framer_visitor_, OnPacket()); + EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_)); + EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_)); + EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_)); + EXPECT_CALL(framer_visitor_, OnPacketHeader(_)); + EXPECT_CALL(framer_visitor_, OnPathResponseFrame(_)).Times(2); + EXPECT_CALL(framer_visitor_, OnPaddingFrame(_)); + EXPECT_CALL(framer_visitor_, OnPacketComplete()); } + server_framer_.ProcessPacket(QuicEncryptedPacket( + encrypted->encrypted_buffer, encrypted->encrypted_length)); } TEST_P(QuicPacketCreatorTest, @@ -1109,30 +1090,26 @@ TEST_P(QuicPacketCreatorTest, QuicPathFrameBuffer payload1 = { {0xad, 0xbe, 0xef, 0xba, 0xdc, 0x0f, 0xee, 0xde}}; - for (int i = ENCRYPTION_INITIAL; i < NUM_ENCRYPTION_LEVELS; ++i) { - EncryptionLevel level = static_cast<EncryptionLevel>(i); - creator_.set_encryption_level(level); + creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE); - QuicCircularDeque<QuicPathFrameBuffer> payloads; - payloads.push_back(payload0); - payloads.push_back(payload1); + QuicCircularDeque<QuicPathFrameBuffer> payloads; + payloads.push_back(payload0); + payloads.push_back(payload1); - std::unique_ptr<SerializedPacket> encrypted( - creator_.SerializePathResponseConnectivityProbingPacket(payloads, - false)); - { - InSequence s; - EXPECT_CALL(framer_visitor_, OnPacket()); - EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_)); - EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_)); - EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_)); - EXPECT_CALL(framer_visitor_, OnPacketHeader(_)); - EXPECT_CALL(framer_visitor_, OnPathResponseFrame(_)).Times(2); - EXPECT_CALL(framer_visitor_, OnPacketComplete()); - } - server_framer_.ProcessPacket(QuicEncryptedPacket( - encrypted->encrypted_buffer, encrypted->encrypted_length)); + std::unique_ptr<SerializedPacket> encrypted( + creator_.SerializePathResponseConnectivityProbingPacket(payloads, false)); + { + InSequence s; + EXPECT_CALL(framer_visitor_, OnPacket()); + EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_)); + EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_)); + EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_)); + EXPECT_CALL(framer_visitor_, OnPacketHeader(_)); + EXPECT_CALL(framer_visitor_, OnPathResponseFrame(_)).Times(2); + EXPECT_CALL(framer_visitor_, OnPacketComplete()); } + server_framer_.ProcessPacket(QuicEncryptedPacket( + encrypted->encrypted_buffer, encrypted->encrypted_length)); } TEST_P(QuicPacketCreatorTest, SerializePathResponseProbePacket3PayloadsPadded) { @@ -1146,32 +1123,28 @@ TEST_P(QuicPacketCreatorTest, SerializePathResponseProbePacket3PayloadsPadded) { QuicPathFrameBuffer payload2 = { {0xbe, 0xef, 0xba, 0xdc, 0x0f, 0xee, 0xde, 0xad}}; - for (int i = ENCRYPTION_INITIAL; i < NUM_ENCRYPTION_LEVELS; ++i) { - EncryptionLevel level = static_cast<EncryptionLevel>(i); - creator_.set_encryption_level(level); + creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE); - QuicCircularDeque<QuicPathFrameBuffer> payloads; - payloads.push_back(payload0); - payloads.push_back(payload1); - payloads.push_back(payload2); + QuicCircularDeque<QuicPathFrameBuffer> payloads; + payloads.push_back(payload0); + payloads.push_back(payload1); + payloads.push_back(payload2); - std::unique_ptr<SerializedPacket> encrypted( - creator_.SerializePathResponseConnectivityProbingPacket(payloads, - true)); - { - InSequence s; - EXPECT_CALL(framer_visitor_, OnPacket()); - EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_)); - EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_)); - EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_)); - EXPECT_CALL(framer_visitor_, OnPacketHeader(_)); - EXPECT_CALL(framer_visitor_, OnPathResponseFrame(_)).Times(3); - EXPECT_CALL(framer_visitor_, OnPaddingFrame(_)); - EXPECT_CALL(framer_visitor_, OnPacketComplete()); - } - server_framer_.ProcessPacket(QuicEncryptedPacket( - encrypted->encrypted_buffer, encrypted->encrypted_length)); + std::unique_ptr<SerializedPacket> encrypted( + creator_.SerializePathResponseConnectivityProbingPacket(payloads, true)); + { + InSequence s; + EXPECT_CALL(framer_visitor_, OnPacket()); + EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_)); + EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_)); + EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_)); + EXPECT_CALL(framer_visitor_, OnPacketHeader(_)); + EXPECT_CALL(framer_visitor_, OnPathResponseFrame(_)).Times(3); + EXPECT_CALL(framer_visitor_, OnPaddingFrame(_)); + EXPECT_CALL(framer_visitor_, OnPacketComplete()); } + server_framer_.ProcessPacket(QuicEncryptedPacket( + encrypted->encrypted_buffer, encrypted->encrypted_length)); } TEST_P(QuicPacketCreatorTest, @@ -1186,30 +1159,26 @@ TEST_P(QuicPacketCreatorTest, QuicPathFrameBuffer payload2 = { {0xbe, 0xef, 0xba, 0xdc, 0x0f, 0xee, 0xde, 0xad}}; - for (int i = ENCRYPTION_INITIAL; i < NUM_ENCRYPTION_LEVELS; ++i) { - EncryptionLevel level = static_cast<EncryptionLevel>(i); - creator_.set_encryption_level(level); + creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE); - QuicCircularDeque<QuicPathFrameBuffer> payloads; - payloads.push_back(payload0); - payloads.push_back(payload1); - payloads.push_back(payload2); + QuicCircularDeque<QuicPathFrameBuffer> payloads; + payloads.push_back(payload0); + payloads.push_back(payload1); + payloads.push_back(payload2); - std::unique_ptr<SerializedPacket> encrypted( - creator_.SerializePathResponseConnectivityProbingPacket(payloads, - false)); - InSequence s; - EXPECT_CALL(framer_visitor_, OnPacket()); - EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_)); - EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_)); - EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_)); - EXPECT_CALL(framer_visitor_, OnPacketHeader(_)); - EXPECT_CALL(framer_visitor_, OnPathResponseFrame(_)).Times(3); - EXPECT_CALL(framer_visitor_, OnPacketComplete()); + std::unique_ptr<SerializedPacket> encrypted( + creator_.SerializePathResponseConnectivityProbingPacket(payloads, false)); + InSequence s; + EXPECT_CALL(framer_visitor_, OnPacket()); + EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_)); + EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_)); + EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_)); + EXPECT_CALL(framer_visitor_, OnPacketHeader(_)); + EXPECT_CALL(framer_visitor_, OnPathResponseFrame(_)).Times(3); + EXPECT_CALL(framer_visitor_, OnPacketComplete()); - server_framer_.ProcessPacket(QuicEncryptedPacket( - encrypted->encrypted_buffer, encrypted->encrypted_length)); - } + server_framer_.ProcessPacket(QuicEncryptedPacket( + encrypted->encrypted_buffer, encrypted->encrypted_length)); } TEST_P(QuicPacketCreatorTest, UpdatePacketSequenceNumberLengthLeastAwaiting) { @@ -1499,6 +1468,7 @@ TEST_P(QuicPacketCreatorTest, AddFrameAndFlush) { } TEST_P(QuicPacketCreatorTest, SerializeAndSendStreamFrame) { + creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE); if (!GetParam().version_serialization) { creator_.StopSendingVersion(); } @@ -1534,6 +1504,7 @@ TEST_P(QuicPacketCreatorTest, SerializeStreamFrameWithPadding) { // Regression test to check that CreateAndSerializeStreamFrame uses a // correctly formatted stream frame header when appending padding. + creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE); if (!GetParam().version_serialization) { creator_.StopSendingVersion(); } @@ -1725,9 +1696,10 @@ TEST_P(QuicPacketCreatorTest, ConsumeDataAndRandomPadding) { TEST_P(QuicPacketCreatorTest, FlushWithExternalBuffer) { creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE); - char external_buffer[kMaxOutgoingPacketSize]; - char* expected_buffer = external_buffer; - EXPECT_CALL(delegate_, GetPacketBuffer()).WillOnce(Return(expected_buffer)); + char* buffer = new char[kMaxOutgoingPacketSize]; + QuicPacketBuffer external_buffer = {buffer, + [](const char* p) { delete[] p; }}; + EXPECT_CALL(delegate_, GetPacketBuffer()).WillOnce(Return(external_buffer)); QuicFrame frame; MakeIOVector("test", &iov_); @@ -1738,10 +1710,13 @@ TEST_P(QuicPacketCreatorTest, FlushWithExternalBuffer) { /*needs_full_padding=*/true, NOT_RETRANSMISSION, &frame)); EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke([expected_buffer](SerializedPacket serialized_packet) { - EXPECT_EQ(expected_buffer, serialized_packet.encrypted_buffer); + .WillOnce(Invoke([&external_buffer](SerializedPacket serialized_packet) { + EXPECT_EQ(external_buffer.buffer, serialized_packet.encrypted_buffer); })); creator_.FlushCurrentPacket(); + if (!GetQuicReloadableFlag(quic_avoid_leak_writer_buffer)) { + delete[] buffer; + } } // Test for error found in @@ -2311,7 +2286,7 @@ class MockDelegate : public QuicPacketCreator::DelegateInterface { MaybeBundleAckOpportunistically, (), (override)); - MOCK_METHOD(char*, GetPacketBuffer, (), (override)); + MOCK_METHOD(QuicPacketBuffer, GetPacketBuffer, (), (override)); MOCK_METHOD(void, OnSerializedPacket, (SerializedPacket), (override)); MOCK_METHOD(void, OnUnrecoverableError, @@ -2466,7 +2441,8 @@ class QuicPacketCreatorMultiplePacketsTest : public QuicTest { &delegate_, &producer_), ack_frame_(InitAckFrame(1)) { - EXPECT_CALL(delegate_, GetPacketBuffer()).WillRepeatedly(Return(nullptr)); + EXPECT_CALL(delegate_, GetPacketBuffer()) + .WillRepeatedly(Return(QuicPacketBuffer())); creator_.SetEncrypter( ENCRYPTION_FORWARD_SECURE, std::make_unique<NullEncrypter>(Perspective::IS_CLIENT)); @@ -2679,6 +2655,37 @@ TEST_F(QuicPacketCreatorMultiplePacketsTest, ConsumeCryptoData) { CheckPacketContains(contents, 0); } +TEST_F(QuicPacketCreatorMultiplePacketsTest, + ConsumeCryptoDataCheckShouldGeneratePacket) { + delegate_.SetCanNotWrite(); + + if (GetQuicReloadableFlag(quic_fix_checking_should_generate_packet)) { + EXPECT_CALL(delegate_, OnSerializedPacket(_)).Times(0); + } else { + EXPECT_CALL(delegate_, OnSerializedPacket(_)) + .WillOnce( + Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket)); + } + std::string data = "crypto data"; + size_t consumed_bytes = + creator_.ConsumeCryptoData(ENCRYPTION_INITIAL, data, 0); + creator_.Flush(); + if (GetQuicReloadableFlag(quic_fix_checking_should_generate_packet)) { + EXPECT_EQ(0u, consumed_bytes); + } else { + EXPECT_EQ(data.length(), consumed_bytes); + } + EXPECT_FALSE(creator_.HasPendingFrames()); + EXPECT_FALSE(creator_.HasPendingRetransmittableFrames()); + if (GetQuicReloadableFlag(quic_fix_checking_should_generate_packet)) { + return; + } + PacketContents contents; + contents.num_crypto_frames = 1; + contents.num_padding_frames = 1; + CheckPacketContains(contents, 0); +} + TEST_F(QuicPacketCreatorMultiplePacketsTest, ConsumeData_NotWritable) { delegate_.SetCanNotWrite(); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packet_writer.h b/chromium/net/third_party/quiche/src/quic/core/quic_packet_writer.h index ab29e15aa88..6efdb6005d8 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_packet_writer.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_packet_writer.h @@ -125,17 +125,22 @@ class QUIC_EXPORT_PRIVATE QuicPacketWriter { // True=Batch mode. False=PassThrough mode. virtual bool IsBatchMode() const = 0; - // PassThrough mode: Return nullptr. + // PassThrough mode: Return {nullptr, nullptr} // // Batch mode: - // Return the starting address for the next packet's data. A minimum of + // Return the QuicPacketBuffer for the next packet. A minimum of // kMaxOutgoingPacketSize is guaranteed to be available from the returned - // address. If the internal buffer does not have enough space, nullptr is - // returned. All arguments should be identical to the follow-up call to - // |WritePacket|, they are here to allow advanced packet memory management in - // packet writers, e.g. one packet buffer pool per |peer_address|. - virtual char* GetNextWriteLocation(const QuicIpAddress& self_address, - const QuicSocketAddress& peer_address) = 0; + // address. If the internal buffer does not have enough space, + // {nullptr, nullptr} is returned. All arguments should be identical to the + // follow-up call to |WritePacket|, they are here to allow advanced packet + // memory management in packet writers, e.g. one packet buffer pool per + // |peer_address|. + // + // If QuicPacketBuffer.release_buffer is !nullptr, it should be called iff + // the caller does not call WritePacket for the returned buffer. + virtual QuicPacketBuffer GetNextWriteLocation( + const QuicIpAddress& self_address, + const QuicSocketAddress& peer_address) = 0; // PassThrough mode: Return WriteResult(WRITE_STATUS_OK, 0). // diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packet_writer_wrapper.cc b/chromium/net/third_party/quiche/src/quic/core/quic_packet_writer_wrapper.cc index f1f25d871bf..d2b54d1b175 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_packet_writer_wrapper.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_packet_writer_wrapper.cc @@ -45,7 +45,7 @@ bool QuicPacketWriterWrapper::IsBatchMode() const { return writer_->IsBatchMode(); } -char* QuicPacketWriterWrapper::GetNextWriteLocation( +QuicPacketBuffer QuicPacketWriterWrapper::GetNextWriteLocation( const QuicIpAddress& self_address, const QuicSocketAddress& peer_address) { return writer_->GetNextWriteLocation(self_address, peer_address); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packet_writer_wrapper.h b/chromium/net/third_party/quiche/src/quic/core/quic_packet_writer_wrapper.h index 0b331aec6f8..afd360580b4 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_packet_writer_wrapper.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_packet_writer_wrapper.h @@ -35,8 +35,9 @@ class QUIC_NO_EXPORT QuicPacketWriterWrapper : public QuicPacketWriter { const QuicSocketAddress& peer_address) const override; bool SupportsReleaseTime() const override; bool IsBatchMode() const override; - char* GetNextWriteLocation(const QuicIpAddress& self_address, - const QuicSocketAddress& peer_address) override; + QuicPacketBuffer GetNextWriteLocation( + const QuicIpAddress& self_address, + const QuicSocketAddress& peer_address) override; WriteResult Flush() override; // Takes ownership of |writer|. diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packets.h b/chromium/net/third_party/quiche/src/quic/core/quic_packets.h index 04522e8538b..3e37a200c21 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_packets.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_packets.h @@ -379,6 +379,8 @@ struct QUIC_EXPORT_PRIVATE SerializedPacket { SerializedPacket(SerializedPacket&& other); ~SerializedPacket(); + // TODO(wub): replace |encrypted_buffer|+|release_encrypted_buffer| by a + // QuicOwnedPacketBuffer. // Not owned if |release_encrypted_buffer| is nullptr. Otherwise it is // released by |release_encrypted_buffer| on destruction. const char* encrypted_buffer; diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.cc b/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.cc index 92401b0db72..43730135c14 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.cc @@ -32,9 +32,6 @@ static const size_t kMaxRetransmissionsOnTimeout = 2; // The path degrading delay is the sum of this number of consecutive RTO delays. const size_t kNumRetransmissionDelaysForPathDegradingDelay = 2; -// The blachkhole delay is the sum of this number of consecutive RTO delays. -const size_t kNumRetransmissionDelaysForBlackholeDelay = 5; - // Ensure the handshake timer isnt't faster than 10ms. // This limits the tenth retransmitted packet to 10s after the initial CHLO. static const int64_t kMinHandshakeTimeoutMs = 10; @@ -110,7 +107,8 @@ QuicSentPacketManager::QuicSentPacketManager( one_rtt_packet_acked_(false), one_rtt_packet_sent_(false), first_pto_srtt_multiplier_(0), - use_standard_deviation_for_pto_(false) { + use_standard_deviation_for_pto_(false), + pto_multiplier_without_rtt_samples_(3) { SetSendAlgorithm(congestion_control_type); if (pto_enabled_) { QUIC_RELOADABLE_FLAG_COUNT_N(quic_default_on_pto, 1, 2); @@ -200,6 +198,9 @@ void QuicSentPacketManager::SetFromConfig(const QuicConfig& config) { } else if (config.HasClientSentConnectionOption(kPLE2, perspective)) { first_pto_srtt_multiplier_ = 1.5; } + if (config.HasClientSentConnectionOption(kAPTO, perspective)) { + pto_multiplier_without_rtt_samples_ = 1.5; + } if (config.HasClientSentConnectionOption(kPSDA, perspective)) { use_standard_deviation_for_pto_ = true; rtt_stats_.EnableStandardDeviationCalculation(); @@ -403,6 +404,17 @@ void QuicSentPacketManager::PostProcessNewlyAckedPackets( } } } + // Records the max consecutive RTO or PTO before forward progress has been + // made. + if (consecutive_rto_count_ > + stats_->max_consecutive_rto_with_forward_progress) { + stats_->max_consecutive_rto_with_forward_progress = + consecutive_rto_count_; + } else if (consecutive_pto_count_ > + stats_->max_consecutive_rto_with_forward_progress) { + stats_->max_consecutive_rto_with_forward_progress = + consecutive_pto_count_; + } // Reset all retransmit counters any time a new packet is acked. consecutive_rto_count_ = 0; consecutive_tlp_count_ = 0; @@ -442,40 +454,27 @@ void QuicSentPacketManager::MaybeInvokeCongestionEvent( } } -void QuicSentPacketManager::RetransmitUnackedPackets( - TransmissionType retransmission_type) { - DCHECK(retransmission_type == ALL_UNACKED_RETRANSMISSION || - retransmission_type == ALL_INITIAL_RETRANSMISSION); +void QuicSentPacketManager::RetransmitZeroRttPackets() { QuicPacketNumber packet_number = unacked_packets_.GetLeastUnacked(); for (QuicUnackedPacketMap::iterator it = unacked_packets_.begin(); it != unacked_packets_.end(); ++it, ++packet_number) { - if ((retransmission_type == ALL_UNACKED_RETRANSMISSION || - it->encryption_level == ENCRYPTION_ZERO_RTT)) { + if (it->encryption_level == ENCRYPTION_ZERO_RTT) { if (it->in_flight) { // Remove 0-RTT packets and packets of the wrong version from flight, // because neither can be processed by the peer. unacked_packets_.RemoveFromInFlight(&*it); } if (unacked_packets_.HasRetransmittableFrames(*it)) { - MarkForRetransmission(packet_number, retransmission_type); + MarkForRetransmission(packet_number, ALL_ZERO_RTT_RETRANSMISSION); } } } - if (retransmission_type == ALL_UNACKED_RETRANSMISSION && - unacked_packets_.bytes_in_flight() > 0) { - QUIC_BUG << "RetransmitUnackedPackets should remove all packets from flight" - << ", bytes_in_flight:" << unacked_packets_.bytes_in_flight(); - } } void QuicSentPacketManager::NeuterUnencryptedPackets() { for (QuicPacketNumber packet_number : unacked_packets_.NeuterUnencryptedPackets()) { - if (avoid_overestimate_bandwidth_with_aggregation_) { - QUIC_RELOADABLE_FLAG_COUNT_N( - quic_avoid_overestimate_bandwidth_with_aggregation, 1, 4); - send_algorithm_->OnPacketNeutered(packet_number); - } + send_algorithm_->OnPacketNeutered(packet_number); } if (handshake_mode_disabled_) { consecutive_pto_count_ = 0; @@ -486,11 +485,7 @@ void QuicSentPacketManager::NeuterUnencryptedPackets() { void QuicSentPacketManager::NeuterHandshakePackets() { for (QuicPacketNumber packet_number : unacked_packets_.NeuterHandshakePackets()) { - if (avoid_overestimate_bandwidth_with_aggregation_) { - QUIC_RELOADABLE_FLAG_COUNT_N( - quic_avoid_overestimate_bandwidth_with_aggregation, 2, 4); - send_algorithm_->OnPacketNeutered(packet_number); - } + send_algorithm_->OnPacketNeutered(packet_number); } if (handshake_mode_disabled_) { consecutive_pto_count_ = 0; @@ -573,7 +568,7 @@ void QuicSentPacketManager::MarkForRetransmission( QUIC_BUG_IF(transmission_type != LOSS_RETRANSMISSION && transmission_type != RTO_RETRANSMISSION && !unacked_packets_.HasRetransmittableFrames(*transmission_info)) - << "transmission_type: " << TransmissionTypeToString(transmission_type); + << "transmission_type: " << transmission_type; // Handshake packets should never be sent as probing retransmissions. DCHECK(!transmission_info->has_crypto_handshake || transmission_type != PROBING_RETRANSMISSION); @@ -646,8 +641,7 @@ void QuicSentPacketManager::MarkPacketHandled(QuicPacketNumber packet_number, // Record as a spurious retransmission if this packet is a // retransmission and no new data gets acked. QUIC_DVLOG(1) << "Detect spurious retransmitted packet " << packet_number - << " transmission type: " - << TransmissionTypeToString(info->transmission_type); + << " transmission type: " << info->transmission_type; RecordOneSpuriousRetransmission(*info); } } @@ -754,6 +748,9 @@ QuicSentPacketManager::OnRetransmissionTimeout() { case PTO_MODE: QUIC_DVLOG(1) << ENDPOINT << "PTO mode"; ++stats_->pto_count; + if (handshake_mode_disabled_ && !ShouldArmPtoForApplicationData()) { + ++stats_->crypto_retransmit_count; + } ++consecutive_pto_count_; pending_timer_transmission_count_ = max_probe_packets_per_pto_; return PTO_MODE; @@ -919,6 +916,26 @@ void QuicSentPacketManager::StartExponentialBackoffAfterNthPto( pto_exponential_backoff_start_point_ = exponential_backoff_start_point; } +void QuicSentPacketManager::RetransmitDataOfSpaceIfAny( + PacketNumberSpace space) { + DCHECK(supports_multiple_packet_number_spaces()); + if (!unacked_packets_.GetLastInFlightPacketSentTime(space).IsInitialized()) { + // No in flight data of space. + return; + } + QuicPacketNumber packet_number = unacked_packets_.GetLeastUnacked(); + for (QuicUnackedPacketMap::const_iterator it = unacked_packets_.begin(); + it != unacked_packets_.end(); ++it, ++packet_number) { + if (it->state == OUTSTANDING && + unacked_packets_.HasRetransmittableFrames(*it) && + unacked_packets_.GetPacketNumberSpace(it->encryption_level) == space) { + DCHECK(it->in_flight); + MarkForRetransmission(packet_number, PTO_RETRANSMISSION); + return; + } + } +} + QuicSentPacketManager::RetransmissionTimeoutMode QuicSentPacketManager::GetRetransmissionMode() const { DCHECK(unacked_packets_.HasInFlightPackets() || @@ -958,14 +975,16 @@ void QuicSentPacketManager::InvokeLossDetection(QuicTime time) { detection_stats.sent_packets_max_sequence_reordering; } + stats_->sent_packets_num_borderline_time_reorderings += + detection_stats.sent_packets_num_borderline_time_reorderings; + + stats_->total_loss_detection_response_time += + detection_stats.total_loss_detection_response_time; + for (const LostPacket& packet : packets_lost_) { QuicTransmissionInfo* info = unacked_packets_.GetMutableTransmissionInfo(packet.packet_number); ++stats_->packets_lost; - if (time > info->sent_time) { - stats_->total_loss_detection_time = - stats_->total_loss_detection_time + (time - info->sent_time); - } if (debug_delegate_ != nullptr) { debug_delegate_->OnPacketLoss(packet.packet_number, info->encryption_level, LOSS_RETRANSMISSION, @@ -1041,6 +1060,16 @@ const QuicTime QuicSentPacketManager::GetRetransmissionTime() const { // Do not set the timer if there is any credit left. return QuicTime::Zero(); } + PacketNumberSpace packet_number_space; + if (GetQuicReloadableFlag(quic_fix_server_pto_timeout) && + supports_multiple_packet_number_spaces() && + unacked_packets_.perspective() == Perspective::IS_SERVER && + !GetEarliestPacketSentTimeForPto(&packet_number_space).IsInitialized()) { + // Do not set the timer on the server side if the only in flight packets are + // half RTT data. + QUIC_RELOADABLE_FLAG_COUNT(quic_fix_server_pto_timeout); + return QuicTime::Zero(); + } switch (GetRetransmissionMode()) { case HANDSHAKE_MODE: return unacked_packets_.GetLastCryptoPacketSentTime() + @@ -1131,9 +1160,10 @@ const QuicTime::Delta QuicSentPacketManager::GetPathDegradingDelay() const { max_tail_loss_probes_ + kNumRetransmissionDelaysForPathDegradingDelay); } -const QuicTime::Delta QuicSentPacketManager::GetNetworkBlackholeDelay() const { +const QuicTime::Delta QuicSentPacketManager::GetNetworkBlackholeDelay( + int8_t num_rtos_for_blackhole_detection) const { return GetNConsecutiveRetransmissionTimeoutDelay( - max_tail_loss_probes_ + kNumRetransmissionDelaysForBlackholeDelay); + max_tail_loss_probes_ + num_rtos_for_blackhole_detection); } const QuicTime::Delta QuicSentPacketManager::GetCryptoRetransmissionDelay() @@ -1202,8 +1232,9 @@ const QuicTime::Delta QuicSentPacketManager::GetProbeTimeoutDelay() const { if (rtt_stats_.smoothed_rtt().IsZero()) { // Respect kMinHandshakeTimeoutMs to avoid a potential amplification attack. QUIC_BUG_IF(rtt_stats_.initial_rtt().IsZero()); - return std::max(3 * rtt_stats_.initial_rtt(), - QuicTime::Delta::FromMilliseconds(kMinHandshakeTimeoutMs)) * + return std::max( + pto_multiplier_without_rtt_samples_ * rtt_stats_.initial_rtt(), + QuicTime::Delta::FromMilliseconds(kMinHandshakeTimeoutMs)) * (1 << consecutive_pto_count_); } const QuicTime::Delta rtt_var = use_standard_deviation_for_pto_ @@ -1354,8 +1385,7 @@ AckResult QuicSentPacketManager::OnAckFrameEnd( << ", least_unacked: " << unacked_packets_.GetLeastUnacked() << ", packets_acked_: " << packets_acked_; } else { - QUIC_PEER_BUG << "Received " - << EncryptionLevelToString(ack_decrypted_level) + QUIC_PEER_BUG << "Received " << ack_decrypted_level << " ack for unackable packet: " << acked_packet.packet_number << " with state: " << QuicUtils::SentPacketStateToString(info->state); @@ -1368,8 +1398,7 @@ AckResult QuicSentPacketManager::OnAckFrameEnd( } continue; } - QUIC_DVLOG(1) << ENDPOINT << "Got an " - << EncryptionLevelToString(ack_decrypted_level) + QUIC_DVLOG(1) << ENDPOINT << "Got an " << ack_decrypted_level << " ack for packet " << acked_packet.packet_number << " , state: " << QuicUtils::SentPacketStateToString(info->state); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.h b/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.h index 371fa814537..72307b3b838 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.h @@ -140,15 +140,11 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager { // TODO(fayang): Rename this function to OnHandshakeComplete. void SetHandshakeConfirmed(); - // Requests retransmission of all unacked packets of |retransmission_type|. - // The behavior of this method depends on the value of |retransmission_type|: - // ALL_UNACKED_RETRANSMISSION - All unacked packets will be retransmitted. - // This can happen, for example, after a version negotiation packet has been - // received and all packets needs to be retransmitted with the new version. - // ALL_INITIAL_RETRANSMISSION - Only initially encrypted packets will be - // retransmitted. This can happen, for example, when a CHLO has been rejected - // and the previously encrypted data needs to be encrypted with a new key. - void RetransmitUnackedPackets(TransmissionType retransmission_type); + // Requests retransmission of all unacked 0-RTT packets. + // Only initially encrypted packets will be retransmitted. This can happen, + // for example, when a CHLO has been rejected and the previously encrypted + // data needs to be encrypted with a new key. + void RetransmitZeroRttPackets(); // Notify the sent packet manager of an external network measurement or // prediction for either |bandwidth| or |rtt|; either can be empty. @@ -216,7 +212,8 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager { const QuicTime::Delta GetPathDegradingDelay() const; // Returns the current delay for detecting network blackhole. - const QuicTime::Delta GetNetworkBlackholeDelay() const; + const QuicTime::Delta GetNetworkBlackholeDelay( + int8_t num_rtos_for_blackhole_detection) const; const RttStats* GetRttStats() const { return &rtt_stats_; } @@ -397,6 +394,9 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager { void StartExponentialBackoffAfterNthPto( size_t exponential_backoff_start_point); + // Called to retransmit in flight packet of |space| if any. + void RetransmitDataOfSpaceIfAny(PacketNumberSpace space); + bool supports_multiple_packet_number_spaces() const { return unacked_packets_.supports_multiple_packet_number_spaces(); } @@ -411,6 +411,8 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager { bool one_rtt_packet_acked() const { return one_rtt_packet_acked_; } + void OnUserAgentIdKnown() { loss_algorithm_->OnUserAgentIdKnown(); } + private: friend class test::QuicConnectionPeer; friend class test::QuicSentPacketManagerPeer; @@ -657,8 +659,9 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager { // calculating PTO timeout. bool use_standard_deviation_for_pto_; - const bool avoid_overestimate_bandwidth_with_aggregation_ = - GetQuicReloadableFlag(quic_avoid_overestimate_bandwidth_with_aggregation); + // The multiplier for caculating PTO timeout before any RTT sample is + // available. + float pto_multiplier_without_rtt_samples_; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager_test.cc index 79fc798568b..97d83f57933 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager_test.cc @@ -7,6 +7,7 @@ #include <memory> #include <utility> +#include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h" #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" #include "net/third_party/quiche/src/quic/test_tools/quic_config_peer.h" @@ -621,7 +622,7 @@ TEST_F(QuicSentPacketManagerTest, RetransmitTwiceThenAckFirst) { // know packet 2 is a spurious until it gets acked. EXPECT_EQ(1u, stats_.packets_spuriously_retransmitted); EXPECT_EQ(1u, stats_.packets_lost); - EXPECT_LT(QuicTime::Delta::Zero(), stats_.total_loss_detection_time); + EXPECT_LT(0.0, stats_.total_loss_detection_response_time); EXPECT_LE(1u, stats_.sent_packets_max_sequence_reordering); } @@ -942,6 +943,7 @@ TEST_F(QuicSentPacketManagerTest, TailLossProbeThenRTO) { manager_.OnRetransmissionTimeout(); EXPECT_EQ(2u, stats_.tlp_count); EXPECT_EQ(1u, stats_.rto_count); + EXPECT_EQ(0u, stats_.max_consecutive_rto_with_forward_progress); // There are 2 RTO retransmissions. EXPECT_EQ(104 * kDefaultLength, manager_.GetBytesInFlight()); QuicPacketNumber largest_acked = QuicPacketNumber(103); @@ -965,6 +967,7 @@ TEST_F(QuicSentPacketManagerTest, TailLossProbeThenRTO) { // All packets before 103 should be lost. // Packet 104 is still in flight. EXPECT_EQ(1000u, manager_.GetBytesInFlight()); + EXPECT_EQ(1u, stats_.max_consecutive_rto_with_forward_progress); } TEST_F(QuicSentPacketManagerTest, CryptoHandshakeTimeout) { @@ -1019,54 +1022,6 @@ TEST_F(QuicSentPacketManagerTest, CryptoHandshakeTimeout) { EXPECT_FALSE(manager_.HasUnackedCryptoPackets()); } -TEST_F(QuicSentPacketManagerTest, CryptoHandshakeTimeoutVersionNegotiation) { - // Send 2 crypto packets and 3 data packets. - const size_t kNumSentCryptoPackets = 2; - for (size_t i = 1; i <= kNumSentCryptoPackets; ++i) { - SendCryptoPacket(i); - } - const size_t kNumSentDataPackets = 3; - for (size_t i = 1; i <= kNumSentDataPackets; ++i) { - SendDataPacket(kNumSentCryptoPackets + i); - } - EXPECT_TRUE(manager_.HasUnackedCryptoPackets()); - - EXPECT_CALL(notifier_, RetransmitFrames(_, _)) - .Times(2) - .WillOnce(InvokeWithoutArgs([this]() { RetransmitCryptoPacket(6); })) - .WillOnce(InvokeWithoutArgs([this]() { RetransmitCryptoPacket(7); })); - manager_.OnRetransmissionTimeout(); - EXPECT_TRUE(manager_.HasUnackedCryptoPackets()); - - // Now act like a version negotiation packet arrived, which would cause all - // unacked packets to be retransmitted. - // Mark packets [1, 7] lost. And the frames in 6 and 7 are same as packets 1 - // and 2, respectively. - EXPECT_CALL(notifier_, OnFrameLost(_)).Times(7); - manager_.RetransmitUnackedPackets(ALL_UNACKED_RETRANSMISSION); - - // Ensure the first two pending packets are the crypto retransmits. - RetransmitCryptoPacket(8); - RetransmitCryptoPacket(9); - RetransmitDataPacket(10, ALL_UNACKED_RETRANSMISSION); - RetransmitDataPacket(11, ALL_UNACKED_RETRANSMISSION); - RetransmitDataPacket(12, ALL_UNACKED_RETRANSMISSION); - - EXPECT_EQ(QuicPacketNumber(1u), manager_.GetLeastUnacked()); - // Least unacked isn't raised until an ack is received, so ack the - // crypto packets. - uint64_t acked[] = {8, 9}; - ExpectAcksAndLosses(true, acked, QUICHE_ARRAYSIZE(acked), nullptr, 0); - manager_.OnAckFrameStart(QuicPacketNumber(9), QuicTime::Delta::Infinite(), - clock_.Now()); - manager_.OnAckRange(QuicPacketNumber(8), QuicPacketNumber(10)); - EXPECT_EQ(PACKETS_NEWLY_ACKED, - manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1), - ENCRYPTION_INITIAL)); - EXPECT_CALL(notifier_, HasUnackedCryptoData()).WillRepeatedly(Return(false)); - EXPECT_EQ(QuicPacketNumber(10u), manager_.GetLeastUnacked()); -} - TEST_F(QuicSentPacketManagerTest, CryptoHandshakeSpuriousRetransmission) { // Send 1 crypto packet. SendCryptoPacket(1); @@ -1119,28 +1074,6 @@ TEST_F(QuicSentPacketManagerTest, CryptoHandshakeTimeoutUnsentDataPacket) { } TEST_F(QuicSentPacketManagerTest, - CryptoHandshakeRetransmissionThenRetransmitAll) { - // Send 1 crypto packet. - SendCryptoPacket(1); - - EXPECT_TRUE(manager_.HasUnackedCryptoPackets()); - - // Retransmit the crypto packet as 2. - EXPECT_CALL(notifier_, RetransmitFrames(_, _)) - .WillOnce(InvokeWithoutArgs([this]() { RetransmitCryptoPacket(2); })); - manager_.OnRetransmissionTimeout(); - // Now retransmit all the unacked packets, which occurs when there is a - // version negotiation. - EXPECT_CALL(notifier_, OnFrameLost(_)).Times(2); - manager_.RetransmitUnackedPackets(ALL_UNACKED_RETRANSMISSION); - // Both packets 1 and 2 are unackable. - EXPECT_FALSE(manager_.unacked_packets().IsUnacked(QuicPacketNumber(1))); - EXPECT_FALSE(manager_.unacked_packets().IsUnacked(QuicPacketNumber(2))); - EXPECT_TRUE(manager_.HasUnackedCryptoPackets()); - EXPECT_FALSE(manager_.HasInFlightPackets()); -} - -TEST_F(QuicSentPacketManagerTest, CryptoHandshakeRetransmissionThenNeuterAndAck) { // Send 1 crypto packet. SendCryptoPacket(1); @@ -2732,6 +2665,7 @@ TEST_F(QuicSentPacketManagerTest, ComputingProbeTimeout) { manager_.OnRetransmissionTimeout(); EXPECT_EQ(QuicTime::Delta::Zero(), manager_.TimeUntilSend(clock_.Now())); EXPECT_EQ(1u, stats_.pto_count); + EXPECT_EQ(0u, stats_.max_consecutive_rto_with_forward_progress); // Verify two probe packets get sent. EXPECT_CALL(notifier_, RetransmitFrames(_, _)) @@ -2765,6 +2699,7 @@ TEST_F(QuicSentPacketManagerTest, ComputingProbeTimeout) { // Verify PTO is correctly re-armed based on sent time of packet 4. EXPECT_EQ(sent_time + expected_pto_delay, manager_.GetRetransmissionTime()); + EXPECT_EQ(1u, stats_.max_consecutive_rto_with_forward_progress); } TEST_F(QuicSentPacketManagerTest, SendOneProbePacket) { @@ -2811,7 +2746,7 @@ TEST_F(QuicSentPacketManagerTest, SendOneProbePacket) { TEST_F(QuicSentPacketManagerTest, DisableHandshakeModeClient) { QuicSentPacketManagerPeer::SetPerspective(&manager_, Perspective::IS_CLIENT); - manager_.EnableIetfPtoAndLossDetection(); + manager_.EnableMultiplePacketNumberSpacesSupport(); // Send CHLO. SendCryptoPacket(1); EXPECT_NE(QuicTime::Zero(), manager_.GetRetransmissionTime()); @@ -3340,6 +3275,7 @@ TEST_F(QuicSentPacketManagerTest, ClientMultiplePacketNumberSpacePtoTimeout) { manager_.OnRetransmissionTimeout(); EXPECT_EQ(QuicTime::Delta::Zero(), manager_.TimeUntilSend(clock_.Now())); EXPECT_EQ(1u, stats_.pto_count); + EXPECT_EQ(1u, stats_.crypto_retransmit_count); // Verify probe packet gets sent. EXPECT_CALL(notifier_, RetransmitFrames(_, _)) @@ -3823,11 +3759,7 @@ TEST_F(QuicSentPacketManagerTest, SetHandshakeConfirmed) { return true; })); - if (GetQuicReloadableFlag( - quic_avoid_overestimate_bandwidth_with_aggregation)) { - EXPECT_CALL(*send_algorithm_, OnPacketNeutered(QuicPacketNumber(2))) - .Times(1); - } + EXPECT_CALL(*send_algorithm_, OnPacketNeutered(QuicPacketNumber(2))).Times(1); manager_.SetHandshakeConfirmed(); } @@ -3841,11 +3773,8 @@ TEST_F(QuicSentPacketManagerTest, NeuterUnencryptedPackets) { .WillOnce(Return(false)) .WillOnce(Return(true)); EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(false)); - if (GetQuicReloadableFlag( - quic_avoid_overestimate_bandwidth_with_aggregation)) { - EXPECT_CALL(*send_algorithm_, OnPacketNeutered(QuicPacketNumber(1))) - .Times(1); - } + + EXPECT_CALL(*send_algorithm_, OnPacketNeutered(QuicPacketNumber(1))).Times(1); manager_.NeuterUnencryptedPackets(); } @@ -3911,7 +3840,7 @@ TEST_F(QuicSentPacketManagerTest, GetPathDegradingDelay) { // Regression test for b/154050235. TEST_F(QuicSentPacketManagerTest, ExponentialBackoffWithNoRttMeasurement) { QuicSentPacketManagerPeer::SetPerspective(&manager_, Perspective::IS_CLIENT); - manager_.EnableIetfPtoAndLossDetection(); + manager_.EnableMultiplePacketNumberSpacesSupport(); RttStats* rtt_stats = const_cast<RttStats*>(manager_.GetRttStats()); EXPECT_EQ(QuicTime::Delta::FromMilliseconds(kInitialRttMs), rtt_stats->initial_rtt()); @@ -3939,7 +3868,7 @@ TEST_F(QuicSentPacketManagerTest, ExponentialBackoffWithNoRttMeasurement) { } TEST_F(QuicSentPacketManagerTest, PtoDelayWithTinyInitialRtt) { - manager_.EnableIetfPtoAndLossDetection(); + manager_.EnableMultiplePacketNumberSpacesSupport(); RttStats* rtt_stats = const_cast<RttStats*>(manager_.GetRttStats()); // Assume client provided a tiny initial RTT. rtt_stats->set_initial_rtt(QuicTime::Delta::FromMicroseconds(1)); @@ -3998,6 +3927,199 @@ TEST_F(QuicSentPacketManagerTest, HandshakeAckCausesInitialKeyDropping) { manager_.MaybeSendProbePackets(); } +// Regression test for b/156487311 +TEST_F(QuicSentPacketManagerTest, ClearLastInflightPacketsSentTime) { + manager_.EnableMultiplePacketNumberSpacesSupport(); + EXPECT_CALL(*send_algorithm_, PacingRate(_)) + .WillRepeatedly(Return(QuicBandwidth::Zero())); + EXPECT_CALL(*send_algorithm_, GetCongestionWindow()) + .WillRepeatedly(Return(10 * kDefaultTCPMSS)); + + // Send INITIAL 1. + SendDataPacket(1, ENCRYPTION_INITIAL); + const QuicTime packet1_sent_time = clock_.Now(); + // Send HANDSHAKE 2. + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10)); + SendDataPacket(2, ENCRYPTION_HANDSHAKE); + SendDataPacket(3, ENCRYPTION_HANDSHAKE); + SendDataPacket(4, ENCRYPTION_HANDSHAKE); + const QuicTime packet2_sent_time = clock_.Now(); + + // Send half RTT 5. + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10)); + SendDataPacket(5, ENCRYPTION_FORWARD_SECURE); + + // Received ACK for INITIAL 1. + ExpectAck(1); + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(90)); + manager_.OnAckFrameStart(QuicPacketNumber(1), QuicTime::Delta::Infinite(), + clock_.Now()); + manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2)); + EXPECT_EQ(PACKETS_NEWLY_ACKED, + manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1), + ENCRYPTION_INITIAL)); + RttStats* rtt_stats = const_cast<RttStats*>(manager_.GetRttStats()); + int pto_rttvar_multiplier = + GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4; + const QuicTime::Delta pto_delay = + rtt_stats->smoothed_rtt() + + pto_rttvar_multiplier * rtt_stats->mean_deviation() + + QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs); + if (GetQuicReloadableFlag(quic_fix_last_inflight_packets_sent_time)) { + // Verify PTO is armed based on handshake data. + EXPECT_EQ(packet2_sent_time + pto_delay, manager_.GetRetransmissionTime()); + } else { + // Problematic: PTO is still armed based on initial data. + EXPECT_EQ(packet1_sent_time + pto_delay, manager_.GetRetransmissionTime()); + clock_.AdvanceTime(pto_delay); + manager_.OnRetransmissionTimeout(); + // Nothing to retransmit in INITIAL space. + EXPECT_CALL(notifier_, RetransmitFrames(_, _)).Times(0); + manager_.MaybeSendProbePackets(); + // PING packet gets sent. + SendPingPacket(6, ENCRYPTION_INITIAL); + manager_.AdjustPendingTimerTransmissions(); + + // Verify PTO is armed based on packet 2. + EXPECT_EQ(packet2_sent_time + pto_delay * 2, + manager_.GetRetransmissionTime()); + clock_.AdvanceTime(pto_delay * 2); + manager_.OnRetransmissionTimeout(); + EXPECT_CALL(notifier_, RetransmitFrames(_, _)).Times(testing::AtLeast(1)); + manager_.MaybeSendProbePackets(); + } +} + +// Regression test for b/157895910. +TEST_F(QuicSentPacketManagerTest, EarliestSentTimeNotInitializedWhenPtoFires) { + SetQuicReloadableFlag(quic_fix_last_inflight_packets_sent_time, true); + manager_.EnableMultiplePacketNumberSpacesSupport(); + EXPECT_CALL(*send_algorithm_, PacingRate(_)) + .WillRepeatedly(Return(QuicBandwidth::Zero())); + EXPECT_CALL(*send_algorithm_, GetCongestionWindow()) + .WillRepeatedly(Return(10 * kDefaultTCPMSS)); + + // Send INITIAL 1. + SendDataPacket(1, ENCRYPTION_INITIAL); + + // Send HANDSHAKE packets. + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10)); + SendDataPacket(2, ENCRYPTION_HANDSHAKE); + SendDataPacket(3, ENCRYPTION_HANDSHAKE); + SendDataPacket(4, ENCRYPTION_HANDSHAKE); + + // Send half RTT packet. + SendDataPacket(5, ENCRYPTION_FORWARD_SECURE); + + // Received ACK for INITIAL packet 1. + ExpectAck(1); + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(90)); + manager_.OnAckFrameStart(QuicPacketNumber(1), QuicTime::Delta::Infinite(), + clock_.Now()); + manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2)); + EXPECT_EQ(PACKETS_NEWLY_ACKED, + manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1), + ENCRYPTION_INITIAL)); + + // Received ACK for HANDSHAKE packets. + uint64_t acked[] = {2, 3, 4}; + ExpectAcksAndLosses(true, acked, QUICHE_ARRAYSIZE(acked), nullptr, 0); + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(90)); + manager_.OnAckFrameStart(QuicPacketNumber(4), QuicTime::Delta::Infinite(), + clock_.Now()); + manager_.OnAckRange(QuicPacketNumber(2), QuicPacketNumber(5)); + EXPECT_EQ(PACKETS_NEWLY_ACKED, + manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(4), + ENCRYPTION_HANDSHAKE)); + if (GetQuicReloadableFlag(quic_fix_server_pto_timeout)) { + // Verify PTO will not be armed. + EXPECT_EQ(QuicTime::Zero(), manager_.GetRetransmissionTime()); + return; + } + // PTO fires but there is nothing to send. + EXPECT_NE(QuicTime::Zero(), manager_.GetRetransmissionTime()); + manager_.OnRetransmissionTimeout(); + EXPECT_QUIC_BUG(manager_.MaybeSendProbePackets(), + "earlist_sent_time not initialized when trying to send PTO " + "retransmissions"); +} + +TEST_F(QuicSentPacketManagerTest, MaybeRetransmitInitialData) { + manager_.EnableMultiplePacketNumberSpacesSupport(); + EXPECT_CALL(*send_algorithm_, PacingRate(_)) + .WillRepeatedly(Return(QuicBandwidth::Zero())); + EXPECT_CALL(*send_algorithm_, GetCongestionWindow()) + .WillRepeatedly(Return(10 * kDefaultTCPMSS)); + RttStats* rtt_stats = const_cast<RttStats*>(manager_.GetRttStats()); + rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(100), + QuicTime::Delta::Zero(), QuicTime::Zero()); + QuicTime::Delta srtt = rtt_stats->smoothed_rtt(); + + // Send packet 1. + SendDataPacket(1, ENCRYPTION_INITIAL); + QuicTime packet1_sent_time = clock_.Now(); + + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10)); + // Send packets 2 and 3. + SendDataPacket(2, ENCRYPTION_HANDSHAKE); + QuicTime packet2_sent_time = clock_.Now(); + SendDataPacket(3, ENCRYPTION_HANDSHAKE); + // Verify PTO is correctly set based on packet 1. + int pto_rttvar_multiplier = + GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4; + QuicTime::Delta expected_pto_delay = + srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() + + QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs); + EXPECT_EQ(packet1_sent_time + expected_pto_delay, + manager_.GetRetransmissionTime()); + + // Assume connection is going to send INITIAL ACK. + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10)); + EXPECT_CALL(notifier_, RetransmitFrames(_, _)) + .WillOnce(WithArgs<1>(Invoke([this](TransmissionType type) { + RetransmitDataPacket(4, type, ENCRYPTION_INITIAL); + }))); + manager_.RetransmitDataOfSpaceIfAny(INITIAL_DATA); + // Verify PTO is re-armed based on packet 2. + EXPECT_EQ(packet2_sent_time + expected_pto_delay, + manager_.GetRetransmissionTime()); + + // Connection is going to send another INITIAL ACK. + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10)); + EXPECT_CALL(notifier_, RetransmitFrames(_, _)) + .WillOnce(WithArgs<1>(Invoke([this](TransmissionType type) { + RetransmitDataPacket(5, type, ENCRYPTION_INITIAL); + }))); + manager_.RetransmitDataOfSpaceIfAny(INITIAL_DATA); + // Verify PTO does not change. + EXPECT_EQ(packet2_sent_time + expected_pto_delay, + manager_.GetRetransmissionTime()); +} + +TEST_F(QuicSentPacketManagerTest, + AggressivePtoBeforeAnyRttSamplesAreAvailable) { + manager_.EnableMultiplePacketNumberSpacesSupport(); + EXPECT_CALL(*send_algorithm_, PacingRate(_)) + .WillRepeatedly(Return(QuicBandwidth::Zero())); + EXPECT_CALL(*send_algorithm_, GetCongestionWindow()) + .WillRepeatedly(Return(10 * kDefaultTCPMSS)); + RttStats* rtt_stats = const_cast<RttStats*>(manager_.GetRttStats()); + + QuicConfig config; + QuicTagVector options; + options.push_back(kAPTO); + QuicConfigPeer::SetReceivedConnectionOptions(&config, options); + EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); + EXPECT_CALL(*network_change_visitor_, OnCongestionChange()); + manager_.SetFromConfig(config); + + // Send INITIAL 1. + SendDataPacket(1, ENCRYPTION_INITIAL); + // Verify retransmission timeout is expected. + EXPECT_EQ(clock_.Now() + 1.5 * rtt_stats->initial_rtt(), + manager_.GetRetransmissionTime()); +} + } // namespace } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_session.cc b/chromium/net/third_party/quiche/src/quic/core/quic_session.cc index 0f00ff3843d..59e6cc8093e 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_session.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_session.cc @@ -73,12 +73,9 @@ QuicSession::QuicSession( config_.GetMaxBidirectionalStreamsToSend(), config_.GetMaxUnidirectionalStreamsToSend() + num_expected_unidirectional_static_streams), - num_dynamic_incoming_streams_(0), - num_draining_incoming_streams_(0), - num_draining_outgoing_streams_(0), - num_outgoing_static_streams_(0), - num_incoming_static_streams_(0), - num_locally_closed_incoming_streams_highest_offset_(0), + num_draining_streams_(0), + num_outgoing_draining_streams_(0), + num_static_streams_(0), flow_controller_( this, QuicUtils::GetInvalidStreamId(connection->transport_version()), @@ -101,10 +98,9 @@ QuicSession::QuicSession( use_http2_priority_write_scheduler_(false), is_configured_(false), enable_round_robin_scheduling_(false), - deprecate_draining_streams_( - GetQuicReloadableFlag(quic_deprecate_draining_streams)), - break_close_loop_( - GetQuicReloadableFlag(quic_break_session_stream_close_loop)) { + was_zero_rtt_rejected_(false), + fix_gquic_stream_type_( + GetQuicReloadableFlag(quic_fix_gquic_stream_type)) { closed_streams_clean_up_alarm_ = QuicWrapUnique<QuicAlarm>(connection_->alarm_factory()->CreateAlarm( new ClosedStreamsCleanUpDelegate(this))); @@ -117,9 +113,6 @@ QuicSession::QuicSession( config_.GetMaxUnidirectionalStreamsToSend() + num_expected_unidirectional_static_streams); } - if (break_close_loop_) { - QUIC_RELOADABLE_FLAG_COUNT(quic_break_session_stream_close_loop); - } } void QuicSession::Initialize() { @@ -127,7 +120,11 @@ void QuicSession::Initialize() { connection_->SetSessionNotifier(this); connection_->SetDataProducer(this); connection_->SetFromConfig(config_); - + if (GetQuicReloadableFlag(quic_support_handshake_done_in_t050) && + version().UsesTls() && !version().HasHandshakeDone() && + perspective_ == Perspective::IS_CLIENT) { + config_.SetSupportHandshakeDone(); + } // On the server side, version negotiation has been done by the dispatcher, // and the server session is created with the right version. if (perspective() == Perspective::IS_SERVER) { @@ -144,16 +141,6 @@ void QuicSession::Initialize() { QuicSession::~QuicSession() { QUIC_LOG_IF(WARNING, !zombie_streams_.empty()) << "Still have zombie streams"; - QUIC_LOG_IF(WARNING, num_locally_closed_incoming_streams_highest_offset() > - stream_id_manager_.max_open_incoming_streams()) - << "Surprisingly high number of locally closed peer initiated streams" - "still waiting for final byte offset: " - << num_locally_closed_incoming_streams_highest_offset(); - QUIC_LOG_IF(WARNING, GetNumLocallyClosedOutgoingStreamsHighestOffset() > - stream_id_manager_.max_open_outgoing_streams()) - << "Surprisingly high number of locally closed self initiated streams" - "still waiting for final byte offset: " - << GetNumLocallyClosedOutgoingStreamsHighestOffset(); } void QuicSession::PendingStreamOnStreamFrame(const QuicStreamFrame& frame) { @@ -197,8 +184,8 @@ void QuicSession::OnStreamFrame(const QuicStreamFrame& frame) { if (UsesPendingStreams() && QuicUtils::GetStreamType(stream_id, perspective(), - IsIncomingStream(stream_id)) == - READ_UNIDIRECTIONAL && + IsIncomingStream(stream_id), + version()) == READ_UNIDIRECTIONAL && stream_map_.find(stream_id) == stream_map_.end()) { PendingStreamOnStreamFrame(frame); return; @@ -245,8 +232,8 @@ void QuicSession::OnStopSendingFrame(const QuicStopSendingFrame& frame) { // If stream_id is READ_UNIDIRECTIONAL, close the connection. if (QuicUtils::GetStreamType(stream_id, perspective(), - IsIncomingStream(stream_id)) == - READ_UNIDIRECTIONAL) { + IsIncomingStream(stream_id), + version()) == READ_UNIDIRECTIONAL) { QUIC_DVLOG(1) << ENDPOINT << "Received STOP_SENDING for a read-only stream_id: " << stream_id << "."; @@ -311,7 +298,7 @@ void QuicSession::PendingStreamOnRstStream(const QuicRstStreamFrame& frame) { // Pending stream is currently read only. We can safely close the stream. DCHECK_EQ(READ_UNIDIRECTIONAL, QuicUtils::GetStreamType(pending->id(), perspective(), - /*peer_initiated = */ true)); + /*peer_initiated = */ true, version())); ClosePendingStream(stream_id); } @@ -326,8 +313,8 @@ void QuicSession::OnRstStream(const QuicRstStreamFrame& frame) { if (VersionHasIetfQuicFrames(transport_version()) && QuicUtils::GetStreamType(stream_id, perspective(), - IsIncomingStream(stream_id)) == - WRITE_UNIDIRECTIONAL) { + IsIncomingStream(stream_id), + version()) == WRITE_UNIDIRECTIONAL) { connection()->CloseConnection( QUIC_INVALID_STREAM_ID, "Received RESET_STREAM for a write-only stream", ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); @@ -340,8 +327,8 @@ void QuicSession::OnRstStream(const QuicRstStreamFrame& frame) { if (UsesPendingStreams() && QuicUtils::GetStreamType(stream_id, perspective(), - IsIncomingStream(stream_id)) == - READ_UNIDIRECTIONAL && + IsIncomingStream(stream_id), + version()) == READ_UNIDIRECTIONAL && stream_map_.find(stream_id) == stream_map_.end()) { PendingStreamOnRstStream(frame); return; @@ -398,10 +385,7 @@ void QuicSession::OnConnectionClosed(const QuicConnectionCloseFrame& frame, on_closed_frame_ = frame; } - if (GetQuicReloadableFlag(quic_notify_handshaker_on_connection_close)) { - QUIC_RELOADABLE_FLAG_COUNT(quic_notify_handshaker_on_connection_close); - GetMutableCryptoStream()->OnConnectionClosed(frame.quic_error_code, source); - } + GetMutableCryptoStream()->OnConnectionClosed(frame.quic_error_code, source); // Copy all non static streams in a new map for the ease of deleting. QuicSmallMap<QuicStreamId, QuicStream*, 10> non_static_streams; @@ -460,12 +444,12 @@ void QuicSession::OnPacketReceived(const QuicSocketAddress& /*self_address*/, void QuicSession::OnPathDegrading() {} +void QuicSession::OnForwardProgressMadeAfterPathDegrading() {} + bool QuicSession::AllowSelfAddressChange() const { return false; } -void QuicSession::OnForwardProgressConfirmed() {} - void QuicSession::OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) { // Stream may be closed by the time we receive a WINDOW_UPDATE, so we can't // assume that it still exists. @@ -483,8 +467,8 @@ void QuicSession::OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) { if (VersionHasIetfQuicFrames(transport_version()) && QuicUtils::GetStreamType(stream_id, perspective(), - IsIncomingStream(stream_id)) == - READ_UNIDIRECTIONAL) { + IsIncomingStream(stream_id), + version()) == READ_UNIDIRECTIONAL) { connection()->CloseConnection( QUIC_WINDOW_UPDATE_RECEIVED_ON_READ_UNIDIRECTIONAL_STREAM, "WindowUpdateFrame received on READ_UNIDIRECTIONAL stream.", @@ -619,7 +603,7 @@ void QuicSession::OnCanWrite() { ConnectionCloseBehavior::SILENT_CLOSE); return; } - if (!connection_->CanWriteStreamData()) { + if (!CanWriteStreamData()) { return; } currently_writing_stream_id_ = write_blocked_streams_.PopFront(); @@ -663,11 +647,26 @@ bool QuicSession::WillingAndAbleToWrite() const { HasPendingHandshake()) { return true; } - return control_frame_manager_.WillingToWrite() || - !streams_with_pending_retransmission_.empty() || - write_blocked_streams_.HasWriteBlockedSpecialStream() || - (!flow_controller_.IsBlocked() && - write_blocked_streams_.HasWriteBlockedDataStreams()); + if (control_frame_manager_.WillingToWrite() || + !streams_with_pending_retransmission_.empty()) { + return true; + } + if (!GetQuicReloadableFlag(quic_fix_willing_and_able_to_write)) { + return write_blocked_streams_.HasWriteBlockedSpecialStream() || + (!flow_controller_.IsBlocked() && + write_blocked_streams_.HasWriteBlockedDataStreams()); + } + QUIC_RELOADABLE_FLAG_COUNT(quic_fix_willing_and_able_to_write); + if (flow_controller_.IsBlocked()) { + if (VersionUsesHttp3(transport_version())) { + return false; + } + // Crypto and headers streams are not blocked by connection level flow + // control. + return write_blocked_streams_.HasWriteBlockedSpecialStream(); + } + return write_blocked_streams_.HasWriteBlockedSpecialStream() || + write_blocked_streams_.HasWriteBlockedDataStreams(); } bool QuicSession::HasPendingHandshake() const { @@ -681,12 +680,6 @@ bool QuicSession::HasPendingHandshake() const { QuicUtils::GetCryptoStreamId(transport_version())); } -uint64_t QuicSession::GetNumOpenDynamicStreams() const { - return stream_map_.size() - GetNumDrainingStreams() + - locally_closed_streams_highest_offset_.size() - - num_incoming_static_streams_ - num_outgoing_static_streams_; -} - void QuicSession::ProcessUdpPacket(const QuicSocketAddress& self_address, const QuicSocketAddress& peer_address, const QuicReceivedPacket& packet) { @@ -763,22 +756,11 @@ void QuicSession::SendRstStream(QuicStreamId id, connection_->OnStreamReset(id, error); } - - if (break_close_loop_) { - return; - } - - if (error != QUIC_STREAM_NO_ERROR && QuicContainsKey(zombie_streams_, id)) { - OnStreamDoneWaitingForAcks(id); - return; - } - CloseStreamInner(id, true); } void QuicSession::ResetStream(QuicStreamId id, QuicRstStreamErrorCode error, QuicStreamOffset bytes_written) { - DCHECK(break_close_loop_); QuicStream* stream = GetStream(id); if (stream != nullptr && stream->is_static()) { connection()->CloseConnection( @@ -800,8 +782,8 @@ void QuicSession::MaybeSendRstStreamFrame(QuicStreamId id, QuicStreamOffset bytes_written) { DCHECK(connection()->connected()); if (!VersionHasIetfQuicFrames(transport_version()) || - QuicUtils::GetStreamType(id, perspective(), IsIncomingStream(id)) != - READ_UNIDIRECTIONAL) { + QuicUtils::GetStreamType(id, perspective(), IsIncomingStream(id), + version()) != READ_UNIDIRECTIONAL) { control_frame_manager_.WriteOrBufferRstStream(id, error, bytes_written); } } @@ -810,8 +792,8 @@ void QuicSession::MaybeSendStopSendingFrame(QuicStreamId id, QuicRstStreamErrorCode error) { DCHECK(connection()->connected()); if (VersionHasIetfQuicFrames(transport_version()) && - QuicUtils::GetStreamType(id, perspective(), IsIncomingStream(id)) != - WRITE_UNIDIRECTIONAL) { + QuicUtils::GetStreamType(id, perspective(), IsIncomingStream(id), + version()) != WRITE_UNIDIRECTIONAL) { control_frame_manager_.WriteOrBufferStopSending(error, id); } } @@ -854,24 +836,11 @@ void QuicSession::SendMaxStreams(QuicStreamCount stream_count, } void QuicSession::CloseStream(QuicStreamId stream_id) { - CloseStreamInner(stream_id, false); -} - -void QuicSession::InsertLocallyClosedStreamsHighestOffset( - const QuicStreamId id, - QuicStreamOffset offset) { - locally_closed_streams_highest_offset_[id] = offset; - if (IsIncomingStream(id)) { - ++num_locally_closed_incoming_streams_highest_offset_; - } -} - -void QuicSession::CloseStreamInner(QuicStreamId stream_id, bool rst_sent) { QUIC_DVLOG(1) << ENDPOINT << "Closing stream " << stream_id; StreamMap::iterator it = stream_map_.find(stream_id); if (it == stream_map_.end()) { - // When CloseStreamInner has been called recursively (via + // When CloseStream has been called recursively (via // QuicStream::OnClose), the stream will already have been deleted // from stream_map_, so return immediately. QUIC_DVLOG(1) << ENDPOINT << "Stream is already closed: " << stream_id; @@ -887,89 +856,18 @@ void QuicSession::CloseStreamInner(QuicStreamId stream_id, bool rst_sent) { ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); return; } - if (break_close_loop_) { - stream->CloseReadSide(); - stream->CloseWriteSide(); - return; - } - StreamType type = stream->type(); - - // Tell the stream that a RST has been sent. - if (rst_sent) { - stream->set_rst_sent(true); - } - - if (stream->IsWaitingForAcks()) { - zombie_streams_[stream->id()] = std::move(it->second); - } else { - // Clean up the stream since it is no longer waiting for acks. - streams_waiting_for_acks_.erase(stream->id()); - closed_streams_.push_back(std::move(it->second)); - // Do not retransmit data of a closed stream. - streams_with_pending_retransmission_.erase(stream_id); - if (!closed_streams_clean_up_alarm_->IsSet()) { - closed_streams_clean_up_alarm_->Set( - connection_->clock()->ApproximateNow()); - } - } - - // If we haven't received a FIN or RST for this stream, we need to keep track - // of the how many bytes the stream's flow controller believes it has - // received, for accurate connection level flow control accounting. - const bool had_fin_or_rst = stream->HasReceivedFinalOffset(); - if (!had_fin_or_rst) { - InsertLocallyClosedStreamsHighestOffset( - stream_id, stream->flow_controller()->highest_received_byte_offset()); - } - bool stream_was_draining = false; - if (deprecate_draining_streams_) { - stream_was_draining = stream->was_draining(); - QUIC_DVLOG_IF(1, stream_was_draining) - << ENDPOINT << "Stream " << stream_id << " was draining"; - } - stream_map_.erase(it); - if (IsIncomingStream(stream_id)) { - --num_dynamic_incoming_streams_; - } - if (!deprecate_draining_streams_) { - stream_was_draining = - draining_streams_.find(stream_id) != draining_streams_.end(); - } - if (stream_was_draining) { - if (IsIncomingStream(stream_id)) { - QUIC_BUG_IF(num_draining_incoming_streams_ == 0); - --num_draining_incoming_streams_; - } else if (deprecate_draining_streams_) { - QUIC_BUG_IF(num_draining_outgoing_streams_ == 0); - --num_draining_outgoing_streams_; - } - draining_streams_.erase(stream_id); - } else if (VersionHasIetfQuicFrames(transport_version())) { - // Stream was not draining, but we did have a fin or rst, so we can now - // free the stream ID if version 99. - if (had_fin_or_rst && connection_->connected()) { - // Do not bother informing stream ID manager if connection is closed. - v99_streamid_manager_.OnStreamClosed(stream_id); - } - } else if (stream_id_manager_.handles_accounting() && had_fin_or_rst && - connection_->connected()) { - stream_id_manager_.OnStreamClosed( - /*is_incoming=*/IsIncomingStream(stream_id)); - } - - stream->OnClose(); + stream->CloseReadSide(); + stream->CloseWriteSide(); +} - if (!stream_was_draining && !IsIncomingStream(stream_id) && had_fin_or_rst && - !VersionHasIetfQuicFrames(transport_version())) { - // Streams that first became draining already called OnCanCreate... - // This covers the case where the stream went directly to being closed. - OnCanCreateNewOutgoingStream(type != BIDIRECTIONAL); - } +void QuicSession::InsertLocallyClosedStreamsHighestOffset( + const QuicStreamId id, + QuicStreamOffset offset) { + locally_closed_streams_highest_offset_[id] = offset; } void QuicSession::OnStreamClosed(QuicStreamId stream_id) { QUIC_DVLOG(1) << ENDPOINT << "Closing stream: " << stream_id; - DCHECK(break_close_loop_); StreamMap::iterator it = stream_map_.find(stream_id); if (it == stream_map_.end()) { QUIC_DVLOG(1) << ENDPOINT << "Stream is already closed: " << stream_id; @@ -1002,48 +900,38 @@ void QuicSession::OnStreamClosed(QuicStreamId stream_id) { InsertLocallyClosedStreamsHighestOffset( stream_id, stream->flow_controller()->highest_received_byte_offset()); stream_map_.erase(it); - if (IsIncomingStream(stream_id)) { - --num_dynamic_incoming_streams_; - } return; } - bool stream_was_draining = false; - if (deprecate_draining_streams_) { - stream_was_draining = stream->was_draining(); - QUIC_DVLOG_IF(1, stream_was_draining) - << ENDPOINT << "Stream " << stream_id << " was draining"; - } + const bool stream_was_draining = stream->was_draining(); + QUIC_DVLOG_IF(1, stream_was_draining) + << ENDPOINT << "Stream " << stream_id << " was draining"; stream_map_.erase(it); - if (IsIncomingStream(stream_id)) { - --num_dynamic_incoming_streams_; - } - if (!deprecate_draining_streams_) { - stream_was_draining = - draining_streams_.find(stream_id) != draining_streams_.end(); - } if (stream_was_draining) { - if (IsIncomingStream(stream_id)) { - QUIC_BUG_IF(num_draining_incoming_streams_ == 0); - --num_draining_incoming_streams_; - } else if (deprecate_draining_streams_) { - QUIC_BUG_IF(num_draining_outgoing_streams_ == 0); - --num_draining_outgoing_streams_; + QUIC_BUG_IF(num_draining_streams_ == 0); + --num_draining_streams_; + if (!IsIncomingStream(stream_id)) { + QUIC_BUG_IF(num_outgoing_draining_streams_ == 0); + --num_outgoing_draining_streams_; } - draining_streams_.erase(stream_id); // Stream Id manager has been informed with draining streams. return; } - if (!connection_->connected()) { + if (!GetQuicReloadableFlag(quic_notify_stream_id_manager_when_disconnected) && + !connection_->connected()) { // Do not bother informing stream ID manager if connection has been // disconnected. return; } - if (stream_id_manager_.handles_accounting() && - !VersionHasIetfQuicFrames(transport_version())) { + if (!VersionHasIetfQuicFrames(transport_version())) { stream_id_manager_.OnStreamClosed( /*is_incoming=*/IsIncomingStream(stream_id)); } + if (GetQuicReloadableFlag(quic_notify_stream_id_manager_when_disconnected) && + !connection_->connected()) { + QUIC_RELOADABLE_FLAG_COUNT(quic_notify_stream_id_manager_when_disconnected); + return; + } if (IsIncomingStream(stream_id)) { // Stream Id manager is only interested in peer initiated stream IDs. if (VersionHasIetfQuicFrames(transport_version())) { @@ -1090,13 +978,11 @@ void QuicSession::OnFinalByteOffsetReceived( flow_controller_.AddBytesConsumed(offset_diff); locally_closed_streams_highest_offset_.erase(it); - if (stream_id_manager_.handles_accounting() && - !VersionHasIetfQuicFrames(transport_version())) { + if (!VersionHasIetfQuicFrames(transport_version())) { stream_id_manager_.OnStreamClosed( /*is_incoming=*/IsIncomingStream(stream_id)); } if (IsIncomingStream(stream_id)) { - --num_locally_closed_incoming_streams_highest_offset_; if (VersionHasIetfQuicFrames(transport_version())) { v99_streamid_manager_.OnStreamClosed(stream_id); } @@ -1120,6 +1006,21 @@ bool QuicSession::OneRttKeysAvailable() const { } void QuicSession::OnConfigNegotiated() { + // In versions with TLS, the configs will be set twice if 0-RTT is available. + // In the second config setting, 1-RTT keys are guaranteed to be available. + if (GetQuicReloadableFlag(quic_enable_zero_rtt_for_tls) && + version().UsesTls() && is_configured_ && + connection_->encryption_level() != ENCRYPTION_FORWARD_SECURE) { + QUIC_BUG + << ENDPOINT + << "1-RTT keys missing when config is negotiated for the second time."; + connection_->CloseConnection( + QUIC_INTERNAL_ERROR, + "1-RTT keys missing when config is negotiated for the second time.", + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); + return; + } + QUIC_DVLOG(1) << ENDPOINT << "OnConfigNegotiated"; connection_->SetFromConfig(config_); @@ -1128,6 +1029,19 @@ void QuicSession::OnConfigNegotiated() { if (config_.HasReceivedMaxBidirectionalStreams()) { max_streams = config_.ReceivedMaxBidirectionalStreams(); } + if (was_zero_rtt_rejected_ && + max_streams < + v99_streamid_manager_.outgoing_bidirectional_stream_count()) { + connection_->CloseConnection( + QUIC_ZERO_RTT_UNRETRANSMITTABLE, + quiche::QuicheStrCat( + "Server rejected 0-RTT, aborting because new bidirectional " + "initial stream limit ", + max_streams, " is less than current open streams: ", + v99_streamid_manager_.outgoing_bidirectional_stream_count()), + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); + return; + } QUIC_DVLOG(1) << ENDPOINT << "Setting Bidirectional outgoing_max_streams_ to " << max_streams; @@ -1135,8 +1049,12 @@ void QuicSession::OnConfigNegotiated() { max_streams < v99_streamid_manager_.max_outgoing_bidirectional_streams()) { connection_->CloseConnection( - QUIC_MAX_STREAMS_ERROR, + was_zero_rtt_rejected_ ? QUIC_ZERO_RTT_REJECTION_LIMIT_REDUCED + : QUIC_ZERO_RTT_RESUMPTION_LIMIT_REDUCED, quiche::QuicheStrCat( + was_zero_rtt_rejected_ + ? "Server rejected 0-RTT, aborting because " + : "", "new bidirectional limit ", max_streams, " decreases the current limit: ", v99_streamid_manager_.max_outgoing_bidirectional_streams()), @@ -1152,11 +1070,30 @@ void QuicSession::OnConfigNegotiated() { if (config_.HasReceivedMaxUnidirectionalStreams()) { max_streams = config_.ReceivedMaxUnidirectionalStreams(); } + + if (was_zero_rtt_rejected_ && + max_streams < + v99_streamid_manager_.outgoing_unidirectional_stream_count()) { + connection_->CloseConnection( + QUIC_ZERO_RTT_UNRETRANSMITTABLE, + quiche::QuicheStrCat( + "Server rejected 0-RTT, aborting because new unidirectional " + "initial stream limit ", + max_streams, " is less than current open streams: ", + v99_streamid_manager_.outgoing_unidirectional_stream_count()), + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); + return; + } + if (max_streams < v99_streamid_manager_.max_outgoing_unidirectional_streams()) { connection_->CloseConnection( - QUIC_MAX_STREAMS_ERROR, + was_zero_rtt_rejected_ ? QUIC_ZERO_RTT_REJECTION_LIMIT_REDUCED + : QUIC_ZERO_RTT_RESUMPTION_LIMIT_REDUCED, quiche::QuicheStrCat( + was_zero_rtt_rejected_ + ? "Server rejected 0-RTT, aborting because " + : "", "new unidirectional limit ", max_streams, " decreases the current limit: ", v99_streamid_manager_.max_outgoing_unidirectional_streams()), @@ -1177,6 +1114,17 @@ void QuicSession::OnConfigNegotiated() { } QUIC_DVLOG(1) << ENDPOINT << "Setting max_open_outgoing_streams_ to " << max_streams; + if (was_zero_rtt_rejected_ && + max_streams < stream_id_manager_.num_open_outgoing_streams()) { + connection_->CloseConnection( + QUIC_INTERNAL_ERROR, + quiche::QuicheStrCat( + "Server rejected 0-RTT, aborting because new stream limit ", + max_streams, " is less than current open streams: ", + stream_id_manager_.num_open_outgoing_streams()), + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); + return; + } stream_id_manager_.set_max_open_outgoing_streams(max_streams); } @@ -1271,11 +1219,16 @@ void QuicSession::OnConfigNegotiated() { OnNewSessionFlowControlWindow( config_.ReceivedInitialSessionFlowControlWindowBytes()); } + is_configured_ = true; connection()->OnConfigNegotiated(); // Ask flow controllers to try again since the config could have unblocked us. - if (connection_->version().AllowsLowFlowControlLimits()) { + // Or if this session is configured on TLS enabled QUIC versions, + // attempt to retransmit 0-RTT data if there's any. + if (connection_->version().AllowsLowFlowControlLimits() || + (GetQuicReloadableFlag(quic_enable_zero_rtt_for_tls) && + version().UsesTls())) { OnCanWrite(); } } @@ -1373,8 +1326,15 @@ void QuicSession::OnNewStreamUnidirectionalFlowControlWindow( // Inform all existing outgoing unidirectional streams about the new window. for (auto const& kv : stream_map_) { const QuicStreamId id = kv.first; - if (QuicUtils::IsBidirectionalStreamId(id)) { - continue; + if (fix_gquic_stream_type_ && !version().HasIetfQuicFrames()) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_fix_gquic_stream_type, 1, 3); + if (kv.second->type() == BIDIRECTIONAL) { + continue; + } + } else { + if (QuicUtils::IsBidirectionalStreamId(id, version())) { + continue; + } } if (!QuicUtils::IsOutgoingStreamId(connection_->version(), id, perspective())) { @@ -1382,6 +1342,9 @@ void QuicSession::OnNewStreamUnidirectionalFlowControlWindow( } QUIC_DVLOG(1) << ENDPOINT << "Informing unidirectional stream " << id << " of new stream flow control window " << new_window; + if (!ValidateStreamFlowControlLimit(new_window, kv.second.get())) { + return; + } if (!kv.second->ConfigSendWindowOffset(new_window)) { return; } @@ -1397,8 +1360,15 @@ void QuicSession::OnNewStreamOutgoingBidirectionalFlowControlWindow( // Inform all existing outgoing bidirectional streams about the new window. for (auto const& kv : stream_map_) { const QuicStreamId id = kv.first; - if (!QuicUtils::IsBidirectionalStreamId(id)) { - continue; + if (fix_gquic_stream_type_ && !version().HasIetfQuicFrames()) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_fix_gquic_stream_type, 2, 3); + if (kv.second->type() != BIDIRECTIONAL) { + continue; + } + } else { + if (!QuicUtils::IsBidirectionalStreamId(id, version())) { + continue; + } } if (!QuicUtils::IsOutgoingStreamId(connection_->version(), id, perspective())) { @@ -1406,6 +1376,9 @@ void QuicSession::OnNewStreamOutgoingBidirectionalFlowControlWindow( } QUIC_DVLOG(1) << ENDPOINT << "Informing outgoing bidirectional stream " << id << " of new stream flow control window " << new_window; + if (!ValidateStreamFlowControlLimit(new_window, kv.second.get())) { + return; + } if (!kv.second->ConfigSendWindowOffset(new_window)) { return; } @@ -1421,8 +1394,15 @@ void QuicSession::OnNewStreamIncomingBidirectionalFlowControlWindow( // Inform all existing incoming bidirectional streams about the new window. for (auto const& kv : stream_map_) { const QuicStreamId id = kv.first; - if (!QuicUtils::IsBidirectionalStreamId(id)) { - continue; + if (fix_gquic_stream_type_ && !version().HasIetfQuicFrames()) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_fix_gquic_stream_type, 3, 3); + if (kv.second->type() != BIDIRECTIONAL) { + continue; + } + } else { + if (!QuicUtils::IsBidirectionalStreamId(id, version())) { + continue; + } } if (QuicUtils::IsOutgoingStreamId(connection_->version(), id, perspective())) { @@ -1430,39 +1410,92 @@ void QuicSession::OnNewStreamIncomingBidirectionalFlowControlWindow( } QUIC_DVLOG(1) << ENDPOINT << "Informing incoming bidirectional stream " << id << " of new stream flow control window " << new_window; + if (!ValidateStreamFlowControlLimit(new_window, kv.second.get())) { + return; + } if (!kv.second->ConfigSendWindowOffset(new_window)) { return; } } } +bool QuicSession::ValidateStreamFlowControlLimit(QuicStreamOffset new_window, + const QuicStream* stream) { + if (was_zero_rtt_rejected_ && + new_window < stream->flow_controller()->bytes_sent()) { + QUIC_BUG_IF(perspective() == Perspective::IS_SERVER) + << "Server should never receive configs twice."; + connection_->CloseConnection( + QUIC_ZERO_RTT_UNRETRANSMITTABLE, + quiche::QuicheStrCat( + "Server rejected 0-RTT, aborting because new stream max data ", + new_window, " for stream ", stream->id(), + " is less than currently used: ", + stream->flow_controller()->bytes_sent()), + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); + return false; + } + + if (version().AllowsLowFlowControlLimits() && + new_window < stream->flow_controller()->send_window_offset()) { + QUIC_BUG_IF(perspective() == Perspective::IS_SERVER) + << "Server should never receive configs twice."; + connection_->CloseConnection( + was_zero_rtt_rejected_ ? QUIC_ZERO_RTT_REJECTION_LIMIT_REDUCED + : QUIC_ZERO_RTT_RESUMPTION_LIMIT_REDUCED, + quiche::QuicheStrCat( + was_zero_rtt_rejected_ ? "Server rejected 0-RTT, aborting because " + : "", + "new stream max data ", new_window, " decreases current limit: ", + stream->flow_controller()->send_window_offset()), + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); + return false; + } + return true; +} + void QuicSession::OnNewSessionFlowControlWindow(QuicStreamOffset new_window) { QUIC_DVLOG(1) << ENDPOINT << "OnNewSessionFlowControlWindow " << new_window; - bool close_connection = false; - if (!connection_->version().AllowsLowFlowControlLimits()) { - if (new_window < kMinimumFlowControlSendWindow) { - close_connection = true; - QUIC_LOG_FIRST_N(ERROR, 1) - << "Peer sent us an invalid session flow control send window: " - << new_window << ", below default: " << kMinimumFlowControlSendWindow; - } - } else if (perspective_ == Perspective::IS_CLIENT && - new_window < flow_controller_.send_window_offset()) { - // The client receives a lower limit than remembered, violating - // https://tools.ietf.org/html/draft-ietf-quic-transport-27#section-7.3.1 - QUIC_LOG_FIRST_N(ERROR, 1) - << "Peer sent us an invalid session flow control send window: " - << new_window - << ", below current: " << flow_controller_.send_window_offset(); - close_connection = true; + + if (was_zero_rtt_rejected_ && new_window < flow_controller_.bytes_sent()) { + std::string error_details = quiche::QuicheStrCat( + "Server rejected 0-RTT. Aborting because the client received session " + "flow control send window: ", + new_window, + ", which is below currently used: ", flow_controller_.bytes_sent()); + QUIC_LOG(ERROR) << error_details; + connection_->CloseConnection( + QUIC_ZERO_RTT_UNRETRANSMITTABLE, error_details, + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); + return; } - if (close_connection) { + if (!connection_->version().AllowsLowFlowControlLimits() && + new_window < kMinimumFlowControlSendWindow) { + std::string error_details = quiche::QuicheStrCat( + "Peer sent us an invalid session flow control send window: ", + new_window, ", below minimum: ", kMinimumFlowControlSendWindow); + QUIC_LOG_FIRST_N(ERROR, 1) << error_details; connection_->CloseConnection( - QUIC_FLOW_CONTROL_INVALID_WINDOW, - quiche::QuicheStrCat("New connection window too low: ", new_window), + QUIC_FLOW_CONTROL_INVALID_WINDOW, error_details, ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); return; } + if (perspective_ == Perspective::IS_CLIENT && + new_window < flow_controller_.send_window_offset()) { + // The client receives a lower limit than remembered, violating + // https://tools.ietf.org/html/draft-ietf-quic-transport-27#section-7.3.1 + std::string error_details = quiche::QuicheStrCat( + was_zero_rtt_rejected_ ? "Server rejected 0-RTT, aborting because " + : "", + "new session max data ", new_window, + " decreases current limit: ", flow_controller_.send_window_offset()); + QUIC_LOG(ERROR) << error_details; + connection_->CloseConnection( + was_zero_rtt_rejected_ ? QUIC_ZERO_RTT_REJECTION_LIMIT_REDUCED + : QUIC_ZERO_RTT_RESUMPTION_LIMIT_REDUCED, + error_details, ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); + return; + } flow_controller_.UpdateSendWindowOffset(new_window); } @@ -1497,31 +1530,17 @@ void QuicSession::OnNewEncryptionKeyAvailable( EncryptionLevel level, std::unique_ptr<QuicEncrypter> encrypter) { connection()->SetEncrypter(level, std::move(encrypter)); - - if (connection_->version().handshake_protocol == PROTOCOL_TLS1_3 && - (perspective() == Perspective::IS_CLIENT || - GetQuicReloadableFlag(quic_change_default_encryption_level))) { - QUIC_DVLOG(1) << ENDPOINT << "Set default encryption level to " - << EncryptionLevelToString(level); - QUIC_RELOADABLE_FLAG_COUNT(quic_change_default_encryption_level); - connection()->SetDefaultEncryptionLevel(level); + if (connection_->version().handshake_protocol != PROTOCOL_TLS1_3) { return; } - if (connection_->version().handshake_protocol == PROTOCOL_TLS1_3 && - level == ENCRYPTION_FORWARD_SECURE) { - // Set connection's default encryption level once 1-RTT write key is - // available. - QUIC_DVLOG(1) << ENDPOINT << "Set default encryption level to " - << EncryptionLevelToString(level); - connection()->SetDefaultEncryptionLevel(level); - } + QUIC_DVLOG(1) << ENDPOINT << "Set default encryption level to " << level; + connection()->SetDefaultEncryptionLevel(level); } void QuicSession::SetDefaultEncryptionLevel(EncryptionLevel level) { DCHECK_EQ(PROTOCOL_QUIC_CRYPTO, connection_->version().handshake_protocol); - QUIC_DVLOG(1) << ENDPOINT << "Set default encryption level to " - << EncryptionLevelToString(level); + QUIC_DVLOG(1) << ENDPOINT << "Set default encryption level to " << level; connection()->SetDefaultEncryptionLevel(level); switch (level) { @@ -1531,7 +1550,7 @@ void QuicSession::SetDefaultEncryptionLevel(EncryptionLevel level) { if (perspective() == Perspective::IS_CLIENT) { // Retransmit old 0-RTT data (if any) with the new 0-RTT keys, since // they can't be decrypted by the server. - connection_->RetransmitUnackedPackets(ALL_INITIAL_RETRANSMISSION); + connection_->RetransmitZeroRttPackets(); // Given any streams blocked by encryption a chance to write. OnCanWrite(); } @@ -1541,13 +1560,9 @@ void QuicSession::SetDefaultEncryptionLevel(EncryptionLevel level) { case ENCRYPTION_FORWARD_SECURE: QUIC_BUG_IF(!config_.negotiated()) << ENDPOINT << "Handshake confirmed without parameter negotiation."; - if (!GetQuicReloadableFlag(quic_bw_sampler_app_limited_starting_value)) { - connection_->ResetHasNonAppLimitedSampleAfterHandshakeCompletion(); - } break; default: - QUIC_BUG << "Unknown encryption level: " - << EncryptionLevelToString(level); + QUIC_BUG << "Unknown encryption level: " << level; } } @@ -1557,15 +1572,17 @@ void QuicSession::OnOneRttKeysAvailable() { << ENDPOINT << "Handshake completes without cipher suite negotiation."; QUIC_BUG_IF(!config_.negotiated()) << ENDPOINT << "Handshake completes without parameter negotiation."; - if (connection()->version().HasHandshakeDone() && + if ((connection()->version().HasHandshakeDone() || + (GetQuicReloadableFlag(quic_support_handshake_done_in_t050) && + config_.PeerSupportsHandshakeDone())) && perspective_ == Perspective::IS_SERVER) { + if (!connection()->version().HasHandshakeDone()) { + QUIC_RELOADABLE_FLAG_COUNT(quic_support_handshake_done_in_t050); + } // Server sends HANDSHAKE_DONE to signal confirmation of the handshake // to the client. control_frame_manager_.WriteOrBufferHandshakeDone(); } - if (!GetQuicReloadableFlag(quic_bw_sampler_app_limited_starting_value)) { - connection_->ResetHasNonAppLimitedSampleAfterHandshakeCompletion(); - } } void QuicSession::DiscardOldDecryptionKey(EncryptionLevel level) { @@ -1576,8 +1593,7 @@ void QuicSession::DiscardOldDecryptionKey(EncryptionLevel level) { } void QuicSession::DiscardOldEncryptionKey(EncryptionLevel level) { - QUIC_DVLOG(1) << ENDPOINT << "Discard keys of " - << EncryptionLevelToString(level); + QUIC_DVLOG(1) << ENDPOINT << "Discard keys of " << level; if (connection()->version().handshake_protocol == PROTOCOL_TLS1_3) { connection()->RemoveEncrypter(level); } @@ -1594,8 +1610,7 @@ void QuicSession::DiscardOldEncryptionKey(EncryptionLevel level) { QUIC_BUG << "Tries to drop 1-RTT keys"; break; default: - QUIC_BUG << "Unknown encryption level: " - << EncryptionLevelToString(level); + QUIC_BUG << "Unknown encryption level: " << level; } } @@ -1603,6 +1618,46 @@ void QuicSession::NeuterHandshakeData() { connection()->OnHandshakeComplete(); } +void QuicSession::OnZeroRttRejected() { + was_zero_rtt_rejected_ = true; + connection_->RetransmitZeroRttPackets(); + if (connection_->encryption_level() == ENCRYPTION_FORWARD_SECURE) { + QUIC_BUG << "1-RTT keys already available when 0-RTT is rejected."; + connection_->CloseConnection( + QUIC_INTERNAL_ERROR, + "1-RTT keys already available when 0-RTT is rejected.", + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); + } +} + +bool QuicSession::FillTransportParameters(TransportParameters* params) { + if (version().AuthenticatesHandshakeConnectionIds()) { + if (perspective() == Perspective::IS_SERVER) { + config_.SetOriginalConnectionIdToSend( + connection_->GetOriginalDestinationConnectionId()); + config_.SetInitialSourceConnectionIdToSend(connection_->connection_id()); + } else { + config_.SetInitialSourceConnectionIdToSend( + connection_->client_connection_id()); + } + } + return config_.FillTransportParameters(params); +} + +QuicErrorCode QuicSession::ProcessTransportParameters( + const TransportParameters& params, + bool is_resumption, + std::string* error_details) { + HelloType hello_type; + if (perspective_ == Perspective::IS_CLIENT) { + hello_type = SERVER; + } else { + hello_type = CLIENT; + } + return config_.ProcessTransportParameters(params, hello_type, is_resumption, + error_details); +} + void QuicSession::OnCryptoHandshakeMessageSent( const CryptoHandshakeMessage& /*message*/) {} @@ -1648,14 +1703,11 @@ void QuicSession::ActivateStream(std::unique_ptr<QuicStream> stream) { << ". activating stream " << stream_id; DCHECK(!QuicContainsKey(stream_map_, stream_id)); stream_map_[stream_id] = std::move(stream); - if (IsIncomingStream(stream_id)) { - is_static ? ++num_incoming_static_streams_ - : ++num_dynamic_incoming_streams_; - } else if (is_static) { - ++num_outgoing_static_streams_; + if (is_static) { + ++num_static_streams_; + return; } - if (stream_id_manager_.handles_accounting() && !is_static && - !VersionHasIetfQuicFrames(transport_version())) { + if (!VersionHasIetfQuicFrames(transport_version())) { // Do not inform stream ID manager of static streams. stream_id_manager_.ActivateStream( /*is_incoming=*/IsIncomingStream(stream_id)); @@ -1678,8 +1730,7 @@ QuicStreamId QuicSession::GetNextOutgoingUnidirectionalStreamId() { bool QuicSession::CanOpenNextOutgoingBidirectionalStream() { if (!VersionHasIetfQuicFrames(transport_version())) { - return stream_id_manager_.CanOpenNextOutgoingStream( - GetNumOpenOutgoingStreams()); + return stream_id_manager_.CanOpenNextOutgoingStream(); } if (v99_streamid_manager_.CanOpenNextOutgoingBidirectionalStream()) { return true; @@ -1695,8 +1746,7 @@ bool QuicSession::CanOpenNextOutgoingBidirectionalStream() { bool QuicSession::CanOpenNextOutgoingUnidirectionalStream() { if (!VersionHasIetfQuicFrames(transport_version())) { - return stream_id_manager_.CanOpenNextOutgoingStream( - GetNumOpenOutgoingStreams()); + return stream_id_manager_.CanOpenNextOutgoingStream(); } if (v99_streamid_manager_.CanOpenNextOutgoingUnidirectionalStream()) { return true; @@ -1745,19 +1795,11 @@ QuicStream* QuicSession::GetOrCreateStream(const QuicStreamId stream_id) { return nullptr; } - if (!VersionHasIetfQuicFrames(transport_version())) { - // TODO(fayang): Let LegacyQuicStreamIdManager count open streams and make - // CanOpenIncomingStream interface consistent with that of v99. - if (!stream_id_manager_.CanOpenIncomingStream( - GetNumOpenIncomingStreams())) { - // Refuse to open the stream. - if (break_close_loop_) { - ResetStream(stream_id, QUIC_REFUSED_STREAM, 0); - } else { - SendRstStream(stream_id, QUIC_REFUSED_STREAM, 0); - } - return nullptr; - } + if (!VersionHasIetfQuicFrames(transport_version()) && + !stream_id_manager_.CanOpenIncomingStream()) { + // Refuse to open the stream. + ResetStream(stream_id, QUIC_REFUSED_STREAM, 0); + return nullptr; } return CreateIncomingStream(stream_id); @@ -1765,48 +1807,17 @@ QuicStream* QuicSession::GetOrCreateStream(const QuicStreamId stream_id) { void QuicSession::StreamDraining(QuicStreamId stream_id, bool unidirectional) { DCHECK(QuicContainsKey(stream_map_, stream_id)); - if (deprecate_draining_streams_) { - QUIC_RELOADABLE_FLAG_COUNT(quic_deprecate_draining_streams); - QUIC_DVLOG(1) << ENDPOINT << "Stream " << stream_id << " is draining"; - if (VersionHasIetfQuicFrames(transport_version())) { - v99_streamid_manager_.OnStreamClosed(stream_id); - } else if (stream_id_manager_.handles_accounting()) { - stream_id_manager_.OnStreamClosed( - /*is_incoming=*/IsIncomingStream(stream_id)); - } - if (IsIncomingStream(stream_id)) { - ++num_draining_incoming_streams_; - return; - } - ++num_draining_outgoing_streams_; - OnCanCreateNewOutgoingStream(unidirectional); - return; - } - if (!QuicContainsKey(draining_streams_, stream_id)) { - draining_streams_.insert(stream_id); - if (IsIncomingStream(stream_id)) { - ++num_draining_incoming_streams_; - } - if (VersionHasIetfQuicFrames(transport_version())) { - v99_streamid_manager_.OnStreamClosed(stream_id); - } else if (stream_id_manager_.handles_accounting()) { - stream_id_manager_.OnStreamClosed( - /*is_incoming=*/IsIncomingStream(stream_id)); - } + QUIC_DVLOG(1) << ENDPOINT << "Stream " << stream_id << " is draining"; + if (VersionHasIetfQuicFrames(transport_version())) { + v99_streamid_manager_.OnStreamClosed(stream_id); + } else { + stream_id_manager_.OnStreamClosed( + /*is_incoming=*/IsIncomingStream(stream_id)); } + ++num_draining_streams_; if (!IsIncomingStream(stream_id)) { - // Inform application that a stream is available. - if (VersionHasIetfQuicFrames(transport_version())) { - OnCanCreateNewOutgoingStream( - !QuicUtils::IsBidirectionalStreamId(stream_id)); - } else { - QuicStream* stream = GetStream(stream_id); - if (!stream) { - QUIC_BUG << "Stream doesn't exist when draining."; - return; - } - OnCanCreateNewOutgoingStream(stream->type() != BIDIRECTIONAL); - } + ++num_outgoing_draining_streams_; + OnCanCreateNewOutgoingStream(unidirectional); } } @@ -1924,46 +1935,15 @@ bool QuicSession::IsStaticStream(QuicStreamId id) const { return it->second->is_static(); } -size_t QuicSession::GetNumOpenIncomingStreams() const { - DCHECK(!VersionHasIetfQuicFrames(transport_version())); - if (stream_id_manager_.handles_accounting()) { - return stream_id_manager_.num_open_incoming_streams(); - } - return num_dynamic_incoming_streams_ - num_draining_incoming_streams_ + - num_locally_closed_incoming_streams_highest_offset_; -} - -size_t QuicSession::GetNumOpenOutgoingStreams() const { - DCHECK(!VersionHasIetfQuicFrames(transport_version())); - if (stream_id_manager_.handles_accounting()) { - return stream_id_manager_.num_open_outgoing_streams(); - } - DCHECK_GE(GetNumDynamicOutgoingStreams() + - GetNumLocallyClosedOutgoingStreamsHighestOffset(), - GetNumDrainingOutgoingStreams()); - return GetNumDynamicOutgoingStreams() + - GetNumLocallyClosedOutgoingStreamsHighestOffset() - - GetNumDrainingOutgoingStreams(); -} - size_t QuicSession::GetNumActiveStreams() const { - if (!VersionHasIetfQuicFrames(transport_version()) && - stream_id_manager_.handles_accounting()) { + if (!VersionHasIetfQuicFrames(transport_version())) { // Exclude locally_closed_streams when determine whether to keep connection // alive. return stream_id_manager_.num_open_incoming_streams() + stream_id_manager_.num_open_outgoing_streams() - locally_closed_streams_highest_offset_.size(); } - return stream_map_.size() - GetNumDrainingStreams() - - num_incoming_static_streams_ - num_outgoing_static_streams_; -} - -size_t QuicSession::GetNumDrainingStreams() const { - if (deprecate_draining_streams_) { - return num_draining_incoming_streams_ + num_draining_outgoing_streams_; - } - return draining_streams_.size(); + return stream_map_.size() - num_draining_streams_ - num_static_streams_; } void QuicSession::MarkConnectionLevelWriteBlocked(QuicStreamId id) { @@ -1994,31 +1974,6 @@ void QuicSession::SendPing() { control_frame_manager_.WritePing(); } -size_t QuicSession::GetNumDynamicOutgoingStreams() const { - DCHECK_GE( - static_cast<size_t>(stream_map_.size() + pending_stream_map_.size()), - num_dynamic_incoming_streams_ + num_outgoing_static_streams_ + - num_incoming_static_streams_); - return stream_map_.size() + pending_stream_map_.size() - - num_dynamic_incoming_streams_ - num_outgoing_static_streams_ - - num_incoming_static_streams_; -} - -size_t QuicSession::GetNumDrainingOutgoingStreams() const { - if (deprecate_draining_streams_) { - return num_draining_outgoing_streams_; - } - DCHECK_GE(draining_streams_.size(), num_draining_incoming_streams_); - return draining_streams_.size() - num_draining_incoming_streams_; -} - -size_t QuicSession::GetNumLocallyClosedOutgoingStreamsHighestOffset() const { - DCHECK_GE(locally_closed_streams_highest_offset_.size(), - num_locally_closed_incoming_streams_highest_offset_); - return locally_closed_streams_highest_offset_.size() - - num_locally_closed_incoming_streams_highest_offset_; -} - bool QuicSession::IsConnectionFlowControlBlocked() const { return flow_controller_.IsBlocked(); } @@ -2273,6 +2228,18 @@ QuicUint128 QuicSession::GetStatelessResetToken() const { return QuicUtils::GenerateStatelessResetToken(connection_->connection_id()); } +bool QuicSession::CanWriteStreamData() const { + // Don't write stream data if there are queued data packets. + if (connection_->HasQueuedPackets()) { + return false; + } + // Immediately write handshake data. + if (HasPendingHandshake()) { + return true; + } + return connection_->CanWrite(HAS_RETRANSMITTABLE_DATA); +} + bool QuicSession::RetransmitLostData() { QuicConnection::ScopedPacketFlusher retransmission_flusher(connection_); // Retransmit crypto data first. @@ -2305,7 +2272,7 @@ bool QuicSession::RetransmitLostData() { } } while (!streams_with_pending_retransmission_.empty()) { - if (!connection_->CanWriteStreamData()) { + if (!CanWriteStreamData()) { break; } // Retransmit lost data on headers and data streams. diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_session.h b/chromium/net/third_party/quiche/src/quic/core/quic_session.h index 5a1ebbc602c..9233402d4ea 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_session.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_session.h @@ -33,6 +33,7 @@ #include "net/third_party/quiche/src/quic/platform/api/quic_containers.h" #include "net/third_party/quiche/src/quic/platform/api/quic_export.h" #include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_optional.h" #include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" namespace quic { @@ -110,17 +111,21 @@ class QUIC_EXPORT_PRIVATE QuicSession bool is_connectivity_probe) override; void OnCanWrite() override; bool SendProbingData() override; + bool ValidateStatelessReset( + const quic::QuicSocketAddress& /*self_address*/, + const quic::QuicSocketAddress& /*peer_address*/) override { + return true; + } void OnCongestionWindowChange(QuicTime /*now*/) override {} void OnConnectionMigration(AddressChangeType /*type*/) override {} // Adds a connection level WINDOW_UPDATE frame. void OnAckNeedsRetransmittableFrame() override; void SendPing() override; bool WillingAndAbleToWrite() const override; - bool HasPendingHandshake() const override; void OnPathDegrading() override; + void OnForwardProgressMadeAfterPathDegrading() override; bool AllowSelfAddressChange() const override; HandshakeState GetHandshakeState() const override; - void OnForwardProgressConfirmed() override; bool OnMaxStreamsFrame(const QuicMaxStreamsFrame& frame) override; bool OnStreamsBlockedFrame(const QuicStreamsBlockedFrame& frame) override; void OnStopSendingFrame(const QuicStopSendingFrame& frame) override; @@ -255,6 +260,11 @@ class QUIC_EXPORT_PRIVATE QuicSession void DiscardOldEncryptionKey(EncryptionLevel level) override; void NeuterUnencryptedData() override; void NeuterHandshakeData() override; + void OnZeroRttRejected() override; + bool FillTransportParameters(TransportParameters* params) override; + QuicErrorCode ProcessTransportParameters(const TransportParameters& params, + bool is_resumption, + std::string* error_details) override; // Implement StreamDelegateInterface. void OnStreamError(QuicErrorCode error_code, @@ -322,33 +332,6 @@ class QUIC_EXPORT_PRIVATE QuicSession // never counting unfinished streams. size_t GetNumActiveStreams() const; - // Returns the number of currently draining streams. - size_t GetNumDrainingStreams() const; - - // Returns the number of currently open peer initiated streams, excluding - // static streams. - // TODO(fayang): remove this and instead use - // LegacyStreamIdManager::num_open_incoming_streams() in tests when - // deprecating quic_stream_id_manager_handles_accounting. - size_t GetNumOpenIncomingStreams() const; - - // Returns the number of currently open self initiated streams, excluding - // static streams. - // TODO(fayang): remove this and instead use - // LegacyStreamIdManager::num_open_outgoing_streams() in tests when - // deprecating quic_stream_id_manager_handles_accounting. - size_t GetNumOpenOutgoingStreams() const; - - // Returns the number of open peer initiated static streams. - size_t num_incoming_static_streams() const { - return num_incoming_static_streams_; - } - - // Returns the number of open self initiated static streams. - size_t num_outgoing_static_streams() const { - return num_outgoing_static_streams_; - } - // Add the stream to the session's write-blocked list because it is blocked by // connection-level flow control but not by its own stream-level flow control. // The stream will be given a chance to write when a connection-level @@ -363,6 +346,10 @@ class QUIC_EXPORT_PRIVATE QuicSession // Called when stream |id| is newly waiting for acks. void OnStreamWaitingForAcks(QuicStreamId id); + // Returns true if there is pending handshake data in the crypto stream. + // TODO(ianswett): Make this private or remove. + bool HasPendingHandshake() const; + // Returns true if the session has data to be sent, either queued in the // connection, or in a write-blocked stream. bool HasDataToWrite() const; @@ -435,12 +422,6 @@ class QUIC_EXPORT_PRIVATE QuicSession // Return true if given stream is peer initiated. bool IsIncomingStream(QuicStreamId id) const; - size_t GetNumLocallyClosedOutgoingStreamsHighestOffset() const; - - size_t num_locally_closed_incoming_streams_highest_offset() const { - return num_locally_closed_incoming_streams_highest_offset_; - } - // Record errors when a connection is closed at the server side, should only // be called from server's perspective. // Noop if |error| is QUIC_NO_ERROR. @@ -478,27 +459,30 @@ class QUIC_EXPORT_PRIVATE QuicSession // uses TLS handshake. virtual void OnAlpnSelected(quiche::QuicheStringPiece alpn); - bool deprecate_draining_streams() const { - return deprecate_draining_streams_; - } - - bool break_close_loop() const { return break_close_loop_; } - // Called on clients by the crypto handshaker to provide application state // necessary for sending application data in 0-RTT. The state provided here is // the same state that was provided to the crypto handshaker in - // QuicCryptoClientStream::OnApplicationState on a previous connection. - // Application protocols that require state to be carried over from the - // previous connection to support 0-RTT data must implement this method to - // ingest this state. For example, an HTTP/3 QuicSession would implement this - // function to process the remembered server SETTINGS frame and apply those - // SETTINGS to 0-RTT data. This function returns true if the application state - // has been successfully processed, and false if there was an error processing - // the cached state and the connection should be closed. - virtual bool SetApplicationState(ApplicationState* /*cached_state*/) { + // QuicCryptoStream::SetServerApplicationStateForResumption on a previous + // connection. Application protocols that require state to be carried over + // from the previous connection to support 0-RTT data must implement this + // method to ingest this state. For example, an HTTP/3 QuicSession would + // implement this function to process the remembered server SETTINGS and apply + // those SETTINGS to 0-RTT data. This function returns true if the application + // state has been successfully processed, and false if there was an error + // processing the cached state and the connection should be closed. + virtual bool ResumeApplicationState(ApplicationState* /*cached_state*/) { return true; } + const quiche::QuicheOptional<std::string> user_agent_id() const { + return user_agent_id_; + } + + void SetUserAgentId(std::string user_agent_id) { + user_agent_id_ = std::move(user_agent_id); + connection()->OnUserAgentIdKnown(); + } + protected: using StreamMap = QuicSmallMap<QuicStreamId, std::unique_ptr<QuicStream>, 10>; @@ -541,18 +525,10 @@ class QUIC_EXPORT_PRIVATE QuicSession bool CanOpenNextOutgoingBidirectionalStream(); bool CanOpenNextOutgoingUnidirectionalStream(); - // Returns the number of open dynamic streams. - uint64_t GetNumOpenDynamicStreams() const; - // Returns the maximum bidirectional streams parameter sent with the handshake // as a transport parameter, or in the most recent MAX_STREAMS frame. QuicStreamCount GetAdvertisedMaxIncomingBidirectionalStreams() const; - // Performs the work required to close |stream_id|. If |rst_sent| then a - // Reset Stream frame has already been sent for this stream. - // TODO(fayang): Remove CloseStreamInner. - virtual void CloseStreamInner(QuicStreamId stream_id, bool rst_sent); - // When a stream is closed locally, it may not yet know how many bytes the // peer sent on that stream. // When this data arrives (via stream frame w. FIN, trailing headers, or RST) @@ -589,10 +565,6 @@ class QUIC_EXPORT_PRIVATE QuicSession return &write_blocked_streams_; } - size_t GetNumDynamicOutgoingStreams() const; - - size_t GetNumDrainingOutgoingStreams() const; - // Returns true if the stream is still active. bool IsOpenStream(QuicStreamId id); @@ -630,6 +602,14 @@ class QUIC_EXPORT_PRIVATE QuicSession QuicDatagramQueue* datagram_queue() { return &datagram_queue_; } + size_t num_static_streams() const { return num_static_streams_; } + + bool was_zero_rtt_rejected() const { return was_zero_rtt_rejected_; } + + size_t num_outgoing_draining_streams() const { + return num_outgoing_draining_streams_; + } + // Processes the stream type information of |pending| depending on // different kinds of sessions' own rules. Returns true if the pending stream // is converted into a normal stream. @@ -704,6 +684,9 @@ class QUIC_EXPORT_PRIVATE QuicSession // if all lost data is retransmitted. Returns false otherwise. bool RetransmitLostData(); + // Returns true if stream data should be written. + bool CanWriteStreamData() const; + // Closes the pending stream |stream_id| before it has been created. void ClosePendingStream(QuicStreamId stream_id); @@ -720,6 +703,12 @@ class QUIC_EXPORT_PRIVATE QuicSession QuicRstStreamErrorCode error, QuicStreamOffset bytes_written); + // Closes the connection and returns false if |new_window| is lower than + // |stream|'s current flow control window. + // Returns true otherwise. + bool ValidateStreamFlowControlLimit(QuicStreamOffset new_window, + const QuicStream* stream); + // Sends a STOP_SENDING frame if the stream type allows. void MaybeSendStopSendingFrame(QuicStreamId id, QuicRstStreamErrorCode error); @@ -756,13 +745,6 @@ class QUIC_EXPORT_PRIVATE QuicSession // which are waiting for the first byte of payload to arrive. PendingStreamMap pending_stream_map_; - // Set of stream ids that are "draining" -- a FIN has been sent and received, - // but the stream object still exists because not all the received data has - // been consumed. - // TODO(fayang): Remove draining_streams_ when deprecate - // quic_deprecate_draining_streams. - QuicHashSet<QuicStreamId> draining_streams_; - // Set of stream ids that are waiting for acks excluding crypto stream id. QuicHashSet<QuicStreamId> streams_waiting_for_acks_; @@ -774,37 +756,16 @@ class QUIC_EXPORT_PRIVATE QuicSession // Manages stream IDs for version99/IETF QUIC UberQuicStreamIdManager v99_streamid_manager_; - // A counter for peer initiated dynamic streams which are in the stream_map_. - // TODO(fayang): Remove this when deprecating - // quic_stream_id_manager_handles_accounting. - size_t num_dynamic_incoming_streams_; + // A counter for streams which have sent and received FIN but waiting for + // application to consume data. + size_t num_draining_streams_; - // A counter for peer initiated streams which have sent and received FIN but + // A counter for self initiated streams which have sent and received FIN but // waiting for application to consume data. - // TODO(fayang): Remove this when deprecating - // quic_stream_id_manager_handles_accounting. - size_t num_draining_incoming_streams_; + size_t num_outgoing_draining_streams_; - // A counter for self initiated streams which have sent and received FIN but - // waiting for application to consume data. Only used when - // deprecate_draining_streams_ is true. - // TODO(fayang): Remove this when deprecating - // quic_stream_id_manager_handles_accounting. - size_t num_draining_outgoing_streams_; - - // A counter for self initiated static streams which are in - // stream_map_. - size_t num_outgoing_static_streams_; - - // A counter for peer initiated static streams which are in - // stream_map_. - size_t num_incoming_static_streams_; - - // A counter for peer initiated streams which are in the - // locally_closed_streams_highest_offset_. - // TODO(fayang): Remove this when deprecating - // quic_stream_id_manager_handles_accounting. - size_t num_locally_closed_incoming_streams_highest_offset_; + // A counter for static streams which are in stream_map_. + size_t num_static_streams_; // Received information for a connection close. QuicConnectionCloseFrame on_closed_frame_; @@ -842,6 +803,8 @@ class QUIC_EXPORT_PRIVATE QuicSession // list may be a superset of the connection framer's supported versions. ParsedQuicVersionVector supported_versions_; + quiche::QuicheOptional<std::string> user_agent_id_; + // If true, write_blocked_streams_ uses HTTP2 (tree-style) priority write // scheduler. bool use_http2_priority_write_scheduler_; @@ -853,11 +816,11 @@ class QUIC_EXPORT_PRIVATE QuicSession // If true, enables round robin scheduling. bool enable_round_robin_scheduling_; - // Latched value of quic_deprecate_draining_streams. - const bool deprecate_draining_streams_; + // Whether the session has received a 0-RTT rejection (QUIC+TLS only). + bool was_zero_rtt_rejected_; - // Latched value of quic_break_session_stream_close_loop. - const bool break_close_loop_; + // Latched value of flag quic_fix_gquic_stream_type. + const bool fix_gquic_stream_type_; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_session_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_session_test.cc index 9d5e977d0a6..12a48300bdb 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_session_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_session_test.cc @@ -10,6 +10,7 @@ #include <utility> #include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h" +#include "net/third_party/quiche/src/quic/core/crypto/null_decrypter.h" #include "net/third_party/quiche/src/quic/core/crypto/null_encrypter.h" #include "net/third_party/quiche/src/quic/core/crypto/transport_parameters.h" #include "net/third_party/quiche/src/quic/core/frames/quic_max_streams_frame.h" @@ -77,6 +78,17 @@ class TestCryptoStream : public QuicCryptoStream, public QuicCryptoHandshaker { kInitialStreamFlowControlWindowForTest); session()->config()->SetInitialSessionFlowControlWindowToSend( kInitialSessionFlowControlWindowForTest); + if (session()->version().AuthenticatesHandshakeConnectionIds()) { + if (session()->perspective() == Perspective::IS_CLIENT) { + session()->config()->SetOriginalConnectionIdToSend( + session()->connection()->connection_id()); + session()->config()->SetInitialSourceConnectionIdToSend( + session()->connection()->connection_id()); + } else { + session()->config()->SetInitialSourceConnectionIdToSend( + session()->connection()->client_connection_id()); + } + } if (session()->connection()->version().handshake_protocol == PROTOCOL_TLS1_3) { TransportParameters transport_parameters; @@ -123,6 +135,8 @@ class TestCryptoStream : public QuicCryptoStream, public QuicCryptoHandshaker { HandshakeState GetHandshakeState() const override { return one_rtt_keys_available() ? HANDSHAKE_COMPLETE : HANDSHAKE_START; } + void SetServerApplicationStateForResumption( + std::unique_ptr<ApplicationState> /*application_state*/) override {} MOCK_METHOD(void, OnCanWrite, (), (override)); bool HasPendingCryptoRetransmission() const override { return false; } @@ -183,6 +197,9 @@ class TestSession : public QuicSession { this->connection()->SetEncrypter( ENCRYPTION_FORWARD_SECURE, std::make_unique<NullEncrypter>(connection->perspective())); + if (this->connection()->version().SupportsAntiAmplificationLimit()) { + QuicConnectionPeer::SetAddressValidated(this->connection()); + } } ~TestSession() override { DeleteConnection(); } @@ -216,7 +233,7 @@ class TestSession : public QuicSession { TestStream* CreateIncomingStream(QuicStreamId id) override { // Enforce the limit on the number of open streams. if (!VersionHasIetfQuicFrames(connection()->transport_version()) && - GetNumOpenIncomingStreams() + 1 > + stream_id_manager().num_open_incoming_streams() + 1 > max_open_incoming_bidirectional_streams()) { // No need to do this test for version 99; it's done by // QuicSession::GetOrCreateStream. @@ -226,11 +243,10 @@ class TestSession : public QuicSession { return nullptr; } - TestStream* stream = - new TestStream(id, this, - DetermineStreamType( - id, connection()->transport_version(), perspective(), - /*is_incoming=*/true, BIDIRECTIONAL)); + TestStream* stream = new TestStream( + id, this, + DetermineStreamType(id, connection()->version(), perspective(), + /*is_incoming=*/true, BIDIRECTIONAL)); ActivateStream(QuicWrapUnique(stream)); ++num_incoming_streams_created_; return stream; @@ -239,8 +255,7 @@ class TestSession : public QuicSession { TestStream* CreateIncomingStream(PendingStream* pending) override { QuicStreamId id = pending->id(); TestStream* stream = new TestStream( - pending, DetermineStreamType(id, connection()->transport_version(), - perspective(), + pending, DetermineStreamType(id, connection()->version(), perspective(), /*is_incoming=*/true, BIDIRECTIONAL)); ActivateStream(QuicWrapUnique(stream)); ++num_incoming_streams_created_; @@ -309,7 +324,7 @@ class TestSession : public QuicSession { MakeIOVector("not empty", &iov); QuicStreamPeer::SendBuffer(stream).SaveStreamData(&iov, 1, 0, 9); QuicConsumedData consumed = - WritevData(stream->id(), 9, 0, FIN, NOT_RETRANSMISSION, QuicheNullOpt); + WritevData(stream->id(), 9, 0, FIN, NOT_RETRANSMISSION, QUICHE_NULLOPT); QuicStreamPeer::SendBuffer(stream).OnStreamDataConsumed( consumed.bytes_consumed); return consumed; @@ -326,7 +341,7 @@ class TestSession : public QuicSession { QuicConsumedData SendLargeFakeData(QuicStream* stream, int bytes) { DCHECK(writev_consumes_all_data_); return WritevData(stream->id(), bytes, 0, FIN, NOT_RETRANSMISSION, - QuicheNullOpt); + QUICHE_NULLOPT); } bool UsesPendingStreams() const override { return uses_pending_streams_; } @@ -421,15 +436,15 @@ class QuicSessionTestBase : public QuicTestWithParam<ParsedQuicVersion> { void CloseStream(QuicStreamId id) { if (VersionHasIetfQuicFrames(transport_version())) { - if (QuicUtils::GetStreamType(id, session_.perspective(), - session_.IsIncomingStream(id)) == - READ_UNIDIRECTIONAL) { + if (QuicUtils::GetStreamType( + id, session_.perspective(), session_.IsIncomingStream(id), + connection_->version()) == READ_UNIDIRECTIONAL) { // Verify reset is not sent for READ_UNIDIRECTIONAL streams. EXPECT_CALL(*connection_, SendControlFrame(_)).Times(0); EXPECT_CALL(*connection_, OnStreamReset(_, _)).Times(0); - } else if (QuicUtils::GetStreamType(id, session_.perspective(), - session_.IsIncomingStream(id)) == - WRITE_UNIDIRECTIONAL) { + } else if (QuicUtils::GetStreamType( + id, session_.perspective(), session_.IsIncomingStream(id), + connection_->version()) == WRITE_UNIDIRECTIONAL) { // Verify RESET_STREAM but not STOP_SENDING is sent for write-only // stream. EXPECT_CALL(*connection_, SendControlFrame(_)) @@ -554,6 +569,11 @@ class QuicSessionTestServer : public QuicSessionTestBase { kQuicDefaultConnectionIdLength) { client_framer_.set_visitor(&framer_visitor_); client_framer_.SetInitialObfuscators(TestConnectionId()); + if (client_framer_.version().KnowsWhichDecrypterToUse()) { + client_framer_.InstallDecrypter( + ENCRYPTION_FORWARD_SECURE, + std::make_unique<NullDecrypter>(Perspective::IS_CLIENT)); + } } QuicPathFrameBuffer path_frame_buffer1_; @@ -595,6 +615,7 @@ TEST_P(QuicSessionTestServer, OneRttKeysAvailable) { if (connection_->version().HasHandshakeDone()) { EXPECT_CALL(*connection_, SendControlFrame(_)); } + connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); session_.GetMutableCryptoStream()->OnHandshakeMessage(message); EXPECT_TRUE(session_.OneRttKeysAvailable()); } @@ -990,6 +1011,7 @@ TEST_P(QuicSessionTestServer, Http2Priority) { QuicTagVector copt; copt.push_back(kH2PR); QuicConfigPeer::SetReceivedConnectionOptions(session_.config(), copt); + connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); session_.OnConfigNegotiated(); ASSERT_TRUE(session_.use_http2_priority_write_scheduler()); @@ -1072,6 +1094,7 @@ TEST_P(QuicSessionTestServer, RoundRobinScheduling) { QuicTagVector copt; copt.push_back(kRRWS); QuicConfigPeer::SetReceivedConnectionOptions(session_.config(), copt); + connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); session_.OnConfigNegotiated(); session_.set_writev_consumes_all_data(true); @@ -1117,6 +1140,7 @@ TEST_P(QuicSessionTestServer, OnCanWriteBundlesStreams) { CryptoHandshakeMessage msg; MockPacketWriter* writer = static_cast<MockPacketWriter*>( QuicConnectionPeer::GetWriter(session_.connection())); + connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); session_.GetMutableCryptoStream()->OnHandshakeMessage(msg); // Drive congestion control manually. @@ -1428,6 +1452,7 @@ TEST_P(QuicSessionTestServer, InvalidGoAway) { // Test that server session will send a connectivity probe in response to a // connectivity probe on the same path. TEST_P(QuicSessionTestServer, ServerReplyToConnectivityProbe) { + connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); QuicSocketAddress old_peer_address = QuicSocketAddress(QuicIpAddress::Loopback4(), kTestPort); EXPECT_EQ(old_peer_address, session_.peer_address()); @@ -1461,6 +1486,7 @@ TEST_P(QuicSessionTestServer, ServerReplyToConnectivityProbes) { if (!VersionHasIetfQuicFrames(transport_version())) { return; } + connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); QuicSocketAddress old_peer_address = QuicSocketAddress(QuicIpAddress::Loopback4(), kTestPort); EXPECT_EQ(old_peer_address, session_.peer_address()); @@ -1495,6 +1521,7 @@ TEST_P(QuicSessionTestServer, IncreasedTimeoutAfterCryptoHandshake) { EXPECT_CALL(*connection_, SendControlFrame(_)); } CryptoHandshakeMessage msg; + connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); session_.GetMutableCryptoStream()->OnHandshakeMessage(msg); EXPECT_EQ(kMaximumIdleTimeoutSecs + 3, QuicConnectionPeer::GetNetworkTimeout(connection_).ToSeconds()); @@ -1775,6 +1802,7 @@ TEST_P(QuicSessionTestServer, InvalidStreamFlowControlWindowInHandshake) { } else { EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0); } + connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); session_.OnConfigNegotiated(); } @@ -1784,6 +1812,7 @@ TEST_P(QuicSessionTestServer, CustomFlowControlWindow) { copt.push_back(kIFW7); QuicConfigPeer::SetReceivedConnectionOptions(session_.config(), copt); + connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); session_.OnConfigNegotiated(); EXPECT_EQ(192 * 1024u, QuicFlowControllerPeer::ReceiveWindowSize( session_.flow_controller())); @@ -2047,8 +2076,13 @@ TEST_P(QuicSessionTestClient, InvalidSessionFlowControlWindowInHandshake) { const uint32_t kInvalidWindow = kMinimumFlowControlSendWindow - 1; QuicConfigPeer::SetReceivedInitialSessionFlowControlWindow(session_.config(), kInvalidWindow); - EXPECT_CALL(*connection_, - CloseConnection(QUIC_FLOW_CONTROL_INVALID_WINDOW, _, _)); + EXPECT_CALL( + *connection_, + CloseConnection(connection_->version().AllowsLowFlowControlLimits() + ? QUIC_ZERO_RTT_RESUMPTION_LIMIT_REDUCED + : QUIC_FLOW_CONTROL_INVALID_WINDOW, + _, _)); + connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); session_.OnConfigNegotiated(); } @@ -2059,7 +2093,9 @@ TEST_P(QuicSessionTestClient, InvalidBidiStreamLimitInHandshake) { } QuicConfigPeer::SetReceivedMaxBidirectionalStreams( session_.config(), kDefaultMaxStreamsPerConnection - 1); - EXPECT_CALL(*connection_, CloseConnection(QUIC_MAX_STREAMS_ERROR, _, _)); + EXPECT_CALL(*connection_, + CloseConnection(QUIC_ZERO_RTT_RESUMPTION_LIMIT_REDUCED, _, _)); + connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); session_.OnConfigNegotiated(); } @@ -2070,7 +2106,9 @@ TEST_P(QuicSessionTestClient, InvalidUniStreamLimitInHandshake) { } QuicConfigPeer::SetReceivedMaxUnidirectionalStreams( session_.config(), kDefaultMaxStreamsPerConnection - 1); - EXPECT_CALL(*connection_, CloseConnection(QUIC_MAX_STREAMS_ERROR, _, _)); + EXPECT_CALL(*connection_, + CloseConnection(QUIC_ZERO_RTT_RESUMPTION_LIMIT_REDUCED, _, _)); + connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); session_.OnConfigNegotiated(); } @@ -2088,6 +2126,8 @@ TEST_P(QuicSessionTestClient, InvalidStreamFlowControlWindowInHandshake) { .WillOnce( Invoke(connection_, &MockQuicConnection::ReallyCloseConnection)); EXPECT_CALL(*connection_, SendConnectionClosePacket(_, _)); + + connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); session_.OnConfigNegotiated(); } @@ -2430,14 +2470,9 @@ TEST_P(QuicSessionTestServer, RetransmitLostDataCausesConnectionClose) { session_.OnFrameLost(QuicFrame(frame)); // Retransmit stream data causes connection close. Stream has not sent fin // yet, so an RST is sent. - if (session_.break_close_loop()) { - EXPECT_CALL(*stream, OnCanWrite()).WillOnce(Invoke([this, stream]() { - session_.CloseStream(stream->id()); - })); - } else { - EXPECT_CALL(*stream, OnCanWrite()) - .WillOnce(Invoke(stream, &QuicStream::OnClose)); - } + EXPECT_CALL(*stream, OnCanWrite()).WillOnce(Invoke([this, stream]() { + session_.CloseStream(stream->id()); + })); if (VersionHasIetfQuicFrames(transport_version())) { // Once for the RST_STREAM, once for the STOP_SENDING EXPECT_CALL(*connection_, SendControlFrame(_)) @@ -2466,6 +2501,7 @@ TEST_P(QuicSessionTestServer, SendMessage) { EXPECT_CALL(*connection_, SendControlFrame(_)); } CryptoHandshakeMessage handshake_message; + connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); session_.GetMutableCryptoStream()->OnHandshakeMessage(handshake_message); EXPECT_TRUE(session_.OneRttKeysAvailable()); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream.cc b/chromium/net/third_party/quiche/src/quic/core/quic_stream.cc index 40a67bba21c..6318ac1ecff 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_stream.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream.cc @@ -46,7 +46,7 @@ QuicByteCount GetInitialStreamFlowControlWindowToSend(QuicSession* session, // Unidirectional streams (v99 only). if (VersionHasIetfQuicFrames(version.transport_version) && - !QuicUtils::IsBidirectionalStreamId(stream_id)) { + !QuicUtils::IsBidirectionalStreamId(stream_id, version)) { return session->config() ->GetInitialMaxStreamDataBytesUnidirectionalToSend(); } @@ -74,7 +74,7 @@ QuicByteCount GetReceivedFlowControlWindow(QuicSession* session, // Unidirectional streams (v99 only). if (VersionHasIetfQuicFrames(version.transport_version) && - !QuicUtils::IsBidirectionalStreamId(stream_id)) { + !QuicUtils::IsBidirectionalStreamId(stream_id, version)) { if (session->config() ->HasReceivedInitialMaxStreamDataBytesUnidirectional()) { return session->config() @@ -359,7 +359,8 @@ QuicStream::QuicStream(QuicStreamId id, type != CRYPTO ? QuicUtils::GetStreamType(id_, session->perspective(), - session->IsIncomingStream(id_)) + session->IsIncomingStream(id_), + session->version()) : type), perspective_(session->perspective()) { if (type_ == WRITE_UNIDIRECTIONAL) { @@ -432,15 +433,13 @@ void QuicStream::OnStreamFrame(const QuicStreamFrame& frame) { return; } - if (frame.fin) { - if (!session_->deprecate_draining_streams() || !fin_received_) { - fin_received_ = true; - if (fin_sent_) { - DCHECK(!was_draining_ || !session_->deprecate_draining_streams()); - session_->StreamDraining(id_, - /*unidirectional=*/type_ != BIDIRECTIONAL); - was_draining_ = true; - } + if (frame.fin && !fin_received_) { + fin_received_ = true; + if (fin_sent_) { + DCHECK(!was_draining_); + session_->StreamDraining(id_, + /*unidirectional=*/type_ != BIDIRECTIONAL); + was_draining_ = true; } } @@ -582,14 +581,12 @@ void QuicStream::Reset(QuicRstStreamErrorCode error) { stream_error_ = error; session()->SendRstStream(id(), error, stream_bytes_written()); rst_sent_ = true; - if (session_->break_close_loop()) { - if (read_side_closed_ && write_side_closed_ && !IsWaitingForAcks()) { - session()->OnStreamDoneWaitingForAcks(id_); - return; - } - CloseReadSide(); - CloseWriteSide(); + if (read_side_closed_ && write_side_closed_ && !IsWaitingForAcks()) { + session()->OnStreamDoneWaitingForAcks(id_); + return; } + CloseReadSide(); + CloseWriteSide(); } void QuicStream::OnUnrecoverableError(QuicErrorCode error, @@ -781,12 +778,8 @@ void QuicStream::CloseReadSide() { if (write_side_closed_) { QUIC_DVLOG(1) << ENDPOINT << "Closing stream " << id(); - if (session_->break_close_loop()) { - session_->OnStreamClosed(id()); - OnClose(); - } else { - session_->CloseStream(id()); - } + session_->OnStreamClosed(id()); + OnClose(); } } @@ -799,12 +792,8 @@ void QuicStream::CloseWriteSide() { write_side_closed_ = true; if (read_side_closed_) { QUIC_DVLOG(1) << ENDPOINT << "Closing stream " << id(); - if (session_->break_close_loop()) { - session_->OnStreamClosed(id()); - OnClose(); - } else { - session_->CloseStream(id()); - } + session_->OnStreamClosed(id()); + OnClose(); } } @@ -827,12 +816,7 @@ void QuicStream::StopReading() { } void QuicStream::OnClose() { - if (session()->break_close_loop()) { - DCHECK(read_side_closed_ && write_side_closed_); - } else { - CloseReadSide(); - CloseWriteSide(); - } + DCHECK(read_side_closed_ && write_side_closed_); if (!fin_sent_ && !rst_sent_) { // For flow control accounting, tell the peer how many bytes have been @@ -946,16 +930,11 @@ bool QuicStream::ConfigSendWindowOffset(QuicStreamOffset new_offset) { << "ConfigSendWindowOffset called on stream without flow control"; return false; } - if (perspective_ == Perspective::IS_CLIENT && - session()->version().AllowsLowFlowControlLimits() && - new_offset < flow_controller_->send_window_offset()) { - OnUnrecoverableError( - QUIC_FLOW_CONTROL_INVALID_WINDOW, - quiche::QuicheStrCat("New stream max data ", new_offset, - " decreases current limit: ", - flow_controller_->send_window_offset())); - return false; - } + + QUIC_BUG_IF(session()->version().AllowsLowFlowControlLimits() && + new_offset < flow_controller_->send_window_offset()) + << ENDPOINT << "The new offset " << new_offset + << " decreases current offset " << flow_controller_->send_window_offset(); if (flow_controller_->UpdateSendWindowOffset(new_offset)) { // Let session unblock this stream. session_->MarkConnectionLevelWriteBlocked(id_); @@ -1048,7 +1027,7 @@ bool QuicStream::RetransmitStreamData(QuicStreamOffset offset, stream_bytes_written()); consumed = stream_delegate_->WritevData( id_, retransmission_length, retransmission_offset, - can_bundle_fin ? FIN : NO_FIN, type, QuicheNullOpt); + can_bundle_fin ? FIN : NO_FIN, type, QUICHE_NULLOPT); QUIC_DVLOG(1) << ENDPOINT << "stream " << id_ << " is forced to retransmit stream data [" << retransmission_offset << ", " @@ -1070,7 +1049,7 @@ bool QuicStream::RetransmitStreamData(QuicStreamOffset offset, QUIC_DVLOG(1) << ENDPOINT << "stream " << id_ << " retransmits fin only frame."; consumed = stream_delegate_->WritevData(id_, 0, stream_bytes_written(), FIN, - type, QuicheNullOpt); + type, QUICHE_NULLOPT); if (!consumed.fin_consumed) { return false; } @@ -1148,7 +1127,7 @@ void QuicStream::WriteBufferedData() { } QuicConsumedData consumed_data = stream_delegate_->WritevData(id(), write_length, stream_bytes_written(), - state, NOT_RETRANSMISSION, QuicheNullOpt); + state, NOT_RETRANSMISSION, QUICHE_NULLOPT); OnStreamDataConsumed(consumed_data.bytes_consumed); @@ -1228,7 +1207,7 @@ void QuicStream::WritePendingRetransmission() { << " retransmits fin only frame."; consumed = stream_delegate_->WritevData(id_, 0, stream_bytes_written(), FIN, - LOSS_RETRANSMISSION, QuicheNullOpt); + LOSS_RETRANSMISSION, QUICHE_NULLOPT); fin_lost_ = !consumed.fin_consumed; if (fin_lost_) { // Connection is write blocked. @@ -1243,7 +1222,7 @@ void QuicStream::WritePendingRetransmission() { (pending.offset + pending.length == stream_bytes_written()); consumed = stream_delegate_->WritevData( id_, pending.length, pending.offset, can_bundle_fin ? FIN : NO_FIN, - LOSS_RETRANSMISSION, QuicheNullOpt); + LOSS_RETRANSMISSION, QUICHE_NULLOPT); QUIC_DVLOG(1) << ENDPOINT << "stream " << id_ << " tries to retransmit stream data [" << pending.offset << ", " << pending.offset + pending.length @@ -1302,6 +1281,22 @@ void QuicStream::SendStopSending(uint16_t code) { session_->SendStopSending(code, id_); } +QuicFlowController* QuicStream::flow_controller() { + if (flow_controller_.has_value()) { + return &flow_controller_.value(); + } + QUIC_BUG << "Trying to access non-existent flow controller."; + return nullptr; +} + +const QuicFlowController* QuicStream::flow_controller() const { + if (flow_controller_.has_value()) { + return &flow_controller_.value(); + } + QUIC_BUG << "Trying to access non-existent flow controller."; + return nullptr; +} + // static spdy::SpdyStreamPrecedence QuicStream::CalculateDefaultPriority( const QuicSession* session) { diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream.h b/chromium/net/third_party/quiche/src/quic/core/quic_stream.h index fe9d04c021f..7a847f09ec1 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_stream.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream.h @@ -165,14 +165,6 @@ class QUIC_EXPORT_PRIVATE QuicStream // stream to write any pending data. virtual void OnCanWrite(); - // Called just before the object is destroyed. - // The object should not be accessed after OnClose is called. - // Sends a RST_STREAM with code QUIC_RST_ACKNOWLEDGEMENT if neither a FIN nor - // a RST_STREAM has been sent. - // TODO(fayang): move this to protected when deprecating - // quic_break_session_stream_close_loop. - virtual void OnClose(); - // Called by the session when the endpoint receives a RST_STREAM from the // peer. virtual void OnStreamReset(const QuicRstStreamFrame& frame); @@ -237,7 +229,9 @@ class QUIC_EXPORT_PRIVATE QuicStream int num_frames_received() const; int num_duplicate_frames_received() const; - QuicFlowController* flow_controller() { return &*flow_controller_; } + QuicFlowController* flow_controller(); + + const QuicFlowController* flow_controller() const; // Called when endpoint receives a frame which could increase the highest // offset. @@ -381,6 +375,12 @@ class QUIC_EXPORT_PRIVATE QuicStream const QuicReferenceCountedPointer<QuicAckListenerInterface>& /*ack_listener*/) {} + // Called just before the object is destroyed. + // The object should not be accessed after OnClose is called. + // Sends a RST_STREAM with code QUIC_RST_ACKNOWLEDGEMENT if neither a FIN nor + // a RST_STREAM has been sent. + virtual void OnClose(); + // True if buffered data in send buffer is below buffered_data_threshold_. bool CanWriteNewData() const; @@ -539,8 +539,7 @@ class QUIC_EXPORT_PRIVATE QuicStream // If initialized, reset this stream at this deadline. QuicTime deadline_; - // True if this stream has entered draining state. Only used when - // quic_deprecate_draining_streams is true. + // True if this stream has entered draining state. bool was_draining_; // Indicates whether this stream is bidirectional, read unidirectional or diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager.cc b/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager.cc index ba31decd2b9..528d9557ec4 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager.cc @@ -55,6 +55,14 @@ bool QuicStreamIdManager::OnStreamsBlockedFrame( " exceeds incoming max stream ", incoming_advertised_max_streams_); return false; } + if (GetQuicReloadableFlag(quic_stop_sending_duplicate_max_streams)) { + QUIC_RELOADABLE_FLAG_COUNT(quic_stop_sending_duplicate_max_streams); + DCHECK_LE(incoming_advertised_max_streams_, incoming_actual_max_streams_); + if (incoming_advertised_max_streams_ == incoming_actual_max_streams_) { + // We have told peer about current max. + return true; + } + } if (frame.stream_count < incoming_actual_max_streams_) { // Peer thinks it's blocked on a stream count that is less than our current // max. Inform the peer of the correct stream count. @@ -104,12 +112,17 @@ void QuicStreamIdManager::MaybeSendMaxStreamsFrame() { } void QuicStreamIdManager::SendMaxStreamsFrame() { + if (GetQuicReloadableFlag(quic_stop_sending_duplicate_max_streams)) { + QUIC_BUG_IF(incoming_advertised_max_streams_ >= + incoming_actual_max_streams_); + } incoming_advertised_max_streams_ = incoming_actual_max_streams_; delegate_->SendMaxStreams(incoming_advertised_max_streams_, unidirectional_); } void QuicStreamIdManager::OnStreamClosed(QuicStreamId stream_id) { - DCHECK_NE(QuicUtils::IsBidirectionalStreamId(stream_id), unidirectional_); + DCHECK_NE(QuicUtils::IsBidirectionalStreamId(stream_id, version_), + unidirectional_); if (QuicUtils::IsOutgoingStreamId(version_, stream_id, perspective_)) { // Nothing to do for outgoing streams. return; @@ -147,7 +160,8 @@ bool QuicStreamIdManager::MaybeIncreaseLargestPeerStreamId( const QuicStreamId stream_id, std::string* error_details) { // |stream_id| must be an incoming stream of the right directionality. - DCHECK_NE(QuicUtils::IsBidirectionalStreamId(stream_id), unidirectional_); + DCHECK_NE(QuicUtils::IsBidirectionalStreamId(stream_id, version_), + unidirectional_); DCHECK_NE(QuicUtils::IsServerInitiatedStreamId(version_.transport_version, stream_id), perspective_ == Perspective::IS_SERVER); @@ -193,7 +207,7 @@ bool QuicStreamIdManager::MaybeIncreaseLargestPeerStreamId( } bool QuicStreamIdManager::IsAvailableStream(QuicStreamId id) const { - DCHECK_NE(QuicUtils::IsBidirectionalStreamId(id), unidirectional_); + DCHECK_NE(QuicUtils::IsBidirectionalStreamId(id, version_), unidirectional_); if (QuicUtils::IsOutgoingStreamId(version_, id, perspective_)) { // Stream IDs under next_ougoing_stream_id_ are either open or previously // open but now closed. diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager_test.cc index 2179ba2c860..689d4112d85 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream_id_manager_test.cc @@ -139,13 +139,18 @@ TEST_P(QuicStreamIdManagerTest, CheckMaxStreamsBadValuesOverMaxFailsOutgoing) { } // Check the case of the stream count in a STREAMS_BLOCKED frame is less than -// the count most recently advertised in a MAX_STREAMS frame. This should cause -// a MAX_STREAMS frame with the most recently advertised count to be sent. +// the count most recently advertised in a MAX_STREAMS frame. TEST_P(QuicStreamIdManagerTest, ProcessStreamsBlockedOk) { QuicStreamCount stream_count = stream_id_manager_.incoming_initial_max_open_streams(); QuicStreamsBlockedFrame frame(0, stream_count - 1, IsUnidirectional()); - EXPECT_CALL(delegate_, SendMaxStreams(stream_count, IsUnidirectional())); + if (GetQuicReloadableFlag(quic_stop_sending_duplicate_max_streams)) { + // We have notified peer about current max. + EXPECT_CALL(delegate_, SendMaxStreams(stream_count, IsUnidirectional())) + .Times(0); + } else { + EXPECT_CALL(delegate_, SendMaxStreams(stream_count, IsUnidirectional())); + } std::string error_details; EXPECT_TRUE(stream_id_manager_.OnStreamsBlockedFrame(frame, &error_details)); } @@ -398,7 +403,12 @@ TEST_P(QuicStreamIdManagerTest, StreamsBlockedEdgeConditions) { // Check that receipt of a STREAMS BLOCKED with stream-count = 0 invokes a // MAX STREAMS, count = 123, when the MaxOpen... is set to 123. EXPECT_CALL(delegate_, SendMaxStreams(123u, IsUnidirectional())); - stream_id_manager_.SetMaxOpenIncomingStreams(123); + if (GetQuicReloadableFlag(quic_stop_sending_duplicate_max_streams)) { + QuicStreamIdManagerPeer::set_incoming_actual_max_streams( + &stream_id_manager_, 123); + } else { + stream_id_manager_.SetMaxOpenIncomingStreams(123); + } frame.stream_count = 0; EXPECT_TRUE(stream_id_manager_.OnStreamsBlockedFrame(frame, &error_details)); } diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_stream_test.cc index f30a3be7216..356a77d2f59 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_stream_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream_test.cc @@ -305,7 +305,7 @@ TEST_P(QuicStreamTest, BlockIfOnlySomeDataConsumed) { EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _)) .WillOnce(InvokeWithoutArgs([this]() { return session_->ConsumeData(stream_->id(), 1u, 0u, NO_FIN, - NOT_RETRANSMISSION, QuicheNullOpt); + NOT_RETRANSMISSION, QUICHE_NULLOPT); })); stream_->WriteOrBufferData(quiche::QuicheStringPiece(kData1, 2), false, nullptr); @@ -324,7 +324,7 @@ TEST_P(QuicStreamTest, BlockIfFinNotConsumedWithData) { EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _)) .WillOnce(InvokeWithoutArgs([this]() { return session_->ConsumeData(stream_->id(), 2u, 0u, NO_FIN, - NOT_RETRANSMISSION, QuicheNullOpt); + NOT_RETRANSMISSION, QUICHE_NULLOPT); })); stream_->WriteOrBufferData(quiche::QuicheStringPiece(kData1, 2), true, nullptr); @@ -372,7 +372,7 @@ TEST_P(QuicStreamTest, WriteOrBufferData) { EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)) .WillOnce(InvokeWithoutArgs([this]() { return session_->ConsumeData(stream_->id(), kDataLen - 1, 0u, NO_FIN, - NOT_RETRANSMISSION, QuicheNullOpt); + NOT_RETRANSMISSION, QUICHE_NULLOPT); })); stream_->WriteOrBufferData(kData1, false, nullptr); @@ -388,7 +388,8 @@ TEST_P(QuicStreamTest, WriteOrBufferData) { EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)) .WillOnce(InvokeWithoutArgs([this]() { return session_->ConsumeData(stream_->id(), kDataLen - 1, kDataLen - 1, - NO_FIN, NOT_RETRANSMISSION, QuicheNullOpt); + NO_FIN, NOT_RETRANSMISSION, + QUICHE_NULLOPT); })); EXPECT_CALL(*stream_, OnCanWriteNewData()); stream_->OnCanWrite(); @@ -398,7 +399,8 @@ TEST_P(QuicStreamTest, WriteOrBufferData) { EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)) .WillOnce(InvokeWithoutArgs([this]() { return session_->ConsumeData(stream_->id(), 2u, 2 * kDataLen - 2, - NO_FIN, NOT_RETRANSMISSION, QuicheNullOpt); + NO_FIN, NOT_RETRANSMISSION, + QUICHE_NULLOPT); })); EXPECT_CALL(*stream_, OnCanWriteNewData()); stream_->OnCanWrite(); @@ -445,7 +447,7 @@ TEST_P(QuicStreamTest, RstAlwaysSentIfNoFinSent) { EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _)) .WillOnce(InvokeWithoutArgs([this]() { return session_->ConsumeData(stream_->id(), 1u, 0u, NO_FIN, - NOT_RETRANSMISSION, QuicheNullOpt); + NOT_RETRANSMISSION, QUICHE_NULLOPT); })); stream_->WriteOrBufferData(quiche::QuicheStringPiece(kData1, 1), false, nullptr); @@ -455,12 +457,8 @@ TEST_P(QuicStreamTest, RstAlwaysSentIfNoFinSent) { // Now close the stream, and expect that we send a RST. EXPECT_CALL(*session_, SendRstStream(_, _, _)); - if (session_->break_close_loop()) { - stream_->CloseReadSide(); - stream_->CloseWriteSide(); - } else { - stream_->OnClose(); - } + stream_->CloseReadSide(); + stream_->CloseWriteSide(); EXPECT_FALSE(session_->HasUnackedStreamData()); EXPECT_FALSE(fin_sent()); EXPECT_TRUE(rst_sent()); @@ -479,7 +477,7 @@ TEST_P(QuicStreamTest, RstNotSentIfFinSent) { EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _)) .WillOnce(InvokeWithoutArgs([this]() { return session_->ConsumeData(stream_->id(), 1u, 0u, FIN, - NOT_RETRANSMISSION, QuicheNullOpt); + NOT_RETRANSMISSION, QUICHE_NULLOPT); })); stream_->WriteOrBufferData(quiche::QuicheStringPiece(kData1, 1), true, nullptr); @@ -487,12 +485,8 @@ TEST_P(QuicStreamTest, RstNotSentIfFinSent) { EXPECT_FALSE(rst_sent()); // Now close the stream, and expect that we do not send a RST. - if (session_->break_close_loop()) { - stream_->CloseReadSide(); - stream_->CloseWriteSide(); - } else { - stream_->OnClose(); - } + stream_->CloseReadSide(); + stream_->CloseWriteSide(); EXPECT_TRUE(fin_sent()); EXPECT_FALSE(rst_sent()); } @@ -516,12 +510,8 @@ TEST_P(QuicStreamTest, OnlySendOneRst) { // Now close the stream (any further resets being sent would break the // expectation above). - if (session_->break_close_loop()) { - stream_->CloseReadSide(); - stream_->CloseWriteSide(); - } else { - stream_->OnClose(); - } + stream_->CloseReadSide(); + stream_->CloseWriteSide(); EXPECT_FALSE(fin_sent()); EXPECT_TRUE(rst_sent()); } @@ -657,12 +647,8 @@ TEST_P(QuicStreamTest, InvalidFinalByteOffsetFromRst) { CloseConnection(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA, _, _)); stream_->OnStreamReset(rst_frame); EXPECT_TRUE(stream_->HasReceivedFinalOffset()); - if (session_->break_close_loop()) { - stream_->CloseReadSide(); - stream_->CloseWriteSide(); - } else { - stream_->OnClose(); - } + stream_->CloseReadSide(); + stream_->CloseWriteSide(); } TEST_P(QuicStreamTest, FinalByteOffsetFromZeroLengthStreamFrame) { @@ -760,13 +746,13 @@ TEST_P(QuicStreamTest, SetDrainingIncomingOutgoing) { EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _)) .WillOnce(InvokeWithoutArgs([this]() { return session_->ConsumeData(stream_->id(), 2u, 0u, FIN, - NOT_RETRANSMISSION, QuicheNullOpt); + NOT_RETRANSMISSION, QUICHE_NULLOPT); })); stream_->WriteOrBufferData(quiche::QuicheStringPiece(kData1, 2), true, nullptr); EXPECT_TRUE(stream_->write_side_closed()); - EXPECT_EQ(1u, session_->GetNumDrainingStreams()); + EXPECT_EQ(1u, QuicSessionPeer::GetNumDrainingStreams(session_.get())); EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get())); } @@ -778,7 +764,7 @@ TEST_P(QuicStreamTest, SetDrainingOutgoingIncoming) { EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _)) .WillOnce(InvokeWithoutArgs([this]() { return session_->ConsumeData(stream_->id(), 2u, 0u, FIN, - NOT_RETRANSMISSION, QuicheNullOpt); + NOT_RETRANSMISSION, QUICHE_NULLOPT); })); stream_->WriteOrBufferData(quiche::QuicheStringPiece(kData1, 2), true, nullptr); @@ -794,7 +780,7 @@ TEST_P(QuicStreamTest, SetDrainingOutgoingIncoming) { EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream_)); EXPECT_FALSE(stream_->reading_stopped()); - EXPECT_EQ(1u, session_->GetNumDrainingStreams()); + EXPECT_EQ(1u, QuicSessionPeer::GetNumDrainingStreams(session_.get())); EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get())); } @@ -1054,7 +1040,7 @@ TEST_P(QuicStreamTest, WriteBufferedData) { EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)) .WillOnce(InvokeWithoutArgs([this]() { return session_->ConsumeData(stream_->id(), 100u, 0u, NO_FIN, - NOT_RETRANSMISSION, QuicheNullOpt); + NOT_RETRANSMISSION, QUICHE_NULLOPT); })); stream_->WriteOrBufferData(data, false, nullptr); stream_->WriteOrBufferData(data, false, nullptr); @@ -1067,7 +1053,7 @@ TEST_P(QuicStreamTest, WriteBufferedData) { EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)) .WillOnce(InvokeWithoutArgs([this]() { return session_->ConsumeData(stream_->id(), 100, 100u, NO_FIN, - NOT_RETRANSMISSION, QuicheNullOpt); + NOT_RETRANSMISSION, QUICHE_NULLOPT); })); // Buffered data size > threshold, do not ask upper layer for more data. EXPECT_CALL(*stream_, OnCanWriteNewData()).Times(0); @@ -1082,7 +1068,7 @@ TEST_P(QuicStreamTest, WriteBufferedData) { EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)) .WillOnce(InvokeWithoutArgs([this, data_to_write]() { return session_->ConsumeData(stream_->id(), data_to_write, 200u, NO_FIN, - NOT_RETRANSMISSION, QuicheNullOpt); + NOT_RETRANSMISSION, QUICHE_NULLOPT); })); // Buffered data size < threshold, ask upper layer for more data. EXPECT_CALL(*stream_, OnCanWriteNewData()).Times(1); @@ -1132,7 +1118,7 @@ TEST_P(QuicStreamTest, WriteBufferedData) { EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)) .WillOnce(InvokeWithoutArgs([this, data_to_write]() { return session_->ConsumeData(stream_->id(), data_to_write, 0u, NO_FIN, - NOT_RETRANSMISSION, QuicheNullOpt); + NOT_RETRANSMISSION, QUICHE_NULLOPT); })); EXPECT_CALL(*stream_, OnCanWriteNewData()).Times(1); @@ -1194,7 +1180,7 @@ TEST_P(QuicStreamTest, WriteMemSlices) { EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)) .WillOnce(InvokeWithoutArgs([this]() { return session_->ConsumeData(stream_->id(), 100u, 0u, NO_FIN, - NOT_RETRANSMISSION, QuicheNullOpt); + NOT_RETRANSMISSION, QUICHE_NULLOPT); })); // There is no buffered data before, all data should be consumed. QuicConsumedData consumed = stream_->WriteMemSlices(span1, false); @@ -1217,7 +1203,7 @@ TEST_P(QuicStreamTest, WriteMemSlices) { EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)) .WillOnce(InvokeWithoutArgs([this, data_to_write]() { return session_->ConsumeData(stream_->id(), data_to_write, 100u, NO_FIN, - NOT_RETRANSMISSION, QuicheNullOpt); + NOT_RETRANSMISSION, QUICHE_NULLOPT); })); EXPECT_CALL(*stream_, OnCanWriteNewData()).Times(1); stream_->OnCanWrite(); @@ -1254,7 +1240,7 @@ TEST_P(QuicStreamTest, WriteMemSlicesReachStreamLimit) { EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)) .WillOnce(InvokeWithoutArgs([this]() { return session_->ConsumeData(stream_->id(), 5u, 0u, NO_FIN, - NOT_RETRANSMISSION, QuicheNullOpt); + NOT_RETRANSMISSION, QUICHE_NULLOPT); })); // There is no buffered data before, all data should be consumed. QuicConsumedData consumed = stream_->WriteMemSlices(span1, false); @@ -1392,7 +1378,7 @@ TEST_P(QuicStreamTest, OnStreamFrameLost) { EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)) .WillOnce(InvokeWithoutArgs([this]() { return session_->ConsumeData(stream_->id(), 9u, 18u, FIN, - NOT_RETRANSMISSION, QuicheNullOpt); + NOT_RETRANSMISSION, QUICHE_NULLOPT); })); stream_->OnCanWrite(); EXPECT_FALSE(stream_->HasPendingRetransmission()); @@ -1422,7 +1408,7 @@ TEST_P(QuicStreamTest, CannotBundleLostFin) { EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)) .WillOnce(InvokeWithoutArgs([this]() { return session_->ConsumeData(stream_->id(), 9u, 0u, NO_FIN, - NOT_RETRANSMISSION, QuicheNullOpt); + NOT_RETRANSMISSION, QUICHE_NULLOPT); })); EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)) .WillOnce(Return(QuicConsumedData(0, true))); @@ -1511,7 +1497,7 @@ TEST_P(QuicStreamTest, RetransmitStreamData) { EXPECT_CALL(*session_, WritevData(stream_->id(), 10, 0, NO_FIN, _, _)) .WillOnce(InvokeWithoutArgs([this]() { return session_->ConsumeData(stream_->id(), 8, 0u, NO_FIN, - NOT_RETRANSMISSION, QuicheNullOpt); + NOT_RETRANSMISSION, QUICHE_NULLOPT); })); EXPECT_FALSE(stream_->RetransmitStreamData(0, 18, true, PTO_RETRANSMISSION)); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_syscall_wrapper.cc b/chromium/net/third_party/quiche/src/quic/core/quic_syscall_wrapper.cc new file mode 100644 index 00000000000..b2404c6ee97 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/quic_syscall_wrapper.cc @@ -0,0 +1,49 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/third_party/quiche/src/quic/core/quic_syscall_wrapper.h" + +#include <atomic> +#include <cerrno> + +namespace quic { +namespace { +std::atomic<QuicSyscallWrapper*> global_syscall_wrapper(new QuicSyscallWrapper); +} // namespace + +ssize_t QuicSyscallWrapper::Sendmsg(int sockfd, const msghdr* msg, int flags) { + return ::sendmsg(sockfd, msg, flags); +} + +int QuicSyscallWrapper::Sendmmsg(int sockfd, + mmsghdr* msgvec, + unsigned int vlen, + int flags) { +#if defined(__linux__) && !defined(__ANDROID__) + return ::sendmmsg(sockfd, msgvec, vlen, flags); +#else + errno = ENOSYS; + return -1; +#endif +} + +QuicSyscallWrapper* GetGlobalSyscallWrapper() { + return global_syscall_wrapper.load(); +} + +void SetGlobalSyscallWrapper(QuicSyscallWrapper* wrapper) { + global_syscall_wrapper.store(wrapper); +} + +ScopedGlobalSyscallWrapperOverride::ScopedGlobalSyscallWrapperOverride( + QuicSyscallWrapper* wrapper_in_scope) + : original_wrapper_(GetGlobalSyscallWrapper()) { + SetGlobalSyscallWrapper(wrapper_in_scope); +} + +ScopedGlobalSyscallWrapperOverride::~ScopedGlobalSyscallWrapperOverride() { + SetGlobalSyscallWrapper(original_wrapper_); +} + +} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_syscall_wrapper.h b/chromium/net/third_party/quiche/src/quic/core/quic_syscall_wrapper.h new file mode 100644 index 00000000000..3a80ac6f6cf --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/quic_syscall_wrapper.h @@ -0,0 +1,49 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_PLATFORM_IMPL_QUIC_SYSCALL_WRAPPER_H_ +#define QUICHE_QUIC_PLATFORM_IMPL_QUIC_SYSCALL_WRAPPER_H_ + +#include <sys/socket.h> +#include <sys/types.h> + +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" + +struct mmsghdr; +namespace quic { + +// QuicSyscallWrapper is a pass-through proxy to the real syscalls. +class QUIC_EXPORT_PRIVATE QuicSyscallWrapper { + public: + virtual ~QuicSyscallWrapper() = default; + + virtual ssize_t Sendmsg(int sockfd, const msghdr* msg, int flags); + + virtual int Sendmmsg(int sockfd, + mmsghdr* msgvec, + unsigned int vlen, + int flags); +}; + +// A global instance of QuicSyscallWrapper, used by some socket util functions. +QuicSyscallWrapper* GetGlobalSyscallWrapper(); + +// Change the global QuicSyscallWrapper to |wrapper|, for testing. +void SetGlobalSyscallWrapper(QuicSyscallWrapper* wrapper); + +// ScopedGlobalSyscallWrapperOverride changes the global QuicSyscallWrapper +// during its lifetime, for testing. +class QUIC_EXPORT_PRIVATE ScopedGlobalSyscallWrapperOverride { + public: + explicit ScopedGlobalSyscallWrapperOverride( + QuicSyscallWrapper* wrapper_in_scope); + ~ScopedGlobalSyscallWrapperOverride(); + + private: + QuicSyscallWrapper* original_wrapper_; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_PLATFORM_IMPL_QUIC_SYSCALL_WRAPPER_H_ diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_tag.cc b/chromium/net/third_party/quiche/src/quic/core/quic_tag.cc index 270383d27ae..d6c2f6c25de 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_tag.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_tag.cc @@ -74,4 +74,35 @@ bool ContainsQuicTag(const QuicTagVector& tag_vector, QuicTag tag) { tag_vector.end(); } +QuicTag ParseQuicTag(quiche::QuicheStringPiece tag_string) { + quiche::QuicheTextUtils::RemoveLeadingAndTrailingWhitespace(&tag_string); + std::string tag_bytes; + if (tag_string.length() == 8) { + tag_bytes = quiche::QuicheTextUtils::HexDecode(tag_string); + tag_string = tag_bytes; + } + QuicTag tag = 0; + // Iterate over every character from right to left. + for (auto it = tag_string.rbegin(); it != tag_string.rend(); ++it) { + // The cast here is required on platforms where char is signed. + unsigned char token_char = static_cast<unsigned char>(*it); + tag <<= 8; + tag |= token_char; + } + return tag; +} + +QuicTagVector ParseQuicTagVector(quiche::QuicheStringPiece tags_string) { + QuicTagVector tag_vector; + quiche::QuicheTextUtils::RemoveLeadingAndTrailingWhitespace(&tags_string); + if (!tags_string.empty()) { + std::vector<quiche::QuicheStringPiece> tag_strings = + quiche::QuicheTextUtils::Split(tags_string, ','); + for (quiche::QuicheStringPiece tag_string : tag_strings) { + tag_vector.push_back(ParseQuicTag(tag_string)); + } + } + return tag_vector; +} + } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_tag.h b/chromium/net/third_party/quiche/src/quic/core/quic_tag.h index 71fcdd597f4..7ba6cfc5f39 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_tag.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_tag.h @@ -10,6 +10,7 @@ #include <vector> #include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" namespace quic { @@ -48,6 +49,17 @@ QUIC_EXPORT_PRIVATE bool FindMutualQuicTag(const QuicTagVector& our_tags, // treat it as a number if not. QUIC_EXPORT_PRIVATE std::string QuicTagToString(QuicTag tag); +// Utility function that converts a string of the form "ABCD" to its +// corresponding QuicTag. Note that tags that are less than four characters +// long are right-padded with zeroes. Tags that contain non-ASCII characters +// are represented as 8-character-long hexadecimal strings. +QUIC_EXPORT_PRIVATE QuicTag ParseQuicTag(quiche::QuicheStringPiece tag_string); + +// Utility function that converts a string of the form "ABCD,EFGH" to a vector +// of the form {kABCD,kEFGH}. Note the caveats on ParseQuicTag. +QUIC_EXPORT_PRIVATE QuicTagVector +ParseQuicTagVector(quiche::QuicheStringPiece tags_string); + } // namespace quic #endif // QUICHE_QUIC_CORE_QUIC_TAG_H_ diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_tag_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_tag_test.cc index 3d58133eeb7..13c899edd41 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_tag_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_tag_test.cc @@ -33,6 +33,48 @@ TEST_F(QuicTagTest, MakeQuicTag) { EXPECT_EQ('D', bytes[3]); } +TEST_F(QuicTagTest, ParseQuicTag) { + QuicTag tag_abcd = MakeQuicTag('A', 'B', 'C', 'D'); + EXPECT_EQ(ParseQuicTag("ABCD"), tag_abcd); + EXPECT_EQ(ParseQuicTag("ABCDE"), tag_abcd); + QuicTag tag_efgh = MakeQuicTag('E', 'F', 'G', 'H'); + EXPECT_EQ(ParseQuicTag("EFGH"), tag_efgh); + QuicTag tag_ijk = MakeQuicTag('I', 'J', 'K', 0); + EXPECT_EQ(ParseQuicTag("IJK"), tag_ijk); + QuicTag tag_l = MakeQuicTag('L', 0, 0, 0); + EXPECT_EQ(ParseQuicTag("L"), tag_l); + QuicTag tag_hex = MakeQuicTag('M', 'N', 'O', static_cast<char>(255)); + EXPECT_EQ(ParseQuicTag("4d4e4fff"), tag_hex); + EXPECT_EQ(ParseQuicTag("4D4E4FFF"), tag_hex); + QuicTag tag_with_numbers = MakeQuicTag('P', 'Q', '1', '2'); + EXPECT_EQ(ParseQuicTag("PQ12"), tag_with_numbers); + QuicTag tag_with_custom_chars = MakeQuicTag('r', '$', '_', '7'); + EXPECT_EQ(ParseQuicTag("r$_7"), tag_with_custom_chars); + QuicTag tag_zero = 0; + EXPECT_EQ(ParseQuicTag(""), tag_zero); + QuicTagVector tag_vector; + EXPECT_EQ(ParseQuicTagVector(""), tag_vector); + EXPECT_EQ(ParseQuicTagVector(" "), tag_vector); + tag_vector.push_back(tag_abcd); + EXPECT_EQ(ParseQuicTagVector("ABCD"), tag_vector); + tag_vector.push_back(tag_efgh); + EXPECT_EQ(ParseQuicTagVector("ABCD,EFGH"), tag_vector); + tag_vector.push_back(tag_ijk); + EXPECT_EQ(ParseQuicTagVector("ABCD,EFGH,IJK"), tag_vector); + tag_vector.push_back(tag_l); + EXPECT_EQ(ParseQuicTagVector("ABCD,EFGH,IJK,L"), tag_vector); + tag_vector.push_back(tag_hex); + EXPECT_EQ(ParseQuicTagVector("ABCD,EFGH,IJK,L,4d4e4fff"), tag_vector); + tag_vector.push_back(tag_with_numbers); + EXPECT_EQ(ParseQuicTagVector("ABCD,EFGH,IJK,L,4d4e4fff,PQ12"), tag_vector); + tag_vector.push_back(tag_with_custom_chars); + EXPECT_EQ(ParseQuicTagVector("ABCD,EFGH,IJK,L,4d4e4fff,PQ12,r$_7"), + tag_vector); + tag_vector.push_back(tag_zero); + EXPECT_EQ(ParseQuicTagVector("ABCD,EFGH,IJK,L,4d4e4fff,PQ12,r$_7,"), + tag_vector); +} + } // namespace } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_time.h b/chromium/net/third_party/quiche/src/quic/core/quic_time.h index adecbcd1514..079b59a6bdc 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_time.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_time.h @@ -184,6 +184,14 @@ class QUIC_EXPORT_PRIVATE QuicWallTime { QUIC_TIME_WARN_UNUSED_RESULT QuicWallTime Subtract(QuicTime::Delta delta) const; + bool operator==(const QuicWallTime& other) const { + return microseconds_ == other.microseconds_; + } + + QuicTime::Delta operator-(const QuicWallTime& rhs) const { + return QuicTime::Delta::FromMicroseconds(microseconds_ - rhs.microseconds_); + } + private: explicit constexpr QuicWallTime(uint64_t microseconds) : microseconds_(microseconds) {} diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_trace_visitor.cc b/chromium/net/third_party/quiche/src/quic/core/quic_trace_visitor.cc index edbce0c709c..eeaf297c1ca 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_trace_visitor.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_trace_visitor.cc @@ -64,6 +64,7 @@ void QuicTraceVisitor::OnPacketSent(const SerializedPacket& serialized_packet, case BLOCKED_FRAME: case PING_FRAME: case HANDSHAKE_DONE_FRAME: + case ACK_FREQUENCY_FRAME: PopulateFrameInfo(frame, event->add_frames()); break; @@ -218,6 +219,7 @@ void QuicTraceVisitor::PopulateFrameInfo(const QuicFrame& frame, case MESSAGE_FRAME: case CRYPTO_FRAME: case NEW_TOKEN_FRAME: + case ACK_FREQUENCY_FRAME: break; case NUM_FRAME_TYPES: diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_types.cc b/chromium/net/third_party/quiche/src/quic/core/quic_types.cc index 36614cd8f0a..a52571e3905 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_types.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_types.cc @@ -173,8 +173,7 @@ std::string TransmissionTypeToString(TransmissionType transmission_type) { switch (transmission_type) { RETURN_STRING_LITERAL(NOT_RETRANSMISSION); RETURN_STRING_LITERAL(HANDSHAKE_RETRANSMISSION); - RETURN_STRING_LITERAL(ALL_UNACKED_RETRANSMISSION); - RETURN_STRING_LITERAL(ALL_INITIAL_RETRANSMISSION); + RETURN_STRING_LITERAL(ALL_ZERO_RTT_RETRANSMISSION); RETURN_STRING_LITERAL(LOSS_RETRANSMISSION); RETURN_STRING_LITERAL(RTO_RETRANSMISSION); RETURN_STRING_LITERAL(TLP_RETRANSMISSION); @@ -191,6 +190,11 @@ std::string TransmissionTypeToString(TransmissionType transmission_type) { } } +std::ostream& operator<<(std::ostream& os, TransmissionType transmission_type) { + os << TransmissionTypeToString(transmission_type); + return os; +} + std::string PacketHeaderFormatToString(PacketHeaderFormat format) { switch (format) { RETURN_STRING_LITERAL(IETF_QUIC_LONG_HEADER_PACKET); @@ -261,11 +265,17 @@ std::string SerializedPacketFateToString(SerializedPacketFate fate) { RETURN_STRING_LITERAL(BUFFER); RETURN_STRING_LITERAL(SEND_TO_WRITER); RETURN_STRING_LITERAL(FAILED_TO_WRITE_COALESCED_PACKET); + RETURN_STRING_LITERAL(LEGACY_VERSION_ENCAPSULATE); default: return quiche::QuicheStrCat("Unknown(", static_cast<int>(fate), ")"); } } +std::ostream& operator<<(std::ostream& os, SerializedPacketFate fate) { + os << SerializedPacketFateToString(fate); + return os; +} + std::string EncryptionLevelToString(EncryptionLevel level) { switch (level) { RETURN_STRING_LITERAL(ENCRYPTION_INITIAL); @@ -278,6 +288,11 @@ std::string EncryptionLevelToString(EncryptionLevel level) { } } +std::ostream& operator<<(std::ostream& os, EncryptionLevel level) { + os << EncryptionLevelToString(level); + return os; +} + std::string QuicConnectionCloseTypeString(QuicConnectionCloseType type) { switch (type) { RETURN_STRING_LITERAL(GOOGLE_QUIC_CONNECTION_CLOSE); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_types.h b/chromium/net/third_party/quiche/src/quic/core/quic_types.h index f2919ef3766..0c736f93178 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_types.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_types.h @@ -163,21 +163,24 @@ struct QUIC_EXPORT_PRIVATE WriteResult { enum TransmissionType : int8_t { NOT_RETRANSMISSION, FIRST_TRANSMISSION_TYPE = NOT_RETRANSMISSION, - HANDSHAKE_RETRANSMISSION, // Retransmits due to handshake timeouts. - // TODO(fayang): remove ALL_UNACKED_RETRANSMISSION. - ALL_UNACKED_RETRANSMISSION, // Retransmits all unacked packets. - ALL_INITIAL_RETRANSMISSION, // Retransmits all initially encrypted packets. - LOSS_RETRANSMISSION, // Retransmits due to loss detection. - RTO_RETRANSMISSION, // Retransmits due to retransmit time out. - TLP_RETRANSMISSION, // Tail loss probes. - PTO_RETRANSMISSION, // Retransmission due to probe timeout. - PROBING_RETRANSMISSION, // Retransmission in order to probe bandwidth. + HANDSHAKE_RETRANSMISSION, // Retransmits due to handshake timeouts. + ALL_ZERO_RTT_RETRANSMISSION, // Retransmits all packets encrypted with 0-RTT + // key. + LOSS_RETRANSMISSION, // Retransmits due to loss detection. + RTO_RETRANSMISSION, // Retransmits due to retransmit time out. + TLP_RETRANSMISSION, // Tail loss probes. + PTO_RETRANSMISSION, // Retransmission due to probe timeout. + PROBING_RETRANSMISSION, // Retransmission in order to probe bandwidth. LAST_TRANSMISSION_TYPE = PROBING_RETRANSMISSION, }; QUIC_EXPORT_PRIVATE std::string TransmissionTypeToString( TransmissionType transmission_type); +QUIC_EXPORT_PRIVATE std::ostream& operator<<( + std::ostream& os, + TransmissionType transmission_type); + enum HasRetransmittableData : uint8_t { NO_RETRANSMITTABLE_DATA, HAS_RETRANSMITTABLE_DATA, @@ -224,6 +227,8 @@ enum QuicFrameType : uint8_t { STOP_WAITING_FRAME = 6, PING_FRAME = 7, CRYPTO_FRAME = 8, + // TODO(b/157935330): stop hard coding this when deprecate T050. + HANDSHAKE_DONE_FRAME = 9, // STREAM and ACK frames are special frames. They are encoded differently on // the wire and their values do not need to be stable. @@ -245,7 +250,7 @@ enum QuicFrameType : uint8_t { MESSAGE_FRAME, NEW_TOKEN_FRAME, RETIRE_CONNECTION_ID_FRAME, - HANDSHAKE_DONE_FRAME, + ACK_FREQUENCY_FRAME, NUM_FRAME_TYPES }; @@ -305,6 +310,9 @@ enum QuicIetfFrameType : uint8_t { IETF_EXTENSION_MESSAGE = 0x21, IETF_EXTENSION_MESSAGE_NO_LENGTH_V99 = 0x30, IETF_EXTENSION_MESSAGE_V99 = 0x31, + + // An QUIC extension frame for sender control of acknowledgement delays + IETF_ACK_FREQUENCY = 0xaf }; QUIC_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os, const QuicIetfFrameType& c); @@ -440,6 +448,9 @@ inline bool EncryptionLevelIsValid(EncryptionLevel level) { QUIC_EXPORT_PRIVATE std::string EncryptionLevelToString(EncryptionLevel level); +QUIC_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os, + EncryptionLevel level); + // Enumeration of whether a server endpoint will request a client certificate, // and whether that endpoint requires a valid client certificate to establish a // connection. @@ -687,11 +698,16 @@ enum SerializedPacketFate : uint8_t { SEND_TO_WRITER, // Send packet to writer. FAILED_TO_WRITE_COALESCED_PACKET, // Packet cannot be coalesced, error occurs // when sending existing coalesced packet. + LEGACY_VERSION_ENCAPSULATE, // Perform Legacy Version Encapsulation on this + // packet. }; QUIC_EXPORT_PRIVATE std::string SerializedPacketFateToString( SerializedPacketFate fate); +QUIC_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os, + const SerializedPacketFate fate); + // There are three different forms of CONNECTION_CLOSE. enum QuicConnectionCloseType { GOOGLE_QUIC_CONNECTION_CLOSE = 0, @@ -734,6 +750,45 @@ struct QUIC_NO_EXPORT NextReleaseTimeResult { bool allow_burst; }; +// QuicPacketBuffer bundles a buffer and a function that releases it. Note +// it does not assume ownership of buffer, i.e. it doesn't release the buffer on +// destruction. +struct QUIC_NO_EXPORT QuicPacketBuffer { + QuicPacketBuffer() = default; + + QuicPacketBuffer(char* buffer, + std::function<void(const char*)> release_buffer) + : buffer(buffer), release_buffer(std::move(release_buffer)) {} + + char* buffer = nullptr; + std::function<void(const char*)> release_buffer; +}; + +// QuicOwnedPacketBuffer is a QuicPacketBuffer that assumes buffer ownership. +struct QUIC_NO_EXPORT QuicOwnedPacketBuffer : public QuicPacketBuffer { + QuicOwnedPacketBuffer(const QuicOwnedPacketBuffer&) = delete; + QuicOwnedPacketBuffer& operator=(const QuicOwnedPacketBuffer&) = delete; + + QuicOwnedPacketBuffer(char* buffer, + std::function<void(const char*)> release_buffer) + : QuicPacketBuffer(buffer, std::move(release_buffer)) {} + + QuicOwnedPacketBuffer(QuicOwnedPacketBuffer&& owned_buffer) + : QuicPacketBuffer(std::move(owned_buffer)) { + // |owned_buffer| does not own a buffer any more. + owned_buffer.buffer = nullptr; + } + + explicit QuicOwnedPacketBuffer(QuicPacketBuffer&& packet_buffer) + : QuicPacketBuffer(std::move(packet_buffer)) {} + + ~QuicOwnedPacketBuffer() { + if (release_buffer != nullptr && buffer != nullptr) { + release_buffer(buffer); + } + } +}; + } // namespace quic #endif // QUICHE_QUIC_CORE_QUIC_TYPES_H_ diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_udp_socket.h b/chromium/net/third_party/quiche/src/quic/core/quic_udp_socket.h index 04f84357dab..258de080118 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_udp_socket.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_udp_socket.h @@ -163,10 +163,14 @@ class QUIC_EXPORT_PRIVATE QuicUdpSocketApi { public: // Creates a non-blocking udp socket, sets the receive/send buffer and enable // receiving of self ip addresses on read. - // Return kQuicInvalidSocketFd if failed. + // If address_family == AF_INET6 and ipv6_only is true, receiving of IPv4 self + // addresses is disabled. This is only necessary for IPv6 sockets on iOS - all + // other platforms can ignore this parameter. Return kQuicInvalidSocketFd if + // failed. QuicUdpSocketFd Create(int address_family, int receive_buffer_size, - int send_buffer_size); + int send_buffer_size, + bool ipv6_only = false); // Closes |fd|. No-op if |fd| equals to kQuicInvalidSocketFd. void Destroy(QuicUdpSocketFd fd); @@ -238,7 +242,8 @@ class QUIC_EXPORT_PRIVATE QuicUdpSocketApi { bool SetupSocket(QuicUdpSocketFd fd, int address_family, int receive_buffer_size, - int send_buffer_size); + int send_buffer_size, + bool ipv6_only); bool EnableReceiveSelfIpAddressForV4(QuicUdpSocketFd fd); bool EnableReceiveSelfIpAddressForV6(QuicUdpSocketFd fd); }; diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_udp_socket_posix.cc b/chromium/net/third_party/quiche/src/quic/core/quic_udp_socket_posix.cc index b6c58cdb1d3..c5ab345f433 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_udp_socket_posix.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_udp_socket_posix.cc @@ -239,7 +239,8 @@ bool NextCmsg(msghdr* hdr, QuicUdpSocketFd QuicUdpSocketApi::Create(int address_family, int receive_buffer_size, - int send_buffer_size) { + int send_buffer_size, + bool ipv6_only) { // DCHECK here so the program exits early(before reading packets) in debug // mode. This should have been a static_assert, however it can't be done on // ios/osx because CMSG_SPACE isn't a constant expression there. @@ -250,7 +251,8 @@ QuicUdpSocketFd QuicUdpSocketApi::Create(int address_family, return kQuicInvalidSocketFd; } - if (!SetupSocket(fd, address_family, receive_buffer_size, send_buffer_size)) { + if (!SetupSocket(fd, address_family, receive_buffer_size, send_buffer_size, + ipv6_only)) { Destroy(fd); return kQuicInvalidSocketFd; } @@ -261,7 +263,8 @@ QuicUdpSocketFd QuicUdpSocketApi::Create(int address_family, bool QuicUdpSocketApi::SetupSocket(QuicUdpSocketFd fd, int address_family, int receive_buffer_size, - int send_buffer_size) { + int send_buffer_size, + bool ipv6_only) { // Receive buffer size. if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &receive_buffer_size, sizeof(receive_buffer_size)) != 0) { @@ -276,14 +279,20 @@ bool QuicUdpSocketApi::SetupSocket(QuicUdpSocketFd fd, return false; } - if (!EnableReceiveSelfIpAddressForV4(fd)) { - QUIC_LOG_FIRST_N(ERROR, 100) << "Failed to enable receiving of self v4 ip"; - return false; + if (!(address_family == AF_INET6 && ipv6_only)) { + if (!EnableReceiveSelfIpAddressForV4(fd)) { + QUIC_LOG_FIRST_N(ERROR, 100) + << "Failed to enable receiving of self v4 ip"; + return false; + } } - if (address_family == AF_INET6 && !EnableReceiveSelfIpAddressForV6(fd)) { - QUIC_LOG_FIRST_N(ERROR, 100) << "Failed to enable receiving of self v6 ip"; - return false; + if (address_family == AF_INET6) { + if (!EnableReceiveSelfIpAddressForV6(fd)) { + QUIC_LOG_FIRST_N(ERROR, 100) + << "Failed to enable receiving of self v6 ip"; + return false; + } } return true; diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_udp_socket_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_udp_socket_test.cc index e43fb10c40b..f54b0edd073 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_udp_socket_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_udp_socket_test.cc @@ -3,6 +3,11 @@ // found in the LICENSE file. #include "net/third_party/quiche/src/quic/core/quic_udp_socket.h" +#include <sys/socket.h> + +#ifdef __APPLE__ +#include <TargetConditionals.h> +#endif #include "net/third_party/quiche/src/quic/core/quic_constants.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" @@ -15,33 +20,49 @@ struct ReadBuffers { char control_buffer[512]; char packet_buffer[1536]; }; + +// Allows IPv6-specific testing. +struct TestParameters { + // If true, the test will only use IPv6. If false, IPv4 will be used if + // possible, with IPv6 used as a fallback. + bool force_ipv6; + // The value of ipv6_only to be used in QuicUdpSocketApi::Create calls. + bool ipv6_only; +}; } // namespace -class QuicUdpSocketTest : public QuicTest { +class QuicUdpSocketTest : public QuicTestWithParam<TestParameters> { protected: void SetUp() override { - // Try creating AF_INET socket, if it fails because of unsupported address - // family then tests are being run under IPv6-only environment, initialize - // address family to use for running the test under as AF_INET6 otherwise - // initialize it as AF_INET. - address_family_ = AF_INET; - fd_client_ = - api_.Create(address_family_, - /*receive_buffer_size =*/kDefaultSocketReceiveBuffer, - /*send_buffer_size =*/kDefaultSocketReceiveBuffer); + const TestParameters& parameters = GetParam(); + if (!parameters.force_ipv6) { + // Try creating AF_INET socket, if it fails because of unsupported address + // family then tests are being run under IPv6-only environment, initialize + // address family to use for running the test under as AF_INET6 otherwise + // initialize it as AF_INET. + address_family_ = AF_INET; + fd_client_ = + api_.Create(address_family_, + /*receive_buffer_size =*/kDefaultSocketReceiveBuffer, + /*send_buffer_size =*/kDefaultSocketReceiveBuffer, + /*ipv6_only =*/parameters.ipv6_only); + } if (fd_client_ == kQuicInvalidSocketFd) { + // Either AF_INET is unsupported, or force_ipv6 is true. address_family_ = AF_INET6; fd_client_ = api_.Create(address_family_, /*receive_buffer_size =*/kDefaultSocketReceiveBuffer, - /*send_buffer_size =*/kDefaultSocketReceiveBuffer); + /*send_buffer_size =*/kDefaultSocketReceiveBuffer, + /*ipv6_only =*/parameters.ipv6_only); } ASSERT_NE(fd_client_, kQuicInvalidSocketFd); fd_server_ = api_.Create(address_family_, /*receive_buffer_size =*/kDefaultSocketReceiveBuffer, - /*send_buffer_size =*/kDefaultSocketReceiveBuffer); + /*send_buffer_size =*/kDefaultSocketReceiveBuffer, + /*ipv6_only =*/parameters.ipv6_only); ASSERT_NE(fd_server_, kQuicInvalidSocketFd); ASSERT_TRUE( @@ -114,8 +135,8 @@ class QuicUdpSocketTest : public QuicTest { } QuicUdpSocketApi api_; - QuicUdpSocketFd fd_client_; - QuicUdpSocketFd fd_server_; + QuicUdpSocketFd fd_client_ = kQuicInvalidSocketFd; + QuicUdpSocketFd fd_server_ = kQuicInvalidSocketFd; QuicSocketAddress server_address_; int address_family_; char client_packet_buffer_[kEthernetMTU] = {0}; @@ -123,7 +144,22 @@ class QuicUdpSocketTest : public QuicTest { char server_control_buffer_[512] = {0}; }; -TEST_F(QuicUdpSocketTest, ReadPacketResultReset) { +INSTANTIATE_TEST_SUITE_P( + PlatformIndependent, + QuicUdpSocketTest, + testing::Values(TestParameters{/*force_ipv6 =*/false, /*ipv6_only =*/false}, + TestParameters{/*force_ipv6 =*/false, /*ipv6_only =*/true}, + TestParameters{/*force_ipv6 =*/true, /*ipv6_only =*/true})); + +#ifndef TARGET_OS_IPHONE +// IPv6 on iOS is known to fail without ipv6_only, so should not be tested. +INSTANTIATE_TEST_SUITE_P(NonIos, + QuicUdpSocketTest, + testing::Values(TestParameters{/*force_ipv6 =*/true, + /*ipv6_only =*/false})); +#endif + +TEST_P(QuicUdpSocketTest, ReadPacketResultReset) { QuicUdpSocketApi::ReadPacketResult result; result.packet_info.SetDroppedPackets(100); result.packet_buffer.buffer_len = 100; @@ -137,7 +173,7 @@ TEST_F(QuicUdpSocketTest, ReadPacketResultReset) { EXPECT_EQ(200u, result.packet_buffer.buffer_len); } -TEST_F(QuicUdpSocketTest, ReadPacketOnly) { +TEST_P(QuicUdpSocketTest, ReadPacketOnly) { const size_t kPacketSize = 512; memset(client_packet_buffer_, '-', kPacketSize); ASSERT_EQ(WriteResult(WRITE_STATUS_OK, kPacketSize), @@ -150,7 +186,7 @@ TEST_F(QuicUdpSocketTest, ReadPacketOnly) { ASSERT_EQ(0, ComparePacketBuffers(kPacketSize)); } -TEST_F(QuicUdpSocketTest, ReadTruncated) { +TEST_P(QuicUdpSocketTest, ReadTruncated) { const size_t kPacketSize = kDefaultMaxPacketSize + 1; memset(client_packet_buffer_, '*', kPacketSize); ASSERT_EQ(WriteResult(WRITE_STATUS_OK, kPacketSize), @@ -161,7 +197,7 @@ TEST_F(QuicUdpSocketTest, ReadTruncated) { ASSERT_FALSE(read_result.ok); } -TEST_F(QuicUdpSocketTest, ReadDroppedPackets) { +TEST_P(QuicUdpSocketTest, ReadDroppedPackets) { const size_t kPacketSize = kDefaultMaxPacketSize; memset(client_packet_buffer_, '-', kPacketSize); ASSERT_EQ(WriteResult(WRITE_STATUS_OK, kPacketSize), @@ -193,7 +229,7 @@ TEST_F(QuicUdpSocketTest, ReadDroppedPackets) { } } -TEST_F(QuicUdpSocketTest, ReadSelfIp) { +TEST_P(QuicUdpSocketTest, ReadSelfIp) { const QuicUdpPacketInfoBit self_ip_bit = (address_family_ == AF_INET) ? QuicUdpPacketInfoBit::V4_SELF_IP : QuicUdpPacketInfoBit::V6_SELF_IP; @@ -214,7 +250,7 @@ TEST_F(QuicUdpSocketTest, ReadSelfIp) { : read_result.packet_info.self_v6_ip()); } -TEST_F(QuicUdpSocketTest, ReadReceiveTimestamp) { +TEST_P(QuicUdpSocketTest, ReadReceiveTimestamp) { const size_t kPacketSize = kDefaultMaxPacketSize; memset(client_packet_buffer_, '-', kPacketSize); ASSERT_EQ(WriteResult(WRITE_STATUS_OK, kPacketSize), @@ -249,7 +285,7 @@ TEST_F(QuicUdpSocketTest, ReadReceiveTimestamp) { QuicWallTime::FromUNIXSeconds(1577836800).IsBefore(recv_timestamp)); } -TEST_F(QuicUdpSocketTest, Ttl) { +TEST_P(QuicUdpSocketTest, Ttl) { const size_t kPacketSize = 512; memset(client_packet_buffer_, '$', kPacketSize); ASSERT_EQ(WriteResult(WRITE_STATUS_OK, kPacketSize), @@ -282,7 +318,7 @@ TEST_F(QuicUdpSocketTest, Ttl) { EXPECT_EQ(13, read_result.packet_info.ttl()); } -TEST_F(QuicUdpSocketTest, ReadMultiplePackets) { +TEST_P(QuicUdpSocketTest, ReadMultiplePackets) { const QuicUdpPacketInfoBit self_ip_bit = (address_family_ == AF_INET) ? QuicUdpPacketInfoBit::V4_SELF_IP : QuicUdpPacketInfoBit::V6_SELF_IP; @@ -335,7 +371,7 @@ TEST_F(QuicUdpSocketTest, ReadMultiplePackets) { } } -TEST_F(QuicUdpSocketTest, ReadMultiplePacketsSomeTruncated) { +TEST_P(QuicUdpSocketTest, ReadMultiplePacketsSomeTruncated) { const QuicUdpPacketInfoBit self_ip_bit = (address_family_ == AF_INET) ? QuicUdpPacketInfoBit::V4_SELF_IP : QuicUdpPacketInfoBit::V6_SELF_IP; diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map.cc b/chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map.cc index 8276f1c287c..f06d0746e40 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map.cc @@ -28,6 +28,7 @@ QuicUnackedPacketMap::QuicUnackedPacketMap(Perspective perspective) : perspective_(perspective), least_unacked_(FirstSendingPacketNumber()), bytes_in_flight_(0), + bytes_in_flight_per_packet_number_space_{0, 0, 0}, packets_in_flight_(0), last_inflight_packet_sent_time_(QuicTime::Zero()), last_inflight_packets_sent_time_{{QuicTime::Zero()}, @@ -72,6 +73,7 @@ void QuicUnackedPacketMap::AddSentPacket(SerializedPacket* packet, const PacketNumberSpace packet_number_space = GetPacketNumberSpace(info.encryption_level); bytes_in_flight_ += bytes_sent; + bytes_in_flight_per_packet_number_space_[packet_number_space] += bytes_sent; ++packets_in_flight_; info.in_flight = true; largest_sent_retransmittable_packets_[packet_number_space] = packet_number; @@ -195,6 +197,27 @@ void QuicUnackedPacketMap::RemoveFromInFlight(QuicTransmissionInfo* info) { QUIC_BUG_IF(packets_in_flight_ == 0); bytes_in_flight_ -= info->bytes_sent; --packets_in_flight_; + + const PacketNumberSpace packet_number_space = + GetPacketNumberSpace(info->encryption_level); + if (bytes_in_flight_per_packet_number_space_[packet_number_space] < + info->bytes_sent) { + QUIC_BUG << "bytes_in_flight: " + << bytes_in_flight_per_packet_number_space_[packet_number_space] + << " is smaller than bytes_sent: " << info->bytes_sent + << " for packet number space: " + << PacketNumberSpaceToString(packet_number_space); + bytes_in_flight_per_packet_number_space_[packet_number_space] = 0; + } else { + bytes_in_flight_per_packet_number_space_[packet_number_space] -= + info->bytes_sent; + } + if (GetQuicReloadableFlag(quic_fix_last_inflight_packets_sent_time) && + bytes_in_flight_per_packet_number_space_[packet_number_space] == 0) { + QUIC_RELOADABLE_FLAG_COUNT(quic_fix_last_inflight_packets_sent_time); + last_inflight_packets_sent_time_[packet_number_space] = QuicTime::Zero(); + } + info->in_flight = false; } } @@ -230,7 +253,12 @@ QuicUnackedPacketMap::NeuterUnencryptedPackets() { } } if (supports_multiple_packet_number_spaces_) { - last_inflight_packets_sent_time_[INITIAL_DATA] = QuicTime::Zero(); + if (GetQuicReloadableFlag(quic_fix_last_inflight_packets_sent_time)) { + DCHECK_EQ(QuicTime::Zero(), + last_inflight_packets_sent_time_[INITIAL_DATA]); + } else { + last_inflight_packets_sent_time_[INITIAL_DATA] = QuicTime::Zero(); + } } return neutered_packets; } @@ -254,7 +282,12 @@ QuicUnackedPacketMap::NeuterHandshakePackets() { } } if (supports_multiple_packet_number_spaces()) { - last_inflight_packets_sent_time_[HANDSHAKE_DATA] = QuicTime::Zero(); + if (GetQuicReloadableFlag(quic_fix_last_inflight_packets_sent_time)) { + DCHECK_EQ(QuicTime::Zero(), + last_inflight_packets_sent_time_[HANDSHAKE_DATA]); + } else { + last_inflight_packets_sent_time_[HANDSHAKE_DATA] = QuicTime::Zero(); + } } return neutered_packets; } diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map.h b/chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map.h index bcf5061927a..43e900802f4 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map.h @@ -281,6 +281,9 @@ class QUIC_EXPORT_PRIVATE QuicUnackedPacketMap { QuicPacketNumber least_unacked_; QuicByteCount bytes_in_flight_; + // Bytes in flight per packet number space. + QuicByteCount + bytes_in_flight_per_packet_number_space_[NUM_PACKET_NUMBER_SPACES]; QuicPacketCount packets_in_flight_; // Time that the last inflight packet was sent. diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_utils.cc b/chromium/net/third_party/quiche/src/quic/core/quic_utils.cc index 60354f332fa..de4350390b0 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_utils.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_utils.cc @@ -6,6 +6,7 @@ #include <algorithm> #include <cstdint> +#include <cstring> #include <string> #include "net/third_party/quiche/src/quic/core/quic_connection_id.h" @@ -335,8 +336,7 @@ bool QuicUtils::ContainsFrameType(const QuicFrames& frames, SentPacketState QuicUtils::RetransmissionTypeToPacketState( TransmissionType retransmission_type) { switch (retransmission_type) { - case ALL_UNACKED_RETRANSMISSION: - case ALL_INITIAL_RETRANSMISSION: + case ALL_ZERO_RTT_RETRANSMISSION: return UNACKABLE; case HANDSHAKE_RETRANSMISSION: return HANDSHAKE_RETRANSMITTED; @@ -351,8 +351,7 @@ SentPacketState QuicUtils::RetransmissionTypeToPacketState( case PROBING_RETRANSMISSION: return PROBE_RETRANSMITTED; default: - QUIC_BUG << TransmissionTypeToString(retransmission_type) - << " is not a retransmission_type"; + QUIC_BUG << retransmission_type << " is not a retransmission_type"; return UNACKABLE; } } @@ -429,15 +428,21 @@ bool QuicUtils::IsOutgoingStreamId(ParsedQuicVersion version, } // static -bool QuicUtils::IsBidirectionalStreamId(QuicStreamId id) { +bool QuicUtils::IsBidirectionalStreamId(QuicStreamId id, + ParsedQuicVersion version) { + DCHECK(!GetQuicReloadableFlag(quic_fix_gquic_stream_type) || + version.HasIetfQuicFrames()); return id % 4 < 2; } // static StreamType QuicUtils::GetStreamType(QuicStreamId id, Perspective perspective, - bool peer_initiated) { - if (IsBidirectionalStreamId(id)) { + bool peer_initiated, + ParsedQuicVersion version) { + DCHECK(!GetQuicReloadableFlag(quic_fix_gquic_stream_type) || + version.HasIetfQuicFrames()); + if (IsBidirectionalStreamId(id, version)) { return BIDIRECTIONAL; } @@ -491,11 +496,37 @@ QuicStreamId QuicUtils::GetFirstUnidirectionalStreamId( // static QuicConnectionId QuicUtils::CreateReplacementConnectionId( - QuicConnectionId connection_id) { - const uint64_t connection_id_hash = FNV1a_64_Hash( + const QuicConnectionId& connection_id) { + return CreateReplacementConnectionId(connection_id, + kQuicDefaultConnectionIdLength); +} + +// static +QuicConnectionId QuicUtils::CreateReplacementConnectionId( + const QuicConnectionId& connection_id, + uint8_t expected_connection_id_length) { + if (expected_connection_id_length == 0) { + return EmptyQuicConnectionId(); + } + const uint64_t connection_id_hash64 = FNV1a_64_Hash( + quiche::QuicheStringPiece(connection_id.data(), connection_id.length())); + if (expected_connection_id_length <= sizeof(uint64_t)) { + return QuicConnectionId( + reinterpret_cast<const char*>(&connection_id_hash64), + expected_connection_id_length); + } + char new_connection_id_data[255] = {}; + const QuicUint128 connection_id_hash128 = FNV1a_128_Hash( quiche::QuicheStringPiece(connection_id.data(), connection_id.length())); - return QuicConnectionId(reinterpret_cast<const char*>(&connection_id_hash), - sizeof(connection_id_hash)); + static_assert(sizeof(connection_id_hash64) + sizeof(connection_id_hash128) <= + sizeof(new_connection_id_data), + "bad size"); + memcpy(new_connection_id_data, &connection_id_hash64, + sizeof(connection_id_hash64)); + memcpy(new_connection_id_data + sizeof(connection_id_hash64), + &connection_id_hash128, sizeof(connection_id_hash128)); + return QuicConnectionId(new_connection_id_data, + expected_connection_id_length); } // static @@ -603,7 +634,7 @@ PacketNumberSpace QuicUtils::GetPacketNumberSpace( return APPLICATION_DATA; default: QUIC_BUG << "Try to get packet number space of encryption level: " - << EncryptionLevelToString(encryption_level); + << encryption_level; return NUM_PACKET_NUMBER_SPACES; } } diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_utils.h b/chromium/net/third_party/quiche/src/quic/core/quic_utils.h index eec9a5f25df..9e190e0b386 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_utils.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_utils.h @@ -146,14 +146,16 @@ class QUIC_EXPORT_PRIVATE QuicUtils { // Returns true if |id| is considered as bidirectional stream ID. Only used in // v99. - static bool IsBidirectionalStreamId(QuicStreamId id); + static bool IsBidirectionalStreamId(QuicStreamId id, + ParsedQuicVersion version); // Returns stream type. Either |perspective| or |peer_initiated| would be // enough together with |id|. This method enforces that the three parameters // are consistent. Only used in v99. static StreamType GetStreamType(QuicStreamId id, Perspective perspective, - bool peer_initiated); + bool peer_initiated, + ParsedQuicVersion version); // Returns the delta between consecutive stream IDs of the same type. static QuicStreamId StreamIdDelta(QuicTransportVersion version); @@ -168,11 +170,19 @@ class QUIC_EXPORT_PRIVATE QuicUtils { QuicTransportVersion version, Perspective perspective); - // Generates a 64bit connection ID derived from the input connection ID. + // Generates a connection ID of length |expected_connection_id_length| + // derived from |connection_id|. // This is guaranteed to be deterministic (calling this method with two // connection IDs that are equal is guaranteed to produce the same result). static QuicConnectionId CreateReplacementConnectionId( - QuicConnectionId connection_id); + const QuicConnectionId& connection_id, + uint8_t expected_connection_id_length); + + // Generates a 64bit connection ID derived from |connection_id|. + // This is guaranteed to be deterministic (calling this method with two + // connection IDs that are equal is guaranteed to produce the same result). + static QuicConnectionId CreateReplacementConnectionId( + const QuicConnectionId& connection_id); // Generates a random 64bit connection ID. static QuicConnectionId CreateRandomConnectionId(); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_utils_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_utils_test.cc index 5b2186acde4..041cd9856a1 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_utils_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_utils_test.cc @@ -125,8 +125,7 @@ TEST_F(QuicUtilsTest, RetransmissionTypeToPacketState) { EXPECT_EQ(HANDSHAKE_RETRANSMITTED, state); } else if (i == LOSS_RETRANSMISSION) { EXPECT_EQ(LOST, state); - } else if (i == ALL_UNACKED_RETRANSMISSION || - i == ALL_INITIAL_RETRANSMISSION) { + } else if (i == ALL_ZERO_RTT_RETRANSMISSION) { EXPECT_EQ(UNACKABLE, state); } else if (i == TLP_RETRANSMISSION) { EXPECT_EQ(TLP_RETRANSMITTED, state); @@ -180,6 +179,23 @@ TEST_F(QuicUtilsTest, ReplacementConnectionIdIsDeterministic) { EXPECT_EQ(connection_id72a, connection_id72b); EXPECT_EQ(QuicUtils::CreateReplacementConnectionId(connection_id72a), QuicUtils::CreateReplacementConnectionId(connection_id72b)); + // Test variant with custom length. + EXPECT_EQ(QuicUtils::CreateReplacementConnectionId(connection_id64a, 7), + QuicUtils::CreateReplacementConnectionId(connection_id64b, 7)); + EXPECT_EQ(QuicUtils::CreateReplacementConnectionId(connection_id64a, 9), + QuicUtils::CreateReplacementConnectionId(connection_id64b, 9)); + EXPECT_EQ(QuicUtils::CreateReplacementConnectionId(connection_id64a, 16), + QuicUtils::CreateReplacementConnectionId(connection_id64b, 16)); + EXPECT_EQ(QuicUtils::CreateReplacementConnectionId(connection_id72a, 7), + QuicUtils::CreateReplacementConnectionId(connection_id72b, 7)); + EXPECT_EQ(QuicUtils::CreateReplacementConnectionId(connection_id72a, 9), + QuicUtils::CreateReplacementConnectionId(connection_id72b, 9)); + EXPECT_EQ(QuicUtils::CreateReplacementConnectionId(connection_id72a, 16), + QuicUtils::CreateReplacementConnectionId(connection_id72b, 16)); + EXPECT_EQ(QuicUtils::CreateReplacementConnectionId(connection_id72a, 32), + QuicUtils::CreateReplacementConnectionId(connection_id72b, 32)); + EXPECT_EQ(QuicUtils::CreateReplacementConnectionId(connection_id72a, 255), + QuicUtils::CreateReplacementConnectionId(connection_id72b, 255)); } TEST_F(QuicUtilsTest, ReplacementConnectionIdLengthIsCorrect) { @@ -191,6 +207,22 @@ TEST_F(QuicUtilsTest, ReplacementConnectionIdLengthIsCorrect) { QuicUtils::CreateReplacementConnectionId(connection_id); EXPECT_EQ(kQuicDefaultConnectionIdLength, replacement_connection_id.length()); + // Test variant with custom length. + QuicConnectionId replacement_connection_id7 = + QuicUtils::CreateReplacementConnectionId(connection_id, 7); + EXPECT_EQ(7, replacement_connection_id7.length()); + QuicConnectionId replacement_connection_id9 = + QuicUtils::CreateReplacementConnectionId(connection_id, 9); + EXPECT_EQ(9, replacement_connection_id9.length()); + QuicConnectionId replacement_connection_id16 = + QuicUtils::CreateReplacementConnectionId(connection_id, 16); + EXPECT_EQ(16, replacement_connection_id16.length()); + QuicConnectionId replacement_connection_id32 = + QuicUtils::CreateReplacementConnectionId(connection_id, 32); + EXPECT_EQ(32, replacement_connection_id32.length()); + QuicConnectionId replacement_connection_id255 = + QuicUtils::CreateReplacementConnectionId(connection_id, 255); + EXPECT_EQ(255, replacement_connection_id255.length()); } } @@ -205,6 +237,17 @@ TEST_F(QuicUtilsTest, ReplacementConnectionIdHasEntropy) { EXPECT_NE(connection_id_i, connection_id_j); EXPECT_NE(QuicUtils::CreateReplacementConnectionId(connection_id_i), QuicUtils::CreateReplacementConnectionId(connection_id_j)); + // Test variant with custom length. + EXPECT_NE(QuicUtils::CreateReplacementConnectionId(connection_id_i, 7), + QuicUtils::CreateReplacementConnectionId(connection_id_j, 7)); + EXPECT_NE(QuicUtils::CreateReplacementConnectionId(connection_id_i, 9), + QuicUtils::CreateReplacementConnectionId(connection_id_j, 9)); + EXPECT_NE(QuicUtils::CreateReplacementConnectionId(connection_id_i, 16), + QuicUtils::CreateReplacementConnectionId(connection_id_j, 16)); + EXPECT_NE(QuicUtils::CreateReplacementConnectionId(connection_id_i, 32), + QuicUtils::CreateReplacementConnectionId(connection_id_j, 32)); + EXPECT_NE(QuicUtils::CreateReplacementConnectionId(connection_id_i, 255), + QuicUtils::CreateReplacementConnectionId(connection_id_j, 255)); } } } diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_version_manager.cc b/chromium/net/third_party/quiche/src/quic/core/quic_version_manager.cc index 0a014bebe78..90c49823d99 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_version_manager.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_version_manager.cc @@ -15,18 +15,20 @@ namespace quic { QuicVersionManager::QuicVersionManager( ParsedQuicVersionVector supported_versions) - : enable_version_draft_27_( - GetQuicReloadableFlag(quic_enable_version_draft_27)), - enable_version_draft_25_( - GetQuicReloadableFlag(quic_enable_version_draft_25_v3)), + : enable_version_draft_29_( + GetQuicReloadableFlag(quic_enable_version_draft_29)), + disable_version_draft_27_( + GetQuicReloadableFlag(quic_disable_version_draft_27)), + disable_version_draft_25_( + GetQuicReloadableFlag(quic_disable_version_draft_25)), disable_version_q050_(GetQuicReloadableFlag(quic_disable_version_q050)), - enable_version_t050_(GetQuicReloadableFlag(quic_enable_version_t050_v2)), + disable_version_t050_(GetQuicReloadableFlag(quic_disable_version_t050)), disable_version_q049_(GetQuicReloadableFlag(quic_disable_version_q049)), disable_version_q048_(GetQuicReloadableFlag(quic_disable_version_q048)), disable_version_q046_(GetQuicReloadableFlag(quic_disable_version_q046)), disable_version_q043_(GetQuicReloadableFlag(quic_disable_version_q043)), allowed_supported_versions_(std::move(supported_versions)) { - static_assert(SupportedVersions().size() == 8u, + static_assert(SupportedVersions().size() == 9u, "Supported versions out of sync"); RefilterSupportedVersions(); } @@ -56,16 +58,18 @@ const std::vector<std::string>& QuicVersionManager::GetSupportedAlpns() { } void QuicVersionManager::MaybeRefilterSupportedVersions() { - static_assert(SupportedVersions().size() == 8u, + static_assert(SupportedVersions().size() == 9u, "Supported versions out of sync"); - if (enable_version_draft_27_ != - GetQuicReloadableFlag(quic_enable_version_draft_27) || - enable_version_draft_25_ != - GetQuicReloadableFlag(quic_enable_version_draft_25_v3) || + if (enable_version_draft_29_ != + GetQuicReloadableFlag(quic_enable_version_draft_29) || + disable_version_draft_27_ != + GetQuicReloadableFlag(quic_disable_version_draft_27) || + disable_version_draft_25_ != + GetQuicReloadableFlag(quic_disable_version_draft_25) || disable_version_q050_ != GetQuicReloadableFlag(quic_disable_version_q050) || - enable_version_t050_ != - GetQuicReloadableFlag(quic_enable_version_t050_v2) || + disable_version_t050_ != + GetQuicReloadableFlag(quic_disable_version_t050) || disable_version_q049_ != GetQuicReloadableFlag(quic_disable_version_q049) || disable_version_q048_ != @@ -74,12 +78,14 @@ void QuicVersionManager::MaybeRefilterSupportedVersions() { GetQuicReloadableFlag(quic_disable_version_q046) || disable_version_q043_ != GetQuicReloadableFlag(quic_disable_version_q043)) { - enable_version_draft_27_ = - GetQuicReloadableFlag(quic_enable_version_draft_27); - enable_version_draft_25_ = - GetQuicReloadableFlag(quic_enable_version_draft_25_v3); + enable_version_draft_29_ = + GetQuicReloadableFlag(quic_enable_version_draft_29); + disable_version_draft_27_ = + GetQuicReloadableFlag(quic_disable_version_draft_27); + disable_version_draft_25_ = + GetQuicReloadableFlag(quic_disable_version_draft_25); disable_version_q050_ = GetQuicReloadableFlag(quic_disable_version_q050); - enable_version_t050_ = GetQuicReloadableFlag(quic_enable_version_t050_v2); + disable_version_t050_ = GetQuicReloadableFlag(quic_disable_version_t050); disable_version_q049_ = GetQuicReloadableFlag(quic_disable_version_q049); disable_version_q048_ = GetQuicReloadableFlag(quic_disable_version_q048); disable_version_q046_ = GetQuicReloadableFlag(quic_disable_version_q046); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_version_manager.h b/chromium/net/third_party/quiche/src/quic/core/quic_version_manager.h index c5111edf260..e6bb8f6b6bd 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_version_manager.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_version_manager.h @@ -52,14 +52,16 @@ class QUIC_EXPORT_PRIVATE QuicVersionManager { private: // Cached value of reloadable flags. - // quic_enable_version_draft_27 flag - bool enable_version_draft_27_; - // quic_enable_version_draft_25_v3 flag - bool enable_version_draft_25_; + // quic_enable_version_draft_29 flag + bool enable_version_draft_29_; + // quic_disable_version_draft_27 flag + bool disable_version_draft_27_; + // quic_disable_version_draft_25 flag + bool disable_version_draft_25_; // quic_disable_version_q050 flag bool disable_version_q050_; - // quic_enable_version_t050_v2 flag - bool enable_version_t050_; + // quic_disable_version_t050 flag + bool disable_version_t050_; // quic_disable_version_q049 flag bool disable_version_q049_; // quic_disable_version_q048 flag diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_version_manager_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_version_manager_test.cc index 3a8e98ff520..4687b791fd9 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_version_manager_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_version_manager_test.cc @@ -18,11 +18,12 @@ namespace { class QuicVersionManagerTest : public QuicTest {}; TEST_F(QuicVersionManagerTest, QuicVersionManager) { - static_assert(SupportedVersions().size() == 8u, + static_assert(SupportedVersions().size() == 9u, "Supported versions out of sync"); - SetQuicReloadableFlag(quic_enable_version_draft_27, false); - SetQuicReloadableFlag(quic_enable_version_draft_25_v3, false); - SetQuicReloadableFlag(quic_enable_version_t050_v2, false); + SetQuicReloadableFlag(quic_enable_version_draft_29, false); + SetQuicReloadableFlag(quic_disable_version_draft_27, true); + SetQuicReloadableFlag(quic_disable_version_draft_25, true); + SetQuicReloadableFlag(quic_disable_version_t050, false); SetQuicReloadableFlag(quic_disable_version_q050, false); SetQuicReloadableFlag(quic_disable_version_q049, false); SetQuicReloadableFlag(quic_disable_version_q048, false); @@ -32,6 +33,8 @@ TEST_F(QuicVersionManagerTest, QuicVersionManager) { ParsedQuicVersionVector expected_parsed_versions; expected_parsed_versions.push_back( + ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_50)); + expected_parsed_versions.push_back( ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50)); expected_parsed_versions.push_back( ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_49)); @@ -43,59 +46,56 @@ TEST_F(QuicVersionManagerTest, QuicVersionManager) { ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43)); EXPECT_EQ(expected_parsed_versions, manager.GetSupportedVersions()); - EXPECT_EQ(expected_parsed_versions, - manager.GetSupportedVersionsWithQuicCrypto()); EXPECT_EQ(FilterSupportedVersions(AllSupportedVersions()), manager.GetSupportedVersions()); EXPECT_EQ(CurrentSupportedVersionsWithQuicCrypto(), manager.GetSupportedVersionsWithQuicCrypto()); - EXPECT_THAT( - manager.GetSupportedAlpns(), - ElementsAre("h3-Q050", "h3-Q049", "h3-Q048", "h3-Q046", "h3-Q043")); + EXPECT_THAT(manager.GetSupportedAlpns(), + ElementsAre("h3-T050", "h3-Q050", "h3-Q049", "h3-Q048", "h3-Q046", + "h3-Q043")); - SetQuicReloadableFlag(quic_enable_version_draft_27, true); - expected_parsed_versions.insert( - expected_parsed_versions.begin(), - ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_27)); + SetQuicReloadableFlag(quic_enable_version_draft_29, true); + expected_parsed_versions.insert(expected_parsed_versions.begin(), + ParsedQuicVersion::Draft29()); EXPECT_EQ(expected_parsed_versions, manager.GetSupportedVersions()); - EXPECT_EQ(expected_parsed_versions.size() - 1, + EXPECT_EQ(expected_parsed_versions.size() - 2, manager.GetSupportedVersionsWithQuicCrypto().size()); EXPECT_EQ(FilterSupportedVersions(AllSupportedVersions()), manager.GetSupportedVersions()); EXPECT_EQ(CurrentSupportedVersionsWithQuicCrypto(), manager.GetSupportedVersionsWithQuicCrypto()); EXPECT_THAT(manager.GetSupportedAlpns(), - ElementsAre("h3-27", "h3-Q050", "h3-Q049", "h3-Q048", "h3-Q046", - "h3-Q043")); + ElementsAre("h3-29", "h3-T050", "h3-Q050", "h3-Q049", "h3-Q048", + "h3-Q046", "h3-Q043")); - SetQuicReloadableFlag(quic_enable_version_draft_25_v3, true); + SetQuicReloadableFlag(quic_disable_version_draft_27, false); expected_parsed_versions.insert( expected_parsed_versions.begin() + 1, - ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_25)); + ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_27)); EXPECT_EQ(expected_parsed_versions, manager.GetSupportedVersions()); - EXPECT_EQ(expected_parsed_versions.size() - 2, + EXPECT_EQ(expected_parsed_versions.size() - 3, manager.GetSupportedVersionsWithQuicCrypto().size()); + EXPECT_EQ(FilterSupportedVersions(AllSupportedVersions()), + manager.GetSupportedVersions()); EXPECT_EQ(CurrentSupportedVersionsWithQuicCrypto(), manager.GetSupportedVersionsWithQuicCrypto()); EXPECT_THAT(manager.GetSupportedAlpns(), - ElementsAre("h3-27", "h3-25", "h3-Q050", "h3-Q049", "h3-Q048", - "h3-Q046", "h3-Q043")); + ElementsAre("h3-29", "h3-27", "h3-T050", "h3-Q050", "h3-Q049", + "h3-Q048", "h3-Q046", "h3-Q043")); - SetQuicReloadableFlag(quic_enable_version_t050_v2, true); + SetQuicReloadableFlag(quic_disable_version_draft_25, false); expected_parsed_versions.insert( expected_parsed_versions.begin() + 2, - ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_50)); + ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_25)); EXPECT_EQ(expected_parsed_versions, manager.GetSupportedVersions()); - EXPECT_EQ(expected_parsed_versions.size() - 3, + EXPECT_EQ(expected_parsed_versions.size() - 4, manager.GetSupportedVersionsWithQuicCrypto().size()); - EXPECT_EQ(FilterSupportedVersions(AllSupportedVersions()), - manager.GetSupportedVersions()); EXPECT_EQ(CurrentSupportedVersionsWithQuicCrypto(), manager.GetSupportedVersionsWithQuicCrypto()); EXPECT_THAT(manager.GetSupportedAlpns(), - ElementsAre("h3-27", "h3-25", "h3-T050", "h3-Q050", "h3-Q049", - "h3-Q048", "h3-Q046", "h3-Q043")); + ElementsAre("h3-29", "h3-27", "h3-25", "h3-T050", "h3-Q050", + "h3-Q049", "h3-Q048", "h3-Q046", "h3-Q043")); } } // namespace diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_versions.cc b/chromium/net/third_party/quiche/src/quic/core/quic_versions.cc index bf93e8383d2..461a4882e2b 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_versions.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_versions.cc @@ -39,6 +39,35 @@ QuicVersionLabel CreateRandomVersionLabelForNegotiation() { return result; } +void SetVersionFlag(const ParsedQuicVersion& version, bool should_enable) { + static_assert(SupportedVersions().size() == 9u, + "Supported versions out of sync"); + const bool enable = should_enable; + const bool disable = !should_enable; + if (version == ParsedQuicVersion::Draft29()) { + SetQuicReloadableFlag(quic_enable_version_draft_29, enable); + } else if (version == ParsedQuicVersion::Draft27()) { + SetQuicReloadableFlag(quic_disable_version_draft_27, disable); + } else if (version == ParsedQuicVersion::Draft25()) { + SetQuicReloadableFlag(quic_disable_version_draft_25, disable); + } else if (version == ParsedQuicVersion::T050()) { + SetQuicReloadableFlag(quic_disable_version_t050, disable); + } else if (version == ParsedQuicVersion::Q050()) { + SetQuicReloadableFlag(quic_disable_version_q050, disable); + } else if (version == ParsedQuicVersion::Q049()) { + SetQuicReloadableFlag(quic_disable_version_q049, disable); + } else if (version == ParsedQuicVersion::Q048()) { + SetQuicReloadableFlag(quic_disable_version_q048, disable); + } else if (version == ParsedQuicVersion::Q046()) { + SetQuicReloadableFlag(quic_disable_version_q046, disable); + } else if (version == ParsedQuicVersion::Q043()) { + SetQuicReloadableFlag(quic_disable_version_q043, disable); + } else { + QUIC_BUG << "Cannot " << (should_enable ? "en" : "dis") << "able version " + << version; + } +} + } // namespace bool ParsedQuicVersion::IsKnown() const { @@ -158,6 +187,11 @@ bool ParsedQuicVersion::HasVarIntTransportParams() const { return transport_version >= QUIC_VERSION_IETF_DRAFT_27; } +bool ParsedQuicVersion::AuthenticatesHandshakeConnectionIds() const { + DCHECK(IsKnown()); + return transport_version > QUIC_VERSION_IETF_DRAFT_27; +} + bool ParsedQuicVersion::UsesTls() const { DCHECK(IsKnown()); return handshake_protocol == PROTOCOL_TLS1_3; @@ -211,7 +245,7 @@ QuicVersionLabel CreateQuicVersionLabel(ParsedQuicVersion parsed_version) { << parsed_version.handshake_protocol; return 0; } - static_assert(SupportedVersions().size() == 8u, + static_assert(SupportedVersions().size() == 9u, "Supported versions out of sync"); switch (parsed_version.transport_version) { case QUIC_VERSION_43: @@ -236,6 +270,12 @@ QuicVersionLabel CreateQuicVersionLabel(ParsedQuicVersion parsed_version) { } QUIC_BUG << "QUIC_VERSION_IETF_DRAFT_27 requires TLS"; return 0; + case QUIC_VERSION_IETF_DRAFT_29: + if (parsed_version.handshake_protocol == PROTOCOL_TLS1_3) { + return MakeVersionLabel(0xff, 0x00, 0x00, 29); + } + QUIC_BUG << "QUIC_VERSION_IETF_DRAFT_29 requires TLS"; + return 0; case QUIC_VERSION_RESERVED_FOR_NEGOTIATION: return CreateRandomVersionLabelForNegotiation(); default: @@ -391,15 +431,20 @@ ParsedQuicVersionVector FilterSupportedVersions( ParsedQuicVersionVector versions) { ParsedQuicVersionVector filtered_versions; filtered_versions.reserve(versions.size()); - for (ParsedQuicVersion version : versions) { - if (version.transport_version == QUIC_VERSION_IETF_DRAFT_27) { + for (const ParsedQuicVersion& version : versions) { + if (version.transport_version == QUIC_VERSION_IETF_DRAFT_29) { + QUIC_BUG_IF(version.handshake_protocol != PROTOCOL_TLS1_3); + if (GetQuicReloadableFlag(quic_enable_version_draft_29)) { + filtered_versions.push_back(version); + } + } else if (version.transport_version == QUIC_VERSION_IETF_DRAFT_27) { QUIC_BUG_IF(version.handshake_protocol != PROTOCOL_TLS1_3); - if (GetQuicReloadableFlag(quic_enable_version_draft_27)) { + if (!GetQuicReloadableFlag(quic_disable_version_draft_27)) { filtered_versions.push_back(version); } } else if (version.transport_version == QUIC_VERSION_IETF_DRAFT_25) { QUIC_BUG_IF(version.handshake_protocol != PROTOCOL_TLS1_3); - if (GetQuicReloadableFlag(quic_enable_version_draft_25_v3)) { + if (!GetQuicReloadableFlag(quic_disable_version_draft_25)) { filtered_versions.push_back(version); } } else if (version.transport_version == QUIC_VERSION_50) { @@ -408,7 +453,7 @@ ParsedQuicVersionVector FilterSupportedVersions( filtered_versions.push_back(version); } } else { - if (GetQuicReloadableFlag(quic_enable_version_t050_v2)) { + if (!GetQuicReloadableFlag(quic_disable_version_t050)) { filtered_versions.push_back(version); } } @@ -518,7 +563,7 @@ HandshakeProtocol QuicVersionLabelToHandshakeProtocol( return #x std::string QuicVersionToString(QuicTransportVersion transport_version) { - static_assert(SupportedTransportVersions().size() == 7u, + static_assert(SupportedTransportVersions().size() == 8u, "Supported versions out of sync"); switch (transport_version) { RETURN_STRING_LITERAL(QUIC_VERSION_43); @@ -528,6 +573,7 @@ std::string QuicVersionToString(QuicTransportVersion transport_version) { RETURN_STRING_LITERAL(QUIC_VERSION_50); RETURN_STRING_LITERAL(QUIC_VERSION_IETF_DRAFT_25); RETURN_STRING_LITERAL(QUIC_VERSION_IETF_DRAFT_27); + RETURN_STRING_LITERAL(QUIC_VERSION_IETF_DRAFT_29); RETURN_STRING_LITERAL(QUIC_VERSION_UNSUPPORTED); RETURN_STRING_LITERAL(QUIC_VERSION_RESERVED_FOR_NEGOTIATION); } @@ -621,21 +667,25 @@ bool QuicVersionLabelUses4BitConnectionIdLength( } ParsedQuicVersion UnsupportedQuicVersion() { - return ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED); + return ParsedQuicVersion::Unsupported(); } ParsedQuicVersion QuicVersionReservedForNegotiation() { - return ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, - QUIC_VERSION_RESERVED_FOR_NEGOTIATION); + return ParsedQuicVersion::ReservedForNegotiation(); +} + +ParsedQuicVersion LegacyVersionForEncapsulation() { + return ParsedQuicVersion::Q043(); } std::string AlpnForVersion(ParsedQuicVersion parsed_version) { if (parsed_version.handshake_protocol == PROTOCOL_TLS1_3) { - if (parsed_version.transport_version == QUIC_VERSION_IETF_DRAFT_25) { - return "h3-25"; - } - if (parsed_version.transport_version == QUIC_VERSION_IETF_DRAFT_27) { + if (parsed_version.transport_version == QUIC_VERSION_IETF_DRAFT_29) { + return "h3-29"; + } else if (parsed_version.transport_version == QUIC_VERSION_IETF_DRAFT_27) { return "h3-27"; + } else if (parsed_version.transport_version == QUIC_VERSION_IETF_DRAFT_25) { + return "h3-25"; } } return "h3-" + ParsedQuicVersionToString(parsed_version); @@ -643,32 +693,21 @@ std::string AlpnForVersion(ParsedQuicVersion parsed_version) { void QuicVersionInitializeSupportForIetfDraft() { // Enable necessary flags. + SetQuicReloadableFlag(quic_enable_tls_resumption, true); + SetQuicReloadableFlag(quic_enable_zero_rtt_for_tls, true); } -void QuicEnableVersion(ParsedQuicVersion parsed_version) { - static_assert(SupportedVersions().size() == 8u, - "Supported versions out of sync"); - if (parsed_version.transport_version == QUIC_VERSION_IETF_DRAFT_27) { - QUIC_BUG_IF(parsed_version.handshake_protocol != PROTOCOL_TLS1_3); - SetQuicReloadableFlag(quic_enable_version_draft_27, true); - } else if (parsed_version.transport_version == QUIC_VERSION_IETF_DRAFT_25) { - QUIC_BUG_IF(parsed_version.handshake_protocol != PROTOCOL_TLS1_3); - SetQuicReloadableFlag(quic_enable_version_draft_25_v3, true); - } else if (parsed_version.transport_version == QUIC_VERSION_50) { - if (parsed_version.handshake_protocol == PROTOCOL_QUIC_CRYPTO) { - SetQuicReloadableFlag(quic_disable_version_q050, false); - } else { - SetQuicReloadableFlag(quic_enable_version_t050_v2, true); - } - } else if (parsed_version.transport_version == QUIC_VERSION_49) { - SetQuicReloadableFlag(quic_disable_version_q049, false); - } else if (parsed_version.transport_version == QUIC_VERSION_48) { - SetQuicReloadableFlag(quic_disable_version_q048, false); - } else if (parsed_version.transport_version == QUIC_VERSION_46) { - SetQuicReloadableFlag(quic_disable_version_q046, false); - } else if (parsed_version.transport_version == QUIC_VERSION_43) { - SetQuicReloadableFlag(quic_disable_version_q043, false); - } +void QuicEnableVersion(const ParsedQuicVersion& version) { + SetVersionFlag(version, /*should_enable=*/true); +} + +void QuicDisableVersion(const ParsedQuicVersion& version) { + SetVersionFlag(version, /*should_enable=*/false); +} + +bool QuicVersionIsEnabled(const ParsedQuicVersion& version) { + ParsedQuicVersionVector current = CurrentSupportedVersions(); + return std::find(current.begin(), current.end(), version) != current.end(); } #undef RETURN_STRING_LITERAL // undef for jumbo builds diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_versions.h b/chromium/net/third_party/quiche/src/quic/core/quic_versions.h index 5f3a9689198..341d39896cb 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_versions.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_versions.h @@ -4,13 +4,21 @@ // Definitions and utility functions related to handling of QUIC versions. // -// QUIC version is a four-byte tag that can be represented in memory as a -// QuicVersionLabel type (which is an alias to uint32_t). In actuality, all -// versions supported by this implementation have the following format: -// [QT]0\d\d -// e.g. Q046. Q or T distinguishes the type of handshake used (Q for QUIC -// Crypto handshake, T for TLS-based handshake), and the two digits at the end -// is the actual numeric value of transport version used by the code. +// QUIC versions are encoded over the wire as an opaque 32bit field. The wire +// encoding is represented in memory as a QuicVersionLabel type (which is an +// alias to uint32_t). Conceptual versions are represented in memory as +// ParsedQuicVersion. +// +// We currently support two kinds of QUIC versions, GoogleQUIC and IETF QUIC. +// +// All GoogleQUIC versions use a wire encoding that matches the following regex +// when converted to ASCII: "[QT]0\d\d" (e.g. Q050). Q or T distinguishes the +// type of handshake used (Q for the QUIC_CRYPTO handshake, T for the QUIC+TLS +// handshake), and the two digits at the end contain the numeric value of +// the transport version used. +// +// All IETF QUIC versions use the wire encoding described in: +// https://tools.ietf.org/html/draft-ietf-quic-transport #ifndef QUICHE_QUIC_CORE_QUIC_VERSIONS_H_ #define QUICHE_QUIC_CORE_QUIC_VERSIONS_H_ @@ -25,11 +33,12 @@ namespace quic { -// The available versions of QUIC. The numeric value of the enum is guaranteed -// to match the number in the name. The versions not currently supported are -// documented in comments. -// -// See go/new-quic-version for more details on how to roll out new versions. +// The list of existing QUIC transport versions. Note that QUIC versions are +// sent over the wire as an encoding of ParsedQuicVersion, which requires a +// QUIC transport version and handshake protocol. For transport versions of the +// form QUIC_VERSION_XX where XX is decimal, the enum numeric value is +// guaranteed to match the name. Older deprecated transport versions are +// documented in comments below. enum QuicTransportVersion { // Special case to indicate unknown/unsupported QUIC version. QUIC_VERSION_UNSUPPORTED = 0, @@ -110,6 +119,8 @@ enum QuicTransportVersion { QUIC_VERSION_50 = 50, // Header protection and initial obfuscators. QUIC_VERSION_IETF_DRAFT_25 = 70, // draft-ietf-quic-transport-25. QUIC_VERSION_IETF_DRAFT_27 = 71, // draft-ietf-quic-transport-27. + // Number 72 used to represent draft-ietf-quic-transport-28. + QUIC_VERSION_IETF_DRAFT_29 = 73, // draft-ietf-quic-transport-29. // Version 99 was a dumping ground for IETF QUIC changes which were not yet // yet ready for production between 2018-02 and 2020-02. @@ -123,13 +134,10 @@ enum QuicTransportVersion { }; // This array contains QUIC transport versions which we currently support. -// This should be ordered such that the highest supported version is the first -// element, with subsequent elements in descending order (versions can be -// skipped as necessary). -// -// See go/new-quic-version for more details on how to roll out new versions. -constexpr std::array<QuicTransportVersion, 7> SupportedTransportVersions() { - return {QUIC_VERSION_IETF_DRAFT_27, +// DEPRECATED. Use SupportedVersions() instead. +constexpr std::array<QuicTransportVersion, 8> SupportedTransportVersions() { + return {QUIC_VERSION_IETF_DRAFT_29, + QUIC_VERSION_IETF_DRAFT_27, QUIC_VERSION_IETF_DRAFT_25, QUIC_VERSION_50, QUIC_VERSION_49, @@ -191,7 +199,8 @@ QUIC_EXPORT_PRIVATE constexpr bool ParsedQuicVersionIsValid( case PROTOCOL_QUIC_CRYPTO: return transport_version != QUIC_VERSION_UNSUPPORTED && transport_version != QUIC_VERSION_IETF_DRAFT_25 && - transport_version != QUIC_VERSION_IETF_DRAFT_27; + transport_version != QUIC_VERSION_IETF_DRAFT_27 && + transport_version != QUIC_VERSION_IETF_DRAFT_29; case PROTOCOL_TLS1_3: // The TLS handshake is only deployable if CRYPTO frames are also used. // We explicitly removed support for T048 and T049 to reduce test load. @@ -242,6 +251,51 @@ struct QUIC_EXPORT_PRIVATE ParsedQuicVersion { transport_version != other.transport_version; } + static constexpr ParsedQuicVersion Draft29() { + return ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_29); + } + + static constexpr ParsedQuicVersion Draft27() { + return ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_27); + } + + static constexpr ParsedQuicVersion Draft25() { + return ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_25); + } + + static constexpr ParsedQuicVersion T050() { + return ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_50); + } + + static constexpr ParsedQuicVersion Q050() { + return ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50); + } + + static constexpr ParsedQuicVersion Q049() { + return ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_49); + } + + static constexpr ParsedQuicVersion Q048() { + return ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_48); + } + + static constexpr ParsedQuicVersion Q046() { + return ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46); + } + + static constexpr ParsedQuicVersion Q043() { + return ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43); + } + + static constexpr ParsedQuicVersion Unsupported() { + return ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED); + } + + static constexpr ParsedQuicVersion ReservedForNegotiation() { + return ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, + QUIC_VERSION_RESERVED_FOR_NEGOTIATION); + } + // Returns whether our codebase understands this version. This should only be // called on valid versions, see ParsedQuicVersionIsValid. Assuming the // version is valid, IsKnown returns whether the version is not @@ -331,6 +385,10 @@ struct QUIC_EXPORT_PRIVATE ParsedQuicVersion { // encoding transport parameter types and lengths. bool HasVarIntTransportParams() const; + // Returns true if this version uses transport parameters to authenticate all + // the connection IDs used during the handshake. + bool AuthenticatesHandshakeConnectionIds() const; + // Returns whether this version uses PROTOCOL_TLS1_3. bool UsesTls() const; @@ -342,6 +400,10 @@ QUIC_EXPORT_PRIVATE ParsedQuicVersion UnsupportedQuicVersion(); QUIC_EXPORT_PRIVATE ParsedQuicVersion QuicVersionReservedForNegotiation(); +// Outer version used when encapsulating other packets using the Legacy Version +// Encapsulation feature. +QUIC_EXPORT_PRIVATE ParsedQuicVersion LegacyVersionForEncapsulation(); + QUIC_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os, const ParsedQuicVersion& version); @@ -365,16 +427,13 @@ constexpr std::array<HandshakeProtocol, 2> SupportedHandshakeProtocols() { return {PROTOCOL_TLS1_3, PROTOCOL_QUIC_CRYPTO}; } -constexpr std::array<ParsedQuicVersion, 8> SupportedVersions() { +constexpr std::array<ParsedQuicVersion, 9> SupportedVersions() { return { - ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_27), - ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_25), - ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_50), - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50), - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_49), - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_48), - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46), - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43), + ParsedQuicVersion::Draft29(), ParsedQuicVersion::Draft27(), + ParsedQuicVersion::Draft25(), ParsedQuicVersion::T050(), + ParsedQuicVersion::Q050(), ParsedQuicVersion::Q049(), + ParsedQuicVersion::Q048(), ParsedQuicVersion::Q046(), + ParsedQuicVersion::Q043(), }; } @@ -604,8 +663,14 @@ QUIC_EXPORT_PRIVATE std::string AlpnForVersion( // correct flags. QUIC_EXPORT_PRIVATE void QuicVersionInitializeSupportForIetfDraft(); -// Enables the flags required to support this version of QUIC. -QUIC_EXPORT_PRIVATE void QuicEnableVersion(ParsedQuicVersion parsed_version); +// Configures the flags required to enable support for this version of QUIC. +QUIC_EXPORT_PRIVATE void QuicEnableVersion(const ParsedQuicVersion& version); + +// Configures the flags required to disable support for this version of QUIC. +QUIC_EXPORT_PRIVATE void QuicDisableVersion(const ParsedQuicVersion& version); + +// Returns whether support for this version of QUIC is currently enabled. +QUIC_EXPORT_PRIVATE bool QuicVersionIsEnabled(const ParsedQuicVersion& version); } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_versions_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_versions_test.cc index 3a07221ab94..c7ebb82a4ed 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_versions_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_versions_test.cc @@ -84,10 +84,8 @@ TEST_F(QuicVersionsTest, KnownAndValid) { } TEST_F(QuicVersionsTest, Features) { - ParsedQuicVersion parsed_version_q043 = - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43); - ParsedQuicVersion parsed_version_draft_27 = - ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_27); + ParsedQuicVersion parsed_version_q043 = ParsedQuicVersion::Q043(); + ParsedQuicVersion parsed_version_draft_27 = ParsedQuicVersion::Draft27(); EXPECT_TRUE(parsed_version_q043.IsKnown()); EXPECT_FALSE(parsed_version_q043.KnowsWhichDecrypterToUse()); @@ -208,35 +206,28 @@ TEST_F(QuicVersionsTest, QuicVersionLabelToHandshakeProtocol) { } TEST_F(QuicVersionsTest, ParseQuicVersionLabel) { - EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43), + EXPECT_EQ(ParsedQuicVersion::Q043(), ParseQuicVersionLabel(MakeVersionLabel('Q', '0', '4', '3'))); - EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46), + EXPECT_EQ(ParsedQuicVersion::Q046(), ParseQuicVersionLabel(MakeVersionLabel('Q', '0', '4', '6'))); - EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_48), + EXPECT_EQ(ParsedQuicVersion::Q048(), ParseQuicVersionLabel(MakeVersionLabel('Q', '0', '4', '8'))); - EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50), + EXPECT_EQ(ParsedQuicVersion::Q050(), ParseQuicVersionLabel(MakeVersionLabel('Q', '0', '5', '0'))); - EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_50), + EXPECT_EQ(ParsedQuicVersion::T050(), ParseQuicVersionLabel(MakeVersionLabel('T', '0', '5', '0'))); } TEST_F(QuicVersionsTest, ParseQuicVersionString) { - EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43), - ParseQuicVersionString("Q043")); - EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46), + EXPECT_EQ(ParsedQuicVersion::Q043(), ParseQuicVersionString("Q043")); + EXPECT_EQ(ParsedQuicVersion::Q046(), ParseQuicVersionString("QUIC_VERSION_46")); - EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46), - ParseQuicVersionString("46")); - EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46), - ParseQuicVersionString("Q046")); - EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_48), - ParseQuicVersionString("Q048")); - EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50), - ParseQuicVersionString("Q050")); - EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50), - ParseQuicVersionString("50")); - EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50), - ParseQuicVersionString("h3-Q050")); + EXPECT_EQ(ParsedQuicVersion::Q046(), ParseQuicVersionString("46")); + EXPECT_EQ(ParsedQuicVersion::Q046(), ParseQuicVersionString("Q046")); + EXPECT_EQ(ParsedQuicVersion::Q048(), ParseQuicVersionString("Q048")); + EXPECT_EQ(ParsedQuicVersion::Q050(), ParseQuicVersionString("Q050")); + EXPECT_EQ(ParsedQuicVersion::Q050(), ParseQuicVersionString("50")); + EXPECT_EQ(ParsedQuicVersion::Q050(), ParseQuicVersionString("h3-Q050")); EXPECT_EQ(UnsupportedQuicVersion(), ParseQuicVersionString("")); EXPECT_EQ(UnsupportedQuicVersion(), ParseQuicVersionString("Q 46")); @@ -244,18 +235,14 @@ TEST_F(QuicVersionsTest, ParseQuicVersionString) { EXPECT_EQ(UnsupportedQuicVersion(), ParseQuicVersionString("99")); EXPECT_EQ(UnsupportedQuicVersion(), ParseQuicVersionString("70")); - EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_50), - ParseQuicVersionString("T050")); - EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_50), - ParseQuicVersionString("h3-T050")); - EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_27), - ParseQuicVersionString("ff00001b")); - EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_27), - ParseQuicVersionString("h3-27")); - EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_25), - ParseQuicVersionString("ff000019")); - EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_25), - ParseQuicVersionString("h3-25")); + EXPECT_EQ(ParsedQuicVersion::T050(), ParseQuicVersionString("T050")); + EXPECT_EQ(ParsedQuicVersion::T050(), ParseQuicVersionString("h3-T050")); + EXPECT_EQ(ParsedQuicVersion::Draft29(), ParseQuicVersionString("ff00001d")); + EXPECT_EQ(ParsedQuicVersion::Draft29(), ParseQuicVersionString("h3-29")); + EXPECT_EQ(ParsedQuicVersion::Draft27(), ParseQuicVersionString("ff00001b")); + EXPECT_EQ(ParsedQuicVersion::Draft27(), ParseQuicVersionString("h3-27")); + EXPECT_EQ(ParsedQuicVersion::Draft25(), ParseQuicVersionString("ff000019")); + EXPECT_EQ(ParsedQuicVersion::Draft25(), ParseQuicVersionString("h3-25")); } TEST_F(QuicVersionsTest, ParseQuicVersionVectorString) { @@ -266,6 +253,7 @@ TEST_F(QuicVersionsTest, ParseQuicVersionVectorString) { QUIC_VERSION_IETF_DRAFT_25); ParsedQuicVersion version_draft_27(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_27); + ParsedQuicVersion version_draft_29 = ParsedQuicVersion::Draft29(); EXPECT_THAT(ParseQuicVersionVectorString(""), IsEmpty()); @@ -286,6 +274,8 @@ TEST_F(QuicVersionsTest, ParseQuicVersionVectorString) { ElementsAre(version_draft_25, version_draft_27)); EXPECT_THAT(ParseQuicVersionVectorString("h3-27,h3-25"), ElementsAre(version_draft_27, version_draft_25)); + EXPECT_THAT(ParseQuicVersionVectorString("h3-29,h3-27"), + ElementsAre(version_draft_29, version_draft_27)); EXPECT_THAT(ParseQuicVersionVectorString("h3-27,50"), ElementsAre(version_draft_27, version_q050)); @@ -332,22 +322,17 @@ TEST_F(QuicVersionsTest, ParseQuicVersionVectorString) { TEST_F(QuicVersionsTest, CreateQuicVersionLabel) { EXPECT_EQ(MakeVersionLabel('Q', '0', '4', '3'), - CreateQuicVersionLabel( - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43))); + CreateQuicVersionLabel(ParsedQuicVersion::Q043())); EXPECT_EQ(MakeVersionLabel('Q', '0', '4', '6'), - CreateQuicVersionLabel( - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46))); + CreateQuicVersionLabel(ParsedQuicVersion::Q046())); EXPECT_EQ(MakeVersionLabel('Q', '0', '4', '8'), - CreateQuicVersionLabel( - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_48))); + CreateQuicVersionLabel(ParsedQuicVersion::Q048())); EXPECT_EQ(MakeVersionLabel('Q', '0', '5', '0'), - CreateQuicVersionLabel( - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50))); + CreateQuicVersionLabel(ParsedQuicVersion::Q050())); // Test a TLS version: EXPECT_EQ(MakeVersionLabel('T', '0', '5', '0'), - CreateQuicVersionLabel( - ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_50))); + CreateQuicVersionLabel(ParsedQuicVersion::T050())); // Make sure the negotiation reserved version is in the IETF reserved space. EXPECT_EQ(MakeVersionLabel(0xda, 0x5a, 0x3a, 0x3a) & 0x0f0f0f0f, @@ -442,97 +427,29 @@ TEST_F(QuicVersionsTest, ParsedQuicVersionToString) { } TEST_F(QuicVersionsTest, FilterSupportedVersionsAllVersions) { - static_assert(SupportedVersions().size() == 8u, - "Supported versions out of sync"); - SetQuicReloadableFlag(quic_enable_version_draft_27, true); - SetQuicReloadableFlag(quic_enable_version_draft_25_v3, true); - SetQuicReloadableFlag(quic_enable_version_t050_v2, true); - SetQuicReloadableFlag(quic_disable_version_q050, false); - SetQuicReloadableFlag(quic_disable_version_q049, false); - SetQuicReloadableFlag(quic_disable_version_q048, false); - SetQuicReloadableFlag(quic_disable_version_q046, false); - SetQuicReloadableFlag(quic_disable_version_q043, false); - - ParsedQuicVersionVector expected_parsed_versions; - expected_parsed_versions.push_back( - ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_27)); - expected_parsed_versions.push_back( - ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_25)); - expected_parsed_versions.push_back( - ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_50)); - expected_parsed_versions.push_back( - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50)); - expected_parsed_versions.push_back( - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_49)); - expected_parsed_versions.push_back( - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_48)); - expected_parsed_versions.push_back( - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46)); - expected_parsed_versions.push_back( - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43)); - - ASSERT_EQ(expected_parsed_versions, - FilterSupportedVersions(AllSupportedVersions())); - ASSERT_EQ(expected_parsed_versions, AllSupportedVersions()); -} - -TEST_F(QuicVersionsTest, FilterSupportedVersionsNo99) { - static_assert(SupportedVersions().size() == 8u, - "Supported versions out of sync"); - SetQuicReloadableFlag(quic_enable_version_draft_27, false); - SetQuicReloadableFlag(quic_enable_version_draft_25_v3, true); - SetQuicReloadableFlag(quic_enable_version_t050_v2, true); - SetQuicReloadableFlag(quic_disable_version_q050, false); - SetQuicReloadableFlag(quic_disable_version_q049, false); - SetQuicReloadableFlag(quic_disable_version_q048, false); - SetQuicReloadableFlag(quic_disable_version_q046, false); - SetQuicReloadableFlag(quic_disable_version_q043, false); - + for (const ParsedQuicVersion& version : AllSupportedVersions()) { + QuicEnableVersion(version); + } ParsedQuicVersionVector expected_parsed_versions; - expected_parsed_versions.push_back( - ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_25)); - expected_parsed_versions.push_back( - ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_50)); - expected_parsed_versions.push_back( - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50)); - expected_parsed_versions.push_back( - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_49)); - expected_parsed_versions.push_back( - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_48)); - expected_parsed_versions.push_back( - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46)); - expected_parsed_versions.push_back( - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43)); - - ASSERT_EQ(expected_parsed_versions, + for (const ParsedQuicVersion& version : SupportedVersions()) { + expected_parsed_versions.push_back(version); + } + EXPECT_EQ(expected_parsed_versions, FilterSupportedVersions(AllSupportedVersions())); + EXPECT_EQ(expected_parsed_versions, AllSupportedVersions()); } -TEST_F(QuicVersionsTest, FilterSupportedVersionsNoFlags) { - static_assert(SupportedVersions().size() == 8u, - "Supported versions out of sync"); - SetQuicReloadableFlag(quic_enable_version_draft_27, false); - SetQuicReloadableFlag(quic_enable_version_draft_25_v3, false); - SetQuicReloadableFlag(quic_enable_version_t050_v2, false); - SetQuicReloadableFlag(quic_disable_version_q050, false); - SetQuicReloadableFlag(quic_disable_version_q049, false); - SetQuicReloadableFlag(quic_disable_version_q048, false); - SetQuicReloadableFlag(quic_disable_version_q046, false); - SetQuicReloadableFlag(quic_disable_version_q043, false); - +TEST_F(QuicVersionsTest, FilterSupportedVersionsWithoutFirstVersion) { + for (const ParsedQuicVersion& version : AllSupportedVersions()) { + QuicEnableVersion(version); + } + QuicDisableVersion(AllSupportedVersions().front()); ParsedQuicVersionVector expected_parsed_versions; - expected_parsed_versions.push_back( - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50)); - expected_parsed_versions.push_back( - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_49)); - expected_parsed_versions.push_back( - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_48)); - expected_parsed_versions.push_back( - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46)); - expected_parsed_versions.push_back( - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43)); - - ASSERT_EQ(expected_parsed_versions, + for (const ParsedQuicVersion& version : SupportedVersions()) { + expected_parsed_versions.push_back(version); + } + expected_parsed_versions.erase(expected_parsed_versions.begin()); + EXPECT_EQ(expected_parsed_versions, FilterSupportedVersions(AllSupportedVersions())); } @@ -540,10 +457,11 @@ TEST_F(QuicVersionsTest, LookUpVersionByIndex) { QuicTransportVersionVector all_versions = {QUIC_VERSION_43}; int version_count = all_versions.size(); for (int i = -5; i <= version_count + 1; ++i) { + QuicTransportVersionVector index = VersionOfIndex(all_versions, i); if (i >= 0 && i < version_count) { - EXPECT_EQ(all_versions[i], VersionOfIndex(all_versions, i)[0]); + EXPECT_EQ(all_versions[i], index[0]); } else { - EXPECT_EQ(QUIC_VERSION_UNSUPPORTED, VersionOfIndex(all_versions, i)[0]); + EXPECT_EQ(QUIC_VERSION_UNSUPPORTED, index[0]); } } } @@ -552,11 +470,11 @@ TEST_F(QuicVersionsTest, LookUpParsedVersionByIndex) { ParsedQuicVersionVector all_versions = AllSupportedVersions(); int version_count = all_versions.size(); for (int i = -5; i <= version_count + 1; ++i) { + ParsedQuicVersionVector index = ParsedVersionOfIndex(all_versions, i); if (i >= 0 && i < version_count) { - EXPECT_EQ(all_versions[i], ParsedVersionOfIndex(all_versions, i)[0]); + EXPECT_EQ(all_versions[i], index[0]); } else { - EXPECT_EQ(UnsupportedQuicVersion(), - ParsedVersionOfIndex(all_versions, i)[0]); + EXPECT_EQ(UnsupportedQuicVersion(), index[0]); } } } @@ -575,7 +493,7 @@ TEST_F(QuicVersionsTest, ParsedVersionsToTransportVersions) { // yet a typo was made in doing the #defines and it was caught // only in some test far removed from here... Better safe than sorry. TEST_F(QuicVersionsTest, CheckTransportVersionNumbersForTypos) { - static_assert(SupportedTransportVersions().size() == 7u, + static_assert(SupportedTransportVersions().size() == 8u, "Supported versions out of sync"); EXPECT_EQ(QUIC_VERSION_43, 43); EXPECT_EQ(QUIC_VERSION_46, 46); @@ -584,23 +502,18 @@ TEST_F(QuicVersionsTest, CheckTransportVersionNumbersForTypos) { EXPECT_EQ(QUIC_VERSION_50, 50); EXPECT_EQ(QUIC_VERSION_IETF_DRAFT_25, 70); EXPECT_EQ(QUIC_VERSION_IETF_DRAFT_27, 71); + EXPECT_EQ(QUIC_VERSION_IETF_DRAFT_29, 73); } TEST_F(QuicVersionsTest, AlpnForVersion) { - static_assert(SupportedVersions().size() == 8u, + static_assert(SupportedVersions().size() == 9u, "Supported versions out of sync"); - ParsedQuicVersion parsed_version_q048 = - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_48); - ParsedQuicVersion parsed_version_q049 = - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_49); - ParsedQuicVersion parsed_version_q050 = - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50); - ParsedQuicVersion parsed_version_t050 = - ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_50); - ParsedQuicVersion parsed_version_draft_25 = - ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_25); - ParsedQuicVersion parsed_version_draft_27 = - ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_27); + ParsedQuicVersion parsed_version_q048 = ParsedQuicVersion::Q048(); + ParsedQuicVersion parsed_version_q049 = ParsedQuicVersion::Q049(); + ParsedQuicVersion parsed_version_q050 = ParsedQuicVersion::Q050(); + ParsedQuicVersion parsed_version_t050 = ParsedQuicVersion::T050(); + ParsedQuicVersion parsed_version_draft_25 = ParsedQuicVersion::Draft25(); + ParsedQuicVersion parsed_version_draft_27 = ParsedQuicVersion::Draft27(); EXPECT_EQ("h3-Q048", AlpnForVersion(parsed_version_q048)); EXPECT_EQ("h3-Q049", AlpnForVersion(parsed_version_q049)); @@ -608,54 +521,16 @@ TEST_F(QuicVersionsTest, AlpnForVersion) { EXPECT_EQ("h3-T050", AlpnForVersion(parsed_version_t050)); EXPECT_EQ("h3-25", AlpnForVersion(parsed_version_draft_25)); EXPECT_EQ("h3-27", AlpnForVersion(parsed_version_draft_27)); + EXPECT_EQ("h3-29", AlpnForVersion(ParsedQuicVersion::Draft29())); } -TEST_F(QuicVersionsTest, QuicEnableVersion) { - static_assert(SupportedVersions().size() == 8u, - "Supported versions out of sync"); - ParsedQuicVersion parsed_version_draft_27 = - ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_27); - ParsedQuicVersion parsed_version_draft_25 = - ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_25); - ParsedQuicVersion parsed_version_q050 = - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50); - ParsedQuicVersion parsed_version_t050 = - ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_50); - - { - QuicFlagSaver flag_saver; - SetQuicReloadableFlag(quic_enable_version_draft_27, false); - QuicEnableVersion(parsed_version_draft_27); - EXPECT_TRUE(GetQuicReloadableFlag(quic_enable_version_draft_27)); - } - - { - QuicFlagSaver flag_saver; - SetQuicReloadableFlag(quic_enable_version_draft_25_v3, false); - QuicEnableVersion(parsed_version_draft_25); - EXPECT_TRUE(GetQuicReloadableFlag(quic_enable_version_draft_25_v3)); - } - - { - QuicFlagSaver flag_saver; - SetQuicReloadableFlag(quic_disable_version_q050, true); - QuicEnableVersion(parsed_version_q050); - EXPECT_FALSE(GetQuicReloadableFlag(quic_disable_version_q050)); - } - - { - QuicFlagSaver flag_saver; - SetQuicReloadableFlag(quic_enable_version_t050_v2, false); - QuicEnableVersion(parsed_version_t050); - EXPECT_TRUE(GetQuicReloadableFlag(quic_enable_version_t050_v2)); - } - - { +TEST_F(QuicVersionsTest, QuicVersionEnabling) { + for (const ParsedQuicVersion& version : AllSupportedVersions()) { QuicFlagSaver flag_saver; - for (const ParsedQuicVersion& version : SupportedVersions()) { - QuicEnableVersion(version); - } - ASSERT_EQ(AllSupportedVersions(), CurrentSupportedVersions()); + QuicDisableVersion(version); + EXPECT_FALSE(QuicVersionIsEnabled(version)); + QuicEnableVersion(version); + EXPECT_TRUE(QuicVersionIsEnabled(version)); } } @@ -676,7 +551,8 @@ TEST_F(QuicVersionsTest, SupportedVersionsHasCorrectList) { SupportedTransportVersions()) { SCOPED_TRACE(index); if (ParsedQuicVersionIsValid(handshake_protocol, transport_version)) { - EXPECT_EQ(SupportedVersions()[index], + ParsedQuicVersion version = SupportedVersions()[index]; + EXPECT_EQ(version, ParsedQuicVersion(handshake_protocol, transport_version)); index++; } diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_chlo_extractor.h b/chromium/net/third_party/quiche/src/quic/core/tls_chlo_extractor.h index 1762566d70a..b50d2e236ab 100644 --- a/chromium/net/third_party/quiche/src/quic/core/tls_chlo_extractor.h +++ b/chromium/net/third_party/quiche/src/quic/core/tls_chlo_extractor.h @@ -9,6 +9,7 @@ #include <string> #include <vector> #include "third_party/boringssl/src/include/openssl/ssl.h" +#include "net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.h" #include "net/third_party/quiche/src/quic/core/quic_framer.h" #include "net/third_party/quiche/src/quic/core/quic_packets.h" #include "net/third_party/quiche/src/quic/core/quic_stream_sequencer.h" @@ -151,6 +152,9 @@ class QUIC_NO_EXPORT TlsChloExtractor bool OnHandshakeDoneFrame(const QuicHandshakeDoneFrame& /*frame*/) override { return true; } + bool OnAckFrequencyFrame(const QuicAckFrequencyFrame& /*frame*/) override { + return true; + } void OnPacketComplete() override {} bool IsValidStatelessResetToken(QuicUint128 /*token*/) const override { return true; diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_chlo_extractor_test.cc b/chromium/net/third_party/quiche/src/quic/core/tls_chlo_extractor_test.cc index ba57ad02bb9..955e58c0ee6 100644 --- a/chromium/net/third_party/quiche/src/quic/core/tls_chlo_extractor_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/tls_chlo_extractor_test.cc @@ -48,8 +48,9 @@ class TlsChloExtractorTest : public QuicTestWithParam<ParsedQuicVersion> { void ValidateChloDetails() { EXPECT_TRUE(tls_chlo_extractor_.HasParsedFullChlo()); - ASSERT_EQ(tls_chlo_extractor_.alpns().size(), 1u); - EXPECT_EQ(tls_chlo_extractor_.alpns()[0], AlpnForVersion(version_)); + std::vector<std::string> alpns = tls_chlo_extractor_.alpns(); + ASSERT_EQ(alpns.size(), 1u); + EXPECT_EQ(alpns[0], AlpnForVersion(version_)); EXPECT_EQ(tls_chlo_extractor_.server_name(), TestHostname()); } diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.cc b/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.cc index d4e8ed023b1..23a74e4fc28 100644 --- a/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.cc +++ b/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.cc @@ -12,6 +12,7 @@ #include "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h" #include "net/third_party/quiche/src/quic/core/crypto/transport_parameters.h" #include "net/third_party/quiche/src/quic/core/quic_session.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" #include "net/third_party/quiche/src/quic/platform/api/quic_hostname_utils.h" #include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" @@ -67,6 +68,7 @@ TlsClientHandshaker::TlsClientHandshaker( pre_shared_key_(crypto_config->pre_shared_key()), crypto_negotiated_params_(new QuicCryptoNegotiatedParameters), has_application_state_(has_application_state), + attempting_zero_rtt_(crypto_config->early_data_enabled_for_tls()), tls_connection_(crypto_config->ssl_ctx(), this) {} TlsClientHandshaker::~TlsClientHandshaker() { @@ -114,17 +116,16 @@ bool TlsClientHandshaker::CryptoConnect() { } // Set a session to resume, if there is one. + std::unique_ptr<QuicResumptionState> cached_state; if (session_cache_) { - std::unique_ptr<QuicResumptionState> cached_state = - session_cache_->Lookup(server_id_, SSL_get_SSL_CTX(ssl())); - if (cached_state) { - SSL_set_session(ssl(), cached_state->tls_session.get()); - if (GetQuicReloadableFlag(quic_enable_zero_rtt_for_tls) && - VersionHasIetfQuicFrames(session()->transport_version()) && - SSL_SESSION_early_data_capable(cached_state->tls_session.get())) { - if (!PrepareZeroRttConfig(cached_state.get())) { - return false; - } + cached_state = session_cache_->Lookup(server_id_, SSL_get_SSL_CTX(ssl())); + } + if (cached_state) { + SSL_set_session(ssl(), cached_state->tls_session.get()); + if (attempting_zero_rtt_ && + SSL_SESSION_early_data_capable(cached_state->tls_session.get())) { + if (!PrepareZeroRttConfig(cached_state.get())) { + return false; } } } @@ -137,8 +138,8 @@ bool TlsClientHandshaker::CryptoConnect() { bool TlsClientHandshaker::PrepareZeroRttConfig( QuicResumptionState* cached_state) { std::string error_details; - if (session()->config()->ProcessTransportParameters( - *(cached_state->transport_params), SERVER, + if (handshaker_delegate()->ProcessTransportParameters( + *(cached_state->transport_params), /*is_resumption = */ true, &error_details) != QUIC_NO_ERROR) { QUIC_BUG << "Unable to parse cached transport parameters."; CloseConnection(QUIC_HANDSHAKE_FAILED, @@ -148,7 +149,7 @@ bool TlsClientHandshaker::PrepareZeroRttConfig( session()->OnConfigNegotiated(); if (has_application_state_) { - if (!session()->SetApplicationState(cached_state->application_state)) { + if (!session()->ResumeApplicationState(cached_state->application_state)) { QUIC_BUG << "Unable to parse cached application state."; CloseConnection(QUIC_HANDSHAKE_FAILED, "Client failed to parse cached application state."); @@ -204,7 +205,7 @@ bool TlsClientHandshaker::SetTransportParameters() { params.version = CreateQuicVersionLabel(session()->supported_versions().front()); - if (!session()->config()->FillTransportParameters(¶ms)) { + if (!handshaker_delegate()->FillTransportParameters(¶ms)) { return false; } if (GetQuicRestartFlag(quic_google_transport_param_send_new)) { @@ -216,6 +217,9 @@ bool TlsClientHandshaker::SetTransportParameters() { params.google_quic_params->SetStringPiece(kUAID, user_agent_id_); } + // Notify QuicConnectionDebugVisitor. + session()->connection()->OnTransportParametersSent(params); + std::vector<uint8_t> param_bytes; return SerializeTransportParameters(session()->connection()->version(), params, ¶m_bytes) && @@ -244,6 +248,10 @@ bool TlsClientHandshaker::ProcessTransportParameters( return false; } + // Notify QuicConnectionDebugVisitor. + session()->connection()->OnTransportParametersReceived( + *received_transport_params_); + // When interoperating with non-Google implementations that do not send // the version extension, set it to what we expect. if (received_transport_params_->version == 0) { @@ -264,8 +272,8 @@ bool TlsClientHandshaker::ProcessTransportParameters( received_transport_params_->supported_versions, session()->connection()->server_supported_versions(), error_details) != QUIC_NO_ERROR || - session()->config()->ProcessTransportParameters( - *received_transport_params_, SERVER, /* is_resumption = */ false, + handshaker_delegate()->ProcessTransportParameters( + *received_transport_params_, /* is_resumption = */ false, error_details) != QUIC_NO_ERROR) { DCHECK(!error_details->empty()); return false; @@ -378,9 +386,12 @@ void TlsClientHandshaker::SetWriteSecret( if (state_ == STATE_CONNECTION_CLOSED) { return; } - if (level == ENCRYPTION_FORWARD_SECURE) { + if (level == ENCRYPTION_FORWARD_SECURE || level == ENCRYPTION_ZERO_RTT) { encryption_established_ = true; } + if (level == ENCRYPTION_FORWARD_SECURE) { + handshaker_delegate()->DiscardOldEncryptionKey(ENCRYPTION_ZERO_RTT); + } TlsHandshaker::SetWriteSecret(level, cipher, write_secret); } @@ -421,6 +432,10 @@ void TlsClientHandshaker::AdvanceHandshake() { } int ssl_error = SSL_get_error(ssl(), rv); bool should_close = true; + if (ssl_error == SSL_ERROR_EARLY_DATA_REJECTED) { + HandleZeroRttReject(); + return; + } switch (state_) { // TODO(b/153726130): handle the case where the server rejects early data. case STATE_HANDSHAKE_RUNNING: @@ -449,6 +464,15 @@ void TlsClientHandshaker::CloseConnection(QuicErrorCode error, } void TlsClientHandshaker::FinishHandshake() { + if (SSL_in_early_data(ssl())) { + // SSL_do_handshake returns after sending the ClientHello if the session is + // 0-RTT-capable, which means that FinishHandshake will get called twice - + // the first time after sending the ClientHello, and the second time after + // the handshake is complete. If we're in the first time FinishHandshake is + // called, we can't do any end-of-handshake processing, so we return early + // from this function. + return; + } QUIC_LOG(INFO) << "Client: handshake finished"; state_ = STATE_HANDSHAKE_COMPLETE; // Fill crypto_negotiated_params_: @@ -498,6 +522,17 @@ void TlsClientHandshaker::FinishHandshake() { handshaker_delegate()->OnOneRttKeysAvailable(); } +void TlsClientHandshaker::HandleZeroRttReject() { + QUIC_LOG(INFO) << "0-RTT handshake attempted but was rejected by the server"; + DCHECK(session_cache_); + // Disable encrytion to block outgoing data until 1-RTT keys are available. + encryption_established_ = false; + handshaker_delegate()->OnZeroRttRejected(); + SSL_reset_early_data_reject(ssl()); + session_cache_->ClearEarlyData(server_id_); + AdvanceHandshake(); +} + enum ssl_verify_result_t TlsClientHandshaker::VerifyCert(uint8_t* out_alert) { if (verify_result_ != ssl_verify_retry || state_ == STATE_CERT_VERIFY_PENDING) { @@ -584,7 +619,7 @@ void TlsClientHandshaker::WriteMessage(EncryptionLevel level, TlsHandshaker::WriteMessage(level, data); } -void TlsClientHandshaker::OnApplicationState( +void TlsClientHandshaker::SetServerApplicationStateForResumption( std::unique_ptr<ApplicationState> application_state) { DCHECK_EQ(STATE_HANDSHAKE_COMPLETE, state_); received_application_state_ = std::move(application_state); diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.h b/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.h index cc601219dfa..573c055c48c 100644 --- a/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.h +++ b/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.h @@ -71,7 +71,7 @@ class QUIC_EXPORT_PRIVATE TlsClientHandshaker void WriteMessage(EncryptionLevel level, quiche::QuicheStringPiece data) override; - void OnApplicationState( + void SetServerApplicationStateForResumption( std::unique_ptr<ApplicationState> application_state) override; void AllowEmptyAlpnForTests() { allow_empty_alpn_for_tests_ = true; } @@ -124,6 +124,7 @@ class QUIC_EXPORT_PRIVATE TlsClientHandshaker bool SetTransportParameters(); bool ProcessTransportParameters(std::string* error_details); void FinishHandshake(); + void HandleZeroRttReject(); // Called when server completes handshake (i.e., either handshake done is // received or 1-RTT packet gets acknowledged). @@ -175,6 +176,7 @@ class QUIC_EXPORT_PRIVATE TlsClientHandshaker bool allow_invalid_sni_for_tests_ = false; const bool has_application_state_; + bool attempting_zero_rtt_; TlsClientConnection tls_connection_; diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker_test.cc b/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker_test.cc index 68c413fbb63..47989a75f5e 100644 --- a/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker_test.cc @@ -8,13 +8,18 @@ #include "net/third_party/quiche/src/quic/core/crypto/quic_decrypter.h" #include "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h" +#include "net/third_party/quiche/src/quic/core/quic_error_codes.h" #include "net/third_party/quiche/src/quic/core/quic_packets.h" #include "net/third_party/quiche/src/quic/core/quic_server_id.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" #include "net/third_party/quiche/src/quic/core/quic_utils.h" +#include "net/third_party/quiche/src/quic/core/quic_versions.h" #include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h" #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" #include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_framer_peer.h" #include "net/third_party/quiche/src/quic/test_tools/quic_session_peer.h" #include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" #include "net/third_party/quiche/src/quic/test_tools/simple_session_cache.h" @@ -167,13 +172,13 @@ class TlsClientHandshakerTest : public QuicTestWithParam<ParsedQuicVersion> { TlsClientHandshakerTest() : supported_versions_({GetParam()}), server_id_(kServerHostname, kServerPort, false), - crypto_config_(std::make_unique<QuicCryptoClientConfig>( - std::make_unique<TestProofVerifier>(), - std::make_unique<test::SimpleSessionCache>())), server_compressed_certs_cache_( QuicCompressedCertsCache::kQuicCompressedCertsCacheSize) { SetQuicReloadableFlag(quic_enable_tls_resumption, true); SetQuicReloadableFlag(quic_enable_zero_rtt_for_tls, true); + crypto_config_ = std::make_unique<QuicCryptoClientConfig>( + std::make_unique<TestProofVerifier>(), + std::make_unique<test::SimpleSessionCache>()); server_crypto_config_ = crypto_test_utils::CryptoServerConfigForTesting(); CreateConnection(); } @@ -342,6 +347,72 @@ TEST_P(TlsClientHandshakerTest, Resumption) { EXPECT_TRUE(stream()->IsResumption()); } +TEST_P(TlsClientHandshakerTest, ZeroRttResumption) { + // Finish establishing the first connection: + CompleteCryptoHandshake(); + + EXPECT_EQ(PROTOCOL_TLS1_3, stream()->handshake_protocol()); + EXPECT_TRUE(stream()->encryption_established()); + EXPECT_TRUE(stream()->one_rtt_keys_available()); + EXPECT_FALSE(stream()->IsResumption()); + + // Create a second connection + CreateConnection(); + CompleteCryptoHandshake(); + + // TODO(b/152551499): Add a test that checks we have keys after calling + // stream()->CryptoConnect(). + EXPECT_EQ(PROTOCOL_TLS1_3, stream()->handshake_protocol()); + EXPECT_TRUE(stream()->encryption_established()); + EXPECT_TRUE(stream()->one_rtt_keys_available()); + EXPECT_TRUE(stream()->IsResumption()); + EXPECT_TRUE(stream()->EarlyDataAccepted()); +} + +// TODO(b/152551499): Also test resumption getting rejected. +TEST_P(TlsClientHandshakerTest, ZeroRttRejection) { + // Finish establishing the first connection: + CompleteCryptoHandshake(); + + EXPECT_EQ(PROTOCOL_TLS1_3, stream()->handshake_protocol()); + EXPECT_TRUE(stream()->encryption_established()); + EXPECT_TRUE(stream()->one_rtt_keys_available()); + EXPECT_FALSE(stream()->IsResumption()); + + // Create a second connection, but disable 0-RTT on the server. + SSL_CTX_set_early_data_enabled(server_crypto_config_->ssl_ctx(), false); + CreateConnection(); + + // 4 packets will be sent in this connection: initial handshake packet, 0-RTT + // packet containing SETTINGS, handshake packet upon 0-RTT rejection, 0-RTT + // packet retransmission. + EXPECT_CALL(*connection_, + OnPacketSent(ENCRYPTION_INITIAL, NOT_RETRANSMISSION)); + if (VersionUsesHttp3(session_->transport_version())) { + EXPECT_CALL(*connection_, + OnPacketSent(ENCRYPTION_ZERO_RTT, NOT_RETRANSMISSION)); + } + EXPECT_CALL(*connection_, + OnPacketSent(ENCRYPTION_HANDSHAKE, NOT_RETRANSMISSION)); + if (VersionUsesHttp3(session_->transport_version())) { + // TODO(b/158027651): change transmission type to + // ALL_ZERO_RTT_RETRANSMISSION. + EXPECT_CALL(*connection_, + OnPacketSent(ENCRYPTION_FORWARD_SECURE, LOSS_RETRANSMISSION)); + } + + CompleteCryptoHandshake(); + + QuicFramer* framer = QuicConnectionPeer::GetFramer(connection_); + EXPECT_EQ(nullptr, QuicFramerPeer::GetEncrypter(framer, ENCRYPTION_ZERO_RTT)); + + EXPECT_EQ(PROTOCOL_TLS1_3, stream()->handshake_protocol()); + EXPECT_TRUE(stream()->encryption_established()); + EXPECT_TRUE(stream()->one_rtt_keys_available()); + EXPECT_TRUE(stream()->IsResumption()); + EXPECT_FALSE(stream()->EarlyDataAccepted()); +} + TEST_P(TlsClientHandshakerTest, ClientSendsNoSNI) { // Reconfigure client to sent an empty server hostname. The crypto config also // needs to be recreated to use a FakeProofVerifier since the server's cert @@ -423,7 +494,6 @@ TEST_P(TlsClientHandshakerTest, BadTransportParams) { if (!connection_->version().UsesHttp3()) { return; } - SetQuicReloadableFlag(quic_notify_handshaker_on_connection_close, true); // Finish establishing the first connection: CompleteCryptoHandshake(); @@ -438,7 +508,8 @@ TEST_P(TlsClientHandshakerTest, BadTransportParams) { config.SetMaxBidirectionalStreamsToSend( config.GetMaxBidirectionalStreamsToSend() - 1); - EXPECT_CALL(*connection_, CloseConnection(QUIC_MAX_STREAMS_ERROR, _, _)) + EXPECT_CALL(*connection_, + CloseConnection(QUIC_ZERO_RTT_REJECTION_LIMIT_REDUCED, _, _)) .WillOnce(testing::Invoke(connection_, &MockQuicConnection::ReallyCloseConnection)); // Close connection will be called again in the handshaker, but this will be diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_handshaker_test.cc b/chromium/net/third_party/quiche/src/quic/core/tls_handshaker_test.cc index 5a2bd6400aa..caf9a9c6b1b 100644 --- a/chromium/net/third_party/quiche/src/quic/core/tls_handshaker_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/tls_handshaker_test.cc @@ -192,6 +192,8 @@ class TestQuicCryptoStream : public QuicCryptoStream { HandshakeState GetHandshakeState() const override { return handshaker()->GetHandshakeState(); } + void SetServerApplicationStateForResumption( + std::unique_ptr<ApplicationState> /*application_state*/) override {} const std::vector<std::pair<std::string, EncryptionLevel>>& pending_writes() { return pending_writes_; diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.cc b/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.cc index 5bd5b3d642d..69b523723d8 100644 --- a/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.cc +++ b/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.cc @@ -13,7 +13,9 @@ #include "net/third_party/quiche/src/quic/core/crypto/transport_parameters.h" #include "net/third_party/quiche/src/quic/platform/api/quic_hostname_utils.h" #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_arraysize.h" #include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_text_utils.h" namespace quic { @@ -123,8 +125,15 @@ void TlsServerHandshaker::SendServerConfigUpdate( } bool TlsServerHandshaker::IsZeroRtt() const { - // TODO(nharper): Support 0-RTT with TLS 1.3 in QUIC. - return false; + return SSL_early_data_accepted(ssl()); +} + +bool TlsServerHandshaker::IsResumption() const { + return SSL_session_reused(ssl()); +} + +bool TlsServerHandshaker::ResumptionAttempted() const { + return ticket_received_; } int TlsServerHandshaker::NumServerConfigUpdateMessagesSent() const { @@ -137,11 +146,6 @@ TlsServerHandshaker::PreviousCachedNetworkParams() const { return nullptr; } -bool TlsServerHandshaker::ZeroRttAttempted() const { - // TODO(nharper): Support 0-RTT with TLS 1.3 in QUIC. - return false; -} - void TlsServerHandshaker::SetPreviousCachedNetworkParams( CachedNetworkParameters /*cached_network_params*/) {} @@ -194,6 +198,11 @@ HandshakeState TlsServerHandshaker::GetHandshakeState() const { return HANDSHAKE_START; } +void TlsServerHandshaker::SetServerApplicationStateForResumption( + std::unique_ptr<ApplicationState> state) { + application_state_ = std::move(state); +} + size_t TlsServerHandshaker::BufferSizeLimitForLevel( EncryptionLevel level) const { return TlsHandshaker::BufferSizeLimitForLevel(level); @@ -201,19 +210,6 @@ size_t TlsServerHandshaker::BufferSizeLimitForLevel( void TlsServerHandshaker::OverrideQuicConfigDefaults(QuicConfig* /*config*/) {} -bool TlsServerHandshaker::SetReadSecret( - EncryptionLevel level, - const SSL_CIPHER* cipher, - const std::vector<uint8_t>& read_secret) { - if (level != ENCRYPTION_FORWARD_SECURE || one_rtt_keys_available_) { - return TlsHandshaker::SetReadSecret(level, cipher, read_secret); - } - // Delay setting read secret for ENCRYPTION_FORWARD_SECURE until handshake - // completes. - app_data_read_secret_ = read_secret; - return true; -} - void TlsServerHandshaker::AdvanceHandshake() { if (state_ == STATE_CONNECTION_CLOSED) { QUIC_LOG(INFO) << "TlsServerHandshaker received handshake message after " @@ -248,8 +244,8 @@ void TlsServerHandshaker::AdvanceHandshake() { should_close = true; } if (should_close && state_ != STATE_CONNECTION_CLOSED) { - QUIC_LOG(WARNING) << "SSL_do_handshake failed; SSL_get_error returns " - << ssl_error << ", state_ = " << state_; + QUIC_VLOG(1) << "SSL_do_handshake failed; SSL_get_error returns " + << ssl_error << ", state_ = " << state_; ERR_print_errors_fp(stderr); CloseConnection(QUIC_HANDSHAKE_FAILED, "Server observed TLS handshake failure"); @@ -284,6 +280,9 @@ bool TlsServerHandshaker::ProcessTransportParameters( return false; } + // Notify QuicConnectionDebugVisitor. + session()->connection()->OnTransportParametersReceived(client_params); + // When interoperating with non-Google implementations that do not send // the version extension, set it to what we expect. if (client_params.version == 0) { @@ -294,12 +293,26 @@ bool TlsServerHandshaker::ProcessTransportParameters( if (CryptoUtils::ValidateClientHelloVersion( client_params.version, session()->connection()->version(), session()->supported_versions(), error_details) != QUIC_NO_ERROR || - session()->config()->ProcessTransportParameters( - client_params, CLIENT, /* is_resumption = */ false, error_details) != + handshaker_delegate()->ProcessTransportParameters( + client_params, /* is_resumption = */ false, error_details) != QUIC_NO_ERROR) { return false; } ProcessAdditionalTransportParameters(client_params); + if (GetQuicReloadableFlag(quic_save_user_agent_in_quic_session) && + !session()->user_agent_id().has_value()) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_save_user_agent_in_quic_session, 2, 3); + + if (client_params.user_agent_id.has_value()) { + session()->SetUserAgentId(client_params.user_agent_id.value()); + } else if (client_params.google_quic_params) { + quiche::QuicheStringPiece user_agent_id; + client_params.google_quic_params->GetStringPiece(kUAID, &user_agent_id); + if (!user_agent_id.empty()) { + session()->SetUserAgentId(user_agent_id.data()); + } + } + } return true; } @@ -312,12 +325,13 @@ bool TlsServerHandshaker::SetTransportParameters() { server_params.version = CreateQuicVersionLabel(session()->connection()->version()); - if (!session()->config()->FillTransportParameters(&server_params)) { + if (!handshaker_delegate()->FillTransportParameters(&server_params)) { return false; } - // TODO(nharper): Provide an actual value for the stateless reset token. - server_params.stateless_reset_token.resize(16); + // Notify QuicConnectionDebugVisitor. + session()->connection()->OnTransportParametersSent(server_params); + std::vector<uint8_t> server_params_bytes; if (!SerializeTransportParameters(session()->connection()->version(), server_params, &server_params_bytes) || @@ -325,6 +339,17 @@ bool TlsServerHandshaker::SetTransportParameters() { server_params_bytes.size()) != 1) { return false; } + if (application_state_) { + std::vector<uint8_t> early_data_context; + if (!SerializeTransportParametersForTicket( + server_params, *application_state_, &early_data_context)) { + QUIC_BUG << "Failed to serialize Transport Parameters for ticket."; + return false; + } + SSL_set_quic_early_data_context(ssl(), early_data_context.data(), + early_data_context.size()); + application_state_.reset(nullptr); + } return true; } @@ -332,8 +357,7 @@ void TlsServerHandshaker::SetWriteSecret( EncryptionLevel level, const SSL_CIPHER* cipher, const std::vector<uint8_t>& write_secret) { - if (GetQuicReloadableFlag(quic_notify_handshaker_on_connection_close) && - state_ == STATE_CONNECTION_CLOSED) { + if (state_ == STATE_CONNECTION_CLOSED) { return; } if (level == ENCRYPTION_FORWARD_SECURE) { @@ -349,6 +373,16 @@ void TlsServerHandshaker::SetWriteSecret( } void TlsServerHandshaker::FinishHandshake() { + if (SSL_in_early_data(ssl())) { + // If the server accepts early data, SSL_do_handshake returns success twice: + // once after processing the ClientHello and sending the server's first + // flight, and then again after the handshake is complete. This results in + // FinishHandshake getting called twice. On the first call to + // FinishHandshake, we don't have any confirmation that the client is live, + // so all end of handshake processing is deferred until the handshake is + // actually complete. + return; + } if (!valid_alpn_received_) { QUIC_DLOG(ERROR) << "Server: handshake finished without receiving a known ALPN"; @@ -363,21 +397,10 @@ void TlsServerHandshaker::FinishHandshake() { state_ = STATE_HANDSHAKE_COMPLETE; one_rtt_keys_available_ = true; - const SSL_CIPHER* cipher = SSL_get_current_cipher(ssl()); - - if (!app_data_read_secret_.empty()) { - if (!SetReadSecret(ENCRYPTION_FORWARD_SECURE, cipher, - app_data_read_secret_)) { - QUIC_BUG << "Failed to set forward secure read key."; - CloseConnection(QUIC_HANDSHAKE_FAILED, "Failed to set app data read key"); - return; - } - app_data_read_secret_.clear(); - } - handshaker_delegate()->OnOneRttKeysAvailable(); handshaker_delegate()->DiscardOldEncryptionKey(ENCRYPTION_HANDSHAKE); handshaker_delegate()->DiscardOldDecryptionKey(ENCRYPTION_HANDSHAKE); + handshaker_delegate()->DiscardOldDecryptionKey(ENCRYPTION_ZERO_RTT); } ssl_private_key_result_t TlsServerHandshaker::PrivateKeySign( @@ -446,6 +469,7 @@ ssl_ticket_aead_result_t TlsServerHandshaker::SessionTicketOpen( DCHECK(proof_source_->GetTicketCrypter()); if (!ticket_decryption_callback_) { + ticket_received_ = true; ticket_decryption_callback_ = new DecryptCallback(this); proof_source_->GetTicketCrypter()->Decrypt( in, std::unique_ptr<DecryptCallback>(ticket_decryption_callback_)); diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.h b/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.h index c62dbbbe47c..13b734e3a78 100644 --- a/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.h +++ b/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.h @@ -40,9 +40,10 @@ class QUIC_EXPORT_PRIVATE TlsServerHandshaker void SendServerConfigUpdate( const CachedNetworkParameters* cached_network_params) override; bool IsZeroRtt() const override; + bool IsResumption() const override; + bool ResumptionAttempted() const override; int NumServerConfigUpdateMessagesSent() const override; const CachedNetworkParameters* PreviousCachedNetworkParams() const override; - bool ZeroRttAttempted() const override; void SetPreviousCachedNetworkParams( CachedNetworkParameters cached_network_params) override; void OnPacketDecrypted(EncryptionLevel level) override; @@ -60,6 +61,8 @@ class QUIC_EXPORT_PRIVATE TlsServerHandshaker const override; CryptoMessageParser* crypto_message_parser() override; HandshakeState GetHandshakeState() const override; + void SetServerApplicationStateForResumption( + std::unique_ptr<ApplicationState> state) override; size_t BufferSizeLimitForLevel(EncryptionLevel level) const override; void SetWriteSecret(EncryptionLevel level, const SSL_CIPHER* cipher, @@ -81,13 +84,6 @@ class QUIC_EXPORT_PRIVATE TlsServerHandshaker virtual void ProcessAdditionalTransportParameters( const TransportParameters& /*params*/) {} - // Override of TlsHandshaker::SetReadSecret so that setting the read secret - // for ENCRYPTION_FORWARD_SECURE can be delayed until the handshake is - // complete. - bool SetReadSecret(EncryptionLevel level, - const SSL_CIPHER* cipher, - const std::vector<uint8_t>& read_secret) override; - // Called when a new message is received on the crypto stream and is available // for the TLS stack to read. void AdvanceHandshake() override; @@ -181,19 +177,21 @@ class QUIC_EXPORT_PRIVATE TlsServerHandshaker // |decrypted_session_ticket_| contains the decrypted session ticket after the // callback has run but before it is passed to BoringSSL. std::vector<uint8_t> decrypted_session_ticket_; + // |ticket_received_| tracks whether we received a resumption ticket from the + // client. It does not matter whether we were able to decrypt said ticket or + // if we actually resumed a session with it - the presence of this ticket + // indicates that the client attempted a resumption. + bool ticket_received_ = false; std::string hostname_; std::string cert_verify_sig_; std::unique_ptr<ProofSource::Details> proof_source_details_; + std::unique_ptr<ApplicationState> application_state_; + // Pre-shared key used during the handshake. std::string pre_shared_key_; - // Used to hold the ENCRYPTION_FORWARD_SECURE read secret until the handshake - // is complete. This is temporary until - // https://bugs.chromium.org/p/boringssl/issues/detail?id=303 is resolved. - std::vector<uint8_t> app_data_read_secret_; - bool encryption_established_ = false; bool one_rtt_keys_available_ = false; bool valid_alpn_received_ = false; diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker_test.cc b/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker_test.cc index a71338c5f5b..70550fcb21d 100644 --- a/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker_test.cc @@ -47,9 +47,12 @@ class TlsServerHandshakerTest : public QuicTest { TlsServerHandshakerTest() : server_compressed_certs_cache_( QuicCompressedCertsCache::kQuicCompressedCertsCacheSize), - server_id_(kServerHostname, kServerPort, false), - client_crypto_config_(crypto_test_utils::ProofVerifierForTesting(), - std::make_unique<test::SimpleSessionCache>()) { + server_id_(kServerHostname, kServerPort, false) { + SetQuicReloadableFlag(quic_enable_tls_resumption, true); + SetQuicReloadableFlag(quic_enable_zero_rtt_for_tls, true); + client_crypto_config_ = std::make_unique<QuicCryptoClientConfig>( + crypto_test_utils::ProofVerifierForTesting(), + std::make_unique<test::SimpleSessionCache>()); InitializeServerConfig(); InitializeServer(); InitializeFakeClient(); @@ -65,7 +68,6 @@ class TlsServerHandshakerTest : public QuicTest { } void InitializeServerConfig() { - SetQuicReloadableFlag(quic_enable_tls_resumption, true); auto ticket_crypter = std::make_unique<TestTicketCrypter>(); ticket_crypter_ = ticket_crypter.get(); auto proof_source = std::make_unique<FakeProofSource>(); @@ -126,7 +128,7 @@ class TlsServerHandshakerTest : public QuicTest { CreateClientSessionForTest( server_id_, QuicTime::Delta::FromSeconds(100000), supported_versions_, helpers_.back().get(), alarm_factories_.back().get(), - &client_crypto_config_, &client_connection_, &client_session); + client_crypto_config_.get(), &client_connection_, &client_session); const std::string default_alpn = AlpnForVersion(client_connection_->version()); ON_CALL(*client_session, GetAlpnsToOffer()) @@ -212,7 +214,7 @@ class TlsServerHandshakerTest : public QuicTest { // Client state. PacketSavingConnection* client_connection_; - QuicCryptoClientConfig client_crypto_config_; + std::unique_ptr<QuicCryptoClientConfig> client_crypto_config_; std::unique_ptr<TestQuicSpdyClientSession> client_session_; crypto_test_utils::FakeClientOptions client_options_; @@ -383,6 +385,8 @@ TEST_F(TlsServerHandshakerTest, Resumption) { CompleteCryptoHandshake(); ExpectHandshakeSuccessful(); EXPECT_FALSE(client_stream()->IsResumption()); + EXPECT_FALSE(server_stream()->IsResumption()); + EXPECT_FALSE(server_stream()->ResumptionAttempted()); // Now do another handshake InitializeServer(); @@ -390,6 +394,8 @@ TEST_F(TlsServerHandshakerTest, Resumption) { CompleteCryptoHandshake(); ExpectHandshakeSuccessful(); EXPECT_TRUE(client_stream()->IsResumption()); + EXPECT_TRUE(server_stream()->IsResumption()); + EXPECT_TRUE(server_stream()->ResumptionAttempted()); } TEST_F(TlsServerHandshakerTest, ResumptionWithAsyncDecryptCallback) { @@ -411,6 +417,8 @@ TEST_F(TlsServerHandshakerTest, ResumptionWithAsyncDecryptCallback) { CompleteCryptoHandshake(); ExpectHandshakeSuccessful(); EXPECT_TRUE(client_stream()->IsResumption()); + EXPECT_TRUE(server_stream()->IsResumption()); + EXPECT_TRUE(server_stream()->ResumptionAttempted()); } TEST_F(TlsServerHandshakerTest, ResumptionWithFailingDecryptCallback) { @@ -426,6 +434,8 @@ TEST_F(TlsServerHandshakerTest, ResumptionWithFailingDecryptCallback) { CompleteCryptoHandshake(); ExpectHandshakeSuccessful(); EXPECT_FALSE(client_stream()->IsResumption()); + EXPECT_FALSE(server_stream()->IsResumption()); + EXPECT_TRUE(server_stream()->ResumptionAttempted()); } TEST_F(TlsServerHandshakerTest, ResumptionWithFailingAsyncDecryptCallback) { @@ -448,6 +458,8 @@ TEST_F(TlsServerHandshakerTest, ResumptionWithFailingAsyncDecryptCallback) { CompleteCryptoHandshake(); ExpectHandshakeSuccessful(); EXPECT_FALSE(client_stream()->IsResumption()); + EXPECT_FALSE(server_stream()->IsResumption()); + EXPECT_TRUE(server_stream()->ResumptionAttempted()); } TEST_F(TlsServerHandshakerTest, HandshakeFailsWithFailingProofSource) { @@ -462,6 +474,53 @@ TEST_F(TlsServerHandshakerTest, HandshakeFailsWithFailingProofSource) { EXPECT_EQ(moved_messages_counts_.second, 0u); } +TEST_F(TlsServerHandshakerTest, ZeroRttResumption) { + std::vector<uint8_t> application_state = {0, 1, 2, 3}; + + // Do the first handshake + server_stream()->SetServerApplicationStateForResumption( + std::make_unique<ApplicationState>(application_state)); + InitializeFakeClient(); + CompleteCryptoHandshake(); + ExpectHandshakeSuccessful(); + EXPECT_FALSE(client_stream()->IsResumption()); + EXPECT_FALSE(server_stream()->IsZeroRtt()); + + // Now do another handshake + InitializeServer(); + server_stream()->SetServerApplicationStateForResumption( + std::make_unique<ApplicationState>(application_state)); + InitializeFakeClient(); + CompleteCryptoHandshake(); + ExpectHandshakeSuccessful(); + EXPECT_TRUE(client_stream()->IsResumption()); + EXPECT_TRUE(server_stream()->IsZeroRtt()); +} + +TEST_F(TlsServerHandshakerTest, ZeroRttRejectOnApplicationStateChange) { + std::vector<uint8_t> original_application_state = {1, 2}; + std::vector<uint8_t> new_application_state = {3, 4}; + + // Do the first handshake + server_stream()->SetServerApplicationStateForResumption( + std::make_unique<ApplicationState>(original_application_state)); + InitializeFakeClient(); + CompleteCryptoHandshake(); + ExpectHandshakeSuccessful(); + EXPECT_FALSE(client_stream()->IsResumption()); + EXPECT_FALSE(server_stream()->IsZeroRtt()); + + // Do another handshake, but change the application state + InitializeServer(); + server_stream()->SetServerApplicationStateForResumption( + std::make_unique<ApplicationState>(new_application_state)); + InitializeFakeClient(); + CompleteCryptoHandshake(); + ExpectHandshakeSuccessful(); + EXPECT_TRUE(client_stream()->IsResumption()); + EXPECT_FALSE(server_stream()->IsZeroRtt()); +} + } // namespace } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.cc b/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.cc index 6951b2cea3f..2f33594e042 100644 --- a/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.cc +++ b/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.cc @@ -17,7 +17,8 @@ UberQuicStreamIdManager::UberQuicStreamIdManager( QuicStreamCount max_open_outgoing_unidirectional_streams, QuicStreamCount max_open_incoming_bidirectional_streams, QuicStreamCount max_open_incoming_unidirectional_streams) - : bidirectional_stream_id_manager_(delegate, + : version_(version), + bidirectional_stream_id_manager_(delegate, /*unidirectional=*/false, perspective, version, @@ -69,7 +70,7 @@ QuicStreamId UberQuicStreamIdManager::GetNextOutgoingUnidirectionalStreamId() { bool UberQuicStreamIdManager::MaybeIncreaseLargestPeerStreamId( QuicStreamId id, std::string* error_details) { - if (QuicUtils::IsBidirectionalStreamId(id)) { + if (QuicUtils::IsBidirectionalStreamId(id, version_)) { return bidirectional_stream_id_manager_.MaybeIncreaseLargestPeerStreamId( id, error_details); } @@ -78,7 +79,7 @@ bool UberQuicStreamIdManager::MaybeIncreaseLargestPeerStreamId( } void UberQuicStreamIdManager::OnStreamClosed(QuicStreamId id) { - if (QuicUtils::IsBidirectionalStreamId(id)) { + if (QuicUtils::IsBidirectionalStreamId(id, version_)) { bidirectional_stream_id_manager_.OnStreamClosed(id); return; } @@ -97,7 +98,7 @@ bool UberQuicStreamIdManager::OnStreamsBlockedFrame( } bool UberQuicStreamIdManager::IsAvailableStream(QuicStreamId id) const { - if (QuicUtils::IsBidirectionalStreamId(id)) { + if (QuicUtils::IsBidirectionalStreamId(id, version_)) { return bidirectional_stream_id_manager_.IsAvailableStream(id); } return unidirectional_stream_id_manager_.IsAvailableStream(id); @@ -162,4 +163,14 @@ UberQuicStreamIdManager::advertised_max_incoming_unidirectional_streams() return unidirectional_stream_id_manager_.incoming_advertised_max_streams(); } +QuicStreamCount UberQuicStreamIdManager::outgoing_bidirectional_stream_count() + const { + return bidirectional_stream_id_manager_.outgoing_stream_count(); +} + +QuicStreamCount UberQuicStreamIdManager::outgoing_unidirectional_stream_count() + const { + return unidirectional_stream_id_manager_.outgoing_stream_count(); +} + } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.h b/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.h index b1fc1260987..0e03b42c8d6 100644 --- a/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.h +++ b/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager.h @@ -87,10 +87,14 @@ class QUIC_EXPORT_PRIVATE UberQuicStreamIdManager { QuicStreamCount advertised_max_incoming_bidirectional_streams() const; QuicStreamCount advertised_max_incoming_unidirectional_streams() const; + QuicStreamCount outgoing_bidirectional_stream_count() const; + QuicStreamCount outgoing_unidirectional_stream_count() const; + private: friend class test::QuicSessionPeer; friend class test::UberQuicStreamIdManagerPeer; + ParsedQuicVersion version_; // Manages stream IDs of bidirectional streams. QuicStreamIdManager bidirectional_stream_id_manager_; diff --git a/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager_test.cc b/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager_test.cc index 7cae0a6e1de..b3dfedcf71f 100644 --- a/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/uber_quic_stream_id_manager_test.cc @@ -287,18 +287,32 @@ TEST_P(UberQuicStreamIdManagerTest, OnStreamsBlockedFrame) { QuicStreamsBlockedFrame frame(kInvalidControlFrameId, stream_count, /*unidirectional=*/false); - EXPECT_CALL(delegate_, - SendMaxStreams(manager_.max_incoming_bidirectional_streams(), - frame.unidirectional)); + if (GetQuicReloadableFlag(quic_stop_sending_duplicate_max_streams)) { + EXPECT_CALL(delegate_, + SendMaxStreams(manager_.max_incoming_bidirectional_streams(), + frame.unidirectional)) + .Times(0); + } else { + EXPECT_CALL(delegate_, + SendMaxStreams(manager_.max_incoming_bidirectional_streams(), + frame.unidirectional)); + } EXPECT_TRUE(manager_.OnStreamsBlockedFrame(frame, nullptr)); stream_count = manager_.advertised_max_incoming_unidirectional_streams() - 1; frame.stream_count = stream_count; frame.unidirectional = true; - EXPECT_CALL(delegate_, - SendMaxStreams(manager_.max_incoming_unidirectional_streams(), - frame.unidirectional)); + if (GetQuicReloadableFlag(quic_stop_sending_duplicate_max_streams)) { + EXPECT_CALL(delegate_, + SendMaxStreams(manager_.max_incoming_unidirectional_streams(), + frame.unidirectional)) + .Times(0); + } else { + EXPECT_CALL(delegate_, + SendMaxStreams(manager_.max_incoming_unidirectional_streams(), + frame.unidirectional)); + } EXPECT_TRUE(manager_.OnStreamsBlockedFrame(frame, nullptr)); } diff --git a/chromium/net/third_party/quiche/src/quic/masque/masque_encapsulated_epoll_client.cc b/chromium/net/third_party/quiche/src/quic/masque/masque_encapsulated_epoll_client.cc index 7c9749aa374..1f3986284ac 100644 --- a/chromium/net/third_party/quiche/src/quic/masque/masque_encapsulated_epoll_client.cc +++ b/chromium/net/third_party/quiche/src/quic/masque/masque_encapsulated_epoll_client.cc @@ -47,10 +47,10 @@ class MasquePacketWriter : public QuicPacketWriter { bool SupportsReleaseTime() const override { return false; } bool IsBatchMode() const override { return false; } - char* GetNextWriteLocation( + QuicPacketBuffer GetNextWriteLocation( const QuicIpAddress& /*self_address*/, const QuicSocketAddress& /*peer_address*/) override { - return nullptr; + return {nullptr, nullptr}; } WriteResult Flush() override { return WriteResult(WRITE_STATUS_OK, 0); } diff --git a/chromium/net/third_party/quiche/src/quic/qbone/qbone_client_session.cc b/chromium/net/third_party/quiche/src/quic/qbone/qbone_client_session.cc index 52ba763118f..98d8a51faa7 100644 --- a/chromium/net/third_party/quiche/src/quic/qbone/qbone_client_session.cc +++ b/chromium/net/third_party/quiche/src/quic/qbone/qbone_client_session.cc @@ -94,8 +94,7 @@ void QboneClientSession::OnProofVerifyDetailsAvailable( const ProofVerifyDetails& verify_details) {} bool QboneClientSession::HasActiveRequests() const { - return (stream_map().size() - num_incoming_static_streams() - - num_outgoing_static_streams()) > 0; + return (stream_map().size() - num_static_streams()) > 0; } } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/qbone/qbone_client_test.cc b/chromium/net/third_party/quiche/src/quic/qbone/qbone_client_test.cc index cdb611c9209..91be62a3c6c 100644 --- a/chromium/net/third_party/quiche/src/quic/qbone/qbone_client_test.cc +++ b/chromium/net/third_party/quiche/src/quic/qbone/qbone_client_test.cc @@ -139,13 +139,6 @@ class QuicQboneDispatcher : public QuicDispatcher { return session; } - QuicConnectionId GenerateNewServerConnectionId( - ParsedQuicVersion version, - QuicConnectionId connection_id) const override { - char connection_id_bytes[kQuicDefaultConnectionIdLength] = {}; - return QuicConnectionId(connection_id_bytes, sizeof(connection_id_bytes)); - } - private: QbonePacketWriter* writer_; }; @@ -248,7 +241,7 @@ TEST_P(QboneClientTest, SendDataFromClient) { crypto_test_utils::ProofVerifierForTesting()); ASSERT_TRUE(client.Initialize()); ASSERT_TRUE(client.Connect()); - ASSERT_TRUE(client.WaitForCryptoHandshakeConfirmed()); + ASSERT_TRUE(client.WaitForOneRttKeysAvailable()); client.SendData(TestPacketIn("hello")); client.SendData(TestPacketIn("world")); client.WaitForWriteToFlush(); diff --git a/chromium/net/third_party/quiche/src/quic/qbone/qbone_stream_test.cc b/chromium/net/third_party/quiche/src/quic/qbone/qbone_stream_test.cc index 10edaf6650d..976847de5f1 100644 --- a/chromium/net/third_party/quiche/src/quic/qbone/qbone_stream_test.cc +++ b/chromium/net/third_party/quiche/src/quic/qbone/qbone_stream_test.cc @@ -131,9 +131,10 @@ class DummyPacketWriter : public QuicPacketWriter { bool IsBatchMode() const override { return false; } - char* GetNextWriteLocation(const QuicIpAddress& self_address, - const QuicSocketAddress& peer_address) override { - return nullptr; + QuicPacketBuffer GetNextWriteLocation( + const QuicIpAddress& self_address, + const QuicSocketAddress& peer_address) override { + return {nullptr, nullptr}; } WriteResult Flush() override { return WriteResult(WRITE_STATUS_OK, 0); } diff --git a/chromium/net/third_party/quiche/src/quic/quartc/counting_packet_filter.h b/chromium/net/third_party/quiche/src/quic/quartc/counting_packet_filter.h deleted file mode 100644 index 4c7c27041ba..00000000000 --- a/chromium/net/third_party/quiche/src/quic/quartc/counting_packet_filter.h +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef QUICHE_QUIC_QUARTC_COUNTING_PACKET_FILTER_H_ -#define QUICHE_QUIC_QUARTC_COUNTING_PACKET_FILTER_H_ - -#include <string> - -#include "net/third_party/quiche/src/quic/test_tools/simulator/packet_filter.h" -#include "net/third_party/quiche/src/quic/test_tools/simulator/port.h" -#include "net/third_party/quiche/src/quic/test_tools/simulator/simulator.h" - -namespace quic { -namespace simulator { - -// Simple packet filter which drops the first N packets it observes. -class CountingPacketFilter : public simulator::PacketFilter { - public: - CountingPacketFilter(simulator::Simulator* simulator, - const std::string& name, - simulator::Endpoint* endpoint) - : PacketFilter(simulator, name, endpoint) {} - - void set_packets_to_drop(int count) { packets_to_drop_ = count; } - - protected: - bool FilterPacket(const simulator::Packet& /*packet*/) override { - if (packets_to_drop_ > 0) { - --packets_to_drop_; - return false; - } - return true; - } - - private: - int packets_to_drop_ = 0; -}; - -} // namespace simulator -} // namespace quic - -#endif // QUICHE_QUIC_QUARTC_COUNTING_PACKET_FILTER_H_ diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_connection_helper.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_connection_helper.cc deleted file mode 100644 index da74858d69b..00000000000 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_connection_helper.cc +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/quiche/src/quic/quartc/quartc_connection_helper.h" - -namespace quic { - -QuartcConnectionHelper::QuartcConnectionHelper(const QuicClock* clock, - QuicRandom* random) - : clock_(clock), random_(random) {} - -const QuicClock* QuartcConnectionHelper::GetClock() const { - return clock_; -} - -QuicRandom* QuartcConnectionHelper::GetRandomGenerator() { - return random_; -} - -QuicBufferAllocator* QuartcConnectionHelper::GetStreamSendBufferAllocator() { - return &buffer_allocator_; -} - -} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_connection_helper.h b/chromium/net/third_party/quiche/src/quic/quartc/quartc_connection_helper.h deleted file mode 100644 index 72cc707aced..00000000000 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_connection_helper.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef QUICHE_QUIC_QUARTC_QUARTC_CONNECTION_HELPER_H_ -#define QUICHE_QUIC_QUARTC_QUARTC_CONNECTION_HELPER_H_ - -#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h" -#include "net/third_party/quiche/src/quic/core/quic_buffer_allocator.h" -#include "net/third_party/quiche/src/quic/core/quic_clock.h" -#include "net/third_party/quiche/src/quic/core/quic_connection.h" -#include "net/third_party/quiche/src/quic/core/quic_simple_buffer_allocator.h" - -namespace quic { - -// Simple implementation of QuicConnectionHelperInterface for Quartc. -class QuartcConnectionHelper : public QuicConnectionHelperInterface { - public: - QuartcConnectionHelper(const QuicClock* clock, QuicRandom* random); - - // QuicConnectionHelperInterface overrides. - const QuicClock* GetClock() const override; - QuicRandom* GetRandomGenerator() override; - QuicBufferAllocator* GetStreamSendBufferAllocator() override; - - private: - const QuicClock* clock_; - QuicRandom* random_; - SimpleBufferAllocator buffer_allocator_; -}; - -} // namespace quic - -#endif // QUICHE_QUIC_QUARTC_QUARTC_CONNECTION_HELPER_H_ diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.cc deleted file mode 100644 index 14645f83da0..00000000000 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.cc +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright (c) 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.h" - -#include <utility> - -#include "net/third_party/quiche/src/quic/core/quic_utils.h" - -namespace quic { - -void DummyProofSource::GetProof(const QuicSocketAddress& server_address, - const QuicSocketAddress& client_address, - const std::string& hostname, - const std::string& /*server_config*/, - QuicTransportVersion /*transport_version*/, - quiche::QuicheStringPiece /*chlo_hash*/, - std::unique_ptr<Callback> callback) { - QuicReferenceCountedPointer<ProofSource::Chain> chain = - GetCertChain(server_address, client_address, hostname); - QuicCryptoProof proof; - proof.signature = "Dummy signature"; - proof.leaf_cert_scts = "Dummy timestamp"; - callback->Run(true, chain, proof, nullptr /* details */); -} - -QuicReferenceCountedPointer<DummyProofSource::Chain> -DummyProofSource::GetCertChain(const QuicSocketAddress& /*server_address*/, - const QuicSocketAddress& /*client_address*/, - const std::string& /*hostname*/) { - std::vector<std::string> certs; - certs.push_back(kDummyCertName); - return QuicReferenceCountedPointer<ProofSource::Chain>( - new ProofSource::Chain(certs)); -} - -void DummyProofSource::ComputeTlsSignature( - const QuicSocketAddress& /*server_address*/, - const QuicSocketAddress& /*client_address*/, - const std::string& /*hostname*/, - uint16_t /*signature_algorithm*/, - quiche::QuicheStringPiece /*in*/, - std::unique_ptr<SignatureCallback> callback) { - callback->Run(true, "Dummy signature", /*details=*/nullptr); -} - -QuicAsyncStatus InsecureProofVerifier::VerifyProof( - const std::string& /*hostname*/, - const uint16_t /*port*/, - const std::string& /*server_config*/, - QuicTransportVersion /*transport_version*/, - quiche::QuicheStringPiece /*chlo_hash*/, - const std::vector<std::string>& /*certs*/, - const std::string& /*cert_sct*/, - const std::string& /*signature*/, - const ProofVerifyContext* /*context*/, - std::string* /*error_details*/, - std::unique_ptr<ProofVerifyDetails>* /*verify_details*/, - std::unique_ptr<ProofVerifierCallback> /*callback*/) { - return QUIC_SUCCESS; -} - -QuicAsyncStatus InsecureProofVerifier::VerifyCertChain( - const std::string& /*hostname*/, - const uint16_t /*port*/, - const std::vector<std::string>& /*certs*/, - const std::string& /*ocsp_response*/, - const std::string& /*cert_sct*/, - const ProofVerifyContext* /*context*/, - std::string* /*error_details*/, - std::unique_ptr<ProofVerifyDetails>* /*details*/, - std::unique_ptr<ProofVerifierCallback> /*callback*/) { - return QUIC_SUCCESS; -} - -std::unique_ptr<ProofVerifyContext> -InsecureProofVerifier::CreateDefaultContext() { - return nullptr; -} - -bool QuartcCryptoServerStreamHelper::CanAcceptClientHello( - const CryptoHandshakeMessage& /*message*/, - const QuicSocketAddress& /*client_address*/, - const QuicSocketAddress& /*peer_address*/, - const QuicSocketAddress& /*self_address*/, - std::string* /*error_details*/) const { - return true; -} - -std::unique_ptr<QuicCryptoClientConfig> CreateCryptoClientConfig( - quiche::QuicheStringPiece pre_shared_key) { - auto config = std::make_unique<QuicCryptoClientConfig>( - std::make_unique<InsecureProofVerifier>()); - config->set_pad_inchoate_hello(false); - config->set_pad_full_hello(false); - if (!pre_shared_key.empty()) { - config->set_pre_shared_key(pre_shared_key); - } - return config; -} - -CryptoServerConfig CreateCryptoServerConfig( - QuicRandom* random, - const QuicClock* clock, - quiche::QuicheStringPiece pre_shared_key) { - CryptoServerConfig crypto_server_config; - - // Generate a random source address token secret. For long-running servers - // it's better to not regenerate it for each connection to enable zero-RTT - // handshakes, but for transient clients it does not matter. - char source_address_token_secret[kInputKeyingMaterialLength]; - random->RandBytes(source_address_token_secret, kInputKeyingMaterialLength); - auto config = std::make_unique<QuicCryptoServerConfig>( - std::string(source_address_token_secret, kInputKeyingMaterialLength), - random, std::make_unique<DummyProofSource>(), - KeyExchangeSource::Default()); - - // We run QUIC over ICE, and ICE is verifying remote side with STUN pings. - // We disable source address token validation in order to allow for 0-rtt - // setup (plus source ip addresses are changing even during the connection - // when ICE is used). - config->set_validate_source_address_token(false); - - // Effectively disables the anti-amplification measures (we don't need - // them because we use ICE, and we need to disable them because we disable - // padding of crypto packets). - // This multiplier must be large enough so that the crypto handshake packet - // (approx. 300 bytes) multiplied by this multiplier is larger than a fully - // sized packet (currently 1200 bytes). - // 1500 is a bit extreme: if you can imagine sending a 1 byte packet, and - // your largest MTU would be below 1500 bytes, 1500*1 >= - // any_packet_that_you_can_imagine_sending. - // (again, we hardcode packet size to 1200, so we are not dealing with jumbo - // frames). - config->set_chlo_multiplier(1500); - - // We are sending small client hello, we must not validate its size. - config->set_validate_chlo_size(false); - - // Provide server with serialized config string to prove ownership. - QuicCryptoServerConfig::ConfigOptions options; - // The |message| is used to handle the return value of AddDefaultConfig - // which is raw pointer of the CryptoHandshakeMessage. - std::unique_ptr<CryptoHandshakeMessage> message( - config->AddDefaultConfig(random, clock, options)); - config->set_pad_rej(false); - config->set_pad_shlo(false); - if (!pre_shared_key.empty()) { - config->set_pre_shared_key(pre_shared_key); - } - crypto_server_config.config = std::move(config); - const QuicData& data = message->GetSerialized(); - - crypto_server_config.serialized_crypto_config = - std::string(data.data(), data.length()); - return crypto_server_config; -} - -} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.h b/chromium/net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.h deleted file mode 100644 index 806786f2f3d..00000000000 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.h +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright (c) 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef QUICHE_QUIC_QUARTC_QUARTC_CRYPTO_HELPERS_H_ -#define QUICHE_QUIC_QUARTC_QUARTC_CRYPTO_HELPERS_H_ - -#include <string> - -#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.h" -#include "net/third_party/quiche/src/quic/core/crypto/proof_source.h" -#include "net/third_party/quiche/src/quic/core/crypto/proof_verifier.h" -#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.h" -#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h" -#include "net/third_party/quiche/src/quic/core/quic_connection_id.h" -#include "net/third_party/quiche/src/quic/core/quic_crypto_server_stream_base.h" -#include "net/third_party/quiche/src/quic/core/quic_versions.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_reference_counted.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h" -#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" - -namespace quic { - -// Never, ever, change this certificate name. You will break 0-rtt handshake if -// you do. -static constexpr char kDummyCertName[] = "Dummy cert"; - -struct CryptoServerConfig { - std::unique_ptr<QuicCryptoServerConfig> config; - std::string serialized_crypto_config; -}; - -// Length of HKDF input keying material, equal to its number of bytes. -// https://tools.ietf.org/html/rfc5869#section-2.2. -// TODO(zhihuang): Verify that input keying material length is correct. -constexpr size_t kInputKeyingMaterialLength = 32; - -// Used by QuicCryptoServerConfig to provide dummy proof credentials. -// TODO(zhihuang): Remove when secure P2P QUIC handshake is possible. -class DummyProofSource : public ProofSource { - public: - DummyProofSource() {} - ~DummyProofSource() override {} - - // ProofSource overrides. - void GetProof(const QuicSocketAddress& server_address, - const QuicSocketAddress& client_address, - const std::string& hostname, - const std::string& server_config, - QuicTransportVersion transport_version, - quiche::QuicheStringPiece chlo_hash, - std::unique_ptr<Callback> callback) override; - - QuicReferenceCountedPointer<Chain> GetCertChain( - const QuicSocketAddress& server_address, - const QuicSocketAddress& client_address, - const std::string& hostname) override; - - void ComputeTlsSignature( - const QuicSocketAddress& server_address, - const QuicSocketAddress& client_address, - const std::string& hostname, - uint16_t signature_algorithm, - quiche::QuicheStringPiece in, - std::unique_ptr<SignatureCallback> callback) override; - - TicketCrypter* GetTicketCrypter() override { return nullptr; } -}; - -// Used by QuicCryptoClientConfig to ignore the peer's credentials -// and establish an insecure QUIC connection. -// TODO(zhihuang): Remove when secure P2P QUIC handshake is possible. -class InsecureProofVerifier : public ProofVerifier { - public: - InsecureProofVerifier() {} - ~InsecureProofVerifier() override {} - - // ProofVerifier overrides. - QuicAsyncStatus VerifyProof( - const std::string& hostname, - const uint16_t port, - const std::string& server_config, - QuicTransportVersion transport_version, - quiche::QuicheStringPiece chlo_hash, - const std::vector<std::string>& certs, - const std::string& cert_sct, - const std::string& signature, - const ProofVerifyContext* context, - std::string* error_details, - std::unique_ptr<ProofVerifyDetails>* verify_details, - std::unique_ptr<ProofVerifierCallback> callback) override; - - QuicAsyncStatus VerifyCertChain( - const std::string& hostname, - const uint16_t port, - const std::vector<std::string>& certs, - const std::string& ocsp_response, - const std::string& cert_sct, - const ProofVerifyContext* context, - std::string* error_details, - std::unique_ptr<ProofVerifyDetails>* details, - std::unique_ptr<ProofVerifierCallback> callback) override; - - std::unique_ptr<ProofVerifyContext> CreateDefaultContext() override; -}; - -// Implementation of the server-side crypto stream helper. -class QuartcCryptoServerStreamHelper - : public QuicCryptoServerStreamBase::Helper { - public: - bool CanAcceptClientHello(const CryptoHandshakeMessage& message, - const QuicSocketAddress& client_address, - const QuicSocketAddress& peer_address, - const QuicSocketAddress& self_address, - std::string* error_details) const override; -}; - -std::unique_ptr<QuicCryptoClientConfig> CreateCryptoClientConfig( - quiche::QuicheStringPiece pre_shared_key); - -CryptoServerConfig CreateCryptoServerConfig( - QuicRandom* random, - const QuicClock* clock, - quiche::QuicheStringPiece pre_shared_key); - -} // namespace quic - -#endif // QUICHE_QUIC_QUARTC_QUARTC_CRYPTO_HELPERS_H_ diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_dispatcher.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_dispatcher.cc deleted file mode 100644 index c5c4c4a742f..00000000000 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_dispatcher.cc +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright (c) 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/quiche/src/quic/quartc/quartc_dispatcher.h" - -#include "net/third_party/quiche/src/quic/core/quic_utils.h" -#include "net/third_party/quiche/src/quic/core/quic_versions.h" -#include "net/third_party/quiche/src/quic/quartc/quartc_factory.h" -#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" - -namespace quic { - -QuartcDispatcher::QuartcDispatcher( - std::unique_ptr<QuicConfig> config, - std::unique_ptr<QuicCryptoServerConfig> crypto_config, - QuicVersionManager* version_manager, - std::unique_ptr<QuicConnectionHelperInterface> helper, - std::unique_ptr<QuicCryptoServerStreamBase::Helper> session_helper, - std::unique_ptr<QuicAlarmFactory> alarm_factory, - std::unique_ptr<QuartcPacketWriter> packet_writer, - Delegate* delegate) - : QuicDispatcher( - config.get(), - crypto_config.get(), - version_manager, - std::move(helper), - std::move(session_helper), - std::move(alarm_factory), - QuicUtils::CreateZeroConnectionId( - version_manager->GetSupportedVersions()[0].transport_version) - .length()), - owned_quic_config_(std::move(config)), - owned_crypto_config_(std::move(crypto_config)), - delegate_(delegate), - packet_writer_(packet_writer.get()) { - // Allow incoming packets to set our expected connection ID length. - SetShouldUpdateExpectedServerConnectionIdLength(true); - // Allow incoming packets with connection ID lengths shorter than allowed. - SetAllowShortInitialServerConnectionIds(true); - // QuicDispatcher takes ownership of the writer. - QuicDispatcher::InitializeWithWriter(packet_writer.release()); - // NB: This must happen *after* InitializeWithWriter. It can call us back - // with OnTransportCanWrite() immediately, and the dispatcher needs to be - // fully initialized to handle that. - packet_writer_->SetPacketTransportDelegate(this); -} - -QuartcDispatcher::~QuartcDispatcher() { - packet_writer_->SetPacketTransportDelegate(nullptr); -} - -std::unique_ptr<QuicSession> QuartcDispatcher::CreateQuicSession( - QuicConnectionId connection_id, - const QuicSocketAddress& client_address, - quiche::QuicheStringPiece /*alpn*/, - const ParsedQuicVersion& version) { - // Make our expected connection ID non-mutable since we have a connection. - SetShouldUpdateExpectedServerConnectionIdLength(false); - std::unique_ptr<QuicConnection> connection = CreateQuicConnection( - connection_id, client_address, helper(), alarm_factory(), writer(), - Perspective::IS_SERVER, ParsedQuicVersionVector{version}); - auto session = std::make_unique<QuartcServerSession>( - std::move(connection), /*visitor=*/this, config(), GetSupportedVersions(), - helper()->GetClock(), crypto_config(), compressed_certs_cache(), - session_helper()); - delegate_->OnSessionCreated(session.get()); - return session; -} - -void QuartcDispatcher::OnTransportCanWrite() { - OnCanWrite(); -} - -void QuartcDispatcher::OnTransportReceived(const char* data, size_t data_len) { - // QuartcPacketTransport does not surface real peer addresses, so the - // dispatcher uses a dummy address when processing incoming packets. Note that - // the dispatcher refuses to process anything with port 0. - static const QuicSocketAddress* dummy_address = - new QuicSocketAddress(QuicIpAddress::Any4(), /*port=*/1); - - QuicReceivedPacket packet(data, data_len, helper()->GetClock()->Now()); - ProcessPacket(/*self_address=*/*dummy_address, - /*peer_address=*/*dummy_address, packet); -} - -} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_dispatcher.h b/chromium/net/third_party/quiche/src/quic/quartc/quartc_dispatcher.h deleted file mode 100644 index ca4fe2d6147..00000000000 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_dispatcher.h +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (c) 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef QUICHE_QUIC_QUARTC_QUARTC_DISPATCHER_H_ -#define QUICHE_QUIC_QUARTC_QUARTC_DISPATCHER_H_ - -#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h" -#include "net/third_party/quiche/src/quic/core/quic_alarm_factory.h" -#include "net/third_party/quiche/src/quic/core/quic_config.h" -#include "net/third_party/quiche/src/quic/core/quic_connection.h" -#include "net/third_party/quiche/src/quic/core/quic_connection_id.h" -#include "net/third_party/quiche/src/quic/core/quic_crypto_server_stream_base.h" -#include "net/third_party/quiche/src/quic/core/quic_dispatcher.h" -#include "net/third_party/quiche/src/quic/core/quic_version_manager.h" -#include "net/third_party/quiche/src/quic/core/quic_versions.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h" -#include "net/third_party/quiche/src/quic/quartc/quartc_session.h" -#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" - -namespace quic { - -class QuartcDispatcher : public QuicDispatcher, - QuartcPacketTransport::Delegate { - public: - class Delegate { - public: - virtual ~Delegate() = default; - virtual void OnSessionCreated(QuartcSession* session) = 0; - }; - - QuartcDispatcher( - std::unique_ptr<QuicConfig> config, - std::unique_ptr<QuicCryptoServerConfig> crypto_config, - QuicVersionManager* version_manager, - std::unique_ptr<QuicConnectionHelperInterface> helper, - std::unique_ptr<QuicCryptoServerStreamBase::Helper> session_helper, - std::unique_ptr<QuicAlarmFactory> alarm_factory, - std::unique_ptr<QuartcPacketWriter> packet_writer, - Delegate* delegate); - ~QuartcDispatcher() override; - - std::unique_ptr<QuicSession> CreateQuicSession( - QuicConnectionId server_connection_id, - const QuicSocketAddress& client_address, - quiche::QuicheStringPiece alpn, - const ParsedQuicVersion& version) override; - - // TODO(b/124399417): Override GenerateNewServerConnectionId and request a - // zero-length connection id when the QUIC server perspective supports it. - - // QuartcPacketTransport::Delegate overrides. - void OnTransportCanWrite() override; - void OnTransportReceived(const char* data, size_t data_len) override; - - private: - // Members owned by QuartcDispatcher but not QuicDispatcher. - std::unique_ptr<QuicConfig> owned_quic_config_; - std::unique_ptr<QuicCryptoServerConfig> owned_crypto_config_; - - // Delegate invoked when the dispatcher creates a new session. - Delegate* delegate_; - - // The packet writer used by this dispatcher. Owned by the base class, but - // the base class upcasts it to QuicPacketWriter (which prevents detaching the - // transport delegate without a downcast). - QuartcPacketWriter* packet_writer_; -}; - -} // namespace quic - -#endif // QUICHE_QUIC_QUARTC_QUARTC_DISPATCHER_H_ diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_endpoint.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_endpoint.cc deleted file mode 100644 index ca8fad6c9c4..00000000000 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_endpoint.cc +++ /dev/null @@ -1,190 +0,0 @@ -// Copyright (c) 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/quiche/src/quic/quartc/quartc_endpoint.h" - -#include <utility> - -#include "net/third_party/quiche/src/quic/core/quic_version_manager.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" -#include "net/third_party/quiche/src/quic/quartc/quartc_connection_helper.h" -#include "net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.h" -#include "net/third_party/quiche/src/quic/quartc/quartc_dispatcher.h" -#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" - -namespace quic { - -namespace { - -// Wrapper around a QuicAlarmFactory which delegates to the wrapped factory. -// Usee to convert an unowned pointer into an owned pointer, so that the new -// "owner" does not delete the underlying factory. Note that this is only valid -// when the unowned pointer is already guaranteed to outlive the new "owner". -class QuartcAlarmFactoryWrapper : public QuicAlarmFactory { - public: - explicit QuartcAlarmFactoryWrapper(QuicAlarmFactory* impl) : impl_(impl) {} - - QuicAlarm* CreateAlarm(QuicAlarm::Delegate* delegate) override; - QuicArenaScopedPtr<QuicAlarm> CreateAlarm( - QuicArenaScopedPtr<QuicAlarm::Delegate> delegate, - QuicConnectionArena* arena) override; - - private: - QuicAlarmFactory* impl_; -}; - -QuicAlarm* QuartcAlarmFactoryWrapper::CreateAlarm( - QuicAlarm::Delegate* delegate) { - return impl_->CreateAlarm(delegate); -} - -QuicArenaScopedPtr<QuicAlarm> QuartcAlarmFactoryWrapper::CreateAlarm( - QuicArenaScopedPtr<QuicAlarm::Delegate> delegate, - QuicConnectionArena* arena) { - return impl_->CreateAlarm(std::move(delegate), arena); -} - -} // namespace - -QuartcClientEndpoint::QuartcClientEndpoint( - QuicAlarmFactory* alarm_factory, - const QuicClock* clock, - QuicRandom* random, - QuartcEndpoint::Delegate* delegate, - const QuartcSessionConfig& config, - quiche::QuicheStringPiece serialized_server_config, - std::unique_ptr<QuicVersionManager> version_manager) - : alarm_factory_(alarm_factory), - clock_(clock), - delegate_(delegate), - serialized_server_config_(serialized_server_config), - version_manager_(version_manager ? std::move(version_manager) - : std::make_unique<QuicVersionManager>( - AllSupportedVersions())), - create_session_alarm_(QuicWrapUnique( - alarm_factory_->CreateAlarm(new CreateSessionDelegate(this)))), - connection_helper_( - std::make_unique<QuartcConnectionHelper>(clock_, random)), - config_(config) {} - -void QuartcClientEndpoint::Connect(QuartcPacketTransport* packet_transport) { - packet_transport_ = packet_transport; - // For the first attempt to connect, use any version that the client supports. - current_versions_ = version_manager_->GetSupportedVersions(); - create_session_alarm_->Set(clock_->Now()); -} - -void QuartcClientEndpoint::OnCreateSessionAlarm() { - session_ = CreateQuartcClientSession( - config_, clock_, alarm_factory_, connection_helper_.get(), - current_versions_, serialized_server_config_, packet_transport_); - session_->SetDelegate(this); - delegate_->OnSessionCreated(session_.get()); -} - -void QuartcClientEndpoint::OnCryptoHandshakeComplete() { - delegate_->OnCryptoHandshakeComplete(); -} - -void QuartcClientEndpoint::OnConnectionWritable() { - delegate_->OnConnectionWritable(); -} - -void QuartcClientEndpoint::OnIncomingStream(QuartcStream* stream) { - delegate_->OnIncomingStream(stream); -} - -void QuartcClientEndpoint::OnCongestionControlChange( - QuicBandwidth bandwidth_estimate, - QuicBandwidth pacing_rate, - QuicTime::Delta latest_rtt) { - delegate_->OnCongestionControlChange(bandwidth_estimate, pacing_rate, - latest_rtt); -} - -void QuartcClientEndpoint::OnConnectionClosed( - const QuicConnectionCloseFrame& frame, - ConnectionCloseSource source) { - // First, see if we can restart the session with a mutually-supported version. - if (frame.quic_error_code == QUIC_INVALID_VERSION && session_ && - session_->connection() && - !session_->connection()->server_supported_versions().empty()) { - for (const auto& client_version : - version_manager_->GetSupportedVersions()) { - if (QuicContainsValue(session_->connection()->server_supported_versions(), - client_version)) { - // Found a mutually-supported version. Reconnect using that version. - current_versions_.clear(); - current_versions_.push_back(client_version); - create_session_alarm_->Set(clock_->Now()); - return; - } - } - } - - // Permanent version negotiation errors are forwarded to the |delegate_|, - // along with all other errors. - delegate_->OnConnectionClosed(frame, source); -} - -void QuartcClientEndpoint::OnMessageReceived( - quiche::QuicheStringPiece message) { - delegate_->OnMessageReceived(message); -} - -void QuartcClientEndpoint::OnMessageSent(int64_t datagram_id) { - delegate_->OnMessageSent(datagram_id); -} - -void QuartcClientEndpoint::OnMessageAcked(int64_t datagram_id, - QuicTime receive_timestamp) { - delegate_->OnMessageAcked(datagram_id, receive_timestamp); -} - -void QuartcClientEndpoint::OnMessageLost(int64_t datagram_id) { - delegate_->OnMessageLost(datagram_id); -} - -QuartcServerEndpoint::QuartcServerEndpoint( - QuicAlarmFactory* alarm_factory, - const QuicClock* clock, - QuicRandom* random, - QuartcEndpoint::Delegate* delegate, - const QuartcSessionConfig& config, - std::unique_ptr<QuicVersionManager> version_manager) - : alarm_factory_(alarm_factory), - delegate_(delegate), - config_(config), - version_manager_(version_manager ? std::move(version_manager) - : std::make_unique<QuicVersionManager>( - AllSupportedVersions())), - pre_connection_helper_( - std::make_unique<QuartcConnectionHelper>(clock, random)), - crypto_config_( - CreateCryptoServerConfig(pre_connection_helper_->GetRandomGenerator(), - clock, - config.pre_shared_key)) {} - -void QuartcServerEndpoint::Connect(QuartcPacketTransport* packet_transport) { - DCHECK(pre_connection_helper_ != nullptr); - dispatcher_ = std::make_unique<QuartcDispatcher>( - std::make_unique<QuicConfig>(CreateQuicConfig(config_)), - std::move(crypto_config_.config), version_manager_.get(), - std::move(pre_connection_helper_), - std::make_unique<QuartcCryptoServerStreamHelper>(), - std::make_unique<QuartcAlarmFactoryWrapper>(alarm_factory_), - std::make_unique<QuartcPacketWriter>(packet_transport, - config_.max_packet_size), - this); - // The dispatcher requires at least one call to |ProcessBufferedChlos| to - // set the number of connections it is allowed to create. - dispatcher_->ProcessBufferedChlos(/*max_connections_to_create=*/1); -} - -void QuartcServerEndpoint::OnSessionCreated(QuartcSession* session) { - session->SetDelegate(delegate_); - delegate_->OnSessionCreated(session); -} - -} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_endpoint.h b/chromium/net/third_party/quiche/src/quic/quartc/quartc_endpoint.h deleted file mode 100644 index ea1a63f0e33..00000000000 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_endpoint.h +++ /dev/null @@ -1,203 +0,0 @@ -// Copyright (c) 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef QUICHE_QUIC_QUARTC_QUARTC_ENDPOINT_H_ -#define QUICHE_QUIC_QUARTC_QUARTC_ENDPOINT_H_ - -#include <string> - -#include "net/third_party/quiche/src/quic/core/quic_alarm_factory.h" -#include "net/third_party/quiche/src/quic/core/quic_clock.h" -#include "net/third_party/quiche/src/quic/core/quic_error_codes.h" -#include "net/third_party/quiche/src/quic/quartc/quartc_connection_helper.h" -#include "net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.h" -#include "net/third_party/quiche/src/quic/quartc/quartc_dispatcher.h" -#include "net/third_party/quiche/src/quic/quartc/quartc_factory.h" -#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" - -namespace quic { - -// Endpoint (client or server) in a peer-to-peer Quartc connection. -class QuartcEndpoint { - public: - class Delegate : public QuartcSession::Delegate { - public: - virtual ~Delegate() = default; - - // Called when an endpoint creates a new session, before any packets are - // processed or sent. The callee should perform any additional - // configuration required, such as setting up congestion control, before - // returning. |session| is owned by the endpoint, but remains safe to use - // until another call to |OnSessionCreated| or |OnConnectionClosed| occurs, - // at which point previous session may be destroyed. - // - // Callees must not change the |session|'s delegate. The Endpoint itself - // manages the delegate and will forward calls. - // - // New calls to |OnSessionCreated| will only occur prior to - // |OnConnectionWritable|, during initial connection negotiation. - virtual void OnSessionCreated(QuartcSession* session) = 0; - }; - - virtual ~QuartcEndpoint() = default; - - // Connects the endpoint using the given session config. After |Connect| is - // called, the endpoint will asynchronously create a session, then call - // |Delegate::OnSessionCreated|. - virtual void Connect(QuartcPacketTransport* packet_transport) = 0; -}; - -// Implementation of QuartcEndpoint which immediately (but asynchronously) -// creates a session by scheduling a QuicAlarm. Only suitable for use with the -// client perspective. -class QuartcClientEndpoint : public QuartcEndpoint, - public QuartcSession::Delegate { - public: - // |alarm_factory|, |clock|, and |delegate| are owned by the caller and must - // outlive the endpoint. - QuartcClientEndpoint( - QuicAlarmFactory* alarm_factory, - const QuicClock* clock, - QuicRandom* random, - QuartcEndpoint::Delegate* delegate, - const QuartcSessionConfig& config, - quiche::QuicheStringPiece serialized_server_config, - std::unique_ptr<QuicVersionManager> version_manager = nullptr); - - void Connect(QuartcPacketTransport* packet_transport) override; - - // QuartcSession::Delegate overrides. - void OnCryptoHandshakeComplete() override; - void OnConnectionWritable() override; - void OnIncomingStream(QuartcStream* stream) override; - void OnCongestionControlChange(QuicBandwidth bandwidth_estimate, - QuicBandwidth pacing_rate, - QuicTime::Delta latest_rtt) override; - void OnConnectionClosed(const QuicConnectionCloseFrame& frame, - ConnectionCloseSource source) override; - void OnMessageReceived(quiche::QuicheStringPiece message) override; - void OnMessageSent(int64_t datagram_id) override; - void OnMessageAcked(int64_t datagram_id, QuicTime receive_timestamp) override; - void OnMessageLost(int64_t datagram_id) override; - - private: - friend class CreateSessionDelegate; - class CreateSessionDelegate : public QuicAlarm::Delegate { - public: - CreateSessionDelegate(QuartcClientEndpoint* endpoint) - : endpoint_(endpoint) {} - - void OnAlarm() override { endpoint_->OnCreateSessionAlarm(); } - - private: - QuartcClientEndpoint* endpoint_; - }; - - // Callback which occurs when |create_session_alarm_| fires. - void OnCreateSessionAlarm(); - - // Implementation of QuicAlarmFactory used by this endpoint. Unowned. - QuicAlarmFactory* alarm_factory_; - - // Implementation of QuicClock used by this endpoint. Unowned. - const QuicClock* clock_; - - // Delegate which receives callbacks for newly created sessions. - QuartcEndpoint::Delegate* delegate_; - - // Server config. If valid, used to perform a 0-RTT connection. - const std::string serialized_server_config_; - - // Version manager. May be injected to control version negotiation in tests. - std::unique_ptr<QuicVersionManager> version_manager_; - - // Versions to be used when the next session is created. The session will - // choose one of these versions for its connection attempt. - // - // If the connection does not succeed, the client session MAY try again using - // another version from this list, or it MAY simply fail with a - // QUIC_INVALID_VERSION error. The latter occurs when it is not possible to - // upgrade a connection in-place (for example, if the way stream ids are - // allocated changes between versions). This failure mode is handled by - // narrowing |current_versions_| to one of that is mutually-supported and - // reconnecting (with a new session). - ParsedQuicVersionVector current_versions_; - - // Alarm for creating sessions asynchronously. The alarm is set when - // Connect() is called. When it fires, the endpoint creates a session and - // calls the delegate. - std::unique_ptr<QuicAlarm> create_session_alarm_; - - // Helper used by QuicConnection. - std::unique_ptr<QuicConnectionHelperInterface> connection_helper_; - - // Config to be used for new sessions. - QuartcSessionConfig config_; - - // The currently-active session. Nullptr until |Connect| and - // |Delegate::OnSessionCreated| are called. - std::unique_ptr<QuartcSession> session_; - - QuartcPacketTransport* packet_transport_; -}; - -// Implementation of QuartcEndpoint which uses a QuartcDispatcher to listen for -// an incoming CHLO and create a session when one arrives. Only suitable for -// use with the server perspective. -class QuartcServerEndpoint : public QuartcEndpoint, - public QuartcDispatcher::Delegate { - public: - QuartcServerEndpoint( - QuicAlarmFactory* alarm_factory, - const QuicClock* clock, - QuicRandom* random, - QuartcEndpoint::Delegate* delegate, - const QuartcSessionConfig& config, - std::unique_ptr<QuicVersionManager> version_manager = nullptr); - - // Implements QuartcEndpoint. - void Connect(QuartcPacketTransport* packet_transport) override; - - // Implements QuartcDispatcher::Delegate. - void OnSessionCreated(QuartcSession* session) override; - - // Accessor to retrieve the server crypto config. May only be called after - // Connect(). - quiche::QuicheStringPiece server_crypto_config() const { - return crypto_config_.serialized_crypto_config; - } - - const std::vector<ParsedQuicVersion> GetSupportedQuicVersions() const { - return version_manager_->GetSupportedVersions(); - } - - private: - // Implementation of QuicAlarmFactory used by this endpoint. Unowned. - QuicAlarmFactory* alarm_factory_; - - // Delegate which receives callbacks for newly created sessions. - QuartcEndpoint::Delegate* delegate_; - - // Config to be used for new sessions. - QuartcSessionConfig config_; - - // Version manager. May be injected to control version negotiation in tests. - std::unique_ptr<QuicVersionManager> version_manager_; - - // QuartcDispatcher waits for an incoming CHLO, then either rejects it or - // creates a session to respond to it. The dispatcher owns all sessions it - // creates. - std::unique_ptr<QuartcDispatcher> dispatcher_; - - // This field is only available before connection was started. - std::unique_ptr<QuartcConnectionHelper> pre_connection_helper_; - - // A configuration, containing public key, that may need to be passed to the - // client to enable 0rtt. - CryptoServerConfig crypto_config_; -}; - -} // namespace quic - -#endif // QUICHE_QUIC_QUARTC_QUARTC_ENDPOINT_H_ diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_endpoint_test.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_endpoint_test.cc deleted file mode 100644 index d2f94202aa1..00000000000 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_endpoint_test.cc +++ /dev/null @@ -1,251 +0,0 @@ -// Copyright (c) 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/quiche/src/quic/quartc/quartc_endpoint.h" - -#include <utility> - -#include "net/third_party/quiche/src/quic/core/quic_versions.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" -#include "net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.h" -#include "net/third_party/quiche/src/quic/quartc/quartc_fakes.h" -#include "net/third_party/quiche/src/quic/quartc/simulated_packet_transport.h" -#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" -#include "net/third_party/quiche/src/quic/test_tools/simulator/link.h" -#include "net/third_party/quiche/src/quic/test_tools/simulator/simulator.h" - -namespace quic { -namespace { - -class QuartcEndpointTest : public QuicTest { - protected: - QuartcEndpointTest() - : client_transport_(&simulator_, - "client_transport", - "server_transport", - 10 * kDefaultMaxPacketSize), - server_transport_(&simulator_, - "server_transport", - "client_transport", - 10 * kDefaultMaxPacketSize), - client_server_link_(&client_transport_, - &server_transport_, - QuicBandwidth::FromKBitsPerSecond(10000), - QuicTime::Delta::FromMilliseconds(1)), - server_endpoint_delegate_(&server_stream_delegate_, - simulator_.GetClock()), - server_endpoint_(std::make_unique<QuartcServerEndpoint>( - simulator_.GetAlarmFactory(), - simulator_.GetClock(), - simulator_.GetRandomGenerator(), - &server_endpoint_delegate_, - QuartcSessionConfig())), - client_endpoint_delegate_(&client_stream_delegate_, - simulator_.GetClock()), - client_endpoint_(std::make_unique<QuartcClientEndpoint>( - simulator_.GetAlarmFactory(), - simulator_.GetClock(), - simulator_.GetRandomGenerator(), - &client_endpoint_delegate_, - QuartcSessionConfig(), - /*serialized_server_config=*/"")) { - // Make sure these versions are enabled since some tests use them. - SetQuicReloadableFlag(quic_disable_version_q043, false); - SetQuicReloadableFlag(quic_disable_version_q046, false); - } - - simulator::Simulator simulator_; - - simulator::SimulatedQuartcPacketTransport client_transport_; - simulator::SimulatedQuartcPacketTransport server_transport_; - simulator::SymmetricLink client_server_link_; - - FakeQuartcStreamDelegate server_stream_delegate_; - FakeQuartcEndpointDelegate server_endpoint_delegate_; - - std::unique_ptr<QuartcServerEndpoint> server_endpoint_; - - FakeQuartcStreamDelegate client_stream_delegate_; - FakeQuartcEndpointDelegate client_endpoint_delegate_; - - std::unique_ptr<QuartcClientEndpoint> client_endpoint_; -}; - -// After calling Connect, the client endpoint must wait for an async callback. -// The callback occurs after a finite amount of time and produces a session. -TEST_F(QuartcEndpointTest, ClientCreatesSessionAsynchronously) { - client_endpoint_->Connect(&client_transport_); - - EXPECT_EQ(client_endpoint_delegate_.session(), nullptr); - - EXPECT_TRUE(simulator_.RunUntil( - [this] { return client_endpoint_delegate_.session() != nullptr; })); -} - -// Tests that the server can negotiate for an older QUIC version if the client -// attempts to connect using a newer version. -TEST_F(QuartcEndpointTest, - QUIC_TEST_DISABLED_IN_CHROME(ServerNegotiatesForOldVersion)) { - // Reset the client endpoint to prefer version 46 but also be capable of - // speaking version 43. - ParsedQuicVersionVector client_versions; - client_versions.push_back({PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46}); - client_versions.push_back({PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43}); - client_endpoint_ = std::make_unique<QuartcClientEndpoint>( - simulator_.GetAlarmFactory(), simulator_.GetClock(), - simulator_.GetRandomGenerator(), &client_endpoint_delegate_, - QuartcSessionConfig(), - /*serialized_server_config=*/"", - std::make_unique<QuicVersionManager>(client_versions)); - - // Reset the server endpoint to only speak version 43. - ParsedQuicVersionVector server_versions; - server_versions.push_back({PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43}); - server_endpoint_ = std::make_unique<QuartcServerEndpoint>( - simulator_.GetAlarmFactory(), simulator_.GetClock(), - simulator_.GetRandomGenerator(), &server_endpoint_delegate_, - QuartcSessionConfig(), - std::make_unique<QuicVersionManager>(server_versions)); - - // The endpoints should be able to establish a connection using version 46. - server_endpoint_->Connect(&server_transport_); - client_endpoint_->Connect(&client_transport_); - - ASSERT_TRUE(simulator_.RunUntil([this] { - return client_endpoint_delegate_.session() != nullptr && - client_endpoint_delegate_.session()->IsEncryptionEstablished() && - server_endpoint_delegate_.session() != nullptr && - server_endpoint_delegate_.session()->IsEncryptionEstablished(); - })); - EXPECT_EQ(client_endpoint_delegate_.session()->connection()->version(), - server_versions[0]); - EXPECT_EQ(server_endpoint_delegate_.session()->connection()->version(), - server_versions[0]); -} - -// Tests that the server can accept connections from clients that use older -// QUIC versions. -TEST_F(QuartcEndpointTest, - QUIC_TEST_DISABLED_IN_CHROME(ServerAcceptsOldVersion)) { - // Reset the client endpoint to only speak version 43. - ParsedQuicVersionVector client_versions; - client_versions.push_back({PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43}); - client_endpoint_ = std::make_unique<QuartcClientEndpoint>( - simulator_.GetAlarmFactory(), simulator_.GetClock(), - simulator_.GetRandomGenerator(), &client_endpoint_delegate_, - QuartcSessionConfig(), - /*serialized_server_config=*/"", - std::make_unique<QuicVersionManager>(client_versions)); - - // Reset the server endpoint to prefer version 46 but also be capable of - // speaking version 43. - ParsedQuicVersionVector server_versions; - server_versions.push_back({PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46}); - server_versions.push_back({PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43}); - server_endpoint_ = std::make_unique<QuartcServerEndpoint>( - simulator_.GetAlarmFactory(), simulator_.GetClock(), - simulator_.GetRandomGenerator(), &server_endpoint_delegate_, - QuartcSessionConfig(), - std::make_unique<QuicVersionManager>(server_versions)); - - // The endpoints should be able to establish a connection using version 46. - server_endpoint_->Connect(&server_transport_); - client_endpoint_->Connect(&client_transport_); - - ASSERT_TRUE(simulator_.RunUntil([this] { - return client_endpoint_delegate_.session() != nullptr && - client_endpoint_delegate_.session()->IsEncryptionEstablished() && - server_endpoint_delegate_.session() != nullptr && - server_endpoint_delegate_.session()->IsEncryptionEstablished(); - })); - EXPECT_EQ(client_endpoint_delegate_.session()->connection()->version(), - client_versions[0]); - EXPECT_EQ(server_endpoint_delegate_.session()->connection()->version(), - client_versions[0]); -} - -// Tests that version negotiation fails when the client and server support -// completely disjoint sets of versions. -TEST_F(QuartcEndpointTest, - QUIC_TEST_DISABLED_IN_CHROME(VersionNegotiationWithDisjointVersions)) { - // Reset the client endpoint to only speak version 43. - ParsedQuicVersionVector client_versions; - client_versions.push_back({PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43}); - client_endpoint_ = std::make_unique<QuartcClientEndpoint>( - simulator_.GetAlarmFactory(), simulator_.GetClock(), - simulator_.GetRandomGenerator(), &client_endpoint_delegate_, - QuartcSessionConfig(), - /*serialized_server_config=*/"", - std::make_unique<QuicVersionManager>(client_versions)); - - // Reset the server endpoint to only speak version 46. - ParsedQuicVersionVector server_versions; - server_versions.push_back({PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46}); - server_endpoint_ = std::make_unique<QuartcServerEndpoint>( - simulator_.GetAlarmFactory(), simulator_.GetClock(), - simulator_.GetRandomGenerator(), &server_endpoint_delegate_, - QuartcSessionConfig(), - std::make_unique<QuicVersionManager>(server_versions)); - - // The endpoints should be unable to establish a connection. - server_endpoint_->Connect(&server_transport_); - client_endpoint_->Connect(&client_transport_); - - // Note that the error is reported from the client and *not* the server. The - // server sees an invalid version, sends a version negotiation packet, and - // never gets a response, because the client stops sending when it can't find - // a mutually supported versions. - ASSERT_TRUE(simulator_.RunUntil([this] { - return client_endpoint_delegate_.session() != nullptr && - client_endpoint_delegate_.session()->error() != QUIC_NO_ERROR; - })); - EXPECT_THAT(client_endpoint_delegate_.session()->error(), - test::IsError(QUIC_INVALID_VERSION)); -} - -// Tests that the client endpoint can create a new session in order to continue -// version negotiation. -TEST_F(QuartcEndpointTest, - QUIC_TEST_DISABLED_IN_CHROME(CreatesNewSessionWhenRequired)) { - // Reset the client endpoint to prefer version 46 but also be capable of - // speaking version 43. - ParsedQuicVersionVector client_versions; - client_versions.push_back({PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46}); - client_versions.push_back({PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43}); - client_endpoint_ = std::make_unique<QuartcClientEndpoint>( - simulator_.GetAlarmFactory(), simulator_.GetClock(), - simulator_.GetRandomGenerator(), &client_endpoint_delegate_, - QuartcSessionConfig(), - /*serialized_server_config=*/"", - std::make_unique<QuicVersionManager>(client_versions)); - - // Reset the server endpoint to only speak version 43. - ParsedQuicVersionVector server_versions; - server_versions.push_back({PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43}); - server_endpoint_ = std::make_unique<QuartcServerEndpoint>( - simulator_.GetAlarmFactory(), simulator_.GetClock(), - simulator_.GetRandomGenerator(), &server_endpoint_delegate_, - QuartcSessionConfig(), - std::make_unique<QuicVersionManager>(server_versions)); - - // The endpoints should be able to establish a connection using version 46. - server_endpoint_->Connect(&server_transport_); - client_endpoint_->Connect(&client_transport_); - - ASSERT_TRUE(simulator_.RunUntil([this] { - return client_endpoint_delegate_.session() != nullptr && - client_endpoint_delegate_.session()->IsEncryptionEstablished() && - server_endpoint_delegate_.session() != nullptr && - server_endpoint_delegate_.session()->IsEncryptionEstablished(); - })); - EXPECT_EQ(client_endpoint_delegate_.session()->connection()->version(), - server_versions[0]); - EXPECT_EQ(server_endpoint_delegate_.session()->connection()->version(), - server_versions[0]); - - EXPECT_EQ(2, client_endpoint_delegate_.num_sessions_created()); -} - -} // namespace -} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_factory.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_factory.cc deleted file mode 100644 index 280d936b25a..00000000000 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_factory.cc +++ /dev/null @@ -1,219 +0,0 @@ -// Copyright (c) 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/quiche/src/quic/quartc/quartc_factory.h" - -#include <utility> - -#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h" -#include "net/third_party/quiche/src/quic/core/quic_utils.h" -#include "net/third_party/quiche/src/quic/core/tls_client_handshaker.h" -#include "net/third_party/quiche/src/quic/core/tls_server_handshaker.h" -#include "net/third_party/quiche/src/quic/core/uber_received_packet_manager.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h" -#include "net/third_party/quiche/src/quic/quartc/quartc_connection_helper.h" -#include "net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.h" -#include "net/third_party/quiche/src/quic/quartc/quartc_session.h" -#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" - -namespace quic { - -std::unique_ptr<QuartcSession> CreateQuartcClientSession( - const QuartcSessionConfig& quartc_session_config, - const QuicClock* clock, - QuicAlarmFactory* alarm_factory, - QuicConnectionHelperInterface* connection_helper, - const ParsedQuicVersionVector& supported_versions, - quiche::QuicheStringPiece server_crypto_config, - QuartcPacketTransport* packet_transport) { - DCHECK(packet_transport); - - // QuartcSession will eventually own both |writer| and |quic_connection|. - auto writer = std::make_unique<QuartcPacketWriter>( - packet_transport, quartc_session_config.max_packet_size); - - // While the QuicConfig is not directly used by the connection, creating it - // also sets flag values which must be set before creating the connection. - QuicConfig quic_config = CreateQuicConfig(quartc_session_config); - - // |dummy_id| and |dummy_address| are used because Quartc network layer will - // not use these two. - QuicConnectionId dummy_id = QuicUtils::CreateZeroConnectionId( - supported_versions[0].transport_version); - QuicSocketAddress dummy_address(QuicIpAddress::Any4(), /*port=*/0); - std::unique_ptr<QuicConnection> quic_connection = CreateQuicConnection( - dummy_id, dummy_address, connection_helper, alarm_factory, writer.get(), - Perspective::IS_CLIENT, supported_versions); - - // Quartc sets its own ack delay; get that ack delay and copy it over - // to the QuicConfig so that it can be properly advertised to the peer - // via transport parameter negotiation. - quic_config.SetMaxAckDelayToSendMs(quic_connection->received_packet_manager() - .max_ack_delay() - .ToMilliseconds()); - - return std::make_unique<QuartcClientSession>( - std::move(quic_connection), quic_config, supported_versions, clock, - std::move(writer), - CreateCryptoClientConfig(quartc_session_config.pre_shared_key), - server_crypto_config); -} - -void ConfigureGlobalQuicSettings() { - // Ensure that we don't drop data because QUIC streams refuse to buffer it. - // TODO(b/120099046): Replace this with correct handling of WriteMemSlices(). - SetQuicFlag(FLAGS_quic_buffered_data_threshold, - std::numeric_limits<int>::max()); - - // Enable and request QUIC to include receive timestamps in ACK frames. - SetQuicReloadableFlag(quic_send_timestamps, true); - - // Enable ACK_DECIMATION_WITH_REORDERING. It requires ack_decimation to be - // false. - SetQuicReloadableFlag(quic_enable_ack_decimation, false); - - // Note: flag settings have no effect for Exoblaze builds since - // SetQuicReloadableFlag() gets stubbed out. - SetQuicReloadableFlag(quic_unified_iw_options, true); // Enable IWXX opts. - SetQuicReloadableFlag(quic_bbr_flexible_app_limited, true); // Enable BBR9. -} - -QuicConfig CreateQuicConfig(const QuartcSessionConfig& quartc_session_config) { - // TODO(b/124398962): Figure out a better way to initialize QUIC flags. - // Creating a config shouldn't have global side-effects on flags. However, - // this has the advantage of ensuring that flag values stay in sync with the - // options requested by configs, so simply splitting the config and flag - // settings doesn't seem preferable. - ConfigureGlobalQuicSettings(); - - QuicTagVector copt; - copt.push_back(kNSTP); - - // Enable and request QUIC to include receive timestamps in ACK frames. - copt.push_back(kSTMP); - - // Enable ACK_DECIMATION_WITH_REORDERING. It requires ack_decimation to be - // false. - copt.push_back(kAKD2); - - // Use unlimited decimation in order to reduce number of unbundled ACKs. - copt.push_back(kAKDU); - - // Enable time-based loss detection. - copt.push_back(kTIME); - - copt.push_back(kBBR3); // Stay in low-gain until in-flight < BDP. - copt.push_back(kBBR5); // 40 RTT ack aggregation. - copt.push_back(kBBR9); // Ignore app-limited if enough data is in flight. - copt.push_back(kBBQ1); // 2.773 pacing gain in STARTUP. - copt.push_back(kBBQ2); // 2.0 CWND gain in STARTUP. - copt.push_back(k1RTT); // Exit STARTUP after 1 RTT with no gains. - copt.push_back(kIW10); // 10-packet (14600 byte) initial cwnd. - - if (!quartc_session_config.enable_tail_loss_probe) { - copt.push_back(kNTLP); - } - - // TODO(b/112192153): Test and possible enable slower startup when pipe - // filling is ready to use. Slower startup is kBBRS. - - QuicConfig quic_config; - - // Use the limits for the session & stream flow control. The default 16KB - // limit leads to significantly undersending (not reaching BWE on the outgoing - // bitrate) due to blocked frames, and it leads to high latency (and one-way - // delay). Setting it to its limits is not going to cause issues (our streams - // are small generally, and if we were to buffer 24MB it wouldn't be the end - // of the world). We can consider setting different limits in future (e.g. 1MB - // stream, 1.5MB session). It's worth noting that on 1mbps bitrate, limit of - // 24MB can capture approx 4 minutes of the call, and the default increase in - // size of the window (half of the window size) is approximately 2 minutes of - // the call. - quic_config.SetInitialSessionFlowControlWindowToSend( - kSessionReceiveWindowLimit); - quic_config.SetInitialStreamFlowControlWindowToSend( - kStreamReceiveWindowLimit); - quic_config.SetConnectionOptionsToSend(copt); - quic_config.SetClientConnectionOptions(copt); - if (quartc_session_config.max_time_before_crypto_handshake > - QuicTime::Delta::Zero()) { - quic_config.set_max_time_before_crypto_handshake( - quartc_session_config.max_time_before_crypto_handshake); - } - if (quartc_session_config.max_idle_time_before_crypto_handshake > - QuicTime::Delta::Zero()) { - quic_config.set_max_idle_time_before_crypto_handshake( - quartc_session_config.max_idle_time_before_crypto_handshake); - } - if (quartc_session_config.idle_network_timeout > QuicTime::Delta::Zero()) { - quic_config.SetIdleNetworkTimeout( - quartc_session_config.idle_network_timeout); - } - - // The ICE transport provides a unique 5-tuple for each connection. Save - // overhead by omitting the connection id. - quic_config.SetBytesForConnectionIdToSend(0); - - // Allow up to 1000 incoming streams at once. Quartc streams typically contain - // one audio or video frame and close immediately. However, when a video frame - // becomes larger than one packet, there is some delay between the start and - // end of each stream. The default maximum of 100 only leaves about 1 second - // of headroom (Quartc sends ~30 video frames per second) before QUIC starts - // to refuse incoming streams. Back-pressure should clear backlogs of - // incomplete streams, but targets 1 second for recovery. Increasing the - // number of open streams gives sufficient headroom to recover before QUIC - // refuses new streams. - quic_config.SetMaxBidirectionalStreamsToSend(1000); - - return quic_config; -} - -std::unique_ptr<QuicConnection> CreateQuicConnection( - QuicConnectionId connection_id, - const QuicSocketAddress& peer_address, - QuicConnectionHelperInterface* connection_helper, - QuicAlarmFactory* alarm_factory, - QuicPacketWriter* packet_writer, - Perspective perspective, - ParsedQuicVersionVector supported_versions) { - auto quic_connection = std::make_unique<QuicConnection>( - connection_id, peer_address, connection_helper, alarm_factory, - packet_writer, - /*owns_writer=*/false, perspective, supported_versions); - quic_connection->SetMaxPacketLength( - packet_writer->GetMaxPacketSize(peer_address)); - - QuicSentPacketManager& sent_packet_manager = - quic_connection->sent_packet_manager(); - UberReceivedPacketManager& received_packet_manager = - quic_connection->received_packet_manager(); - - // Default delayed ack time is 25ms. - // If data packets are sent less often (e.g. because p-time was modified), - // we would force acks to be sent every 25ms regardless, increasing - // overhead. Since generally we guarantee a packet every 20ms, changing - // this value should have miniscule effect on quality on good connections, - // but on poor connections, changing this number significantly reduced the - // number of ack-only packets. - // The p-time can go up to as high as 120ms, and when it does, it's - // when the low overhead is the most important thing. Ideally it should be - // above 120ms, but it cannot be higher than 0.5*RTO, which equals to 100ms. - received_packet_manager.set_max_ack_delay( - QuicTime::Delta::FromMilliseconds(100)); - sent_packet_manager.set_peer_max_ack_delay( - QuicTime::Delta::FromMilliseconds(100)); - - quic_connection->set_fill_up_link_during_probing(true); - - // We start ack decimation after 15 packets. Typically, we would see - // 1-2 crypto handshake packets, one media packet, and 10 probing packets. - // We want to get acks for the probing packets as soon as possible, - // but we can start using ack decimation right after first probing completes. - // The default was to not start ack decimation for the first 100 packets. - quic_connection->set_min_received_before_ack_decimation(15); - - return quic_connection; -} - -} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_factory.h b/chromium/net/third_party/quiche/src/quic/quartc/quartc_factory.h deleted file mode 100644 index 665b8e7111d..00000000000 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_factory.h +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef QUICHE_QUIC_QUARTC_QUARTC_FACTORY_H_ -#define QUICHE_QUIC_QUARTC_QUARTC_FACTORY_H_ - -#include "net/third_party/quiche/src/quic/core/quic_alarm_factory.h" -#include "net/third_party/quiche/src/quic/core/quic_connection.h" -#include "net/third_party/quiche/src/quic/core/quic_simple_buffer_allocator.h" -#include "net/third_party/quiche/src/quic/quartc/quartc_packet_writer.h" -#include "net/third_party/quiche/src/quic/quartc/quartc_session.h" -#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" - -namespace quic { - -struct QuartcSessionConfig { - // If a pre-shared cryptographic key is available for this session, specify it - // here. This value will only be used if non-empty. - std::string pre_shared_key; - - // The maximum size of the packet can be written with the packet writer. - // 1200 bytes by default. - QuicPacketLength max_packet_size = 1200; - - // Timeouts for the crypto handshake. Set them to higher values to - // prevent closing the session before it started on a slow network. - // Zero entries are ignored and QUIC defaults are used in that case. - QuicTime::Delta max_idle_time_before_crypto_handshake = - QuicTime::Delta::Zero(); - QuicTime::Delta max_time_before_crypto_handshake = QuicTime::Delta::Zero(); - QuicTime::Delta idle_network_timeout = QuicTime::Delta::Zero(); - - // Tail loss probes (TLP) are enabled by default, but it may be useful to - // disable them in tests. We can also consider disabling them in production - // if we discover that tail loss probes add overhead in low bitrate audio. - bool enable_tail_loss_probe = true; -}; - -// Creates a new QuartcClientSession using the given configuration. -std::unique_ptr<QuartcSession> CreateQuartcClientSession( - const QuartcSessionConfig& quartc_session_config, - const QuicClock* clock, - QuicAlarmFactory* alarm_factory, - QuicConnectionHelperInterface* connection_helper, - const ParsedQuicVersionVector& supported_versions, - quiche::QuicheStringPiece server_crypto_config, - QuartcPacketTransport* packet_transport); - -// Configures global settings, such as supported quic versions. -// Must execute on QUIC thread. -void ConfigureGlobalQuicSettings(); - -// Must execute on QUIC thread. -QuicConfig CreateQuicConfig(const QuartcSessionConfig& quartc_session_config); - -std::unique_ptr<QuicConnection> CreateQuicConnection( - QuicConnectionId connection_id, - const QuicSocketAddress& peer_address, - QuicConnectionHelperInterface* connection_helper, - QuicAlarmFactory* alarm_factory, - QuicPacketWriter* packet_writer, - Perspective perspective, - ParsedQuicVersionVector supported_versions); - -} // namespace quic - -#endif // QUICHE_QUIC_QUARTC_QUARTC_FACTORY_H_ diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_fakes.h b/chromium/net/third_party/quiche/src/quic/quartc/quartc_fakes.h deleted file mode 100644 index 94bf1add1e7..00000000000 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_fakes.h +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright (c) 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef QUICHE_QUIC_QUARTC_QUARTC_FAKES_H_ -#define QUICHE_QUIC_QUARTC_QUARTC_FAKES_H_ - -#include <string> - -#include "net/third_party/quiche/src/quic/core/quic_clock.h" -#include "net/third_party/quiche/src/quic/core/quic_error_codes.h" -#include "net/third_party/quiche/src/quic/core/quic_types.h" -#include "net/third_party/quiche/src/quic/quartc/quartc_endpoint.h" -#include "net/third_party/quiche/src/quic/quartc/quartc_session.h" -#include "net/third_party/quiche/src/quic/quartc/quartc_stream.h" -#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" - -namespace quic { - -class FakeQuartcEndpointDelegate : public QuartcEndpoint::Delegate { - public: - explicit FakeQuartcEndpointDelegate(QuartcStream::Delegate* stream_delegate, - const QuicClock* clock) - : stream_delegate_(stream_delegate), clock_(clock) {} - - void OnSessionCreated(QuartcSession* session) override { - CHECK_NE(session, nullptr); - session_ = session; - session_->StartCryptoHandshake(); - ++num_sessions_created_; - } - - void OnConnectionWritable() override { - QUIC_LOG(INFO) << "Connection writable!"; - if (!writable_time_.IsInitialized()) { - writable_time_ = clock_->Now(); - } - } - - // Called when peers have established forward-secure encryption - void OnCryptoHandshakeComplete() override { - QUIC_LOG(INFO) << "Crypto handshake complete!"; - crypto_handshake_time_ = clock_->Now(); - } - - // Called when connection closes locally, or remotely by peer. - void OnConnectionClosed(const QuicConnectionCloseFrame& /*frame*/, - ConnectionCloseSource /*source*/) override { - connected_ = false; - } - - // Called when an incoming QUIC stream is created. - void OnIncomingStream(QuartcStream* quartc_stream) override { - last_incoming_stream_ = quartc_stream; - last_incoming_stream_->SetDelegate(stream_delegate_); - } - - void OnMessageReceived(quiche::QuicheStringPiece message) override { - incoming_messages_.emplace_back(message); - } - - void OnMessageSent(int64_t datagram_id) override { - sent_datagram_ids_.push_back(datagram_id); - } - - void OnMessageAcked(int64_t datagram_id, - QuicTime receive_timestamp) override { - acked_datagram_id_to_receive_timestamp_.emplace(datagram_id, - receive_timestamp); - } - - void OnMessageLost(int64_t datagram_id) override { - lost_datagram_ids_.push_back(datagram_id); - } - - void OnCongestionControlChange(QuicBandwidth /*bandwidth_estimate*/, - QuicBandwidth /*pacing_rate*/, - QuicTime::Delta /*latest_rtt*/) override {} - - QuartcSession* session() { return session_; } - - int num_sessions_created() const { return num_sessions_created_; } - - QuartcStream* last_incoming_stream() const { return last_incoming_stream_; } - - // Returns all received messages. - const std::vector<std::string>& incoming_messages() const { - return incoming_messages_; - } - - // Returns all sent datagram ids in the order sent. - const std::vector<int64_t>& sent_datagram_ids() const { - return sent_datagram_ids_; - } - - // Returns all ACKEd datagram ids in the order ACKs were received. - const std::map<int64_t, QuicTime>& acked_datagram_id_to_receive_timestamp() - const { - return acked_datagram_id_to_receive_timestamp_; - } - - const std::vector<int64_t>& lost_datagram_ids() const { - return lost_datagram_ids_; - } - - bool connected() const { return connected_; } - QuicTime writable_time() const { return writable_time_; } - QuicTime crypto_handshake_time() const { return crypto_handshake_time_; } - - private: - // Current session. - QuartcSession* session_ = nullptr; - - // Number of new sessions created by the endpoint. - int num_sessions_created_ = 0; - - QuartcStream* last_incoming_stream_; - std::vector<std::string> incoming_messages_; - std::vector<int64_t> sent_datagram_ids_; - std::map<int64_t, QuicTime> acked_datagram_id_to_receive_timestamp_; - std::vector<int64_t> lost_datagram_ids_; - bool connected_ = true; - QuartcStream::Delegate* stream_delegate_; - QuicTime writable_time_ = QuicTime::Zero(); - QuicTime crypto_handshake_time_ = QuicTime::Zero(); - const QuicClock* clock_; -}; - -class FakeQuartcStreamDelegate : public QuartcStream::Delegate { - public: - size_t OnReceived(QuartcStream* stream, - iovec* iov, - size_t iov_length, - bool /*fin*/) override { - size_t bytes_consumed = 0; - for (size_t i = 0; i < iov_length; ++i) { - received_data_[stream->id()] += std::string( - static_cast<const char*>(iov[i].iov_base), iov[i].iov_len); - bytes_consumed += iov[i].iov_len; - } - return bytes_consumed; - } - - void OnClose(QuartcStream* stream) override { - errors_[stream->id()] = stream->stream_error(); - } - - void OnBufferChanged(QuartcStream* /*stream*/) override {} - - bool has_data() { return !received_data_.empty(); } - std::map<QuicStreamId, std::string> data() { return received_data_; } - - QuicRstStreamErrorCode stream_error(QuicStreamId id) { return errors_[id]; } - - private: - std::map<QuicStreamId, std::string> received_data_; - std::map<QuicStreamId, QuicRstStreamErrorCode> errors_; -}; - -} // namespace quic - -#endif // QUICHE_QUIC_QUARTC_QUARTC_FAKES_H_ diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_interval_counter.h b/chromium/net/third_party/quiche/src/quic/quartc/quartc_interval_counter.h deleted file mode 100644 index fe3b083c695..00000000000 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_interval_counter.h +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright (c) 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef QUICHE_QUIC_QUARTC_QUARTC_INTERVAL_COUNTER_H_ -#define QUICHE_QUIC_QUARTC_QUARTC_INTERVAL_COUNTER_H_ - -#include <stddef.h> -#include <vector> - -#include "net/third_party/quiche/src/quic/core/quic_interval.h" -#include "net/third_party/quiche/src/quic/core/quic_interval_set.h" - -namespace quic { - -// QuartcIntervalCounter counts the number of times each value appears within -// a set of potentially overlapping intervals. -// -// QuartcIntervalCounter is not intended for widespread use. Consider replacing -// it with a full interval-map if more use cases arise. -// -// QuartcIntervalCounter is only suitable for cases where the maximum count is -// expected to remain low. (For example, counting the number of times the same -// portions of stream data are lost.) It is inefficient when the maximum count -// becomes high. -template <typename T> -class QuartcIntervalCounter { - public: - // Adds |interval| to the counter. The count associated with each value in - // |interval| is incremented by one. |interval| may overlap with previous - // intervals added to the counter. - // - // For each possible value: - // - If the value is present in both |interval| and the counter, the count - // associated with that value is incremented by one. - // - If the value is present in |interval| but not counter, the count - // associated with that value is set to one (incremented from zero). - // - If the value is absent from |interval|, the count is unchanged. - // - // Time complexity is O(|MaxCount| * the complexity of adding an interval to a - // QuicIntervalSet). - void AddInterval(QuicInterval<T> interval); - - // Removes an interval from the counter. This method may be called to prune - // irrelevant intervals from the counter. This is useful to prevent unbounded - // growth. - // - // Time complexity is O(|MaxCount| * the complexity of removing an interval - // from a QuicIntervalSet). - void RemoveInterval(QuicInterval<T> interval); - - // Returns the maximum number of times any single value has appeared in - // intervals added to the counter. - // - // Time complexity is constant. - size_t MaxCount() const { return intervals_by_count_.size(); } - - // Returns the maximum number of times a particular value has appeared in - // intervals added to the counter. - // - // Time complexity is O(|MaxCount| * log(number of non-contiguous intervals)). - size_t Count(const T& value) const; - - private: - // Each entry in this vector represents the intervals of values counted at - // least i + 1 times, where i is the index of the entry. - // - // Whenever an interval is added to the counter, each value in the interval is - // added to the first entry which does not already contain that value. If - // part of an interval is already present in the last entry, a new entry is - // added containing that part. - // - // Note that this means each value present in one of the interval sets will be - // present in all previous sets. - std::vector<QuicIntervalSet<T>> intervals_by_count_; -}; - -template <typename T> -void QuartcIntervalCounter<T>::AddInterval(QuicInterval<T> interval) { - // After the Nth iteration, |leftover| contains the parts of |interval| that - // are already present in the first N entries. These parts of |interval| have - // been added to the counter more than N times. - QuicIntervalSet<T> leftover(interval); - for (auto& intervals : intervals_by_count_) { - QuicIntervalSet<T> tmp = leftover; - leftover.Intersection(intervals); - intervals.Union(tmp); - } - - // Whatever ranges are still in |leftover| are already in all the entries - // Add a new entry containing |leftover|. - if (!leftover.Empty()) { - intervals_by_count_.push_back(leftover); - } -} - -template <typename T> -void QuartcIntervalCounter<T>::RemoveInterval(QuicInterval<T> interval) { - // Remove the interval from each entry in the vector, popping any entries that - // become empty. - for (size_t i = intervals_by_count_.size(); i > 0; --i) { - intervals_by_count_[i - 1].Difference(interval); - if (intervals_by_count_[i - 1].Empty()) { - intervals_by_count_.pop_back(); - } - } -} - -template <typename T> -size_t QuartcIntervalCounter<T>::Count(const T& value) const { - // The index of the last entry containing |value| gives its count. - for (size_t i = intervals_by_count_.size(); i > 0; --i) { - if (intervals_by_count_[i - 1].Contains(value)) { - return i; - } - } - return 0; -} - -} // namespace quic - -#endif // QUICHE_QUIC_QUARTC_QUARTC_INTERVAL_COUNTER_H_ diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_interval_counter_test.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_interval_counter_test.cc deleted file mode 100644 index 028aaf2dab6..00000000000 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_interval_counter_test.cc +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (c) 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/quiche/src/quic/quartc/quartc_interval_counter.h" - -#include "net/third_party/quiche/src/quic/core/quic_interval.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" - -namespace quic { -namespace { - -class QuartcIntervalCounterTest : public QuicTest { - protected: - QuartcIntervalCounter<int> counter_; -}; - -void ExpectCount(const QuartcIntervalCounter<int>& counter, - QuicInterval<int> interval, - size_t count) { - for (int i = interval.min(); i < interval.max(); ++i) { - EXPECT_EQ(counter.Count(i), count) << "i=" << i; - } -} - -TEST_F(QuartcIntervalCounterTest, InitiallyEmpty) { - EXPECT_EQ(counter_.MaxCount(), 0u); -} - -TEST_F(QuartcIntervalCounterTest, SameInterval) { - counter_.AddInterval(QuicInterval<int>(0, 6)); - EXPECT_EQ(counter_.MaxCount(), 1u); - ExpectCount(counter_, QuicInterval<int>(0, 6), 1); - - counter_.AddInterval(QuicInterval<int>(0, 6)); - EXPECT_EQ(counter_.MaxCount(), 2u); - ExpectCount(counter_, QuicInterval<int>(0, 6), 2); -} - -TEST_F(QuartcIntervalCounterTest, DisjointIntervals) { - counter_.AddInterval(QuicInterval<int>(0, 5)); - EXPECT_EQ(counter_.MaxCount(), 1u); - ExpectCount(counter_, QuicInterval<int>(0, 5), 1); - ExpectCount(counter_, QuicInterval<int>(5, 10), 0); - - counter_.AddInterval(QuicInterval<int>(5, 10)); - EXPECT_EQ(counter_.MaxCount(), 1u); - ExpectCount(counter_, QuicInterval<int>(0, 5), 1); - ExpectCount(counter_, QuicInterval<int>(5, 10), 1); -} - -TEST_F(QuartcIntervalCounterTest, OverlappingIntervals) { - counter_.AddInterval(QuicInterval<int>(0, 6)); - EXPECT_EQ(counter_.MaxCount(), 1u); - ExpectCount(counter_, QuicInterval<int>(0, 6), 1); - ExpectCount(counter_, QuicInterval<int>(6, 10), 0); - - counter_.AddInterval(QuicInterval<int>(5, 10)); - EXPECT_EQ(counter_.MaxCount(), 2u); - ExpectCount(counter_, QuicInterval<int>(0, 5), 1); - EXPECT_EQ(counter_.Count(5), 2u); - ExpectCount(counter_, QuicInterval<int>(6, 10), 1); -} - -TEST_F(QuartcIntervalCounterTest, IntervalsWithGapThenOverlap) { - counter_.AddInterval(QuicInterval<int>(0, 4)); - EXPECT_EQ(counter_.MaxCount(), 1u); - ExpectCount(counter_, QuicInterval<int>(0, 4), 1); - ExpectCount(counter_, QuicInterval<int>(4, 10), 0); - - counter_.AddInterval(QuicInterval<int>(7, 10)); - EXPECT_EQ(counter_.MaxCount(), 1u); - ExpectCount(counter_, QuicInterval<int>(0, 4), 1); - ExpectCount(counter_, QuicInterval<int>(4, 7), 0); - ExpectCount(counter_, QuicInterval<int>(7, 10), 1); - - counter_.AddInterval(QuicInterval<int>(3, 8)); - EXPECT_EQ(counter_.MaxCount(), 2u); - ExpectCount(counter_, QuicInterval<int>(0, 3), 1); - EXPECT_EQ(counter_.Count(3), 2u); - ExpectCount(counter_, QuicInterval<int>(4, 7), 1); - EXPECT_EQ(counter_.Count(7), 2u); - ExpectCount(counter_, QuicInterval<int>(8, 10), 1); -} - -TEST_F(QuartcIntervalCounterTest, RemoveIntervals) { - counter_.AddInterval(QuicInterval<int>(0, 5)); - EXPECT_EQ(counter_.MaxCount(), 1u); - ExpectCount(counter_, QuicInterval<int>(0, 5), 1); - - counter_.AddInterval(QuicInterval<int>(4, 10)); - EXPECT_EQ(counter_.MaxCount(), 2u); - ExpectCount(counter_, QuicInterval<int>(0, 4), 1); - EXPECT_EQ(counter_.Count(4), 2u); - ExpectCount(counter_, QuicInterval<int>(5, 10), 1); - - counter_.RemoveInterval(QuicInterval<int>(0, 5)); - EXPECT_EQ(counter_.MaxCount(), 1u); - ExpectCount(counter_, QuicInterval<int>(0, 5), 0); - ExpectCount(counter_, QuicInterval<int>(5, 10), 1); - - counter_.RemoveInterval(QuicInterval<int>(5, 10)); - EXPECT_EQ(counter_.MaxCount(), 0u); - ExpectCount(counter_, QuicInterval<int>(0, 10), 0); -} - -} // namespace -} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_multiplexer.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_multiplexer.cc deleted file mode 100644 index 376fac02c8c..00000000000 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_multiplexer.cc +++ /dev/null @@ -1,271 +0,0 @@ -// Copyright (c) 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/quiche/src/quic/quartc/quartc_multiplexer.h" - -#include <cstdint> -#include <utility> - -#include "net/third_party/quiche/src/quic/core/quic_buffer_allocator.h" -#include "net/third_party/quiche/src/quic/core/quic_data_writer.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_mem_slice.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_mem_slice_span.h" -#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" - -namespace quic { - -QuartcSendChannel::QuartcSendChannel(QuartcMultiplexer* multiplexer, - uint64_t id, - QuicBufferAllocator* allocator, - Delegate* delegate) - : multiplexer_(multiplexer), - id_(id), - encoded_length_(QuicDataWriter::GetVarInt62Len(id_)), - allocator_(allocator), - delegate_(delegate) {} - -QuartcStream* QuartcSendChannel::CreateOutgoingBidirectionalStream() { - if (!session_) { - QUIC_LOG(DFATAL) << "Session is not ready to write yet; channel_id=" << id_; - return nullptr; - } - QuicMemSlice id_slice = EncodeChannelId(); - - QuartcStream* stream = session_->CreateOutgoingBidirectionalStream(); - QuicConsumedData consumed = - stream->WriteMemSlices(QuicMemSliceSpan(&id_slice), /*fin=*/false); - DCHECK_EQ(consumed.bytes_consumed, encoded_length_); - return stream; -} - -bool QuartcSendChannel::SendOrQueueMessage(QuicMemSliceSpan message, - int64_t datagram_id) { - if (!session_) { - QUIC_LOG(DFATAL) << "Session is not ready to write yet; channel_id=" << id_ - << "datagram size=" << message.total_length(); - return false; - } - QuicMemSliceStorage storage(nullptr, 0, nullptr, 0); // Empty storage. - storage.Append(EncodeChannelId()); - - message.ConsumeAll( - [&storage](QuicMemSlice slice) { storage.Append(std::move(slice)); }); - - // Allocate a unique datagram id so that notifications can be routed back to - // the right send channel. - int64_t unique_datagram_id = multiplexer_->AllocateDatagramId(this); - multiplexer_to_user_datagram_ids_[unique_datagram_id] = datagram_id; - - return session_->SendOrQueueMessage(storage.ToSpan(), unique_datagram_id); -} - -void QuartcSendChannel::OnMessageSent(int64_t datagram_id) { - // Map back to the caller-chosen |datagram_id|. - datagram_id = multiplexer_to_user_datagram_ids_[datagram_id]; - delegate_->OnMessageSent(datagram_id); -} - -void QuartcSendChannel::OnMessageAcked(int64_t datagram_id, - QuicTime receive_timestamp) { - // Map back to the caller-chosen |datagram_id|. - auto it = multiplexer_to_user_datagram_ids_.find(datagram_id); - if (it == multiplexer_to_user_datagram_ids_.end()) { - QUIC_LOG(DFATAL) << "Datagram acked/lost multiple times; datagram_id=" - << datagram_id; - return; - } - delegate_->OnMessageAcked(it->second, receive_timestamp); - multiplexer_to_user_datagram_ids_.erase(it); -} - -void QuartcSendChannel::OnMessageLost(int64_t datagram_id) { - // Map back to the caller-chosen |datagram_id|. - auto it = multiplexer_to_user_datagram_ids_.find(datagram_id); - if (it == multiplexer_to_user_datagram_ids_.end()) { - QUIC_LOG(DFATAL) << "Datagram acked/lost multiple times; datagram_id=" - << datagram_id; - return; - } - delegate_->OnMessageLost(it->second); - multiplexer_to_user_datagram_ids_.erase(it); -} - -void QuartcSendChannel::OnSessionCreated(QuartcSession* session) { - session_ = session; -} - -QuicMemSlice QuartcSendChannel::EncodeChannelId() { - QuicUniqueBufferPtr buffer = MakeUniqueBuffer(allocator_, encoded_length_); - QuicDataWriter writer(encoded_length_, buffer.get()); - writer.WriteVarInt62(id_); - return QuicMemSlice(std::move(buffer), encoded_length_); -} - -QuartcMultiplexer::QuartcMultiplexer( - QuicBufferAllocator* allocator, - QuartcSessionEventDelegate* session_delegate, - QuartcReceiveChannel* default_receive_channel) - : allocator_(allocator), - session_delegate_(session_delegate), - default_receive_channel_(default_receive_channel) { - CHECK_NE(session_delegate_, nullptr); - CHECK_NE(default_receive_channel_, nullptr); -} - -QuartcSendChannel* QuartcMultiplexer::CreateSendChannel( - uint64_t channel_id, - QuartcSendChannel::Delegate* delegate) { - send_channels_.push_back(std::make_unique<QuartcSendChannel>( - this, channel_id, allocator_, delegate)); - if (session_) { - send_channels_.back()->OnSessionCreated(session_); - } - return send_channels_.back().get(); -} - -void QuartcMultiplexer::RegisterReceiveChannel(uint64_t channel_id, - QuartcReceiveChannel* channel) { - if (channel == nullptr) { - receive_channels_.erase(channel_id); - return; - } - auto& registered_channel = receive_channels_[channel_id]; - if (registered_channel) { - QUIC_LOG(DFATAL) << "Attempted to overwrite existing channel_id=" - << channel_id; - return; - } - registered_channel = channel; -} - -int64_t QuartcMultiplexer::AllocateDatagramId(QuartcSendChannel* channel) { - send_channels_by_datagram_id_[next_datagram_id_] = channel; - return next_datagram_id_++; -} - -void QuartcMultiplexer::OnSessionCreated(QuartcSession* session) { - for (auto& channel : send_channels_) { - channel->OnSessionCreated(session); - } - session_ = session; - session_delegate_->OnSessionCreated(session); -} - -void QuartcMultiplexer::OnCryptoHandshakeComplete() { - session_delegate_->OnCryptoHandshakeComplete(); -} - -void QuartcMultiplexer::OnConnectionWritable() { - session_delegate_->OnConnectionWritable(); -} - -void QuartcMultiplexer::OnIncomingStream(QuartcStream* stream) { - stream->SetDelegate(this); -} - -void QuartcMultiplexer::OnCongestionControlChange( - QuicBandwidth bandwidth_estimate, - QuicBandwidth pacing_rate, - QuicTime::Delta latest_rtt) { - session_delegate_->OnCongestionControlChange(bandwidth_estimate, pacing_rate, - latest_rtt); -} - -void QuartcMultiplexer::OnConnectionClosed( - const QuicConnectionCloseFrame& frame, - ConnectionCloseSource source) { - session_delegate_->OnConnectionClosed(frame, source); -} - -void QuartcMultiplexer::OnMessageReceived(quiche::QuicheStringPiece message) { - QuicDataReader reader(message); - QuicVariableLengthIntegerLength channel_id_length = - reader.PeekVarInt62Length(); - - uint64_t channel_id; - if (!reader.ReadVarInt62(&channel_id)) { - QUIC_LOG(DFATAL) << "Received message without properly encoded channel id"; - return; - } - - QuartcReceiveChannel* channel = default_receive_channel_; - auto it = receive_channels_.find(channel_id); - if (it != receive_channels_.end()) { - channel = it->second; - } - - channel->OnMessageReceived(channel_id, message.substr(channel_id_length)); -} - -void QuartcMultiplexer::OnMessageSent(int64_t datagram_id) { - auto it = send_channels_by_datagram_id_.find(datagram_id); - if (it == send_channels_by_datagram_id_.end()) { - return; - } - it->second->OnMessageSent(datagram_id); -} - -void QuartcMultiplexer::OnMessageAcked(int64_t datagram_id, - QuicTime receive_timestamp) { - auto it = send_channels_by_datagram_id_.find(datagram_id); - if (it == send_channels_by_datagram_id_.end()) { - return; - } - it->second->OnMessageAcked(datagram_id, receive_timestamp); - send_channels_by_datagram_id_.erase(it); -} - -void QuartcMultiplexer::OnMessageLost(int64_t datagram_id) { - auto it = send_channels_by_datagram_id_.find(datagram_id); - if (it == send_channels_by_datagram_id_.end()) { - return; - } - it->second->OnMessageLost(datagram_id); - send_channels_by_datagram_id_.erase(it); -} - -size_t QuartcMultiplexer::OnReceived(QuartcStream* stream, - iovec* iov, - size_t iov_length, - bool /*fin*/) { - if (iov == nullptr || iov_length <= 0) { - return 0; - } - - QuicDataReader reader(static_cast<char*>(iov[0].iov_base), iov[0].iov_len); - QuicVariableLengthIntegerLength channel_id_length = - reader.PeekVarInt62Length(); - - uint64_t channel_id; - if (reader.BytesRemaining() >= channel_id_length) { - // Fast path, have enough data to read immediately. - if (!reader.ReadVarInt62(&channel_id)) { - return 0; - } - } else { - // Slow path, need to coalesce multiple iovecs. - std::string data; - for (size_t i = 0; i < iov_length; ++i) { - data += std::string(static_cast<char*>(iov[i].iov_base), iov[i].iov_len); - } - QuicDataReader combined_reader(data); - if (!combined_reader.ReadVarInt62(&channel_id)) { - return 0; - } - } - - QuartcReceiveChannel* channel = default_receive_channel_; - auto it = receive_channels_.find(channel_id); - if (it != receive_channels_.end()) { - channel = it->second; - } - channel->OnIncomingStream(channel_id, stream); - return channel_id_length; -} - -void QuartcMultiplexer::OnClose(QuartcStream* /*stream*/) {} - -void QuartcMultiplexer::OnBufferChanged(QuartcStream* /*stream*/) {} - -} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_multiplexer.h b/chromium/net/third_party/quiche/src/quic/quartc/quartc_multiplexer.h deleted file mode 100644 index 1e6c2e5dbdf..00000000000 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_multiplexer.h +++ /dev/null @@ -1,190 +0,0 @@ -// Copyright (c) 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef QUICHE_QUIC_QUARTC_QUARTC_MULTIPLEXER_H_ -#define QUICHE_QUIC_QUARTC_QUARTC_MULTIPLEXER_H_ - -#include <cstdint> - -#include "net/third_party/quiche/src/quic/core/quic_time.h" -#include "net/third_party/quiche/src/quic/core/quic_types.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_mem_slice_span.h" -#include "net/third_party/quiche/src/quic/quartc/quartc_endpoint.h" -#include "net/third_party/quiche/src/quic/quartc/quartc_session.h" -#include "net/third_party/quiche/src/quic/quartc/quartc_stream.h" -#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" - -namespace quic { - -class QuartcMultiplexer; - -// A single, multiplexed send channel within a Quartc session. A send channel -// wraps send-side operations with an outgoing multiplex id. -class QuartcSendChannel { - public: - class Delegate { - public: - virtual ~Delegate() = default; - - // Called when a message with |datagram_id| is sent by this channel. - virtual void OnMessageSent(int64_t datagram_id) = 0; - - // Called when a message sent on this channel with |datagram_id| is acked. - // |receive_timestamp| indicates when the peer received this message, - // according to the peer's clock. - virtual void OnMessageAcked(int64_t datagram_id, - QuicTime receive_timestamp) = 0; - - // Called when a message sent on this channel with |datagram_id| is lost. - virtual void OnMessageLost(int64_t datagram_id) = 0; - }; - - QuartcSendChannel(QuartcMultiplexer* multiplexer, - uint64_t id, - QuicBufferAllocator* allocator, - Delegate* delegate); - virtual ~QuartcSendChannel() = default; - - // Creates a new, outgoing stream on this channel. - // - // Automatically writes the channel id to the start of the stream. The caller - // SHOULD create a |ScopedPacketFlusher| before calling this function to - // prevent the channel id from being sent by itself. - QuartcStream* CreateOutgoingBidirectionalStream(); - - // Writes |message| to the session. Prepends the channel's send id before any - // following message data. - bool SendOrQueueMessage(QuicMemSliceSpan message, int64_t datagram_id); - - // Gets the current largest message payload for this channel. Returns the - // largest payload size supported by the session minus overhead required to - // encode this channel's send id. - QuicPacketLength GetCurrentLargestMessagePayload() const; - - // The following are called by the multiplexer to deliver message - // notifications. The |datagram_id| passed to these is unique per-message, - // and must be translated back to the sender's chosen datagram_id. - void OnMessageSent(int64_t datagram_id); - void OnMessageAcked(int64_t datagram_id, QuicTime receive_timestamp); - void OnMessageLost(int64_t datagram_id); - void OnSessionCreated(QuartcSession* session); - - private: - // Creates a mem slice containing a varint-62 encoded channel id. - QuicMemSlice EncodeChannelId(); - - QuartcMultiplexer* const multiplexer_; - const uint64_t id_; - const QuicVariableLengthIntegerLength encoded_length_; - QuicBufferAllocator* const allocator_; - Delegate* const delegate_; - - QuartcSession* session_; - - // Map of multiplexer-chosen to user/caller-specified datagram ids. The user - // may specify any number as a datagram's id. This number does not have to be - // unique across channels (nor even within a single channel). In order - // to demux sent, acked, and lost messages, the multiplexer assigns a globally - // unique id to each message. This map is used to restore the original caller - // datagram id before issuing callbacks. - QuicHashMap<int64_t, int64_t> multiplexer_to_user_datagram_ids_; -}; - -// A single, multiplexed receive channel within a Quartc session. A receive -// channel is a delegate which accepts incoming streams and datagrams on one (or -// more) channel ids. -class QuartcReceiveChannel { - public: - virtual ~QuartcReceiveChannel() = default; - - // Called when a new incoming stream arrives on this channel. - virtual void OnIncomingStream(uint64_t channel_id, QuartcStream* stream) = 0; - - // Called when a message is recieved by this channel. - virtual void OnMessageReceived(uint64_t channel_id, - quiche::QuicheStringPiece message) = 0; -}; - -// Delegate for session-wide events. -class QuartcSessionEventDelegate { - public: - virtual ~QuartcSessionEventDelegate() = default; - - virtual void OnSessionCreated(QuartcSession* session) = 0; - virtual void OnCryptoHandshakeComplete() = 0; - virtual void OnConnectionWritable() = 0; - virtual void OnCongestionControlChange(QuicBandwidth bandwidth_estimate, - QuicBandwidth pacing_rate, - QuicTime::Delta latest_rtt) = 0; - virtual void OnConnectionClosed(const QuicConnectionCloseFrame& frame, - ConnectionCloseSource source) = 0; -}; - -// A multiplexer capable of sending and receiving data on multiple channels. -class QuartcMultiplexer : public QuartcEndpoint::Delegate, - public QuartcStream::Delegate { - public: - // Creates a new multiplexer. |session_delegate| handles all session-wide - // events, while |default_receive_channel| handles incoming data on unknown - // or unregistered channel ids. Neither |session_delegate| nor - // |default_receive_channel| may be nullptr, and both must outlive the - // multiplexer. - QuartcMultiplexer(QuicBufferAllocator* allocator, - QuartcSessionEventDelegate* session_delegate, - QuartcReceiveChannel* default_receive_channel); - - // Creates a new send channel. The channel is owned by the multiplexer, and - // references to it must not outlive the multiplexer. - QuartcSendChannel* CreateSendChannel(uint64_t channel_id, - QuartcSendChannel::Delegate* delegate); - - // Registers a receiver for incoming data on |channel_id|. - void RegisterReceiveChannel(uint64_t channel_id, - QuartcReceiveChannel* channel); - - // Allocates a datagram id to |channel|. - int64_t AllocateDatagramId(QuartcSendChannel* channel); - - // QuartcEndpoint::Delegate overrides. - void OnSessionCreated(QuartcSession* session) override; - - // QuartcSession::Delegate overrides. - void OnCryptoHandshakeComplete() override; - void OnConnectionWritable() override; - void OnIncomingStream(QuartcStream* stream) override; - void OnCongestionControlChange(QuicBandwidth bandwidth_estimate, - QuicBandwidth pacing_rate, - QuicTime::Delta latest_rtt) override; - void OnConnectionClosed(const QuicConnectionCloseFrame& frame, - ConnectionCloseSource source) override; - void OnMessageReceived(quiche::QuicheStringPiece message) override; - void OnMessageSent(int64_t datagram_id) override; - void OnMessageAcked(int64_t datagram_id, QuicTime receive_timestamp) override; - void OnMessageLost(int64_t datagram_id) override; - - // QuartcStream::Delegate overrides. - size_t OnReceived(QuartcStream* stream, - iovec* iov, - size_t iov_length, - bool fin) override; - void OnClose(QuartcStream* stream) override; - void OnBufferChanged(QuartcStream* stream) override; - - private: - QuicBufferAllocator* const allocator_; - QuartcSessionEventDelegate* const session_delegate_; - - QuartcSession* session_ = nullptr; - std::vector<std::unique_ptr<QuartcSendChannel>> send_channels_; - QuicHashMap<uint64_t, QuartcReceiveChannel*> receive_channels_; - QuartcReceiveChannel* default_receive_channel_ = nullptr; - - int64_t next_datagram_id_ = 1; - QuicHashMap<int64_t, QuartcSendChannel*> send_channels_by_datagram_id_; -}; - -} // namespace quic - -#endif // QUICHE_QUIC_QUARTC_QUARTC_MULTIPLEXER_H_ diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_multiplexer_test.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_multiplexer_test.cc deleted file mode 100644 index 024b67d8a94..00000000000 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_multiplexer_test.cc +++ /dev/null @@ -1,496 +0,0 @@ -// Copyright (c) 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/quiche/src/quic/quartc/quartc_multiplexer.h" - -#include <memory> -#include <utility> - -#include "net/third_party/quiche/src/quic/core/frames/quic_connection_close_frame.h" -#include "net/third_party/quiche/src/quic/core/quic_bandwidth.h" -#include "net/third_party/quiche/src/quic/core/quic_buffer_allocator.h" -#include "net/third_party/quiche/src/quic/core/quic_time.h" -#include "net/third_party/quiche/src/quic/core/quic_types.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_test_mem_slice_vector.h" -#include "net/third_party/quiche/src/quic/quartc/counting_packet_filter.h" -#include "net/third_party/quiche/src/quic/quartc/quartc_endpoint.h" -#include "net/third_party/quiche/src/quic/quartc/quartc_fakes.h" -#include "net/third_party/quiche/src/quic/quartc/quartc_session.h" -#include "net/third_party/quiche/src/quic/quartc/quartc_stream.h" -#include "net/third_party/quiche/src/quic/quartc/simulated_packet_transport.h" -#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" -#include "net/third_party/quiche/src/quic/test_tools/simulator/link.h" -#include "net/third_party/quiche/src/quic/test_tools/simulator/simulator.h" -#include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h" -#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" - -namespace quic { -namespace { - -using ::testing::ElementsAreArray; -using ::testing::Gt; -using ::testing::IsEmpty; -using ::testing::Pair; - -constexpr QuicTime::Delta kPropagationDelay = - QuicTime::Delta::FromMilliseconds(10); - -class FakeSessionEventDelegate : public QuartcSessionEventDelegate { - public: - void OnSessionCreated(QuartcSession* session) override { - session->StartCryptoHandshake(); - session_ = session; - } - - void OnConnectionWritable() override { ++writable_count_; } - - void OnCryptoHandshakeComplete() override { ++handshake_count_; } - - void OnConnectionClosed(const QuicConnectionCloseFrame& frame, - ConnectionCloseSource source) override { - error_ = frame.quic_error_code; - close_source_ = source; - } - - void OnCongestionControlChange(QuicBandwidth bandwidth_estimate, - QuicBandwidth pacing_rate, - QuicTime::Delta latest_rtt) override { - latest_bandwidth_estimate_ = bandwidth_estimate; - latest_pacing_rate_ = pacing_rate; - latest_rtt_ = latest_rtt; - } - - QuartcSession* session() { return session_; } - int writable_count() const { return writable_count_; } - int handshake_count() const { return handshake_count_; } - QuicErrorCode error() const { return error_; } - ConnectionCloseSource close_source() const { return close_source_; } - QuicBandwidth latest_bandwidth_estimate() const { - return latest_bandwidth_estimate_; - } - QuicBandwidth latest_pacing_rate() const { return latest_pacing_rate_; } - QuicTime::Delta latest_rtt() const { return latest_rtt_; } - - private: - QuartcSession* session_ = nullptr; - int writable_count_ = 0; - int handshake_count_ = 0; - QuicErrorCode error_ = QUIC_NO_ERROR; - ConnectionCloseSource close_source_; - QuicBandwidth latest_bandwidth_estimate_ = QuicBandwidth::Zero(); - QuicBandwidth latest_pacing_rate_ = QuicBandwidth::Zero(); - QuicTime::Delta latest_rtt_ = QuicTime::Delta::Zero(); -}; - -class FakeSendDelegate : public QuartcSendChannel::Delegate { - public: - void OnMessageSent(int64_t datagram_id) override { - datagrams_sent_.push_back(datagram_id); - } - - void OnMessageAcked(int64_t datagram_id, - QuicTime receive_timestamp) override { - datagrams_acked_.push_back({datagram_id, receive_timestamp}); - } - - void OnMessageLost(int64_t datagram_id) override { - datagrams_lost_.push_back(datagram_id); - } - - const std::vector<int64_t>& datagrams_sent() const { return datagrams_sent_; } - const std::vector<std::pair<int64_t, QuicTime>>& datagrams_acked() const { - return datagrams_acked_; - } - const std::vector<int64_t>& datagrams_lost() const { return datagrams_lost_; } - - private: - std::vector<int64_t> datagrams_sent_; - std::vector<std::pair<int64_t, QuicTime>> datagrams_acked_; - std::vector<int64_t> datagrams_lost_; -}; - -class FakeReceiveDelegate : public QuartcReceiveChannel, - public QuartcStream::Delegate { - public: - const std::vector<std::pair<uint64_t, std::string>> messages_received() - const { - return messages_received_; - } - - void OnIncomingStream(uint64_t channel_id, QuartcStream* stream) override { - stream->SetDelegate(this); - stream_to_channel_id_[stream] = channel_id; - } - - void OnMessageReceived(uint64_t channel_id, - quiche::QuicheStringPiece message) override { - messages_received_.emplace_back(channel_id, message); - } - - // Stream delegate overrides. - size_t OnReceived(QuartcStream* stream, - iovec* iov, - size_t iov_length, - bool fin) override { - if (!fin) { - return 0; - } - - size_t bytes = 0; - std::string message; - for (size_t i = 0; i < iov_length; ++i) { - message += - std::string(static_cast<char*>(iov[i].iov_base), iov[i].iov_len); - bytes += iov[i].iov_len; - } - QUIC_LOG(INFO) << "Received " << bytes << " byte message on channel " - << stream_to_channel_id_[stream]; - messages_received_.emplace_back(stream_to_channel_id_[stream], message); - return bytes; - } - - void OnClose(QuartcStream* stream) override { - stream_to_channel_id_.erase(stream); - } - - void OnBufferChanged(QuartcStream* /*stream*/) override {} - - private: - std::vector<std::pair<uint64_t, std::string>> messages_received_; - QuicUnorderedMap<QuartcStream*, uint64_t> stream_to_channel_id_; -}; - -class QuartcMultiplexerTest : public QuicTest { - public: - QuartcMultiplexerTest() - : simulator_(), - client_transport_(&simulator_, - "client_transport", - "server_transport", - 10 * kDefaultMaxPacketSize), - server_transport_(&simulator_, - "server_transport", - "client_transport", - 10 * kDefaultMaxPacketSize), - client_filter_(&simulator_, "client_filter", &client_transport_), - client_server_link_(&client_filter_, - &server_transport_, - QuicBandwidth::FromKBitsPerSecond(10 * 1000), - kPropagationDelay), - client_multiplexer_(simulator_.GetStreamSendBufferAllocator(), - &client_session_delegate_, - &client_default_receiver_), - server_multiplexer_(simulator_.GetStreamSendBufferAllocator(), - &server_session_delegate_, - &server_default_receiver_), - client_endpoint_(std::make_unique<QuartcClientEndpoint>( - simulator_.GetAlarmFactory(), - simulator_.GetClock(), - simulator_.GetRandomGenerator(), - &client_multiplexer_, - quic::QuartcSessionConfig(), - /*serialized_server_config=*/"")), - server_endpoint_(std::make_unique<QuartcServerEndpoint>( - simulator_.GetAlarmFactory(), - simulator_.GetClock(), - simulator_.GetRandomGenerator(), - &server_multiplexer_, - quic::QuartcSessionConfig())) { - // TODO(b/150224094): Re-enable TLS handshake. - // TODO(b/150236522): Parametrize by QUIC version. - quic::test::DisableQuicVersionsWithTls(); - } - - void Connect() { - client_endpoint_->Connect(&client_transport_); - server_endpoint_->Connect(&server_transport_); - ASSERT_TRUE(simulator_.RunUntil([this]() { - return client_session_delegate_.writable_count() > 0 && - server_session_delegate_.writable_count() > 0; - })); - } - - void Disconnect() { - client_session_delegate_.session()->CloseConnection("test"); - server_session_delegate_.session()->CloseConnection("test"); - } - - protected: - QuartcMultiplexer* client_multiplexer() { return &client_multiplexer_; } - - QuartcMultiplexer* server_multiplexer() { return &server_multiplexer_; } - - simulator::Simulator simulator_; - - simulator::SimulatedQuartcPacketTransport client_transport_; - simulator::SimulatedQuartcPacketTransport server_transport_; - simulator::CountingPacketFilter client_filter_; - simulator::SymmetricLink client_server_link_; - - FakeSessionEventDelegate client_session_delegate_; - FakeSessionEventDelegate server_session_delegate_; - - FakeReceiveDelegate client_default_receiver_; - FakeReceiveDelegate server_default_receiver_; - - QuartcMultiplexer client_multiplexer_; - QuartcMultiplexer server_multiplexer_; - - std::unique_ptr<QuartcClientEndpoint> client_endpoint_; - std::unique_ptr<QuartcServerEndpoint> server_endpoint_; -}; - -TEST_F(QuartcMultiplexerTest, MultiplexMessages) { - Connect(); - - FakeSendDelegate send_delegate_1; - QuartcSendChannel* send_channel_1 = - client_multiplexer()->CreateSendChannel(1, &send_delegate_1); - FakeSendDelegate send_delegate_2; - QuartcSendChannel* send_channel_2 = - client_multiplexer()->CreateSendChannel(2, &send_delegate_2); - - FakeReceiveDelegate receive_delegate_1; - server_multiplexer()->RegisterReceiveChannel(1, &receive_delegate_1); - - int num_messages = 10; - std::vector<std::pair<uint64_t, std::string>> messages_1; - messages_1.reserve(num_messages); - std::vector<std::pair<uint64_t, std::string>> messages_2; - messages_2.reserve(num_messages); - std::vector<int64_t> messages_sent_1; - std::vector<int64_t> messages_sent_2; - std::vector<testing::Matcher<std::pair<int64_t, QuicTime>>> ack_matchers_1; - std::vector<testing::Matcher<std::pair<int64_t, QuicTime>>> ack_matchers_2; - for (int i = 0; i < num_messages; ++i) { - messages_1.emplace_back(1, quiche::QuicheStrCat("message for 1: ", i)); - test::QuicTestMemSliceVector slice_1( - {std::make_pair(const_cast<char*>(messages_1.back().second.data()), - messages_1.back().second.size())}); - send_channel_1->SendOrQueueMessage(slice_1.span(), i); - messages_sent_1.push_back(i); - ack_matchers_1.push_back(Pair(i, Gt(QuicTime::Zero()))); - - messages_2.emplace_back(2, quiche::QuicheStrCat("message for 2: ", i)); - test::QuicTestMemSliceVector slice_2( - {std::make_pair(const_cast<char*>(messages_2.back().second.data()), - messages_2.back().second.size())}); - // Use i + 5 as the datagram id for channel 2, so that some of the ids - // overlap and some are disjoint. - send_channel_2->SendOrQueueMessage(slice_2.span(), i + 5); - messages_sent_2.push_back(i + 5); - ack_matchers_2.push_back(Pair(i + 5, Gt(QuicTime::Zero()))); - } - - EXPECT_TRUE(simulator_.RunUntil([&send_delegate_1, &send_delegate_2]() { - return send_delegate_1.datagrams_acked().size() == 10 && - send_delegate_2.datagrams_acked().size() == 10; - })); - - EXPECT_EQ(send_delegate_1.datagrams_sent(), messages_sent_1); - EXPECT_EQ(send_delegate_2.datagrams_sent(), messages_sent_2); - - EXPECT_EQ(receive_delegate_1.messages_received(), messages_1); - EXPECT_EQ(server_default_receiver_.messages_received(), messages_2); - - EXPECT_THAT(send_delegate_1.datagrams_acked(), - ElementsAreArray(ack_matchers_1)); - EXPECT_THAT(send_delegate_2.datagrams_acked(), - ElementsAreArray(ack_matchers_2)); -} - -TEST_F(QuartcMultiplexerTest, MultiplexStreams) { - FakeSendDelegate send_delegate_1; - QuartcSendChannel* send_channel_1 = - client_multiplexer()->CreateSendChannel(1, &send_delegate_1); - FakeSendDelegate send_delegate_2; - QuartcSendChannel* send_channel_2 = - client_multiplexer()->CreateSendChannel(2, &send_delegate_2); - - FakeQuartcStreamDelegate fake_send_stream_delegate; - - FakeReceiveDelegate receive_delegate_1; - server_multiplexer()->RegisterReceiveChannel(1, &receive_delegate_1); - - Connect(); - - int num_messages = 10; - std::vector<std::pair<uint64_t, std::string>> messages_1; - messages_1.reserve(num_messages); - std::vector<std::pair<uint64_t, std::string>> messages_2; - messages_2.reserve(num_messages); - for (int i = 0; i < num_messages; ++i) { - messages_1.emplace_back(1, quiche::QuicheStrCat("message for 1: ", i)); - test::QuicTestMemSliceVector slice_1( - {std::make_pair(const_cast<char*>(messages_1.back().second.data()), - messages_1.back().second.size())}); - QuartcStream* stream_1 = - send_channel_1->CreateOutgoingBidirectionalStream(); - stream_1->SetDelegate(&fake_send_stream_delegate); - stream_1->WriteMemSlices(slice_1.span(), /*fin=*/true); - - messages_2.emplace_back(2, quiche::QuicheStrCat("message for 2: ", i)); - test::QuicTestMemSliceVector slice_2( - {std::make_pair(const_cast<char*>(messages_2.back().second.data()), - messages_2.back().second.size())}); - QuartcStream* stream_2 = - send_channel_2->CreateOutgoingBidirectionalStream(); - stream_2->SetDelegate(&fake_send_stream_delegate); - stream_2->WriteMemSlices(slice_2.span(), /*fin=*/true); - } - - EXPECT_TRUE(simulator_.RunUntilOrTimeout( - [this, &receive_delegate_1]() { - return receive_delegate_1.messages_received().size() == 10 && - server_default_receiver_.messages_received().size() == 10; - }, - QuicTime::Delta::FromSeconds(5))); - - EXPECT_EQ(receive_delegate_1.messages_received(), messages_1); - EXPECT_EQ(server_default_receiver_.messages_received(), messages_2); -} - -// Tests that datagram-lost callbacks are invoked on the right send channel -// delegate, and that they work with overlapping datagram ids. -TEST_F(QuartcMultiplexerTest, MultiplexLostDatagrams) { - Connect(); - ASSERT_TRUE(simulator_.RunUntil([this]() { - return client_session_delegate_.handshake_count() > 0 && - server_session_delegate_.handshake_count() > 0; - })); - - // Just drop everything we try to send. - client_filter_.set_packets_to_drop(30); - - FakeSendDelegate send_delegate_1; - QuartcSendChannel* send_channel_1 = - client_multiplexer()->CreateSendChannel(1, &send_delegate_1); - FakeSendDelegate send_delegate_2; - QuartcSendChannel* send_channel_2 = - client_multiplexer()->CreateSendChannel(2, &send_delegate_2); - - FakeQuartcStreamDelegate fake_send_stream_delegate; - - FakeReceiveDelegate receive_delegate_1; - server_multiplexer()->RegisterReceiveChannel(1, &receive_delegate_1); - - int num_messages = 10; - std::vector<std::pair<uint64_t, std::string>> messages_1; - messages_1.reserve(num_messages); - std::vector<std::pair<uint64_t, std::string>> messages_2; - messages_2.reserve(num_messages); - std::vector<int64_t> messages_sent_1; - std::vector<int64_t> messages_sent_2; - for (int i = 0; i < num_messages; ++i) { - messages_1.emplace_back(1, quiche::QuicheStrCat("message for 1: ", i)); - test::QuicTestMemSliceVector slice_1( - {std::make_pair(const_cast<char*>(messages_1.back().second.data()), - messages_1.back().second.size())}); - send_channel_1->SendOrQueueMessage(slice_1.span(), i); - messages_sent_1.push_back(i); - - messages_2.emplace_back(2, quiche::QuicheStrCat("message for 2: ", i)); - test::QuicTestMemSliceVector slice_2( - {std::make_pair(const_cast<char*>(messages_2.back().second.data()), - messages_2.back().second.size())}); - // Use i + 5 as the datagram id for channel 2, so that some of the ids - // overlap and some are disjoint. - send_channel_2->SendOrQueueMessage(slice_2.span(), i + 5); - messages_sent_2.push_back(i + 5); - } - - // Now send something retransmittable to prompt loss detection. - // If we never send anything retransmittable, we will never get acks, and - // never detect losses. - messages_1.emplace_back( - 1, quiche::QuicheStrCat("message for 1: ", num_messages)); - test::QuicTestMemSliceVector slice( - {std::make_pair(const_cast<char*>(messages_1.back().second.data()), - messages_1.back().second.size())}); - QuartcStream* stream_1 = send_channel_1->CreateOutgoingBidirectionalStream(); - stream_1->SetDelegate(&fake_send_stream_delegate); - stream_1->WriteMemSlices(slice.span(), /*fin=*/true); - - EXPECT_TRUE(simulator_.RunUntilOrTimeout( - [&send_delegate_1, &send_delegate_2]() { - return send_delegate_1.datagrams_lost().size() == 10 && - send_delegate_2.datagrams_lost().size() == 10; - }, - QuicTime::Delta::FromSeconds(60))); - - EXPECT_EQ(send_delegate_1.datagrams_lost(), messages_sent_1); - EXPECT_EQ(send_delegate_2.datagrams_lost(), messages_sent_2); - - EXPECT_THAT(send_delegate_1.datagrams_acked(), IsEmpty()); - EXPECT_THAT(send_delegate_2.datagrams_acked(), IsEmpty()); - - EXPECT_THAT(receive_delegate_1.messages_received(), IsEmpty()); - EXPECT_THAT(server_default_receiver_.messages_received(), IsEmpty()); -} - -TEST_F(QuartcMultiplexerTest, UnregisterReceiveChannel) { - Connect(); - - FakeSendDelegate send_delegate; - QuartcSendChannel* send_channel = - client_multiplexer()->CreateSendChannel(1, &send_delegate); - FakeQuartcStreamDelegate fake_send_stream_delegate; - - FakeReceiveDelegate receive_delegate; - server_multiplexer()->RegisterReceiveChannel(1, &receive_delegate); - server_multiplexer()->RegisterReceiveChannel(1, nullptr); - - int num_messages = 10; - std::vector<std::pair<uint64_t, std::string>> messages; - messages.reserve(num_messages); - std::vector<int64_t> messages_sent; - std::vector<testing::Matcher<std::pair<int64_t, QuicTime>>> ack_matchers; - for (int i = 0; i < num_messages; ++i) { - messages.emplace_back(1, quiche::QuicheStrCat("message for 1: ", i)); - test::QuicTestMemSliceVector slice( - {std::make_pair(const_cast<char*>(messages.back().second.data()), - messages.back().second.size())}); - send_channel->SendOrQueueMessage(slice.span(), i); - messages_sent.push_back(i); - ack_matchers.push_back(Pair(i, Gt(QuicTime::Zero()))); - } - - EXPECT_TRUE(simulator_.RunUntil([&send_delegate]() { - return send_delegate.datagrams_acked().size() == 10; - })); - - EXPECT_EQ(send_delegate.datagrams_sent(), messages_sent); - EXPECT_EQ(server_default_receiver_.messages_received(), messages); - EXPECT_THAT(send_delegate.datagrams_acked(), ElementsAreArray(ack_matchers)); -} - -TEST_F(QuartcMultiplexerTest, CloseEvent) { - Connect(); - Disconnect(); - - EXPECT_THAT(client_session_delegate_.error(), - test::IsError(QUIC_CONNECTION_CANCELLED)); - EXPECT_THAT(server_session_delegate_.error(), - test::IsError(QUIC_CONNECTION_CANCELLED)); -} - -TEST_F(QuartcMultiplexerTest, CongestionEvent) { - Connect(); - ASSERT_TRUE(simulator_.RunUntil([this]() { - return client_session_delegate_.handshake_count() > 0 && - server_session_delegate_.handshake_count() > 0; - })); - - EXPECT_GT(client_session_delegate_.latest_bandwidth_estimate(), - QuicBandwidth::Zero()); - EXPECT_GT(client_session_delegate_.latest_pacing_rate(), - QuicBandwidth::Zero()); - EXPECT_GT(client_session_delegate_.latest_rtt(), QuicTime::Delta::Zero()); -} - -} // namespace -} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_packet_writer.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_packet_writer.cc deleted file mode 100644 index f67cc774ea8..00000000000 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_packet_writer.cc +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright (c) 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/quiche/src/quic/quartc/quartc_packet_writer.h" - -#include <utility> - -namespace quic { - -std::unique_ptr<PerPacketOptions> QuartcPerPacketOptions::Clone() const { - return std::make_unique<QuartcPerPacketOptions>(*this); -} - -QuartcPacketWriter::QuartcPacketWriter(QuartcPacketTransport* packet_transport, - QuicByteCount max_packet_size) - : packet_transport_(packet_transport), max_packet_size_(max_packet_size) {} - -WriteResult QuartcPacketWriter::WritePacket( - const char* buffer, - size_t buf_len, - const QuicIpAddress& /*self_address*/, - const QuicSocketAddress& /*peer_address*/, - PerPacketOptions* options) { - DCHECK(packet_transport_); - - QuartcPacketTransport::PacketInfo info; - QuartcPerPacketOptions* quartc_options = - static_cast<QuartcPerPacketOptions*>(options); - if (quartc_options && quartc_options->connection) { - info.packet_number = - quartc_options->connection->packet_creator().packet_number(); - } - int bytes_written = packet_transport_->Write(buffer, buf_len, info); - if (bytes_written <= 0) { - writable_ = false; - return WriteResult(WRITE_STATUS_BLOCKED, EWOULDBLOCK); - } - return WriteResult(WRITE_STATUS_OK, bytes_written); -} - -bool QuartcPacketWriter::IsWriteBlocked() const { - return !writable_; -} - -QuicByteCount QuartcPacketWriter::GetMaxPacketSize( - const QuicSocketAddress& /*peer_address*/) const { - return max_packet_size_; -} - -void QuartcPacketWriter::SetWritable() { - writable_ = true; -} - -bool QuartcPacketWriter::SupportsReleaseTime() const { - return false; -} - -bool QuartcPacketWriter::IsBatchMode() const { - return false; -} - -char* QuartcPacketWriter::GetNextWriteLocation( - const QuicIpAddress& /*self_address*/, - const QuicSocketAddress& /*peer_address*/) { - return nullptr; -} - -WriteResult QuartcPacketWriter::Flush() { - return WriteResult(WRITE_STATUS_OK, 0); -} - -void QuartcPacketWriter::SetPacketTransportDelegate( - QuartcPacketTransport::Delegate* delegate) { - packet_transport_->SetDelegate(delegate); -} - -} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_packet_writer.h b/chromium/net/third_party/quiche/src/quic/quartc/quartc_packet_writer.h deleted file mode 100644 index f3eb885fd53..00000000000 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_packet_writer.h +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright (c) 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef QUICHE_QUIC_QUARTC_QUARTC_PACKET_WRITER_H_ -#define QUICHE_QUIC_QUARTC_QUARTC_PACKET_WRITER_H_ - -#include "net/third_party/quiche/src/quic/core/quic_connection.h" -#include "net/third_party/quiche/src/quic/core/quic_packet_writer.h" -#include "net/third_party/quiche/src/quic/core/quic_types.h" - -namespace quic { - -// Send and receive packets, like a virtual UDP socket. For example, this -// could be implemented by WebRTC's IceTransport. -class QuartcPacketTransport { - public: - // Additional metadata provided for each packet written. - struct PacketInfo { - QuicPacketNumber packet_number; - }; - - // Delegate for packet transport callbacks. Note that the delegate is not - // thread-safe. Packet transport implementations must ensure that callbacks - // are synchronized with all other work done by QUIC. - class Delegate { - public: - virtual ~Delegate() = default; - - // Called whenever the transport can write. - virtual void OnTransportCanWrite() = 0; - - // Called when the transport receives a packet. - virtual void OnTransportReceived(const char* data, size_t data_len) = 0; - }; - - virtual ~QuartcPacketTransport() {} - - // Called by the QuartcPacketWriter when writing packets to the network. - // Return the number of written bytes. Return 0 if the write is blocked. - virtual int Write(const char* buffer, - size_t buf_len, - const PacketInfo& info) = 0; - - // Sets the delegate which must be called when the transport can write or - // a packet is received. QUIC sets |delegate| to a nonnull pointer when it - // is ready to process incoming packets and sets |delegate| to nullptr before - // QUIC is deleted. Implementations may assume |delegate| remains valid until - // it is set to nullptr. - virtual void SetDelegate(Delegate* delegate) = 0; -}; - -struct QuartcPerPacketOptions : public PerPacketOptions { - std::unique_ptr<PerPacketOptions> Clone() const override; - - // The connection which is sending this packet. - QuicConnection* connection = nullptr; -}; - -// Implements a QuicPacketWriter using a QuartcPacketTransport, which allows a -// QuicConnection to use (for example), a WebRTC IceTransport. -class QuartcPacketWriter : public QuicPacketWriter { - public: - QuartcPacketWriter(QuartcPacketTransport* packet_transport, - QuicByteCount max_packet_size); - ~QuartcPacketWriter() override {} - - // The QuicConnection calls WritePacket and the QuicPacketWriter writes them - // to the QuartcSession::PacketTransport. - WriteResult WritePacket(const char* buffer, - size_t buf_len, - const QuicIpAddress& self_address, - const QuicSocketAddress& peer_address, - PerPacketOptions* options) override; - - // Whether the underneath |transport_| is blocked. If this returns true, - // outgoing QUIC packets are queued by QuicConnection until SetWritable() is - // called. - bool IsWriteBlocked() const override; - - // Maximum size of the QUIC packet which can be written. Users such as WebRTC - // can set the value through the QuartcFactoryConfig without updating the QUIC - // code. - QuicByteCount GetMaxPacketSize( - const QuicSocketAddress& peer_address) const override; - - // Sets the packet writer to a writable (non-blocked) state. - void SetWritable() override; - - bool SupportsReleaseTime() const override; - - bool IsBatchMode() const override; - - char* GetNextWriteLocation(const QuicIpAddress& self_address, - const QuicSocketAddress& peer_address) override; - - WriteResult Flush() override; - - void SetPacketTransportDelegate(QuartcPacketTransport::Delegate* delegate); - - private: - // QuartcPacketWriter will not own the transport. - QuartcPacketTransport* packet_transport_; - // The maximum size of the packet can be written by this writer. - QuicByteCount max_packet_size_; - - // Whether packets can be written. - bool writable_ = false; -}; - -} // namespace quic - -#endif // QUICHE_QUIC_QUARTC_QUARTC_PACKET_WRITER_H_ diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_session.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_session.cc deleted file mode 100644 index 0a7fca933bf..00000000000 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_session.cc +++ /dev/null @@ -1,470 +0,0 @@ -// Copyright (c) 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/quiche/src/quic/quartc/quartc_session.h" - -#include <utility> - -#include "net/third_party/quiche/src/quic/core/quic_utils.h" -#include "net/third_party/quiche/src/quic/core/tls_client_handshaker.h" -#include "net/third_party/quiche/src/quic/core/tls_server_handshaker.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_mem_slice_storage.h" -#include "net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.h" -#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" - -namespace quic { -namespace { - -// Arbitrary server port number for net::QuicCryptoClientConfig. -const int kQuicServerPort = 0; - -} // namespace - -QuartcSession::QuartcSession(std::unique_ptr<QuicConnection> connection, - Visitor* visitor, - const QuicConfig& config, - const ParsedQuicVersionVector& supported_versions, - const QuicClock* clock) - : QuicSession(connection.get(), - visitor, - config, - supported_versions, - /*num_expected_unidirectional_static_streams = */ 0), - connection_(std::move(connection)), - clock_(clock), - per_packet_options_(std::make_unique<QuartcPerPacketOptions>()) { - per_packet_options_->connection = connection_.get(); - connection_->set_per_packet_options(per_packet_options_.get()); -} - -QuartcSession::~QuartcSession() {} - -QuartcStream* QuartcSession::CreateOutgoingBidirectionalStream() { - // Use default priority for incoming QUIC streams. - // TODO(zhihuang): Determine if this value is correct. - return ActivateDataStream(CreateDataStream( - GetNextOutgoingBidirectionalStreamId(), QuicStream::kDefaultPriority)); -} - -bool QuartcSession::SendOrQueueMessage(QuicMemSliceSpan message, - int64_t datagram_id) { - if (!CanSendMessage()) { - QUIC_LOG(ERROR) << "Quic session does not support SendMessage"; - return false; - } - - if (message.total_length() > GetCurrentLargestMessagePayload()) { - QUIC_LOG(ERROR) << "Message is too big, message_size=" - << message.total_length() - << ", GetCurrentLargestMessagePayload=" - << GetCurrentLargestMessagePayload(); - return false; - } - - // There may be other messages in send queue, so we have to add message - // to the queue and call queue processing helper. - QueuedMessage queued_message; - queued_message.datagram_id = datagram_id; - message.ConsumeAll([&queued_message](QuicMemSlice slice) { - queued_message.message.Append(std::move(slice)); - }); - send_message_queue_.push_back(std::move(queued_message)); - - ProcessSendMessageQueue(); - - return true; -} - -void QuartcSession::ProcessSendMessageQueue() { - QuicConnection::ScopedPacketFlusher flusher(connection()); - while (!send_message_queue_.empty()) { - QueuedMessage& it = send_message_queue_.front(); - QuicMemSliceSpan span = it.message.ToSpan(); - const size_t message_size = span.total_length(); - MessageResult result = SendMessage(span); - - // Handle errors. - switch (result.status) { - case MESSAGE_STATUS_SUCCESS: { - QUIC_VLOG(1) << "Quartc message sent, message_id=" << result.message_id - << ", message_size=" << message_size; - - auto element = message_to_datagram_id_.find(result.message_id); - - DCHECK(element == message_to_datagram_id_.end()) - << "Mapped message_id already exists, message_id=" - << result.message_id << ", datagram_id=" << element->second; - - message_to_datagram_id_[result.message_id] = it.datagram_id; - - // Notify that datagram was sent. - session_delegate_->OnMessageSent(it.datagram_id); - } break; - - // If connection is congestion controlled or not writable yet, stop - // send loop and we'll retry again when we get OnCanWrite notification. - case MESSAGE_STATUS_ENCRYPTION_NOT_ESTABLISHED: - case MESSAGE_STATUS_BLOCKED: - QUIC_VLOG(1) << "Quartc message not sent because connection is blocked" - << ", message will be retried later, status=" - << result.status << ", message_size=" << message_size; - - return; - - // Other errors are unexpected. We do not propagate error to Quartc, - // because writes can be delayed. - case MESSAGE_STATUS_UNSUPPORTED: - case MESSAGE_STATUS_TOO_LARGE: - case MESSAGE_STATUS_INTERNAL_ERROR: - QUIC_DLOG(DFATAL) - << "Failed to send quartc message due to unexpected error" - << ", message will not be retried, status=" << result.status - << ", message_size=" << message_size; - break; - } - - send_message_queue_.pop_front(); - } -} - -void QuartcSession::OnCanWrite() { - // TODO(b/119640244): Since we currently use messages for audio and streams - // for video, it makes sense to process queued messages first, then call quic - // core OnCanWrite, which will resend queued streams. Long term we may need - // better solution especially if quic connection is used for both data and - // media. - - // Process quartc messages that were previously blocked. - ProcessSendMessageQueue(); - - QuicSession::OnCanWrite(); -} - -bool QuartcSession::SendProbingData() { - if (QuicSession::SendProbingData()) { - return true; - } - - // Set transmission type to PROBING_RETRANSMISSION such that the packets will - // be padded to full. - SetTransmissionType(PROBING_RETRANSMISSION); - // TODO(mellem): this sent PING will be retransmitted if it is lost which is - // not ideal. Consider to send stream data as probing data instead. - SendPing(); - return true; -} - -void QuartcSession::SetDefaultEncryptionLevel(EncryptionLevel level) { - QuicSession::SetDefaultEncryptionLevel(level); - switch (level) { - case ENCRYPTION_INITIAL: - break; - case ENCRYPTION_ZERO_RTT: - if (connection()->perspective() == Perspective::IS_CLIENT) { - DCHECK(IsEncryptionEstablished()); - DCHECK(session_delegate_); - session_delegate_->OnConnectionWritable(); - } - break; - case ENCRYPTION_HANDSHAKE: - break; - case ENCRYPTION_FORWARD_SECURE: - // On the server, handshake confirmed is the first time when you can start - // writing packets. - DCHECK(IsEncryptionEstablished()); - DCHECK(OneRttKeysAvailable()); - - DCHECK(session_delegate_); - session_delegate_->OnConnectionWritable(); - session_delegate_->OnCryptoHandshakeComplete(); - break; - default: - QUIC_BUG << "Unknown encryption level: " - << EncryptionLevelToString(level); - } -} - -void QuartcSession::OnOneRttKeysAvailable() { - QuicSession::OnOneRttKeysAvailable(); - // On the server, handshake confirmed is the first time when you can start - // writing packets. - DCHECK(IsEncryptionEstablished()); - DCHECK(OneRttKeysAvailable()); - - DCHECK(session_delegate_); - session_delegate_->OnConnectionWritable(); - session_delegate_->OnCryptoHandshakeComplete(); -} - -void QuartcSession::CancelStream(QuicStreamId stream_id) { - ResetQuartcStream(stream_id, QuicRstStreamErrorCode::QUIC_STREAM_CANCELLED); -} - -void QuartcSession::ResetQuartcStream(QuicStreamId stream_id, - QuicRstStreamErrorCode error) { - if (!IsOpenStream(stream_id)) { - return; - } - QuicStream* stream = QuicSession::GetOrCreateStream(stream_id); - if (stream) { - stream->Reset(error); - } -} - -void QuartcSession::OnCongestionWindowChange(QuicTime /*now*/) { - DCHECK(session_delegate_); - const RttStats* rtt_stats = connection_->sent_packet_manager().GetRttStats(); - - QuicBandwidth bandwidth_estimate = - connection_->sent_packet_manager().BandwidthEstimate(); - - QuicByteCount in_flight = - connection_->sent_packet_manager().GetBytesInFlight(); - QuicBandwidth pacing_rate = - connection_->sent_packet_manager().GetSendAlgorithm()->PacingRate( - in_flight); - - session_delegate_->OnCongestionControlChange(bandwidth_estimate, pacing_rate, - rtt_stats->latest_rtt()); -} - -bool QuartcSession::ShouldKeepConnectionAlive() const { - // TODO(mellem): Quartc may want different keepalive logic than HTTP. - return GetNumActiveStreams() > 0; -} - -void QuartcSession::OnConnectionClosed(const QuicConnectionCloseFrame& frame, - ConnectionCloseSource source) { - QuicSession::OnConnectionClosed(frame, source); - DCHECK(session_delegate_); - session_delegate_->OnConnectionClosed(frame, source); -} - -void QuartcSession::CloseConnection(const std::string& details) { - connection_->CloseConnection( - QuicErrorCode::QUIC_CONNECTION_CANCELLED, details, - ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); -} - -void QuartcSession::SetDelegate(Delegate* session_delegate) { - if (session_delegate_) { - QUIC_LOG(WARNING) << "The delegate for the session has already been set."; - } - session_delegate_ = session_delegate; - DCHECK(session_delegate_); -} - -void QuartcSession::OnTransportCanWrite() { - connection()->writer()->SetWritable(); - if (HasDataToWrite()) { - connection()->OnCanWrite(); - } -} - -void QuartcSession::OnTransportReceived(const char* data, size_t data_len) { - QuicReceivedPacket packet(data, data_len, clock_->Now()); - ProcessUdpPacket(connection()->self_address(), connection()->peer_address(), - packet); -} - -void QuartcSession::OnMessageReceived(quiche::QuicheStringPiece message) { - session_delegate_->OnMessageReceived(message); -} - -void QuartcSession::OnMessageAcked(QuicMessageId message_id, - QuicTime receive_timestamp) { - auto element = message_to_datagram_id_.find(message_id); - - if (element == message_to_datagram_id_.end()) { - return; - } - - session_delegate_->OnMessageAcked(/*datagram_id=*/element->second, - receive_timestamp); - - // Free up space -- we should never see message_id again. - message_to_datagram_id_.erase(element); -} - -void QuartcSession::OnMessageLost(QuicMessageId message_id) { - auto it = message_to_datagram_id_.find(message_id); - if (it == message_to_datagram_id_.end()) { - return; - } - - session_delegate_->OnMessageLost(/*datagram_id=*/it->second); - - // Free up space. - message_to_datagram_id_.erase(it); -} - -QuicStream* QuartcSession::CreateIncomingStream(QuicStreamId id) { - return ActivateDataStream(CreateDataStream(id, QuicStream::kDefaultPriority)); -} - -QuicStream* QuartcSession::CreateIncomingStream(PendingStream* /*pending*/) { - QUIC_NOTREACHED(); - return nullptr; -} - -std::unique_ptr<QuartcStream> QuartcSession::CreateDataStream( - QuicStreamId id, - spdy::SpdyPriority priority) { - if (GetCryptoStream() == nullptr || - !GetCryptoStream()->encryption_established()) { - // Encryption not active so no stream created - return nullptr; - } - return InitializeDataStream(std::make_unique<QuartcStream>(id, this), - priority); -} - -std::unique_ptr<QuartcStream> QuartcSession::InitializeDataStream( - std::unique_ptr<QuartcStream> stream, - spdy::SpdyPriority priority) { - // Register the stream to the QuicWriteBlockedList. |priority| is clamped - // between 0 and 7, with 0 being the highest priority and 7 the lowest - // priority. - write_blocked_streams()->UpdateStreamPriority( - stream->id(), spdy::SpdyStreamPrecedence(priority)); - - if (IsIncomingStream(stream->id())) { - DCHECK(session_delegate_); - // Incoming streams need to be registered with the session_delegate_. - session_delegate_->OnIncomingStream(stream.get()); - } - return stream; -} - -QuartcStream* QuartcSession::ActivateDataStream( - std::unique_ptr<QuartcStream> stream) { - // Transfer ownership of the data stream to the session via ActivateStream(). - QuartcStream* raw = stream.release(); - if (raw) { - // Make QuicSession take ownership of the stream. - ActivateStream(std::unique_ptr<QuicStream>(raw)); - } - return raw; -} - -QuartcClientSession::QuartcClientSession( - std::unique_ptr<QuicConnection> connection, - const QuicConfig& config, - const ParsedQuicVersionVector& supported_versions, - const QuicClock* clock, - std::unique_ptr<QuartcPacketWriter> packet_writer, - std::unique_ptr<QuicCryptoClientConfig> client_crypto_config, - quiche::QuicheStringPiece server_crypto_config) - : QuartcSession(std::move(connection), - /*visitor=*/nullptr, - config, - supported_versions, - clock), - packet_writer_(std::move(packet_writer)), - client_crypto_config_(std::move(client_crypto_config)), - server_config_(server_crypto_config) { - DCHECK_EQ(QuartcSession::connection()->perspective(), Perspective::IS_CLIENT); -} - -QuartcClientSession::~QuartcClientSession() { - // The client session is the packet transport delegate, so it must be unset - // before the session is deleted. - packet_writer_->SetPacketTransportDelegate(nullptr); -} - -void QuartcClientSession::Initialize() { - DCHECK(crypto_stream_) << "Do not call QuartcSession::Initialize(), call " - "StartCryptoHandshake() instead."; - QuartcSession::Initialize(); - - // QUIC is ready to process incoming packets after Initialize(). - // Set the packet transport delegate to begin receiving packets. - packet_writer_->SetPacketTransportDelegate(this); -} - -const QuicCryptoStream* QuartcClientSession::GetCryptoStream() const { - return crypto_stream_.get(); -} - -QuicCryptoStream* QuartcClientSession::GetMutableCryptoStream() { - return crypto_stream_.get(); -} - -void QuartcClientSession::StartCryptoHandshake() { - QuicServerId server_id(/*host=*/"", kQuicServerPort, - /*privacy_mode_enabled=*/false); - - if (!server_config_.empty()) { - QuicCryptoServerConfig::ConfigOptions options; - - std::string error; - QuicWallTime now = clock()->WallNow(); - QuicCryptoClientConfig::CachedState::ServerConfigState result = - client_crypto_config_->LookupOrCreate(server_id)->SetServerConfig( - server_config_, now, - /*expiry_time=*/now.Add(QuicTime::Delta::Infinite()), &error); - - if (result == QuicCryptoClientConfig::CachedState::SERVER_CONFIG_VALID) { - DCHECK_EQ(error, ""); - client_crypto_config_->LookupOrCreate(server_id)->SetProof( - std::vector<std::string>{kDummyCertName}, /*cert_sct=*/"", - /*chlo_hash=*/"", /*signature=*/"anything"); - } else { - QUIC_LOG(DFATAL) << "Unable to set server config, error=" << error; - } - } - - crypto_stream_ = std::make_unique<QuicCryptoClientStream>( - server_id, this, - client_crypto_config_->proof_verifier()->CreateDefaultContext(), - client_crypto_config_.get(), this, /*has_application_state = */ true); - Initialize(); - crypto_stream_->CryptoConnect(); -} - -void QuartcClientSession::OnProofValid( - const QuicCryptoClientConfig::CachedState& /*cached*/) { - // TODO(zhihuang): Handle the proof verification. -} - -void QuartcClientSession::OnProofVerifyDetailsAvailable( - const ProofVerifyDetails& /*verify_details*/) { - // TODO(zhihuang): Handle the proof verification. -} - -QuartcServerSession::QuartcServerSession( - std::unique_ptr<QuicConnection> connection, - Visitor* visitor, - const QuicConfig& config, - const ParsedQuicVersionVector& supported_versions, - const QuicClock* clock, - const QuicCryptoServerConfig* server_crypto_config, - QuicCompressedCertsCache* const compressed_certs_cache, - QuicCryptoServerStreamBase::Helper* const stream_helper) - : QuartcSession(std::move(connection), - visitor, - config, - supported_versions, - clock), - server_crypto_config_(server_crypto_config), - compressed_certs_cache_(compressed_certs_cache), - stream_helper_(stream_helper) { - DCHECK_EQ(QuartcSession::connection()->perspective(), Perspective::IS_SERVER); -} - -const QuicCryptoStream* QuartcServerSession::GetCryptoStream() const { - return crypto_stream_.get(); -} - -QuicCryptoStream* QuartcServerSession::GetMutableCryptoStream() { - return crypto_stream_.get(); -} - -void QuartcServerSession::StartCryptoHandshake() { - crypto_stream_ = CreateCryptoServerStream( - server_crypto_config_, compressed_certs_cache_, this, stream_helper_); - Initialize(); -} - -} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_session.h b/chromium/net/third_party/quiche/src/quic/quartc/quartc_session.h deleted file mode 100644 index 66ddfc3617f..00000000000 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_session.h +++ /dev/null @@ -1,339 +0,0 @@ -// Copyright (c) 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef QUICHE_QUIC_QUARTC_QUARTC_SESSION_H_ -#define QUICHE_QUIC_QUARTC_QUARTC_SESSION_H_ - -#include <memory> -#include <string> - -#include "net/third_party/quiche/src/quic/core/quic_crypto_client_stream.h" -#include "net/third_party/quiche/src/quic/core/quic_crypto_server_stream_base.h" -#include "net/third_party/quiche/src/quic/core/quic_crypto_stream.h" -#include "net/third_party/quiche/src/quic/core/quic_error_codes.h" -#include "net/third_party/quiche/src/quic/core/quic_session.h" -#include "net/third_party/quiche/src/quic/core/quic_types.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_mem_slice_storage.h" -#include "net/third_party/quiche/src/quic/quartc/quartc_packet_writer.h" -#include "net/third_party/quiche/src/quic/quartc/quartc_stream.h" -#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" - -namespace quic { - -// QuartcSession owns and manages a QUIC connection. -class QuartcSession : public QuicSession, - public QuartcPacketTransport::Delegate { - public: - QuartcSession(std::unique_ptr<QuicConnection> connection, - Visitor* visitor, - const QuicConfig& config, - const ParsedQuicVersionVector& supported_versions, - const QuicClock* clock); - QuartcSession(const QuartcSession&) = delete; - QuartcSession& operator=(const QuartcSession&) = delete; - ~QuartcSession() override; - - // QuicSession overrides. - QuartcStream* CreateOutgoingBidirectionalStream(); - - // Sends short unreliable message using quic message frame (message must fit - // in one quic packet). If connection is blocked by congestion control, - // message will be queued and resent later after receiving an OnCanWrite - // notification. - // - // Message size must be <= GetLargestMessagePayload(). - // - // Supported in quic version 45 or later. - // - // Returns false and logs error if message is too long or session does not - // support SendMessage API. Other unexpected errors during send will not be - // returned, because messages can be sent later if connection is congestion - // controlled. - // - // |datagram_id| is used to notify when message was sent in - // Delegate::OnMessageSent. - // - // TODO(sukhanov): We can not use QUIC message ID for notifications, because - // QUIC does not take ownership of messages and if connection is congestion - // controlled, message is not sent and does not get message id until it is - // sent successfully. It also creates problem of flow control between - // messages and streams if they are used together. We discussed it with QUIC - // team and there are multiple solutions, but for now we have to use our - // own datagram identification. - bool SendOrQueueMessage(QuicMemSliceSpan message, int64_t datagram_id); - - // Returns largest message payload acceptable in SendQuartcMessage. - QuicPacketLength GetCurrentLargestMessagePayload() const { - return connection()->GetCurrentLargestMessagePayload(); - } - - // Return true if transport support message frame. - bool CanSendMessage() const { - return VersionSupportsMessageFrames(transport_version()); - } - - void SetDefaultEncryptionLevel(EncryptionLevel level) override; - void OnOneRttKeysAvailable() override; - - // QuicConnectionVisitorInterface overrides. - void OnCongestionWindowChange(QuicTime now) override; - bool ShouldKeepConnectionAlive() const override; - - void OnCanWrite() override; - bool SendProbingData() override; - - void OnConnectionClosed(const QuicConnectionCloseFrame& frame, - ConnectionCloseSource source) override; - - // QuartcSession methods. - virtual void StartCryptoHandshake() = 0; - - // Closes the connection with the given human-readable error details. - // The connection closes with the QUIC_CONNECTION_CANCELLED error code to - // indicate the application closed it. - // - // Informs the peer that the connection has been closed. This prevents the - // peer from waiting until the connection times out. - // - // Cleans up the underlying QuicConnection's state. Closing the connection - // makes it safe to delete the QuartcSession. - void CloseConnection(const std::string& details); - - // If the given stream is still open, sends a reset frame to cancel it. - // Note: This method cancels a stream by QuicStreamId rather than by pointer - // (or by a method on QuartcStream) because QuartcSession (and not - // the caller) owns the streams. Streams may finish and be deleted before the - // caller tries to cancel them, rendering the caller's pointers invalid. - void CancelStream(QuicStreamId stream_id); - - // Callbacks called by the QuartcSession to notify the user of the - // QuartcSession of certain events. - class Delegate { - public: - virtual ~Delegate() {} - - // Called when the crypto handshake is complete. Crypto handshake on the - // client is only completed _after_ SHLO is received, but we can actually - // start sending media data right after CHLO is sent. - virtual void OnCryptoHandshakeComplete() = 0; - - // Connection can be writable even before crypto handshake is complete. - // In particular, on the client, we can start sending data after sending - // full CHLO, without waiting for SHLO. This reduces a send delay by 1-rtt. - // - // This may be called multiple times. - virtual void OnConnectionWritable() = 0; - - // Called when a new stream is received from the remote endpoint. - virtual void OnIncomingStream(QuartcStream* stream) = 0; - - // Called when network parameters change in response to an ack frame. - virtual void OnCongestionControlChange(QuicBandwidth bandwidth_estimate, - QuicBandwidth pacing_rate, - QuicTime::Delta latest_rtt) = 0; - - // Called when the connection is closed. This means all of the streams will - // be closed and no new streams can be created. - virtual void OnConnectionClosed(const QuicConnectionCloseFrame& frame, - ConnectionCloseSource source) = 0; - - // Called when message (sent as SendMessage) is received. - virtual void OnMessageReceived(quiche::QuicheStringPiece message) = 0; - - // Called when message is sent to QUIC. - // - // Takes into account delay due to congestion control, but does not take - // into account any additional socket delays. - // - // Passed |datagram_id| is the same used in SendOrQueueMessage. - // - // TODO(sukhanov): We can take into account socket delay, but it's not clear - // if it's worth doing if we eventually plan to move congestion control to - // QUIC in QRTP model. If we need to do it, mellem@ thinks it's fairly - // strtaightforward: QUIC does not know about socket delay, but ICE does. We - // can tell ICE the QUIC packet number for each packet sent, and it will - // echo it back to us when the packet actually goes out. We just need to - // plumb that signal up to RTP's congestion control. - virtual void OnMessageSent(int64_t datagram_id) = 0; - - // Called when message with |datagram_id| gets acked. |receive_timestamp| - // indicates when the peer received this message, according to its own - // clock. - virtual void OnMessageAcked(int64_t datagram_id, - QuicTime receive_timestamp) = 0; - - // Called when message with |datagram_id| is lost. - virtual void OnMessageLost(int64_t datagram_id) = 0; - - // TODO(zhihuang): Add proof verification. - }; - - // The |delegate| is not owned by QuartcSession. - void SetDelegate(Delegate* session_delegate); - - // Called when CanWrite() changes from false to true. - void OnTransportCanWrite() override; - - // Called when a packet has been received and should be handled by the - // QuicConnection. - void OnTransportReceived(const char* data, size_t data_len) override; - - void OnMessageReceived(quiche::QuicheStringPiece message) override; - - // Called when message with |message_id| gets acked. - void OnMessageAcked(QuicMessageId message_id, - QuicTime receive_timestamp) override; - - void OnMessageLost(QuicMessageId message_id) override; - - // Returns number of queued (not sent) messages submitted by - // SendOrQueueMessage. Messages are queued if connection is congestion - // controlled. - size_t send_message_queue_size() const { return send_message_queue_.size(); } - - protected: - // QuicSession override. - QuicStream* CreateIncomingStream(QuicStreamId id) override; - QuicStream* CreateIncomingStream(PendingStream* pending) override; - - std::unique_ptr<QuartcStream> CreateDataStream(QuicStreamId id, - spdy::SpdyPriority priority); - // Activates a QuartcStream. The session takes ownership of the stream, but - // returns an unowned pointer to the stream for convenience. - QuartcStream* ActivateDataStream(std::unique_ptr<QuartcStream> stream); - - void ResetQuartcStream(QuicStreamId stream_id, QuicRstStreamErrorCode error); - - const QuicClock* clock() { return clock_; } - - private: - std::unique_ptr<QuartcStream> InitializeDataStream( - std::unique_ptr<QuartcStream> stream, - spdy::SpdyPriority priority); - - // Holds message until it's sent. - struct QueuedMessage { - QueuedMessage() : message(nullptr, 0, nullptr, 0), datagram_id(0) {} - - QuicMemSliceStorage message; - int64_t datagram_id; - }; - - void ProcessSendMessageQueue(); - - // Take ownership of the QuicConnection. Note: if |connection_| changes, - // the new value of |connection_| must be given to |packet_writer_| before any - // packets are written. Otherwise, |packet_writer_| will crash. - std::unique_ptr<QuicConnection> connection_; - - // For recording packet receipt time - const QuicClock* clock_; - - // Not owned by QuartcSession. - Delegate* session_delegate_ = nullptr; - - // Options passed to the packet writer for each packet. - std::unique_ptr<QuartcPerPacketOptions> per_packet_options_; - - // Queue of pending messages sent by SendQuartcMessage that were not sent - // yet or blocked by congestion control. Messages are queued in the order - // of sent by SendOrQueueMessage(). - QuicCircularDeque<QueuedMessage> send_message_queue_; - - // Maps message ids to datagram ids, so we could translate message ACKs - // received from QUIC to datagram ACKs that are propagated up the stack. - QuicHashMap<QuicMessageId, int64_t> message_to_datagram_id_; -}; - -class QuartcClientSession : public QuartcSession, - public QuicCryptoClientStream::ProofHandler { - public: - QuartcClientSession( - std::unique_ptr<QuicConnection> connection, - const QuicConfig& config, - const ParsedQuicVersionVector& supported_versions, - const QuicClock* clock, - std::unique_ptr<QuartcPacketWriter> packet_writer, - std::unique_ptr<QuicCryptoClientConfig> client_crypto_config, - quiche::QuicheStringPiece server_crypto_config); - QuartcClientSession(const QuartcClientSession&) = delete; - QuartcClientSession& operator=(const QuartcClientSession&) = delete; - - ~QuartcClientSession() override; - - // Initialize should not be called on a QuartcSession. Instead, call - // StartCryptoHandshake(). - // TODO(mellem): Move creation of the crypto stream into Initialize() and - // remove StartCryptoHandshake() to bring QuartcSession in line with other - // implementations of QuicSession, which can be started by calling - // Initialize(). - void Initialize() override; - - // Accessors for the client crypto stream. - QuicCryptoStream* GetMutableCryptoStream() override; - const QuicCryptoStream* GetCryptoStream() const override; - - // Initializes the session and sends a handshake. - void StartCryptoHandshake() override; - - // ProofHandler overrides. - void OnProofValid(const QuicCryptoClientConfig::CachedState& cached) override; - - // Called by the client crypto handshake when proof verification details - // become available, either because proof verification is complete, or when - // cached details are used. - void OnProofVerifyDetailsAvailable( - const ProofVerifyDetails& verify_details) override; - - private: - // Packet writer used by |connection_|. - std::unique_ptr<QuartcPacketWriter> packet_writer_; - - // Config for QUIC crypto stream. - std::unique_ptr<QuicCryptoClientConfig> client_crypto_config_; - - // Client perspective crypto stream. - std::unique_ptr<QuicCryptoClientStream> crypto_stream_; - - const std::string server_config_; -}; - -class QuartcServerSession : public QuartcSession { - public: - QuartcServerSession(std::unique_ptr<QuicConnection> connection, - Visitor* visitor, - const QuicConfig& config, - const ParsedQuicVersionVector& supported_versions, - const QuicClock* clock, - const QuicCryptoServerConfig* server_crypto_config, - QuicCompressedCertsCache* const compressed_certs_cache, - QuicCryptoServerStreamBase::Helper* const stream_helper); - QuartcServerSession(const QuartcServerSession&) = delete; - QuartcServerSession& operator=(const QuartcServerSession&) = delete; - - // Accessors for the server crypto stream. - QuicCryptoStream* GetMutableCryptoStream() override; - const QuicCryptoStream* GetCryptoStream() const override; - - // Initializes the session and prepares to receive a handshake. - void StartCryptoHandshake() override; - - private: - // Config for QUIC crypto stream. - const QuicCryptoServerConfig* server_crypto_config_; - - // Used by QUIC crypto server stream to track most recently compressed certs. - QuicCompressedCertsCache* const compressed_certs_cache_; - - // This helper is needed to create QuicCryptoServerStream. - QuicCryptoServerStreamBase::Helper* const stream_helper_; - - // Server perspective crypto stream. - std::unique_ptr<QuicCryptoServerStreamBase> crypto_stream_; -}; - -} // namespace quic - -#endif // QUICHE_QUIC_QUARTC_QUARTC_SESSION_H_ diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_session_test.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_session_test.cc deleted file mode 100644 index 93172e7c55d..00000000000 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_session_test.cc +++ /dev/null @@ -1,680 +0,0 @@ -// Copyright (c) 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/quiche/src/quic/quartc/quartc_session.h" - -#include <utility> - -#include "net/third_party/quiche/src/quic/core/quic_clock.h" -#include "net/third_party/quiche/src/quic/core/quic_simple_buffer_allocator.h" -#include "net/third_party/quiche/src/quic/core/quic_types.h" -#include "net/third_party/quiche/src/quic/core/tls_client_handshaker.h" -#include "net/third_party/quiche/src/quic/core/tls_server_handshaker.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_string_utils.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_test_mem_slice_vector.h" -#include "net/third_party/quiche/src/quic/quartc/counting_packet_filter.h" -#include "net/third_party/quiche/src/quic/quartc/quartc_endpoint.h" -#include "net/third_party/quiche/src/quic/quartc/quartc_fakes.h" -#include "net/third_party/quiche/src/quic/quartc/quartc_packet_writer.h" -#include "net/third_party/quiche/src/quic/quartc/simulated_packet_transport.h" -#include "net/third_party/quiche/src/quic/test_tools/mock_clock.h" -#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" -#include "net/third_party/quiche/src/quic/test_tools/simulator/packet_filter.h" -#include "net/third_party/quiche/src/quic/test_tools/simulator/simulator.h" -#include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h" -#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" - -namespace quic { - -namespace { - -using ::testing::ElementsAre; -using ::testing::ElementsAreArray; -using ::testing::Gt; -using ::testing::Pair; - -constexpr QuicTime::Delta kPropagationDelay = - QuicTime::Delta::FromMilliseconds(10); -// Propagation delay and a bit, but no more than full RTT. -constexpr QuicTime::Delta kPropagationDelayAndABit = - QuicTime::Delta::FromMilliseconds(12); - -static QuicByteCount kDefaultMaxPacketSize = 1200; - -test::QuicTestMemSliceVector CreateMemSliceVector( - quiche::QuicheStringPiece data) { - return test::QuicTestMemSliceVector( - {std::pair<char*, size_t>(const_cast<char*>(data.data()), data.size())}); -} - -class QuartcSessionTest : public QuicTest { - public: - ~QuartcSessionTest() override {} - - void Init(bool create_client_endpoint = true) { - // TODO(b/150224094): Re-enable TLS handshake. - // TODO(b/150236522): Parametrize by QUIC version. - quic::test::DisableQuicVersionsWithTls(); - - client_transport_ = - std::make_unique<simulator::SimulatedQuartcPacketTransport>( - &simulator_, "client_transport", "server_transport", - 10 * kDefaultMaxPacketSize); - server_transport_ = - std::make_unique<simulator::SimulatedQuartcPacketTransport>( - &simulator_, "server_transport", "client_transport", - 10 * kDefaultMaxPacketSize); - - client_filter_ = std::make_unique<simulator::CountingPacketFilter>( - &simulator_, "client_filter", client_transport_.get()); - - client_server_link_ = std::make_unique<simulator::SymmetricLink>( - client_filter_.get(), server_transport_.get(), - QuicBandwidth::FromKBitsPerSecond(10 * 1000), kPropagationDelay); - - client_stream_delegate_ = std::make_unique<FakeQuartcStreamDelegate>(); - client_session_delegate_ = std::make_unique<FakeQuartcEndpointDelegate>( - client_stream_delegate_.get(), simulator_.GetClock()); - - server_stream_delegate_ = std::make_unique<FakeQuartcStreamDelegate>(); - server_session_delegate_ = std::make_unique<FakeQuartcEndpointDelegate>( - server_stream_delegate_.get(), simulator_.GetClock()); - - // No 0-rtt setup, because server config is empty. - // CannotCreateDataStreamBeforeHandshake depends on 1-rtt setup. - if (create_client_endpoint) { - client_endpoint_ = std::make_unique<QuartcClientEndpoint>( - simulator_.GetAlarmFactory(), simulator_.GetClock(), - simulator_.GetRandomGenerator(), client_session_delegate_.get(), - quic::QuartcSessionConfig(), - /*serialized_server_config=*/""); - } - server_endpoint_ = std::make_unique<QuartcServerEndpoint>( - simulator_.GetAlarmFactory(), simulator_.GetClock(), - simulator_.GetRandomGenerator(), server_session_delegate_.get(), - quic::QuartcSessionConfig()); - } - - // Note that input session config will apply to both server and client. - // Perspective and packet_transport will be overwritten. - void CreateClientAndServerSessions( - const QuartcSessionConfig& /*session_config*/, - bool init = true) { - if (init) { - Init(); - } - - server_endpoint_->Connect(server_transport_.get()); - client_endpoint_->Connect(client_transport_.get()); - - CHECK(simulator_.RunUntil([this] { - return client_session_delegate_->session() != nullptr && - server_session_delegate_->session() != nullptr; - })); - - client_peer_ = client_session_delegate_->session(); - server_peer_ = server_session_delegate_->session(); - } - - // Runs all tasks scheduled in the next 200 ms. - void RunTasks() { simulator_.RunFor(QuicTime::Delta::FromMilliseconds(200)); } - - void AwaitHandshake() { - simulator_.RunUntil([this] { - return client_peer_->OneRttKeysAvailable() && - server_peer_->OneRttKeysAvailable(); - }); - } - - // Test handshake establishment and sending/receiving of data for two - // directions. - void TestSendReceiveStreams() { - ASSERT_TRUE(server_peer_->OneRttKeysAvailable()); - ASSERT_TRUE(client_peer_->OneRttKeysAvailable()); - ASSERT_TRUE(server_peer_->IsEncryptionEstablished()); - ASSERT_TRUE(client_peer_->IsEncryptionEstablished()); - - // Now we can establish encrypted outgoing stream. - QuartcStream* outgoing_stream = - server_peer_->CreateOutgoingBidirectionalStream(); - QuicStreamId stream_id = outgoing_stream->id(); - ASSERT_NE(nullptr, outgoing_stream); - EXPECT_TRUE(server_peer_->ShouldKeepConnectionAlive()); - - outgoing_stream->SetDelegate(server_stream_delegate_.get()); - - // Send a test message from peer 1 to peer 2. - test::QuicTestMemSliceVector data = CreateMemSliceVector("Hello"); - outgoing_stream->WriteMemSlices(data.span(), /*fin=*/false); - RunTasks(); - - // Wait for peer 2 to receive messages. - ASSERT_TRUE(client_stream_delegate_->has_data()); - - QuartcStream* incoming = client_session_delegate_->last_incoming_stream(); - ASSERT_TRUE(incoming); - EXPECT_EQ(incoming->id(), stream_id); - EXPECT_TRUE(client_peer_->ShouldKeepConnectionAlive()); - - EXPECT_EQ(client_stream_delegate_->data()[stream_id], "Hello"); - // Send a test message from peer 2 to peer 1. - test::QuicTestMemSliceVector response = CreateMemSliceVector("Response"); - incoming->WriteMemSlices(response.span(), /*fin=*/false); - RunTasks(); - // Wait for peer 1 to receive messages. - ASSERT_TRUE(server_stream_delegate_->has_data()); - - EXPECT_EQ(server_stream_delegate_->data()[stream_id], "Response"); - } - - // Test sending/receiving of messages for two directions. - void TestSendReceiveMessage() { - ASSERT_TRUE(server_peer_->CanSendMessage()); - ASSERT_TRUE(client_peer_->CanSendMessage()); - - // Disable probing retransmissions such that the first message from either - // side can be sent without being queued. - client_peer_->connection()->set_fill_up_link_during_probing(false); - server_peer_->connection()->set_fill_up_link_during_probing(false); - - int64_t server_datagram_id = 111; - int64_t client_datagram_id = 222; - - // Send message from peer 1 to peer 2. - test::QuicTestMemSliceVector message = - CreateMemSliceVector("Message from server"); - ASSERT_TRUE( - server_peer_->SendOrQueueMessage(message.span(), server_datagram_id)); - - // First message in each direction should not be queued. - EXPECT_EQ(server_peer_->send_message_queue_size(), 0u); - - // Wait for peer 2 to receive message. - RunTasks(); - - EXPECT_THAT(client_session_delegate_->incoming_messages(), - testing::ElementsAre("Message from server")); - - EXPECT_THAT(server_session_delegate_->sent_datagram_ids(), - testing::ElementsAre(server_datagram_id)); - - EXPECT_THAT( - server_session_delegate_->acked_datagram_id_to_receive_timestamp(), - ElementsAre(Pair(server_datagram_id, Gt(QuicTime::Zero())))); - - // Send message from peer 2 to peer 1. - message = CreateMemSliceVector("Message from client"); - ASSERT_TRUE( - client_peer_->SendOrQueueMessage(message.span(), client_datagram_id)); - - // First message in each direction should not be queued. - EXPECT_EQ(client_peer_->send_message_queue_size(), 0u); - - // Wait for peer 1 to receive message. - RunTasks(); - - EXPECT_THAT(server_session_delegate_->incoming_messages(), - testing::ElementsAre("Message from client")); - - EXPECT_THAT(client_session_delegate_->sent_datagram_ids(), - testing::ElementsAre(client_datagram_id)); - - EXPECT_THAT( - client_session_delegate_->acked_datagram_id_to_receive_timestamp(), - ElementsAre(Pair(client_datagram_id, Gt(QuicTime::Zero())))); - } - - // Test for sending multiple messages that also result in queueing. - // This is one-way test, which is run in given direction. - void TestSendReceiveQueuedMessages(bool direction_from_server) { - // Send until queue_size number of messages are queued. - constexpr size_t queue_size = 10; - - ASSERT_TRUE(server_peer_->CanSendMessage()); - ASSERT_TRUE(client_peer_->CanSendMessage()); - - QuartcSession* const peer_sending = - direction_from_server ? server_peer_ : client_peer_; - - FakeQuartcEndpointDelegate* const delegate_receiving = - direction_from_server ? client_session_delegate_.get() - : server_session_delegate_.get(); - - FakeQuartcEndpointDelegate* const delegate_sending = - direction_from_server ? server_session_delegate_.get() - : client_session_delegate_.get(); - - // There should be no messages in the queue before we start sending. - EXPECT_EQ(peer_sending->send_message_queue_size(), 0u); - - // Send messages from peer 1 to peer 2 until required number of messages - // are queued in unsent message queue. - std::vector<std::string> sent_messages; - std::vector<int64_t> sent_datagram_ids; - int64_t current_datagram_id = 0; - while (peer_sending->send_message_queue_size() < queue_size) { - sent_messages.push_back(quiche::QuicheStrCat("Sending message, index=", - sent_messages.size())); - ASSERT_TRUE(peer_sending->SendOrQueueMessage( - CreateMemSliceVector(sent_messages.back()).span(), - current_datagram_id)); - - sent_datagram_ids.push_back(current_datagram_id); - ++current_datagram_id; - } - - // Wait for peer 2 to receive all messages. - RunTasks(); - - std::vector<testing::Matcher<std::pair<int64_t, QuicTime>>> ack_matchers; - for (int64_t id : sent_datagram_ids) { - ack_matchers.push_back(Pair(id, Gt(QuicTime::Zero()))); - } - EXPECT_EQ(delegate_receiving->incoming_messages(), sent_messages); - EXPECT_EQ(delegate_sending->sent_datagram_ids(), sent_datagram_ids); - EXPECT_THAT(delegate_sending->acked_datagram_id_to_receive_timestamp(), - ElementsAreArray(ack_matchers)); - } - - // Test sending long messages: - // - message of maximum allowed length should succeed - // - message of > maximum allowed length should fail. - void TestSendLongMessage() { - ASSERT_TRUE(server_peer_->CanSendMessage()); - ASSERT_TRUE(client_peer_->CanSendMessage()); - - // Send message of maximum allowed length. - std::string message_max_long = - std::string(server_peer_->GetCurrentLargestMessagePayload(), 'A'); - test::QuicTestMemSliceVector message = - CreateMemSliceVector(message_max_long); - ASSERT_TRUE( - server_peer_->SendOrQueueMessage(message.span(), /*datagram_id=*/0)); - - // Send long message which should fail. - std::string message_too_long = - std::string(server_peer_->GetCurrentLargestMessagePayload() + 1, 'B'); - message = CreateMemSliceVector(message_too_long); - ASSERT_FALSE( - server_peer_->SendOrQueueMessage(message.span(), /*datagram_id=*/0)); - - // Wait for peer 2 to receive message. - RunTasks(); - - // Client should only receive one message of allowed length. - EXPECT_THAT(client_session_delegate_->incoming_messages(), - testing::ElementsAre(message_max_long)); - } - - // Test that client and server are not connected after handshake failure. - void TestDisconnectAfterFailedHandshake() { - EXPECT_TRUE(!client_session_delegate_->connected()); - EXPECT_TRUE(!server_session_delegate_->connected()); - - EXPECT_FALSE(client_peer_->IsEncryptionEstablished()); - EXPECT_FALSE(client_peer_->OneRttKeysAvailable()); - - EXPECT_FALSE(server_peer_->IsEncryptionEstablished()); - EXPECT_FALSE(server_peer_->OneRttKeysAvailable()); - } - - protected: - simulator::Simulator simulator_; - - std::unique_ptr<simulator::SimulatedQuartcPacketTransport> client_transport_; - std::unique_ptr<simulator::SimulatedQuartcPacketTransport> server_transport_; - std::unique_ptr<simulator::CountingPacketFilter> client_filter_; - std::unique_ptr<simulator::SymmetricLink> client_server_link_; - - std::unique_ptr<FakeQuartcStreamDelegate> client_stream_delegate_; - std::unique_ptr<FakeQuartcEndpointDelegate> client_session_delegate_; - std::unique_ptr<FakeQuartcStreamDelegate> server_stream_delegate_; - std::unique_ptr<FakeQuartcEndpointDelegate> server_session_delegate_; - - std::unique_ptr<QuartcClientEndpoint> client_endpoint_; - std::unique_ptr<QuartcServerEndpoint> server_endpoint_; - - QuartcSession* client_peer_ = nullptr; - QuartcSession* server_peer_ = nullptr; -}; - -TEST_F(QuartcSessionTest, SendReceiveStreams) { - CreateClientAndServerSessions(QuartcSessionConfig()); - AwaitHandshake(); - TestSendReceiveStreams(); -} - -TEST_F(QuartcSessionTest, SendReceiveMessages) { - CreateClientAndServerSessions(QuartcSessionConfig()); - AwaitHandshake(); - TestSendReceiveMessage(); -} - -TEST_F(QuartcSessionTest, SendReceiveQueuedMessages) { - CreateClientAndServerSessions(QuartcSessionConfig()); - AwaitHandshake(); - TestSendReceiveQueuedMessages(/*direction_from_server=*/true); - TestSendReceiveQueuedMessages(/*direction_from_server=*/false); -} - -TEST_F(QuartcSessionTest, SendMultiMemSliceMessage) { - CreateClientAndServerSessions(QuartcSessionConfig()); - AwaitHandshake(); - ASSERT_TRUE(server_peer_->CanSendMessage()); - - std::vector<std::pair<char*, size_t>> buffers; - char first_piece[] = "Hello, "; - char second_piece[] = "world!"; - buffers.emplace_back(first_piece, 7); - buffers.emplace_back(second_piece, 6); - test::QuicTestMemSliceVector message(buffers); - ASSERT_TRUE( - server_peer_->SendOrQueueMessage(message.span(), /*datagram_id=*/1)); - - // Wait for the client to receive the message. - RunTasks(); - - // The message is not fragmented along MemSlice boundaries. - EXPECT_THAT(client_session_delegate_->incoming_messages(), - testing::ElementsAre("Hello, world!")); -} - -TEST_F(QuartcSessionTest, SendMessageFails) { - CreateClientAndServerSessions(QuartcSessionConfig()); - AwaitHandshake(); - TestSendLongMessage(); -} - -TEST_F(QuartcSessionTest, TestCryptoHandshakeCanWriteTriggers) { - CreateClientAndServerSessions(QuartcSessionConfig()); - - AwaitHandshake(); - - RunTasks(); - - ASSERT_TRUE(client_session_delegate_->writable_time().IsInitialized()); - ASSERT_TRUE( - client_session_delegate_->crypto_handshake_time().IsInitialized()); - // On client, we are writable 1-rtt before crypto handshake is complete. - ASSERT_LT(client_session_delegate_->writable_time(), - client_session_delegate_->crypto_handshake_time()); - - ASSERT_TRUE(server_session_delegate_->writable_time().IsInitialized()); - ASSERT_TRUE( - server_session_delegate_->crypto_handshake_time().IsInitialized()); - // On server, the writable time and crypto handshake are the same. (when SHLO - // is sent). - ASSERT_EQ(server_session_delegate_->writable_time(), - server_session_delegate_->crypto_handshake_time()); -} - -TEST_F(QuartcSessionTest, PreSharedKeyHandshake) { - QuartcSessionConfig config; - config.pre_shared_key = "foo"; - CreateClientAndServerSessions(config); - AwaitHandshake(); - TestSendReceiveStreams(); - TestSendReceiveMessage(); -} - -// Test that data streams are not created before handshake. -TEST_F(QuartcSessionTest, CannotCreateDataStreamBeforeHandshake) { - CreateClientAndServerSessions(QuartcSessionConfig()); - EXPECT_EQ(nullptr, server_peer_->CreateOutgoingBidirectionalStream()); - EXPECT_EQ(nullptr, client_peer_->CreateOutgoingBidirectionalStream()); -} - -TEST_F(QuartcSessionTest, CancelQuartcStream) { - CreateClientAndServerSessions(QuartcSessionConfig()); - AwaitHandshake(); - ASSERT_TRUE(client_peer_->OneRttKeysAvailable()); - ASSERT_TRUE(server_peer_->OneRttKeysAvailable()); - - QuartcStream* stream = client_peer_->CreateOutgoingBidirectionalStream(); - ASSERT_NE(nullptr, stream); - - uint32_t id = stream->id(); - EXPECT_FALSE(client_peer_->IsClosedStream(id)); - stream->SetDelegate(client_stream_delegate_.get()); - client_peer_->CancelStream(id); - EXPECT_EQ(stream->stream_error(), - QuicRstStreamErrorCode::QUIC_STREAM_CANCELLED); - EXPECT_TRUE(client_peer_->IsClosedStream(id)); -} - -// TODO(b/112561077): This is the wrong layer for this test. We should write a -// test specifically for QuartcPacketWriter with a stubbed-out -// QuartcPacketTransport and remove -// SimulatedQuartcPacketTransport::last_packet_number(). -TEST_F(QuartcSessionTest, WriterGivesPacketNumberToTransport) { - CreateClientAndServerSessions(QuartcSessionConfig()); - AwaitHandshake(); - ASSERT_TRUE(client_peer_->OneRttKeysAvailable()); - ASSERT_TRUE(server_peer_->OneRttKeysAvailable()); - - QuartcStream* stream = client_peer_->CreateOutgoingBidirectionalStream(); - stream->SetDelegate(client_stream_delegate_.get()); - - test::QuicTestMemSliceVector stream_data = CreateMemSliceVector("Hello"); - stream->WriteMemSlices(stream_data.span(), /*fin=*/false); - RunTasks(); - - // The transport should see the latest packet number sent by QUIC. - EXPECT_EQ( - client_transport_->last_packet_number(), - client_peer_->connection()->sent_packet_manager().GetLargestSentPacket()); -} - -TEST_F(QuartcSessionTest, CloseConnection) { - CreateClientAndServerSessions(QuartcSessionConfig()); - AwaitHandshake(); - ASSERT_TRUE(client_peer_->OneRttKeysAvailable()); - ASSERT_TRUE(server_peer_->OneRttKeysAvailable()); - - client_peer_->CloseConnection("Connection closed by client"); - EXPECT_FALSE(client_session_delegate_->connected()); - RunTasks(); - EXPECT_FALSE(server_session_delegate_->connected()); -} - -TEST_F(QuartcSessionTest, StreamRetransmissionEnabled) { - CreateClientAndServerSessions(QuartcSessionConfig()); - AwaitHandshake(); - ASSERT_TRUE(client_peer_->OneRttKeysAvailable()); - ASSERT_TRUE(server_peer_->OneRttKeysAvailable()); - - QuartcStream* stream = client_peer_->CreateOutgoingBidirectionalStream(); - QuicStreamId stream_id = stream->id(); - stream->SetDelegate(client_stream_delegate_.get()); - stream->set_cancel_on_loss(false); - - client_filter_->set_packets_to_drop(1); - - test::QuicTestMemSliceVector stream_data = CreateMemSliceVector("Hello"); - stream->WriteMemSlices(stream_data.span(), /*fin=*/false); - RunTasks(); - - // Stream data should make it despite packet loss. - ASSERT_TRUE(server_stream_delegate_->has_data()); - EXPECT_EQ(server_stream_delegate_->data()[stream_id], "Hello"); -} - -TEST_F(QuartcSessionTest, StreamRetransmissionDisabled) { - // Disable tail loss probe, otherwise test maybe flaky because dropped - // message will be retransmitted to detect tail loss. - QuartcSessionConfig session_config; - session_config.enable_tail_loss_probe = false; - CreateClientAndServerSessions(session_config); - - // Disable probing retransmissions, otherwise test maybe flaky because dropped - // message will be retransmitted to to probe for more bandwidth. - client_peer_->connection()->set_fill_up_link_during_probing(false); - - AwaitHandshake(); - ASSERT_TRUE(client_peer_->OneRttKeysAvailable()); - ASSERT_TRUE(server_peer_->OneRttKeysAvailable()); - - // The client sends an ACK for the crypto handshake next. This must be - // flushed before we set the filter to drop the next packet, in order to - // ensure that the filter drops a data-bearing packet instead of just an ack. - RunTasks(); - - QuartcStream* stream = client_peer_->CreateOutgoingBidirectionalStream(); - QuicStreamId stream_id = stream->id(); - stream->SetDelegate(client_stream_delegate_.get()); - stream->set_cancel_on_loss(true); - - client_filter_->set_packets_to_drop(1); - - test::QuicTestMemSliceVector stream_data = CreateMemSliceVector("Hello"); - stream->WriteMemSlices(stream_data.span(), /*fin=*/false); - simulator_.RunFor(QuicTime::Delta::FromMilliseconds(1)); - - // Send another packet to trigger loss detection. - QuartcStream* stream_1 = client_peer_->CreateOutgoingBidirectionalStream(); - stream_1->SetDelegate(client_stream_delegate_.get()); - - test::QuicTestMemSliceVector stream_data_1 = - CreateMemSliceVector("Second message"); - stream_1->WriteMemSlices(stream_data_1.span(), /*fin=*/false); - RunTasks(); - - // QUIC should try to retransmit the first stream by loss detection. Instead, - // it will cancel itself. - EXPECT_THAT(server_stream_delegate_->data()[stream_id], testing::IsEmpty()); - - EXPECT_TRUE(client_peer_->IsClosedStream(stream_id)); - EXPECT_TRUE(server_peer_->IsClosedStream(stream_id)); - EXPECT_THAT(client_stream_delegate_->stream_error(stream_id), - test::IsStreamError(QUIC_STREAM_CANCELLED)); - EXPECT_THAT(server_stream_delegate_->stream_error(stream_id), - test::IsStreamError(QUIC_STREAM_CANCELLED)); -} - -TEST_F(QuartcSessionTest, LostDatagramNotifications) { - // Disable tail loss probe, otherwise test maybe flaky because dropped - // message will be retransmitted to detect tail loss. - QuartcSessionConfig session_config; - session_config.enable_tail_loss_probe = false; - CreateClientAndServerSessions(session_config); - - // Disable probing retransmissions, otherwise test maybe flaky because dropped - // message will be retransmitted to to probe for more bandwidth. - client_peer_->connection()->set_fill_up_link_during_probing(false); - server_peer_->connection()->set_fill_up_link_during_probing(false); - - AwaitHandshake(); - ASSERT_TRUE(client_peer_->OneRttKeysAvailable()); - ASSERT_TRUE(server_peer_->OneRttKeysAvailable()); - - // The client sends an ACK for the crypto handshake next. This must be - // flushed before we set the filter to drop the next packet, in order to - // ensure that the filter drops a data-bearing packet instead of just an ack. - RunTasks(); - - // Drop the next packet. - client_filter_->set_packets_to_drop(1); - - test::QuicTestMemSliceVector message = - CreateMemSliceVector("This message will be lost"); - ASSERT_TRUE(client_peer_->SendOrQueueMessage(message.span(), 1)); - - RunTasks(); - - // Send another packet to elicit an ack and trigger loss detection. - message = CreateMemSliceVector("This message will arrive"); - ASSERT_TRUE(client_peer_->SendOrQueueMessage(message.span(), 2)); - - RunTasks(); - - EXPECT_THAT(server_session_delegate_->incoming_messages(), - ElementsAre("This message will arrive")); - EXPECT_THAT(client_session_delegate_->sent_datagram_ids(), ElementsAre(1, 2)); - EXPECT_THAT( - client_session_delegate_->acked_datagram_id_to_receive_timestamp(), - ElementsAre(Pair(2, Gt(QuicTime::Zero())))); - EXPECT_THAT(client_session_delegate_->lost_datagram_ids(), ElementsAre(1)); -} - -TEST_F(QuartcSessionTest, ServerRegistersAsWriteBlocked) { - // Initialize client and server session, but with the server write-blocked. - Init(); - server_transport_->SetWritable(false); - CreateClientAndServerSessions(QuartcSessionConfig(), /*init=*/false); - - // Let the client send a few copies of the CHLO. The server can't respond, as - // it's still write-blocked. - RunTasks(); - - // Making the server's transport writable should trigger a callback that - // reaches the server session, allowing it to write packets. - server_transport_->SetWritable(true); - - // Now the server should respond with the SHLO, encryption should be - // established, and data should flow normally. - // Note that if the server is *not* correctly registered as write-blocked, - // it will crash here (see b/124527328 for details). - AwaitHandshake(); - TestSendReceiveStreams(); -} - -TEST_F(QuartcSessionTest, PreSharedKeyHandshakeIs0RTT) { - QuartcSessionConfig session_config; - session_config.pre_shared_key = "foo"; - - // Client endpoint is created below. Destructing client endpoint - // causes issues with the simulator. - Init(/*create_client_endpoint=*/false); - - server_endpoint_->Connect(server_transport_.get()); - - client_endpoint_ = std::make_unique<QuartcClientEndpoint>( - simulator_.GetAlarmFactory(), simulator_.GetClock(), - simulator_.GetRandomGenerator(), client_session_delegate_.get(), - QuartcSessionConfig(), - // This is the key line here. It passes through the server config - // from the server to the client. - server_endpoint_->server_crypto_config()); - - client_endpoint_->Connect(client_transport_.get()); - - // Running for 1ms. This is shorter than the RTT, so the - // client session should be created, but server won't be created yet. - simulator_.RunFor(QuicTime::Delta::FromMilliseconds(1)); - - client_peer_ = client_session_delegate_->session(); - server_peer_ = server_session_delegate_->session(); - - ASSERT_NE(client_peer_, nullptr); - ASSERT_EQ(server_peer_, nullptr); - - // Write data to the client before running tasks. This should be sent by the - // client and received by the server if the handshake is 0RTT. - // If this test fails, add 'RunTasks()' above, and see what error is sent - // by the server in the rejection message. - QuartcStream* stream = client_peer_->CreateOutgoingBidirectionalStream(); - ASSERT_NE(stream, nullptr); - QuicStreamId stream_id = stream->id(); - stream->SetDelegate(client_stream_delegate_.get()); - - char message[] = "Hello in 0RTTs!"; - test::QuicTestMemSliceVector data({std::make_pair(message, strlen(message))}); - stream->WriteMemSlices(data.span(), /*fin=*/false); - - // This will now run the rest of the connection. But the - // Server peer will receive the CHLO and message after 1 delay. - simulator_.RunFor(kPropagationDelayAndABit); - - // If we can decrypt the data, it means that 0 rtt was successful. - // This is because we waited only a propagation delay. So if the decryption - // failed, we would send sREJ instead of SHLO, but it wouldn't be delivered to - // the client yet. - ASSERT_TRUE(server_stream_delegate_->has_data()); - EXPECT_EQ(server_stream_delegate_->data()[stream_id], message); -} - -} // namespace - -} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_stream.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_stream.cc deleted file mode 100644 index 01494c5ddf5..00000000000 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_stream.cc +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright (c) 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/quiche/src/quic/quartc/quartc_stream.h" - -#include <memory> -#include <utility> - -#include "net/third_party/quiche/src/quic/core/quic_ack_listener_interface.h" -#include "net/third_party/quiche/src/quic/core/quic_error_codes.h" -#include "net/third_party/quiche/src/quic/core/quic_stream_send_buffer.h" -#include "net/third_party/quiche/src/quic/core/quic_stream_sequencer.h" -#include "net/third_party/quiche/src/quic/core/quic_stream_sequencer_buffer.h" -#include "net/third_party/quiche/src/quic/core/quic_types.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_reference_counted.h" -#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" - -namespace quic { - -QuartcStream::QuartcStream(QuicStreamId id, QuicSession* session) - : QuicStream(id, session, /*is_static=*/false, BIDIRECTIONAL) { - sequencer()->set_level_triggered(true); -} - -QuartcStream::~QuartcStream() {} - -void QuartcStream::OnDataAvailable() { - size_t bytes_consumed = 0; - do { - bool fin = sequencer()->ReadableBytes() + sequencer()->NumBytesConsumed() == - sequencer()->close_offset(); - - // Upper bound on number of readable regions. Each complete block's worth - // of data crosses at most one region boundary. The remainder may cross one - // more boundary. Number of regions is one more than the number of region - // boundaries crossed. - size_t iov_length = sequencer()->ReadableBytes() / - QuicStreamSequencerBuffer::kBlockSizeBytes + - 2; - std::unique_ptr<iovec[]> iovecs = std::make_unique<iovec[]>(iov_length); - iov_length = sequencer()->GetReadableRegions(iovecs.get(), iov_length); - - bytes_consumed = delegate_->OnReceived(this, iovecs.get(), iov_length, fin); - sequencer()->MarkConsumed(bytes_consumed); - if (sequencer()->IsClosed()) { - OnFinRead(); - break; - } - } while (bytes_consumed > 0); -} - -void QuartcStream::OnClose() { - QuicStream::OnClose(); - DCHECK(delegate_); - delegate_->OnClose(this); -} - -void QuartcStream::OnStreamDataConsumed(QuicByteCount bytes_consumed) { - QuicStream::OnStreamDataConsumed(bytes_consumed); - - if (delegate_) { - delegate_->OnBufferChanged(this); - } -} - -void QuartcStream::OnDataBuffered( - QuicStreamOffset /*offset*/, - QuicByteCount /*data_length*/, - const QuicReferenceCountedPointer< - QuicAckListenerInterface>& /*ack_listener*/) { - if (delegate_) { - delegate_->OnBufferChanged(this); - } -} - -bool QuartcStream::OnStreamFrameAcked(QuicStreamOffset offset, - QuicByteCount data_length, - bool fin_acked, - QuicTime::Delta ack_delay_time, - QuicTime receive_timestamp, - QuicByteCount* newly_acked_length) { - // Previous losses of acked data are no longer relevant to the retransmission - // count. Once data is acked, it will never be retransmitted. - lost_frame_counter_.RemoveInterval( - QuicInterval<QuicStreamOffset>(offset, offset + data_length)); - - return QuicStream::OnStreamFrameAcked(offset, data_length, fin_acked, - ack_delay_time, receive_timestamp, - newly_acked_length); -} - -void QuartcStream::OnStreamFrameRetransmitted(QuicStreamOffset offset, - QuicByteCount data_length, - bool fin_retransmitted) { - QuicStream::OnStreamFrameRetransmitted(offset, data_length, - fin_retransmitted); - - DCHECK(delegate_); - delegate_->OnBufferChanged(this); -} - -void QuartcStream::OnStreamFrameLost(QuicStreamOffset offset, - QuicByteCount data_length, - bool fin_lost) { - QuicStream::OnStreamFrameLost(offset, data_length, fin_lost); - - lost_frame_counter_.AddInterval( - QuicInterval<QuicStreamOffset>(offset, offset + data_length)); - - DCHECK(delegate_); - delegate_->OnBufferChanged(this); -} - -void QuartcStream::OnCanWrite() { - if (lost_frame_counter_.MaxCount() > - static_cast<size_t>(max_retransmission_count_) && - HasPendingRetransmission()) { - Reset(QUIC_STREAM_CANCELLED); - return; - } - QuicStream::OnCanWrite(); -} - -bool QuartcStream::cancel_on_loss() { - return max_retransmission_count_ == 0; -} - -void QuartcStream::set_cancel_on_loss(bool cancel_on_loss) { - if (cancel_on_loss) { - max_retransmission_count_ = 0; - } else { - max_retransmission_count_ = std::numeric_limits<int>::max(); - } -} - -int QuartcStream::max_retransmission_count() const { - return max_retransmission_count_; -} - -void QuartcStream::set_max_retransmission_count(int max_retransmission_count) { - max_retransmission_count_ = max_retransmission_count; -} - -QuicByteCount QuartcStream::BytesPendingRetransmission() { - if (lost_frame_counter_.MaxCount() > - static_cast<size_t>(max_retransmission_count_)) { - return 0; // Lost bytes will never be retransmitted. - } - QuicByteCount bytes = 0; - for (const auto& interval : send_buffer().pending_retransmissions()) { - bytes += interval.Length(); - } - return bytes; -} - -QuicStreamOffset QuartcStream::ReadOffset() { - return sequencer()->NumBytesConsumed(); -} - -void QuartcStream::FinishWriting() { - WriteOrBufferData(quiche::QuicheStringPiece(nullptr, 0), true, nullptr); -} - -void QuartcStream::SetDelegate(Delegate* delegate) { - delegate_ = delegate; - DCHECK(delegate_); -} - -} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_stream.h b/chromium/net/third_party/quiche/src/quic/quartc/quartc_stream.h deleted file mode 100644 index 7f3c28d005c..00000000000 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_stream.h +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright (c) 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef QUICHE_QUIC_QUARTC_QUARTC_STREAM_H_ -#define QUICHE_QUIC_QUARTC_QUARTC_STREAM_H_ - -#include <stddef.h> -#include <limits> - -#include "net/third_party/quiche/src/quic/core/quic_ack_listener_interface.h" -#include "net/third_party/quiche/src/quic/core/quic_session.h" -#include "net/third_party/quiche/src/quic/core/quic_stream.h" -#include "net/third_party/quiche/src/quic/core/quic_types.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_mem_slice_span.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_reference_counted.h" -#include "net/quic/platform/impl/quic_export_impl.h" -#include "net/third_party/quiche/src/quic/quartc/quartc_interval_counter.h" - -namespace quic { - -// Sends and receives data with a particular QUIC stream ID, reliably and -// in-order. To send/receive data out of order, use separate streams. To -// send/receive unreliably, close a stream after reliability is no longer -// needed. -class QuartcStream : public QuicStream { - public: - QuartcStream(QuicStreamId id, QuicSession* session); - - ~QuartcStream() override; - - // QuicStream overrides. - void OnDataAvailable() override; - - void OnClose() override; - - void OnStreamDataConsumed(QuicByteCount bytes_consumed) override; - - void OnDataBuffered( - QuicStreamOffset offset, - QuicByteCount data_length, - const QuicReferenceCountedPointer<QuicAckListenerInterface>& ack_listener) - override; - - bool OnStreamFrameAcked(QuicStreamOffset offset, - QuicByteCount data_length, - bool fin_acked, - QuicTime::Delta ack_delay_time, - QuicTime receive_timestamp, - QuicByteCount* newly_acked_length) override; - - void OnStreamFrameRetransmitted(QuicStreamOffset offset, - QuicByteCount data_length, - bool fin_retransmitted) override; - - void OnStreamFrameLost(QuicStreamOffset offset, - QuicByteCount data_length, - bool fin_lost) override; - - void OnCanWrite() override; - - // QuartcStream interface methods. - - // Whether the stream should be cancelled instead of retransmitted on loss. - // If set to true, the stream will reset itself instead of retransmitting lost - // stream frames. Defaults to false. Setting it to true is equivalent to - // setting |max_retransmission_count| to zero. - bool cancel_on_loss(); - void set_cancel_on_loss(bool cancel_on_loss); - - // Maximum number of times this stream's data may be retransmitted. Each byte - // of stream data may be retransmitted this many times. If any byte (or range - // of bytes) is lost and would be retransmitted more than this number of - // times, the stream resets itself instead of retransmitting the data again. - // Setting this value to zero disables retransmissions. - // - // Note that this limit applies only to stream data, not to the FIN bit. If - // only the FIN bit needs to be retransmitted, there is no benefit to - // cancelling the stream and sending a reset frame instead. - int max_retransmission_count() const; - void set_max_retransmission_count(int max_retransmission_count); - - QuicByteCount BytesPendingRetransmission(); - - // Returns the current read offset for this stream. During a call to - // Delegate::OnReceived, this value is the offset of the first byte read. - QuicStreamOffset ReadOffset(); - - // Marks this stream as finished writing. Asynchronously sends a FIN and - // closes the write-side. It is not necessary to call FinishWriting() if the - // last call to Write() sends a FIN. - void FinishWriting(); - - // Implemented by the user of the QuartcStream to receive incoming - // data and be notified of state changes. - class Delegate { - public: - virtual ~Delegate() {} - - // Called when the stream receives data. |iov| is a pointer to the first of - // |iov_length| readable regions. |iov| points to readable data within - // |stream|'s sequencer buffer. QUIC may modify or delete this data after - // the application consumes it. |fin| indicates the end of stream data. - // Returns the number of bytes consumed. May return 0 if the delegate is - // unable to consume any bytes at this time. - virtual size_t OnReceived(QuartcStream* stream, - iovec* iov, - size_t iov_length, - bool fin) = 0; - - // Called when the stream is closed, either locally or by the remote - // endpoint. Streams close when (a) fin bits are both sent and received, - // (b) Close() is called, or (c) the stream is reset. - // TODO(zhihuang) Creates a map from the integer error_code to WebRTC native - // error code. - virtual void OnClose(QuartcStream* stream) = 0; - - // Called when the contents of the stream's buffer changes. - virtual void OnBufferChanged(QuartcStream* stream) = 0; - }; - - // The |delegate| is not owned by QuartcStream. - void SetDelegate(Delegate* delegate); - - private: - Delegate* delegate_ = nullptr; - - // Maximum number of times this stream's data may be retransmitted. - int max_retransmission_count_ = std::numeric_limits<int>::max(); - - // Counter which tracks the number of times each frame has been lost - // (accounting for the possibility of overlapping frames). - // - // If the maximum count of any lost frame exceeds |max_retransmission_count_|, - // the stream will cancel itself on the next attempt to retransmit data (the - // next call to |OnCanWrite|). - QuartcIntervalCounter<QuicStreamOffset> lost_frame_counter_; -}; - -} // namespace quic - -#endif // QUICHE_QUIC_QUARTC_QUARTC_STREAM_H_ diff --git a/chromium/net/third_party/quiche/src/quic/quartc/quartc_stream_test.cc b/chromium/net/third_party/quiche/src/quic/quartc/quartc_stream_test.cc deleted file mode 100644 index b387e7f9723..00000000000 --- a/chromium/net/third_party/quiche/src/quic/quartc/quartc_stream_test.cc +++ /dev/null @@ -1,656 +0,0 @@ -// Copyright (c) 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/quiche/src/quic/quartc/quartc_stream.h" - -#include <memory> -#include <string> -#include <type_traits> -#include <utility> - -#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h" -#include "net/third_party/quiche/src/quic/core/frames/quic_stream_frame.h" -#include "net/third_party/quiche/src/quic/core/quic_alarm_factory.h" -#include "net/third_party/quiche/src/quic/core/quic_buffer_allocator.h" -#include "net/third_party/quiche/src/quic/core/quic_clock.h" -#include "net/third_party/quiche/src/quic/core/quic_config.h" -#include "net/third_party/quiche/src/quic/core/quic_connection.h" -#include "net/third_party/quiche/src/quic/core/quic_crypto_stream.h" -#include "net/third_party/quiche/src/quic/core/quic_data_writer.h" -#include "net/third_party/quiche/src/quic/core/quic_error_codes.h" -#include "net/third_party/quiche/src/quic/core/quic_packet_writer.h" -#include "net/third_party/quiche/src/quic/core/quic_session.h" -#include "net/third_party/quiche/src/quic/core/quic_simple_buffer_allocator.h" -#include "net/third_party/quiche/src/quic/core/quic_time.h" -#include "net/third_party/quiche/src/quic/core/quic_types.h" -#include "net/third_party/quiche/src/quic/core/quic_utils.h" -#include "net/third_party/quiche/src/quic/core/quic_versions.h" -#include "net/third_party/quiche/src/quic/core/quic_write_blocked_list.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_ip_address.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_test_mem_slice_vector.h" -#include "net/third_party/quiche/src/quic/quartc/quartc_factory.h" -#include "net/third_party/quiche/src/quic/test_tools/mock_clock.h" -#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" -#include "net/third_party/quiche/src/common/platform/api/quiche_endian.h" -#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" - -using ::quic::test::IsQuicStreamNoError; -using ::quic::test::IsStreamError; - -namespace quic { - -namespace { - -static const QuicStreamId kStreamId = 5; - -// MockQuicSession that does not create streams and writes data from -// QuicStream to a string. -class MockQuicSession : public QuicSession { - public: - MockQuicSession(QuicConnection* connection, - const QuicConfig& config, - std::string* write_buffer) - : QuicSession(connection, - nullptr /*visitor*/, - config, - CurrentSupportedVersions(), - /*num_expected_unidirectional_static_streams = */ 0), - write_buffer_(write_buffer) {} - - ~MockQuicSession() override {} - - // Writes outgoing data from QuicStream to a string. - QuicConsumedData WritevData( - QuicStreamId id, - size_t write_length, - QuicStreamOffset offset, - StreamSendingState state, - TransmissionType /*type*/, - quiche::QuicheOptional<EncryptionLevel> /*level*/) override { - if (!writable_) { - return QuicConsumedData(0, false); - } - - // WritevData does not pass down a iovec, data is saved in stream before - // data is consumed. Retrieve data from stream. - char* buf = new char[write_length]; - QuicDataWriter writer(write_length, buf, quiche::NETWORK_BYTE_ORDER); - QuicStream* stream = GetOrCreateStream(id); - DCHECK(stream); - if (write_length > 0) { - stream->WriteStreamData(offset, write_length, &writer); - } - write_buffer_->append(buf, write_length); - delete[] buf; - return QuicConsumedData(write_length, state != StreamSendingState::NO_FIN); - } - - QuartcStream* CreateIncomingStream(QuicStreamId /*id*/) override { - return nullptr; - } - - QuartcStream* CreateIncomingStream(PendingStream* /*pending*/) override { - return nullptr; - } - - const QuicCryptoStream* GetCryptoStream() const override { return nullptr; } - QuicCryptoStream* GetMutableCryptoStream() override { return nullptr; } - bool ShouldKeepConnectionAlive() const override { - return GetNumActiveStreams() > 0; - } - - // Called by QuicStream when they want to close stream. - void SendRstStream(QuicStreamId /*id*/, - QuicRstStreamErrorCode /*error*/, - QuicStreamOffset /*bytes_written*/) override {} - - // Sets whether data is written to buffer, or else if this is write blocked. - void set_writable(bool writable) { writable_ = writable; } - - // Tracks whether the stream is write blocked and its priority. - void RegisterReliableStream(QuicStreamId stream_id, - spdy::SpdyPriority priority) { - write_blocked_streams()->RegisterStream( - stream_id, - /*is_static_stream=*/false, spdy::SpdyStreamPrecedence(priority)); - } - - // The session take ownership of the stream. - void ActivateReliableStream(std::unique_ptr<QuicStream> stream) { - ActivateStream(std::move(stream)); - } - - private: - // Stores written data from ReliableQuicStreamAdapter. - std::string* write_buffer_; - // Whether data is written to write_buffer_. - bool writable_ = true; -}; - -// Packet writer that does nothing. This is required for QuicConnection but -// isn't used for writing data. -class DummyPacketWriter : public QuicPacketWriter { - public: - DummyPacketWriter() {} - - // QuicPacketWriter overrides. - WriteResult WritePacket(const char* /*buffer*/, - size_t /*buf_len*/, - const QuicIpAddress& /*self_address*/, - const QuicSocketAddress& /*peer_address*/, - PerPacketOptions* /*options*/) override { - return WriteResult(WRITE_STATUS_ERROR, 0); - } - - bool IsWriteBlocked() const override { return false; } - - void SetWritable() override {} - - QuicByteCount GetMaxPacketSize( - const QuicSocketAddress& /*peer_address*/) const override { - return 0; - } - - bool SupportsReleaseTime() const override { return false; } - - bool IsBatchMode() const override { return false; } - - char* GetNextWriteLocation( - const QuicIpAddress& /*self_address*/, - const QuicSocketAddress& /*peer_address*/) override { - return nullptr; - } - - WriteResult Flush() override { return WriteResult(WRITE_STATUS_OK, 0); } -}; - -class MockQuartcStreamDelegate : public QuartcStream::Delegate { - public: - MockQuartcStreamDelegate(QuicStreamId id, std::string* read_buffer) - : id_(id), read_buffer_(read_buffer) {} - - void OnBufferChanged(QuartcStream* stream) override { - last_bytes_buffered_ = stream->BufferedDataBytes(); - last_bytes_pending_retransmission_ = stream->BytesPendingRetransmission(); - } - - size_t OnReceived(QuartcStream* stream, - iovec* iov, - size_t iov_length, - bool /*fin*/) override { - EXPECT_EQ(id_, stream->id()); - EXPECT_EQ(stream->ReadOffset(), read_buffer_->size()); - size_t bytes_consumed = 0; - for (size_t i = 0; i < iov_length; ++i) { - read_buffer_->append(static_cast<const char*>(iov[i].iov_base), - iov[i].iov_len); - bytes_consumed += iov[i].iov_len; - } - return bytes_consumed; - } - - void OnClose(QuartcStream* /*stream*/) override { closed_ = true; } - - bool closed() { return closed_; } - - QuicByteCount last_bytes_buffered() { return last_bytes_buffered_; } - QuicByteCount last_bytes_pending_retransmission() { - return last_bytes_pending_retransmission_; - } - - protected: - QuicStreamId id_; - // Data read by the QuicStream. - std::string* read_buffer_; - // Whether the QuicStream is closed. - bool closed_ = false; - - // Last amount of data observed as buffered. - QuicByteCount last_bytes_buffered_ = 0; - QuicByteCount last_bytes_pending_retransmission_ = 0; -}; - -class QuartcStreamTest : public QuicTestWithParam<ParsedQuicVersion>, - public QuicConnectionHelperInterface { - public: - QuartcStreamTest() : version_(GetParam()) {} - - ~QuartcStreamTest() override = default; - - void CreateReliableQuicStream() { - // Arbitrary values for QuicConnection. - Perspective perspective = Perspective::IS_SERVER; - QuicIpAddress ip; - ip.FromString("0.0.0.0"); - bool owns_writer = true; - - alarm_factory_ = std::make_unique<test::MockAlarmFactory>(); - - connection_ = std::make_unique<QuicConnection>( - QuicUtils::CreateZeroConnectionId(version_.transport_version), - QuicSocketAddress(ip, 0), this /*QuicConnectionHelperInterface*/, - alarm_factory_.get(), new DummyPacketWriter(), owns_writer, perspective, - ParsedQuicVersionVector{version_}); - clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1)); - session_ = std::make_unique<MockQuicSession>(connection_.get(), - QuicConfig(), &write_buffer_); - mock_stream_delegate_ = - std::make_unique<MockQuartcStreamDelegate>(kStreamId, &read_buffer_); - stream_ = new QuartcStream(kStreamId, session_.get()); - stream_->SetDelegate(mock_stream_delegate_.get()); - session_->ActivateReliableStream(std::unique_ptr<QuartcStream>(stream_)); - } - - const QuicClock* GetClock() const override { return &clock_; } - - QuicRandom* GetRandomGenerator() override { - return QuicRandom::GetInstance(); - } - - QuicBufferAllocator* GetStreamSendBufferAllocator() override { - return &buffer_allocator_; - } - - protected: - const ParsedQuicVersion version_; - // The QuicSession will take the ownership. - QuartcStream* stream_; - std::unique_ptr<MockQuartcStreamDelegate> mock_stream_delegate_; - std::unique_ptr<MockQuicSession> session_; - // Data written by the ReliableQuicStreamAdapterTest. - std::string write_buffer_; - // Data read by the ReliableQuicStreamAdapterTest. - std::string read_buffer_; - std::unique_ptr<QuicAlarmFactory> alarm_factory_; - std::unique_ptr<QuicConnection> connection_; - // Used to implement the QuicConnectionHelperInterface. - SimpleBufferAllocator buffer_allocator_; - MockClock clock_; -}; - -// TODO(b/150224094): Enable versions with TLS handshake. -INSTANTIATE_TEST_SUITE_P( - Tests, - QuartcStreamTest, - ::testing::ValuesIn(CurrentSupportedVersionsWithQuicCrypto()), - ::testing::PrintToStringParamName()); - -// Write an entire string. -TEST_P(QuartcStreamTest, WriteDataWhole) { - CreateReliableQuicStream(); - char message[] = "Foo bar"; - test::QuicTestMemSliceVector data({std::make_pair(message, 7)}); - stream_->WriteMemSlices(data.span(), /*fin=*/false); - EXPECT_EQ("Foo bar", write_buffer_); -} - -// Write part of a string. -TEST_P(QuartcStreamTest, WriteDataPartial) { - CreateReliableQuicStream(); - char message[] = "Foo bar"; - test::QuicTestMemSliceVector data({std::make_pair(message, 5)}); - stream_->WriteMemSlices(data.span(), /*fin=*/false); - EXPECT_EQ("Foo b", write_buffer_); -} - -// Test that a QuartcStream buffers writes correctly. -TEST_P(QuartcStreamTest, StreamBuffersData) { - CreateReliableQuicStream(); - - char message[] = "Foo bar"; - test::QuicTestMemSliceVector data({std::make_pair(message, 7)}); - - // The stream is not yet writable, so data will be buffered. - session_->set_writable(false); - stream_->WriteMemSlices(data.span(), /*fin=*/false); - - // Check that data is buffered. - EXPECT_TRUE(stream_->HasBufferedData()); - EXPECT_EQ(7u, stream_->BufferedDataBytes()); - - // Check that the stream told its delegate about the buffer change. - EXPECT_EQ(7u, mock_stream_delegate_->last_bytes_buffered()); - - // Check that none of the data was written yet. - // Note that |write_buffer_| actually holds data written by the QuicSession - // (not data buffered by the stream). - EXPECT_EQ(0ul, write_buffer_.size()); - - char message1[] = "xyzzy"; - test::QuicTestMemSliceVector data1({std::make_pair(message1, 5)}); - - // More writes go into the buffer. - stream_->WriteMemSlices(data1.span(), /*fin=*/false); - - EXPECT_TRUE(stream_->HasBufferedData()); - EXPECT_EQ(12u, stream_->BufferedDataBytes()); - EXPECT_EQ(12u, mock_stream_delegate_->last_bytes_buffered()); - EXPECT_EQ(0ul, write_buffer_.size()); - - // The stream becomes writable, so it sends the buffered data. - session_->set_writable(true); - stream_->OnCanWrite(); - - EXPECT_FALSE(stream_->HasBufferedData()); - EXPECT_EQ(0u, stream_->BufferedDataBytes()); - EXPECT_EQ(0u, mock_stream_delegate_->last_bytes_buffered()); - EXPECT_EQ("Foo barxyzzy", write_buffer_); -} - -// Finish writing to a stream. -// It delivers the fin bit and closes the write-side as soon as possible. -TEST_P(QuartcStreamTest, FinishWriting) { - CreateReliableQuicStream(); - - session_->set_writable(false); - stream_->FinishWriting(); - EXPECT_FALSE(stream_->fin_sent()); - - // Fin is sent as soon as the stream becomes writable. - session_->set_writable(true); - stream_->OnCanWrite(); - EXPECT_TRUE(stream_->fin_sent()); - EXPECT_TRUE(stream_->write_side_closed()); -} - -// Read an entire string. -TEST_P(QuartcStreamTest, ReadDataWhole) { - CreateReliableQuicStream(); - QuicStreamFrame frame(kStreamId, false, 0, "Hello, World!"); - stream_->OnStreamFrame(frame); - - EXPECT_EQ("Hello, World!", read_buffer_); -} - -// Read part of a string. -TEST_P(QuartcStreamTest, ReadDataPartial) { - CreateReliableQuicStream(); - QuicStreamFrame frame(kStreamId, false, 0, "Hello, World!"); - frame.data_length = 5; - stream_->OnStreamFrame(frame); - - EXPECT_EQ("Hello", read_buffer_); -} - -// Streams do not call OnReceived() after StopReading(). -// Note: this is tested here because Quartc relies on this behavior. -TEST_P(QuartcStreamTest, StopReading) { - CreateReliableQuicStream(); - stream_->StopReading(); - - QuicStreamFrame frame(kStreamId, false, 0, "Hello, World!"); - stream_->OnStreamFrame(frame); - - EXPECT_EQ(0ul, read_buffer_.size()); - - QuicStreamFrame frame2(kStreamId, true, 0, "Hello, World!"); - stream_->OnStreamFrame(frame2); - - EXPECT_EQ(0ul, read_buffer_.size()); - EXPECT_TRUE(stream_->fin_received()); -} - -// Test that closing the stream results in a callback. -TEST_P(QuartcStreamTest, CloseStream) { - CreateReliableQuicStream(); - EXPECT_FALSE(mock_stream_delegate_->closed()); - if (GetQuicReloadableFlag(quic_break_session_stream_close_loop)) { - stream_->CloseWriteSide(); - stream_->CloseReadSide(); - } else { - stream_->OnClose(); - } - EXPECT_TRUE(mock_stream_delegate_->closed()); -} - -// Both sending and receiving fin automatically closes a stream. -TEST_P(QuartcStreamTest, CloseOnFins) { - CreateReliableQuicStream(); - QuicStreamFrame frame(kStreamId, true, 0, 0); - stream_->OnStreamFrame(frame); - - test::QuicTestMemSliceVector data({}); - stream_->WriteMemSlices(data.span(), /*fin=*/true); - - // Check that the OnClose() callback occurred. - EXPECT_TRUE(mock_stream_delegate_->closed()); -} - -TEST_P(QuartcStreamTest, TestCancelOnLossDisabled) { - CreateReliableQuicStream(); - - // This should be the default state. - EXPECT_FALSE(stream_->cancel_on_loss()); - - char message[] = "Foo bar"; - test::QuicTestMemSliceVector data({std::make_pair(message, 7)}); - stream_->WriteMemSlices(data.span(), /*fin=*/false); - - EXPECT_EQ("Foo bar", write_buffer_); - - stream_->OnStreamFrameLost(0, 7, false); - stream_->OnCanWrite(); - - EXPECT_EQ("Foo barFoo bar", write_buffer_); - EXPECT_THAT(stream_->stream_error(), IsQuicStreamNoError()); -} - -TEST_P(QuartcStreamTest, TestCancelOnLossEnabled) { - CreateReliableQuicStream(); - stream_->set_cancel_on_loss(true); - - char message[] = "Foo bar"; - test::QuicTestMemSliceVector data({std::make_pair(message, 7)}); - stream_->WriteMemSlices(data.span(), /*fin=*/false); - - EXPECT_EQ("Foo bar", write_buffer_); - - stream_->OnStreamFrameLost(0, 7, false); - stream_->OnCanWrite(); - - EXPECT_EQ("Foo bar", write_buffer_); - EXPECT_THAT(stream_->stream_error(), IsStreamError(QUIC_STREAM_CANCELLED)); -} - -TEST_P(QuartcStreamTest, MaxRetransmissionsAbsent) { - CreateReliableQuicStream(); - - // This should be the default state. - EXPECT_EQ(stream_->max_retransmission_count(), - std::numeric_limits<int>::max()); - - char message[] = "Foo bar"; - test::QuicTestMemSliceVector data({std::make_pair(message, 7)}); - stream_->WriteMemSlices(data.span(), /*fin=*/false); - - EXPECT_EQ("Foo bar", write_buffer_); - - stream_->OnStreamFrameLost(0, 7, false); - stream_->OnCanWrite(); - - EXPECT_EQ("Foo barFoo bar", write_buffer_); - EXPECT_THAT(stream_->stream_error(), IsQuicStreamNoError()); -} - -TEST_P(QuartcStreamTest, MaxRetransmissionsSet) { - CreateReliableQuicStream(); - stream_->set_max_retransmission_count(2); - - char message[] = "Foo bar"; - test::QuicTestMemSliceVector data({std::make_pair(message, 7)}); - stream_->WriteMemSlices(data.span(), /*fin=*/false); - - EXPECT_EQ("Foo bar", write_buffer_); - - stream_->OnStreamFrameLost(0, 7, false); - stream_->OnCanWrite(); - - EXPECT_EQ("Foo barFoo bar", write_buffer_); - - stream_->OnStreamFrameLost(0, 7, false); - stream_->OnCanWrite(); - - EXPECT_EQ("Foo barFoo barFoo bar", write_buffer_); - - stream_->OnStreamFrameLost(0, 7, false); - stream_->OnCanWrite(); - - EXPECT_EQ("Foo barFoo barFoo bar", write_buffer_); - EXPECT_THAT(stream_->stream_error(), IsStreamError(QUIC_STREAM_CANCELLED)); -} - -TEST_P(QuartcStreamTest, MaxRetransmissionsDisjointFrames) { - CreateReliableQuicStream(); - stream_->set_max_retransmission_count(2); - - char message[] = "Foo bar"; - test::QuicTestMemSliceVector data({std::make_pair(message, 7)}); - stream_->WriteMemSlices(data.span(), /*fin=*/false); - - EXPECT_EQ("Foo bar", write_buffer_); - - // Retransmit bytes [0, 3]. - stream_->OnStreamFrameLost(0, 4, false); - stream_->OnCanWrite(); - - EXPECT_EQ("Foo barFoo ", write_buffer_); - - // Retransmit bytes [4, 6]. Everything has been retransmitted once. - stream_->OnStreamFrameLost(4, 3, false); - stream_->OnCanWrite(); - - EXPECT_EQ("Foo barFoo bar", write_buffer_); - - // Retransmit bytes [0, 6]. Everything can be retransmitted a second time. - stream_->OnStreamFrameLost(0, 7, false); - stream_->OnCanWrite(); - - EXPECT_EQ("Foo barFoo barFoo bar", write_buffer_); -} - -TEST_P(QuartcStreamTest, MaxRetransmissionsOverlappingFrames) { - CreateReliableQuicStream(); - stream_->set_max_retransmission_count(2); - - char message[] = "Foo bar"; - test::QuicTestMemSliceVector data({std::make_pair(message, 7)}); - stream_->WriteMemSlices(data.span(), /*fin=*/false); - - EXPECT_EQ("Foo bar", write_buffer_); - - // Retransmit bytes 0 to 3. - stream_->OnStreamFrameLost(0, 4, false); - stream_->OnCanWrite(); - - EXPECT_EQ("Foo barFoo ", write_buffer_); - - // Retransmit bytes 3 to 6. Byte 3 has been retransmitted twice. - stream_->OnStreamFrameLost(3, 4, false); - stream_->OnCanWrite(); - - EXPECT_EQ("Foo barFoo bar", write_buffer_); - - // Retransmit byte 3 a third time. This should cause cancellation. - stream_->OnStreamFrameLost(3, 1, false); - stream_->OnCanWrite(); - - EXPECT_EQ("Foo barFoo bar", write_buffer_); - EXPECT_THAT(stream_->stream_error(), IsStreamError(QUIC_STREAM_CANCELLED)); -} - -TEST_P(QuartcStreamTest, MaxRetransmissionsWithAckedFrame) { - CreateReliableQuicStream(); - stream_->set_max_retransmission_count(1); - - char message[] = "Foo bar"; - test::QuicTestMemSliceVector data({std::make_pair(message, 7)}); - stream_->WriteMemSlices(data.span(), /*fin=*/false); - - EXPECT_EQ("Foo bar", write_buffer_); - - // Retransmit bytes [0, 7). - stream_->OnStreamFrameLost(0, 7, false); - stream_->OnCanWrite(); - - EXPECT_EQ("Foo barFoo bar", write_buffer_); - - // Ack bytes [0, 7). These bytes should be pruned from the data tracked by - // the stream. - QuicByteCount newly_acked_length = 0; - stream_->OnStreamFrameAcked(0, 7, false, QuicTime::Delta::FromMilliseconds(1), - QuicTime::Zero(), &newly_acked_length); - EXPECT_EQ(7u, newly_acked_length); - stream_->OnCanWrite(); - - EXPECT_EQ("Foo barFoo bar", write_buffer_); - - // Retransmit bytes [0, 7) again. - // QUIC will never mark frames as lost after they've been acked, but this lets - // us test that QuartcStream stopped tracking these bytes after the acked. - stream_->OnStreamFrameLost(0, 7, false); - stream_->OnCanWrite(); - - // QuartcStream should be cancelled, but it stopped tracking the lost bytes - // after they were acked, so it's not. - EXPECT_THAT(stream_->stream_error(), IsQuicStreamNoError()); -} - -TEST_P(QuartcStreamTest, TestBytesPendingRetransmission) { - CreateReliableQuicStream(); - stream_->set_cancel_on_loss(false); - - char message[] = "Foo bar"; - test::QuicTestMemSliceVector data({std::make_pair(message, 7)}); - stream_->WriteMemSlices(data.span(), /*fin=*/false); - - EXPECT_EQ("Foo bar", write_buffer_); - - stream_->OnStreamFrameLost(0, 4, false); - EXPECT_EQ(stream_->BytesPendingRetransmission(), 4u); - EXPECT_EQ(mock_stream_delegate_->last_bytes_pending_retransmission(), 4u); - - stream_->OnStreamFrameLost(4, 3, false); - EXPECT_EQ(stream_->BytesPendingRetransmission(), 7u); - EXPECT_EQ(mock_stream_delegate_->last_bytes_pending_retransmission(), 7u); - - stream_->OnCanWrite(); - EXPECT_EQ(stream_->BytesPendingRetransmission(), 0u); - EXPECT_EQ(mock_stream_delegate_->last_bytes_pending_retransmission(), 0u); - - EXPECT_EQ("Foo barFoo bar", write_buffer_); - EXPECT_THAT(stream_->stream_error(), IsQuicStreamNoError()); -} - -TEST_P(QuartcStreamTest, TestBytesPendingRetransmissionWithCancelOnLoss) { - CreateReliableQuicStream(); - stream_->set_cancel_on_loss(true); - - char message[] = "Foo bar"; - test::QuicTestMemSliceVector data({std::make_pair(message, 7)}); - stream_->WriteMemSlices(data.span(), /*fin=*/false); - - EXPECT_EQ("Foo bar", write_buffer_); - - stream_->OnStreamFrameLost(0, 4, false); - EXPECT_EQ(stream_->BytesPendingRetransmission(), 0u); - EXPECT_EQ(mock_stream_delegate_->last_bytes_pending_retransmission(), 0u); - - stream_->OnStreamFrameLost(4, 3, false); - EXPECT_EQ(stream_->BytesPendingRetransmission(), 0u); - EXPECT_EQ(mock_stream_delegate_->last_bytes_pending_retransmission(), 0u); - - stream_->OnCanWrite(); - EXPECT_EQ(stream_->BytesPendingRetransmission(), 0u); - EXPECT_EQ(mock_stream_delegate_->last_bytes_pending_retransmission(), 0u); - - EXPECT_EQ("Foo bar", write_buffer_); - EXPECT_THAT(stream_->stream_error(), IsStreamError(QUIC_STREAM_CANCELLED)); -} - -} // namespace - -} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/quartc/simulated_packet_transport.cc b/chromium/net/third_party/quiche/src/quic/quartc/simulated_packet_transport.cc deleted file mode 100644 index 263c21395e0..00000000000 --- a/chromium/net/third_party/quiche/src/quic/quartc/simulated_packet_transport.cc +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright (c) 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/quiche/src/quic/quartc/simulated_packet_transport.h" - -#include <utility> - -#include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h" - -namespace quic { -namespace simulator { - -SimulatedQuartcPacketTransport::SimulatedQuartcPacketTransport( - Simulator* simulator, - const std::string& name, - const std::string& peer_name, - QuicByteCount queue_capacity) - : Endpoint(simulator, name), - peer_name_(peer_name), - egress_queue_(simulator, - quiche::QuicheStringPrintf("%s (TX Queue)", name.c_str()), - queue_capacity) { - egress_queue_.set_listener_interface(this); -} - -int SimulatedQuartcPacketTransport::Write(const char* buffer, - size_t buf_len, - const PacketInfo& info) { - if (!writable_) { - return 0; - } - if (egress_queue_.bytes_queued() + buf_len > egress_queue_.capacity()) { - return 0; - } - - last_packet_number_ = info.packet_number; - - auto packet = std::make_unique<Packet>(); - packet->contents = std::string(buffer, buf_len); - packet->size = buf_len; - packet->tx_timestamp = clock_->Now(); - packet->source = name(); - packet->destination = peer_name_; - - egress_queue_.AcceptPacket(std::move(packet)); - return buf_len; -} - -void SimulatedQuartcPacketTransport::SetDelegate(Delegate* delegate) { - delegate_ = delegate; - Schedule(clock_->Now()); -} - -UnconstrainedPortInterface* SimulatedQuartcPacketTransport::GetRxPort() { - return this; -} - -void SimulatedQuartcPacketTransport::SetTxPort(ConstrainedPortInterface* port) { - egress_queue_.set_tx_port(port); - Schedule(clock_->Now()); -} - -void SimulatedQuartcPacketTransport::AcceptPacket( - std::unique_ptr<Packet> packet) { - // Simulated switches broadcast packets to all ports if the cannot determine - // the recipient, so we need to drop packets that aren't intended for us. - if (packet->destination != name()) { - return; - } - - if (delegate_) { - delegate_->OnTransportReceived(packet->contents.data(), packet->size); - } -} - -void SimulatedQuartcPacketTransport::OnPacketDequeued() { - if (delegate_ && writable_) { - delegate_->OnTransportCanWrite(); - } -} - -void SimulatedQuartcPacketTransport::Act() { - if (delegate_ && writable_) { - delegate_->OnTransportCanWrite(); - } -} - -void SimulatedQuartcPacketTransport::SetWritable(bool writable) { - writable_ = writable; - if (writable_) { - // May need to call |Delegate::OnTransportCanWrite|. - Schedule(clock_->Now()); - } -} - -} // namespace simulator -} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/quartc/simulated_packet_transport.h b/chromium/net/third_party/quiche/src/quic/quartc/simulated_packet_transport.h deleted file mode 100644 index 185668b528a..00000000000 --- a/chromium/net/third_party/quiche/src/quic/quartc/simulated_packet_transport.h +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright (c) 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef QUICHE_QUIC_QUARTC_SIMULATED_PACKET_TRANSPORT_H_ -#define QUICHE_QUIC_QUARTC_SIMULATED_PACKET_TRANSPORT_H_ - -#include <string> - -#include "net/third_party/quiche/src/quic/quartc/quartc_packet_writer.h" -#include "net/third_party/quiche/src/quic/test_tools/simulator/port.h" -#include "net/third_party/quiche/src/quic/test_tools/simulator/queue.h" - -namespace quic { -namespace simulator { - -// Simulated implementation of QuartcPacketTransport. This packet transport -// implementation connects Quartc to a QUIC simulator's network fabric. -// Assumes that its caller and delegate run on the same thread as the network -// simulation and therefore require no additional synchronization. -class SimulatedQuartcPacketTransport : public Endpoint, - public QuartcPacketTransport, - public UnconstrainedPortInterface, - public Queue::ListenerInterface { - public: - SimulatedQuartcPacketTransport(Simulator* simulator, - const std::string& name, - const std::string& peer_name, - QuicByteCount queue_capacity); - - // QuartcPacketTransport methods. - int Write(const char* buffer, - size_t buf_len, - const PacketInfo& info) override; - void SetDelegate(Delegate* delegate) override; - - // Simulation methods below. These are implementation details. - - // Endpoint methods. Called by the simulation to connect the transport. - UnconstrainedPortInterface* GetRxPort() override; - void SetTxPort(ConstrainedPortInterface* port) override; - - // UnconstrainedPortInterface method. Called by the simulation to deliver a - // packet to this transport. - void AcceptPacket(std::unique_ptr<Packet> packet) override; - - // Queue::ListenerInterface method. Called when the internal egress queue has - // dispatched a packet and may have room for more. - void OnPacketDequeued() override; - - // Actor method. The transport schedules this to run when the delegate is set - // in order to trigger an initial call to |Delegate::OnTransportCanWrite()|. - // (The Quartc packet writer starts in a blocked state and needs an initial - // callback to unblock it.) - void Act() override; - - // Changes whether the transport is writable. If |writable| is false, the - // transport will reject calls to |Write| and will not call - // |Delegate::OnTransportCanWrite|. If |writable| is true, the transport will - // allow calls to |Write| and will call |Delegate::OnTransportCanWrite| - // whenever it is able to write another packet. - void SetWritable(bool writable); - - // Last packet number sent over this simulated transport. - // TODO(b/112561077): Reorganize tests so that this method can be deleted. - // This exists purely for use by quartc_session_test.cc, to test that the - // packet writer passes packet numbers to the transport. - QuicPacketNumber last_packet_number() { return last_packet_number_; } - - private: - std::string peer_name_; - Delegate* delegate_ = nullptr; - Queue egress_queue_; - QuicPacketNumber last_packet_number_; - - // Controls whether the transport is considered to be writable. Used to - // simulate behavior that arises when the transport is blocked. - bool writable_ = true; -}; - -} // namespace simulator -} // namespace quic - -#endif // QUICHE_QUIC_QUARTC_SIMULATED_PACKET_TRANSPORT_H_ diff --git a/chromium/net/third_party/quiche/src/quic/quartc/simulated_packet_transport_test.cc b/chromium/net/third_party/quiche/src/quic/quartc/simulated_packet_transport_test.cc deleted file mode 100644 index 24a4f4fc49f..00000000000 --- a/chromium/net/third_party/quiche/src/quic/quartc/simulated_packet_transport_test.cc +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright (c) 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/third_party/quiche/src/quic/quartc/simulated_packet_transport.h" - -#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" -#include "net/third_party/quiche/src/quic/quartc/quartc_packet_writer.h" -#include "net/third_party/quiche/src/quic/test_tools/simulator/simulator.h" -#include "net/third_party/quiche/src/quic/test_tools/simulator/switch.h" - -namespace quic { -namespace simulator { -namespace { - -using ::testing::ElementsAre; - -const QuicBandwidth kDefaultBandwidth = - QuicBandwidth::FromKBitsPerSecond(10 * 1000); -const QuicTime::Delta kDefaultPropagationDelay = - QuicTime::Delta::FromMilliseconds(20); -const QuicByteCount kDefaultBdp = kDefaultBandwidth * kDefaultPropagationDelay; -const QuicByteCount kDefaultPacketSize = 1200; -const QuicPacketCount kDefaultQueueLength = 10; - -class FakeDelegate : public QuartcPacketTransport::Delegate { - public: - explicit FakeDelegate(QuartcPacketTransport* transport) - : transport_(transport) { - transport_->SetDelegate(this); - } - - ~FakeDelegate() { transport_->SetDelegate(nullptr); } - - void OnTransportCanWrite() override { - while (!packets_to_send_.empty()) { - const std::string& packet = packets_to_send_.front(); - if (transport_->Write(packet.data(), packet.size(), - QuartcPacketTransport::PacketInfo()) < - static_cast<int>(packet.size())) { - ++write_blocked_count_; - return; - } - packets_to_send_.pop(); - } - } - - void OnTransportReceived(const char* data, size_t data_len) override { - packets_received_.emplace_back(data, data_len); - } - - void AddPacketToSend(const std::string& packet) { - packets_to_send_.push(packet); - } - - size_t packets_to_send() { return packets_to_send_.size(); } - const std::vector<std::string>& packets_received() { - return packets_received_; - } - int write_blocked_count() { return write_blocked_count_; } - - private: - QuartcPacketTransport* const transport_ = nullptr; - std::queue<std::string> packets_to_send_; - std::vector<std::string> packets_received_; - int write_blocked_count_ = 0; -}; - -class SimulatedPacketTransportTest : public QuicTest { - protected: - SimulatedPacketTransportTest() - : switch_(&simulator_, "Switch", /*port_count=*/8, 2 * kDefaultBdp), - client_(&simulator_, - "sender", - "receiver", - kDefaultQueueLength * kDefaultPacketSize), - server_(&simulator_, - "receiver", - "sender", - kDefaultQueueLength * kDefaultPacketSize), - client_link_(&client_, - switch_.port(1), - kDefaultBandwidth, - kDefaultPropagationDelay), - server_link_(&server_, - switch_.port(2), - kDefaultBandwidth, - kDefaultPropagationDelay), - client_delegate_(&client_), - server_delegate_(&server_) {} - - Simulator simulator_; - Switch switch_; - - SimulatedQuartcPacketTransport client_; - SimulatedQuartcPacketTransport server_; - - SymmetricLink client_link_; - SymmetricLink server_link_; - - FakeDelegate client_delegate_; - FakeDelegate server_delegate_; -}; - -TEST_F(SimulatedPacketTransportTest, OneWayTransmission) { - std::string packet_1(kDefaultPacketSize, 'a'); - std::string packet_2(kDefaultPacketSize, 'b'); - client_delegate_.AddPacketToSend(packet_1); - client_delegate_.AddPacketToSend(packet_2); - - simulator_.RunUntil( - [this] { return client_delegate_.packets_to_send() == 0; }); - simulator_.RunFor(3 * kDefaultPropagationDelay); - - EXPECT_THAT(server_delegate_.packets_received(), - ElementsAre(packet_1, packet_2)); - EXPECT_THAT(client_delegate_.packets_received(), ElementsAre()); -} - -TEST_F(SimulatedPacketTransportTest, TwoWayTransmission) { - std::string packet_1(kDefaultPacketSize, 'a'); - std::string packet_2(kDefaultPacketSize, 'b'); - std::string packet_3(kDefaultPacketSize, 'c'); - std::string packet_4(kDefaultPacketSize, 'd'); - - client_delegate_.AddPacketToSend(packet_1); - client_delegate_.AddPacketToSend(packet_2); - server_delegate_.AddPacketToSend(packet_3); - server_delegate_.AddPacketToSend(packet_4); - - simulator_.RunUntil( - [this] { return client_delegate_.packets_to_send() == 0; }); - simulator_.RunUntil( - [this] { return server_delegate_.packets_to_send() == 0; }); - simulator_.RunFor(3 * kDefaultPropagationDelay); - - EXPECT_THAT(server_delegate_.packets_received(), - ElementsAre(packet_1, packet_2)); - EXPECT_THAT(client_delegate_.packets_received(), - ElementsAre(packet_3, packet_4)); -} - -TEST_F(SimulatedPacketTransportTest, TestWriteBlocked) { - // Add 10 packets beyond what fits in the egress queue. - std::vector<std::string> packets; - for (unsigned int i = 0; i < kDefaultQueueLength + 10; ++i) { - packets.push_back(std::string(kDefaultPacketSize, 'a' + i)); - client_delegate_.AddPacketToSend(packets.back()); - } - - simulator_.RunUntil( - [this] { return client_delegate_.packets_to_send() == 0; }); - simulator_.RunFor(3 * kDefaultPropagationDelay); - - // Each of the 10 packets in excess of the sender's egress queue length will - // block the first time |client_delegate_| tries to write them. - EXPECT_EQ(client_delegate_.write_blocked_count(), 10); - EXPECT_EQ(server_delegate_.packets_received(), packets); -} - -} // namespace -} // namespace simulator -} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_stream.cc b/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_stream.cc index 401ae7e4278..0fb988aed37 100644 --- a/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_stream.cc +++ b/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_stream.cc @@ -23,7 +23,8 @@ QuicTransportStream::QuicTransportStream( /*is_static=*/false, QuicUtils::GetStreamType(id, session->connection()->perspective(), - session->IsIncomingStream(id))), + session->IsIncomingStream(id), + session->version())), session_interface_(session_interface) {} size_t QuicTransportStream::Read(char* buffer, size_t buffer_size) { diff --git a/chromium/net/third_party/quiche/src/quic/quic_transport/web_transport_fingerprint_proof_verifier.cc b/chromium/net/third_party/quiche/src/quic/quic_transport/web_transport_fingerprint_proof_verifier.cc new file mode 100644 index 00000000000..81466de1240 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/quic_transport/web_transport_fingerprint_proof_verifier.cc @@ -0,0 +1,221 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/third_party/quiche/src/quic/quic_transport/web_transport_fingerprint_proof_verifier.h" + +#include <cstdint> +#include <memory> + +#include "third_party/boringssl/src/include/openssl/sha.h" +#include "net/third_party/quiche/src/quic/core/crypto/certificate_view.h" +#include "net/third_party/quiche/src/quic/core/quic_time.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_text_utils.h" + +namespace quic { +namespace { + +constexpr size_t kFingerprintLength = SHA256_DIGEST_LENGTH * 3 - 1; + +constexpr std::array<char, 16> kHexDigits = {'0', '1', '2', '3', '4', '5', + '6', '7', '8', '9', 'a', 'b', + 'c', 'd', 'e', 'f'}; + +// Assumes that the character is normalized to lowercase beforehand. +bool IsNormalizedHexDigit(char c) { + return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f'); +} + +void NormalizeFingerprint(CertificateFingerprint& fingerprint) { + fingerprint.fingerprint = + quiche::QuicheTextUtils::ToLower(fingerprint.fingerprint); +} + +} // namespace + +constexpr char CertificateFingerprint::kSha256[]; + +std::string ComputeSha256Fingerprint(quiche::QuicheStringPiece input) { + std::vector<uint8_t> raw_hash; + raw_hash.resize(SHA256_DIGEST_LENGTH); + SHA256(reinterpret_cast<const uint8_t*>(input.data()), input.size(), + raw_hash.data()); + + std::string output; + output.resize(kFingerprintLength); + for (size_t i = 0; i < output.size(); i++) { + uint8_t hash_byte = raw_hash[i / 3]; + switch (i % 3) { + case 0: + output[i] = kHexDigits[hash_byte >> 4]; + break; + case 1: + output[i] = kHexDigits[hash_byte & 0xf]; + break; + case 2: + output[i] = ':'; + break; + } + } + return output; +} + +ProofVerifyDetails* WebTransportFingerprintProofVerifier::Details::Clone() + const { + return new Details(*this); +} + +WebTransportFingerprintProofVerifier::WebTransportFingerprintProofVerifier( + const QuicClock* clock, + int max_validity_days) + : clock_(clock), + max_validity_days_(max_validity_days), + // Add an extra second to max validity to accomodate various edge cases. + max_validity_( + QuicTime::Delta::FromSeconds(max_validity_days * 86400 + 1)) {} + +bool WebTransportFingerprintProofVerifier::AddFingerprint( + CertificateFingerprint fingerprint) { + NormalizeFingerprint(fingerprint); + if (fingerprint.algorithm != CertificateFingerprint::kSha256) { + QUIC_DLOG(WARNING) << "Algorithms other than SHA-256 are not supported"; + return false; + } + if (fingerprint.fingerprint.size() != kFingerprintLength) { + QUIC_DLOG(WARNING) << "Invalid fingerprint length"; + return false; + } + for (size_t i = 0; i < fingerprint.fingerprint.size(); i++) { + char current = fingerprint.fingerprint[i]; + if (i % 3 == 2) { + if (current != ':') { + QUIC_DLOG(WARNING) + << "Missing colon separator between the bytes of the hash"; + return false; + } + } else { + if (!IsNormalizedHexDigit(current)) { + QUIC_DLOG(WARNING) << "Fingerprint must be in hexadecimal"; + return false; + } + } + } + + fingerprints_.push_back(fingerprint); + return true; +} + +QuicAsyncStatus WebTransportFingerprintProofVerifier::VerifyProof( + const std::string& /*hostname*/, + const uint16_t /*port*/, + const std::string& /*server_config*/, + QuicTransportVersion /*transport_version*/, + quiche::QuicheStringPiece /*chlo_hash*/, + const std::vector<std::string>& /*certs*/, + const std::string& /*cert_sct*/, + const std::string& /*signature*/, + const ProofVerifyContext* /*context*/, + std::string* error_details, + std::unique_ptr<ProofVerifyDetails>* details, + std::unique_ptr<ProofVerifierCallback> /*callback*/) { + *error_details = + "QUIC crypto certificate verification is not supported in " + "WebTransportFingerprintProofVerifier"; + QUIC_BUG << *error_details; + *details = std::make_unique<Details>(Status::kInternalError); + return QUIC_FAILURE; +} + +QuicAsyncStatus WebTransportFingerprintProofVerifier::VerifyCertChain( + const std::string& /*hostname*/, + const uint16_t /*port*/, + const std::vector<std::string>& certs, + const std::string& /*ocsp_response*/, + const std::string& /*cert_sct*/, + const ProofVerifyContext* /*context*/, + std::string* error_details, + std::unique_ptr<ProofVerifyDetails>* details, + std::unique_ptr<ProofVerifierCallback> /*callback*/) { + if (certs.empty()) { + *details = std::make_unique<Details>(Status::kInternalError); + *error_details = "No certificates provided"; + return QUIC_FAILURE; + } + + if (!HasKnownFingerprint(certs[0])) { + *details = std::make_unique<Details>(Status::kUnknownFingerprint); + *error_details = "Certificate does not match any fingerprint"; + return QUIC_FAILURE; + } + + std::unique_ptr<CertificateView> view = + CertificateView::ParseSingleCertificate(certs[0]); + if (view == nullptr) { + *details = std::make_unique<Details>(Status::kCertificateParseFailure); + *error_details = "Failed to parse the certificate"; + return QUIC_FAILURE; + } + + if (!HasValidExpiry(*view)) { + *details = std::make_unique<Details>(Status::kExpiryTooLong); + *error_details = quiche::QuicheStrCat( + "Certificate expiry exceeds the configured limit of ", + max_validity_days_, " days"); + return QUIC_FAILURE; + } + + if (!IsWithinValidityPeriod(*view)) { + *details = std::make_unique<Details>(Status::kExpired); + *error_details = + "Certificate has expired or has validity listed in the future"; + return QUIC_FAILURE; + } + + *details = std::make_unique<Details>(Status::kValidCertificate); + return QUIC_SUCCESS; +} + +std::unique_ptr<ProofVerifyContext> +WebTransportFingerprintProofVerifier::CreateDefaultContext() { + return nullptr; +} + +bool WebTransportFingerprintProofVerifier::HasKnownFingerprint( + quiche::QuicheStringPiece der_certificate) { + // https://wicg.github.io/web-transport/#verify-a-certificate-fingerprint + const std::string fingerprint = ComputeSha256Fingerprint(der_certificate); + for (const CertificateFingerprint& reference : fingerprints_) { + if (reference.algorithm != CertificateFingerprint::kSha256) { + QUIC_BUG << "Unexpected non-SHA-256 hash"; + continue; + } + if (fingerprint == reference.fingerprint) { + return true; + } + } + return false; +} + +bool WebTransportFingerprintProofVerifier::HasValidExpiry( + const CertificateView& certificate) { + if (!certificate.validity_start().IsBefore(certificate.validity_end())) { + return false; + } + + const QuicTime::Delta duration_seconds = + certificate.validity_end() - certificate.validity_start(); + return duration_seconds <= max_validity_; +} + +bool WebTransportFingerprintProofVerifier::IsWithinValidityPeriod( + const CertificateView& certificate) { + QuicWallTime now = clock_->WallNow(); + return now.IsAfter(certificate.validity_start()) && + now.IsBefore(certificate.validity_end()); +} + +} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/quic_transport/web_transport_fingerprint_proof_verifier.h b/chromium/net/third_party/quiche/src/quic/quic_transport/web_transport_fingerprint_proof_verifier.h new file mode 100644 index 00000000000..7e4358de60d --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/quic_transport/web_transport_fingerprint_proof_verifier.h @@ -0,0 +1,119 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_QUIC_TRANSPORT_FINGERPRINT_PROOF_VERIFIER_H_ +#define QUICHE_QUIC_QUIC_TRANSPORT_FINGERPRINT_PROOF_VERIFIER_H_ + +#include <vector> + +#include "net/third_party/quiche/src/quic/core/crypto/certificate_view.h" +#include "net/third_party/quiche/src/quic/core/crypto/proof_verifier.h" +#include "net/third_party/quiche/src/quic/core/quic_clock.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" + +namespace quic { + +// Represents a fingerprint of an X.509 certificate in a format based on +// https://w3c.github.io/webrtc-pc/#dom-rtcdtlsfingerprint. +struct QUIC_EXPORT_PRIVATE CertificateFingerprint { + static constexpr char kSha256[] = "sha-256"; + + // An algorithm described by one of the names in + // https://www.iana.org/assignments/hash-function-text-names/hash-function-text-names.xhtml + std::string algorithm; + // Hex-encoded, colon-separated fingerprint of the certificate. For example, + // "12:3d:5b:71:8c:54:df:85:7e:bd:e3:7c:66:da:f9:db:6a:94:8f:85:cb:6e:44:7f:09:3e:05:f2:dd:d4:f7:86" + std::string fingerprint; +}; + +// Computes a SHA-256 fingerprint of the specified input formatted in the same +// format as CertificateFingerprint::fingerprint would contain. +QUIC_EXPORT_PRIVATE std::string ComputeSha256Fingerprint( + quiche::QuicheStringPiece input); + +// WebTransportFingerprintProofVerifier verifies the server leaf certificate +// against a supplied list of certificate fingerprints following the procedure +// described in the WebTransport specification. The certificate is deemed +// trusted if it matches a fingerprint in the list, has expiry dates that are +// not too long and has not expired. Only the leaf is checked, the rest of the +// chain is ignored. Reference specification: +// https://wicg.github.io/web-transport/#dom-quictransportconfiguration-server_certificate_fingerprints +class QUIC_EXPORT_PRIVATE WebTransportFingerprintProofVerifier + : public ProofVerifier { + public: + // Note: the entries in this list may be logged into a UMA histogram, and thus + // should not be renumbered. + enum class Status { + kValidCertificate = 0, + kUnknownFingerprint = 1, + kCertificateParseFailure = 2, + kExpiryTooLong = 3, + kExpired = 4, + kInternalError = 5, + + kMaxValue = kInternalError, + }; + + class QUIC_EXPORT_PRIVATE Details : public ProofVerifyDetails { + public: + explicit Details(Status status) : status_(status) {} + Status status() const { return status_; } + + ProofVerifyDetails* Clone() const override; + + private: + const Status status_; + }; + + // |clock| is used to check if the certificate has expired. It is not owned + // and must outlive the object. |max_validity_days| is the maximum time for + // which the certificate is allowed to be valid. + WebTransportFingerprintProofVerifier(const QuicClock* clock, + int max_validity_days); + + // Adds a certificate fingerprint to be trusted. The fingerprints are + // case-insensitive and are validated internally; the function returns true if + // the validation passes. + bool AddFingerprint(CertificateFingerprint fingerprint); + + // ProofVerifier implementation. + QuicAsyncStatus VerifyProof( + const std::string& hostname, + const uint16_t port, + const std::string& server_config, + QuicTransportVersion transport_version, + quiche::QuicheStringPiece chlo_hash, + const std::vector<std::string>& certs, + const std::string& cert_sct, + const std::string& signature, + const ProofVerifyContext* context, + std::string* error_details, + std::unique_ptr<ProofVerifyDetails>* details, + std::unique_ptr<ProofVerifierCallback> callback) override; + QuicAsyncStatus VerifyCertChain( + const std::string& hostname, + const uint16_t port, + const std::vector<std::string>& certs, + const std::string& ocsp_response, + const std::string& cert_sct, + const ProofVerifyContext* context, + std::string* error_details, + std::unique_ptr<ProofVerifyDetails>* details, + std::unique_ptr<ProofVerifierCallback> callback) override; + std::unique_ptr<ProofVerifyContext> CreateDefaultContext() override; + + private: + bool HasKnownFingerprint(quiche::QuicheStringPiece der_certificate); + bool HasValidExpiry(const CertificateView& certificate); + bool IsWithinValidityPeriod(const CertificateView& certificate); + + const QuicClock* clock_; // Unowned. + const int max_validity_days_; + const QuicTime::Delta max_validity_; + std::vector<CertificateFingerprint> fingerprints_; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_QUIC_TRANSPORT_FINGERPRINT_PROOF_VERIFIER_H_ diff --git a/chromium/net/third_party/quiche/src/quic/quic_transport/web_transport_fingerprint_proof_verifier_test.cc b/chromium/net/third_party/quiche/src/quic/quic_transport/web_transport_fingerprint_proof_verifier_test.cc new file mode 100644 index 00000000000..f9f27e5db69 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/quic_transport/web_transport_fingerprint_proof_verifier_test.cc @@ -0,0 +1,183 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/third_party/quiche/src/quic/quic_transport/web_transport_fingerprint_proof_verifier.h" + +#include <memory> + +#include "net/third_party/quiche/src/quic/core/quic_types.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/test_tools/mock_clock.h" +#include "net/third_party/quiche/src/quic/test_tools/test_certificates.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" + +namespace quic { +namespace test { +namespace { + +using ::testing::HasSubstr; + +// 2020-02-01 12:35:56 UTC +constexpr QuicTime::Delta kValidTime = QuicTime::Delta::FromSeconds(1580560556); + +struct VerifyResult { + QuicAsyncStatus status; + WebTransportFingerprintProofVerifier::Status detailed_status; + std::string error; +}; + +class WebTransportFingerprintProofVerifierTest : public QuicTest { + public: + WebTransportFingerprintProofVerifierTest() { + clock_.AdvanceTime(kValidTime); + verifier_ = std::make_unique<WebTransportFingerprintProofVerifier>( + &clock_, /*max_validity_days=*/365); + AddTestCertificate(); + } + + protected: + VerifyResult Verify(quiche::QuicheStringPiece certificate) { + VerifyResult result; + std::unique_ptr<ProofVerifyDetails> details; + result.status = verifier_->VerifyCertChain( + /*hostname=*/"", /*port=*/0, + std::vector<std::string>{std::string(certificate)}, + /*ocsp_response=*/"", + /*cert_sct=*/"", + /*context=*/nullptr, &result.error, &details, + /*callback=*/nullptr); + result.detailed_status = + static_cast<WebTransportFingerprintProofVerifier::Details*>( + details.get()) + ->status(); + return result; + } + + void AddTestCertificate() { + EXPECT_TRUE(verifier_->AddFingerprint( + CertificateFingerprint{CertificateFingerprint::kSha256, + ComputeSha256Fingerprint(kTestCertificate)})); + } + + MockClock clock_; + std::unique_ptr<WebTransportFingerprintProofVerifier> verifier_; +}; + +TEST_F(WebTransportFingerprintProofVerifierTest, Sha256Fingerprint) { + // Computed using `openssl x509 -fingerprint -sha256`. + EXPECT_EQ(ComputeSha256Fingerprint(kTestCertificate), + "f2:e5:46:5e:2b:f7:ec:d6:f6:30:66:a5:a3:75:11:73:4a:a0:eb:7c:47:01:" + "0e:86:d6:75:8e:d4:f4:fa:1b:0f"); +} + +TEST_F(WebTransportFingerprintProofVerifierTest, SimpleFingerprint) { + VerifyResult result = Verify(kTestCertificate); + EXPECT_EQ(result.status, QUIC_SUCCESS); + EXPECT_EQ(result.detailed_status, + WebTransportFingerprintProofVerifier::Status::kValidCertificate); + + result = Verify(kWildcardCertificate); + EXPECT_EQ(result.status, QUIC_FAILURE); + EXPECT_EQ(result.detailed_status, + WebTransportFingerprintProofVerifier::Status::kUnknownFingerprint); + + result = Verify("Some random text"); + EXPECT_EQ(result.status, QUIC_FAILURE); +} + +TEST_F(WebTransportFingerprintProofVerifierTest, Validity) { + // Validity periods of kTestCertificate, according to `openssl x509 -text`: + // Not Before: Jan 30 18:13:59 2020 GMT + // Not After : Feb 2 18:13:59 2020 GMT + + // 2020-01-29 19:00:00 UTC + constexpr QuicTime::Delta kStartTime = + QuicTime::Delta::FromSeconds(1580324400); + clock_.Reset(); + clock_.AdvanceTime(kStartTime); + + VerifyResult result = Verify(kTestCertificate); + EXPECT_EQ(result.status, QUIC_FAILURE); + EXPECT_EQ(result.detailed_status, + WebTransportFingerprintProofVerifier::Status::kExpired); + + clock_.AdvanceTime(QuicTime::Delta::FromSeconds(86400)); + result = Verify(kTestCertificate); + EXPECT_EQ(result.status, QUIC_SUCCESS); + EXPECT_EQ(result.detailed_status, + WebTransportFingerprintProofVerifier::Status::kValidCertificate); + + clock_.AdvanceTime(QuicTime::Delta::FromSeconds(4 * 86400)); + result = Verify(kTestCertificate); + EXPECT_EQ(result.status, QUIC_FAILURE); + EXPECT_EQ(result.detailed_status, + WebTransportFingerprintProofVerifier::Status::kExpired); +} + +TEST_F(WebTransportFingerprintProofVerifierTest, MaxValidity) { + verifier_ = std::make_unique<WebTransportFingerprintProofVerifier>( + &clock_, /*max_validity_days=*/2); + AddTestCertificate(); + VerifyResult result = Verify(kTestCertificate); + EXPECT_EQ(result.status, QUIC_FAILURE); + EXPECT_EQ(result.detailed_status, + WebTransportFingerprintProofVerifier::Status::kExpiryTooLong); + EXPECT_THAT(result.error, HasSubstr("limit of 2 days")); + + // kTestCertificate is valid for exactly four days. + verifier_ = std::make_unique<WebTransportFingerprintProofVerifier>( + &clock_, /*max_validity_days=*/4); + AddTestCertificate(); + result = Verify(kTestCertificate); + EXPECT_EQ(result.status, QUIC_SUCCESS); + EXPECT_EQ(result.detailed_status, + WebTransportFingerprintProofVerifier::Status::kValidCertificate); +} + +TEST_F(WebTransportFingerprintProofVerifierTest, InvalidCertificate) { + constexpr quiche::QuicheStringPiece kInvalidCertificate = "Hello, world!"; + ASSERT_TRUE(verifier_->AddFingerprint( + {CertificateFingerprint::kSha256, + ComputeSha256Fingerprint(kInvalidCertificate)})); + + VerifyResult result = Verify(kInvalidCertificate); + EXPECT_EQ(result.status, QUIC_FAILURE); + EXPECT_EQ( + result.detailed_status, + WebTransportFingerprintProofVerifier::Status::kCertificateParseFailure); +} + +TEST_F(WebTransportFingerprintProofVerifierTest, AddCertificate) { + // Accept all-uppercase fingerprints. + verifier_ = std::make_unique<WebTransportFingerprintProofVerifier>( + &clock_, /*max_validity_days=*/365); + EXPECT_TRUE(verifier_->AddFingerprint( + {CertificateFingerprint::kSha256, + "F2:E5:46:5E:2B:F7:EC:D6:F6:30:66:A5:A3:75:11:73:4A:A0:EB:" + "7C:47:01:0E:86:D6:75:8E:D4:F4:FA:1B:0F"})); + EXPECT_EQ(Verify(kTestCertificate).detailed_status, + WebTransportFingerprintProofVerifier::Status::kValidCertificate); + + // Reject unknown hash algorithms. + EXPECT_FALSE(verifier_->AddFingerprint( + {"sha-1", + "00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00"})); + // Reject invalid length. + EXPECT_FALSE(verifier_->AddFingerprint( + {CertificateFingerprint::kSha256, "00:00:00:00"})); + // Reject missing colons. + EXPECT_FALSE(verifier_->AddFingerprint( + {CertificateFingerprint::kSha256, + "00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00." + "00.00.00.00.00.00.00.00.00.00.00.00.00"})); + // Reject non-hex symbols. + EXPECT_FALSE(verifier_->AddFingerprint( + {CertificateFingerprint::kSha256, + "zz:zz:zz:zz:zz:zz:zz:zz:zz:zz:zz:zz:zz:zz:zz:zz:zz:zz:zz:" + "zz:zz:zz:zz:zz:zz:zz:zz:zz:zz:zz:zz:zz"})); +} + +} // namespace +} // namespace test +} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/crypto_test_utils.cc b/chromium/net/third_party/quiche/src/quic/test_tools/crypto_test_utils.cc index 486444183c9..eacbca5287c 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/crypto_test_utils.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/crypto_test_utils.cc @@ -242,7 +242,12 @@ int HandshakeWithFakeServer(QuicConfig* server_quic_config, TestQuicSpdyServerSession server_session( server_conn, *server_quic_config, client_conn->supported_versions(), crypto_config, &compressed_certs_cache); + // Call SetServerApplicationStateForResumption so that the fake server + // supports 0-RTT in TLS. server_session.Initialize(); + server_session.GetMutableCryptoStream() + ->SetServerApplicationStateForResumption( + std::make_unique<ApplicationState>()); EXPECT_CALL(*server_session.helper(), CanAcceptClientHello(testing::_, testing::_, testing::_, testing::_, testing::_)) @@ -404,9 +409,6 @@ std::pair<size_t, size_t> AdvanceHandshake(PacketSavingConnection* client_conn, QUIC_LOG(INFO) << "Processing " << server_conn->encrypted_packets_.size() - server_i << " packets server->client"; - if (server_conn->encrypted_packets_.size() - server_i == 2) { - QUIC_LOG(INFO) << "here"; - } MovePackets(server_conn, &server_i, client, client_conn, Perspective::IS_CLIENT); @@ -574,7 +576,7 @@ void CompareCrypters(const QuicEncrypter* encrypter, std::string label) { if (encrypter == nullptr || decrypter == nullptr) { ADD_FAILURE() << "Expected non-null crypters; have " << encrypter << " and " - << decrypter; + << decrypter << " for " << label; return; } quiche::QuicheStringPiece encrypter_key = encrypter->GetKey(); @@ -605,7 +607,8 @@ void CompareClientAndServerKeys(QuicCryptoClientStream* client, const QuicDecrypter* server_decrypter( QuicFramerPeer::GetDecrypter(server_framer, level)); if (level == ENCRYPTION_FORWARD_SECURE || - !((level == ENCRYPTION_HANDSHAKE || client_encrypter == nullptr) && + !((level == ENCRYPTION_HANDSHAKE || level == ENCRYPTION_ZERO_RTT || + client_encrypter == nullptr) && server_decrypter == nullptr)) { CompareCrypters(client_encrypter, server_decrypter, "client " + EncryptionLevelString(level) + " write"); @@ -616,7 +619,8 @@ void CompareClientAndServerKeys(QuicCryptoClientStream* client, QuicFramerPeer::GetDecrypter(client_framer, level)); if (level == ENCRYPTION_FORWARD_SECURE || !(server_encrypter == nullptr && - (level == ENCRYPTION_HANDSHAKE || client_decrypter == nullptr))) { + (level == ENCRYPTION_HANDSHAKE || level == ENCRYPTION_ZERO_RTT || + client_decrypter == nullptr))) { CompareCrypters(server_encrypter, client_decrypter, "server " + EncryptionLevelString(level) + " write"); } @@ -748,10 +752,11 @@ void MovePackets(PacketSavingConnection* source_conn, QuicConnectionPeer::AddBytesReceived( dest_conn, source_conn->encrypted_packets_[index]->length()); if (!framer.ProcessPacket(*source_conn->encrypted_packets_[index])) { - // The framer will be unable to decrypt forward-secure packets sent after - // the handshake is complete. Don't treat them as handshake packets. + // The framer will be unable to decrypt zero-rtt packets sent during + // handshake or forward-secure packets sent after the handshake is + // complete. Don't treat them as handshake packets. QuicConnectionPeer::SwapCrypters(dest_conn, framer.framer()); - break; + continue; } QuicConnectionPeer::SwapCrypters(dest_conn, framer.framer()); dest_conn->OnDecryptedPacket(framer.last_decrypted_level()); diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/first_flight.h b/chromium/net/third_party/quiche/src/quic/test_tools/first_flight.h index b2a4ebd36be..ad5f792e0b9 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/first_flight.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/first_flight.h @@ -49,10 +49,10 @@ class QUIC_NO_EXPORT DelegatedPacketWriter : public QuicPacketWriter { } bool SupportsReleaseTime() const override { return false; } bool IsBatchMode() const override { return false; } - char* GetNextWriteLocation( + QuicPacketBuffer GetNextWriteLocation( const QuicIpAddress& /*self_address*/, const QuicSocketAddress& /*peer_address*/) override { - return nullptr; + return {nullptr, nullptr}; } WriteResult Flush() override { return WriteResult(WRITE_STATUS_OK, 0); } diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/mock_clock.cc b/chromium/net/third_party/quiche/src/quic/test_tools/mock_clock.cc index 1761dd9af32..21c080a3c4c 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/mock_clock.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/mock_clock.cc @@ -14,6 +14,10 @@ void MockClock::AdvanceTime(QuicTime::Delta delta) { now_ = now_ + delta; } +void MockClock::Reset() { + now_ = QuicTime::Zero(); +} + QuicTime MockClock::Now() const { return now_; } diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/mock_clock.h b/chromium/net/third_party/quiche/src/quic/test_tools/mock_clock.h index 4bd51e9d6d6..2ce2e966a9c 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/mock_clock.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/mock_clock.h @@ -24,6 +24,8 @@ class MockClock : public QuicClock { // Advances the current time by |delta|, which may be negative. void AdvanceTime(QuicTime::Delta delta); + // Resets time back to zero. + void Reset(); private: QuicTime now_; diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/packet_dropping_test_writer.h b/chromium/net/third_party/quiche/src/quic/test_tools/packet_dropping_test_writer.h index 75b9a5dcb30..f066e9191e4 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/packet_dropping_test_writer.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/packet_dropping_test_writer.h @@ -54,12 +54,12 @@ class PacketDroppingTestWriter : public QuicPacketWriterWrapper { void SetWritable() override; - char* GetNextWriteLocation( + QuicPacketBuffer GetNextWriteLocation( const QuicIpAddress& /*self_address*/, const QuicSocketAddress& /*peer_address*/) override { // If the wrapped writer supports zero-copy, disable it, because it is not // compatible with delayed writes in this class. - return nullptr; + return {nullptr, nullptr}; } // Writes out any packet which should have been sent by now diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_config_peer.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_config_peer.cc index 3e752154f27..52325d16650 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_config_peer.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_config_peer.cc @@ -94,8 +94,8 @@ void QuicConfigPeer::SetReceivedStatelessResetToken(QuicConfig* config, // static void QuicConfigPeer::SetReceivedMaxPacketSize(QuicConfig* config, - uint32_t max_packet_size) { - config->max_packet_size_.SetReceivedValue(max_packet_size); + uint32_t max_udp_payload_size) { + config->max_udp_payload_size_.SetReceivedValue(max_udp_payload_size); } // static @@ -106,8 +106,23 @@ void QuicConfigPeer::SetNegotiated(QuicConfig* config, bool negotiated) { // static void QuicConfigPeer::SetReceivedOriginalConnectionId( QuicConfig* config, - const QuicConnectionId& original_connection_id) { - config->received_original_connection_id_ = original_connection_id; + const QuicConnectionId& original_destination_connection_id) { + config->received_original_destination_connection_id_ = + original_destination_connection_id; +} + +// static +void QuicConfigPeer::SetReceivedInitialSourceConnectionId( + QuicConfig* config, + const QuicConnectionId& initial_source_connection_id) { + config->received_initial_source_connection_id_ = initial_source_connection_id; +} + +// static +void QuicConfigPeer::SetReceivedRetrySourceConnectionId( + QuicConfig* config, + const QuicConnectionId& retry_source_connection_id) { + config->received_retry_source_connection_id_ = retry_source_connection_id; } // static @@ -117,5 +132,10 @@ void QuicConfigPeer::SetReceivedMaxDatagramFrameSize( config->max_datagram_frame_size_.SetReceivedValue(max_datagram_frame_size); } +// static +void QuicConfigPeer::DisableSupportHandshakeDone(QuicConfig* config) { + config->support_handshake_done_.SetSendValue(0); +} + } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_config_peer.h b/chromium/net/third_party/quiche/src/quic/test_tools/quic_config_peer.h index c435f2282da..109bd6453b3 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_config_peer.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_config_peer.h @@ -58,16 +58,25 @@ class QuicConfigPeer { QuicUint128 token); static void SetReceivedMaxPacketSize(QuicConfig* config, - uint32_t max_packet_size); + uint32_t max_udp_payload_size); static void SetNegotiated(QuicConfig* config, bool negotiated); static void SetReceivedOriginalConnectionId( QuicConfig* config, - const QuicConnectionId& original_connection_id); + const QuicConnectionId& original_destination_connection_id); + + static void SetReceivedInitialSourceConnectionId( + QuicConfig* config, + const QuicConnectionId& initial_source_connection_id); + + static void SetReceivedRetrySourceConnectionId( + QuicConfig* config, + const QuicConnectionId& retry_source_connection_id); static void SetReceivedMaxDatagramFrameSize(QuicConfig* config, uint64_t max_datagram_frame_size); + static void DisableSupportHandshakeDone(QuicConfig* config); }; } // namespace test diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_connection_peer.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_connection_peer.cc index d276f6327ea..54616b2e407 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_connection_peer.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_connection_peer.cc @@ -377,5 +377,10 @@ void QuicConnectionPeer::SetServerConnectionId( connection->InstallInitialCrypters(server_connection_id); } +// static +size_t QuicConnectionPeer::NumUndecryptablePackets(QuicConnection* connection) { + return connection->undecryptable_packets_.size(); +} + } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h b/chromium/net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h index 9882f62ee35..a5b94ef2c53 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h @@ -147,6 +147,8 @@ class QuicConnectionPeer { static void SetServerConnectionId( QuicConnection* connection, const QuicConnectionId& server_connection_id); + + static size_t NumUndecryptablePackets(QuicConnection* connection); }; } // namespace test diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_mock_syscall_wrapper.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_mock_syscall_wrapper.cc new file mode 100644 index 00000000000..3cce97eed80 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_mock_syscall_wrapper.cc @@ -0,0 +1,22 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/third_party/quiche/src/quic/test_tools/quic_mock_syscall_wrapper.h" + +using testing::_; +using testing::Invoke; + +namespace quic { +namespace test { + +MockQuicSyscallWrapper::MockQuicSyscallWrapper(QuicSyscallWrapper* delegate) { + ON_CALL(*this, Sendmsg(_, _, _)) + .WillByDefault(Invoke(delegate, &QuicSyscallWrapper::Sendmsg)); + + ON_CALL(*this, Sendmmsg(_, _, _, _)) + .WillByDefault(Invoke(delegate, &QuicSyscallWrapper::Sendmmsg)); +} + +} // namespace test +} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_mock_syscall_wrapper.h b/chromium/net/third_party/quiche/src/quic/test_tools/quic_mock_syscall_wrapper.h new file mode 100644 index 00000000000..8dac5ad00c9 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_mock_syscall_wrapper.h @@ -0,0 +1,37 @@ +// Copyright (c) 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_PLATFORM_IMPL_QUIC_MOCK_SYSCALL_WRAPPER_H_ +#define QUICHE_QUIC_PLATFORM_IMPL_QUIC_MOCK_SYSCALL_WRAPPER_H_ + +#include "net/third_party/quiche/src/quic/core/quic_syscall_wrapper.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" + +namespace quic { +namespace test { + +class MockQuicSyscallWrapper : public QuicSyscallWrapper { + public: + // Create a standard mock object. + MockQuicSyscallWrapper() = default; + + // Create a 'mockable' object that delegates everything to |delegate| by + // default. + explicit MockQuicSyscallWrapper(QuicSyscallWrapper* delegate); + + MOCK_METHOD(ssize_t, + Sendmsg, + (int sockfd, const msghdr*, int flags), + (override)); + + MOCK_METHOD(int, + Sendmmsg, + (int sockfd, mmsghdr*, unsigned int vlen, int flags), + (override)); +}; + +} // namespace test +} // namespace quic + +#endif // QUICHE_QUIC_PLATFORM_IMPL_QUIC_MOCK_SYSCALL_WRAPPER_H_ diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_packet_creator_peer.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_packet_creator_peer.cc index 44fed8809ec..151575a0db0 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_packet_creator_peer.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_packet_creator_peer.cc @@ -111,7 +111,7 @@ SerializedPacket QuicPacketCreatorPeer::SerializeAllFrames( bool success = creator->AddFrame(frame, NOT_RETRANSMISSION); DCHECK(success); } - creator->SerializePacket(buffer, buffer_len); + creator->SerializePacket(QuicOwnedPacketBuffer(buffer, nullptr), buffer_len); SerializedPacket packet = std::move(creator->packet_); // The caller takes ownership of the QuicEncryptedPacket. creator->packet_.encrypted_buffer = nullptr; diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.cc index ab28828cc14..ea9dc062fd1 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.cc @@ -242,12 +242,17 @@ size_t QuicSessionPeer::GetNumOpenDynamicStreams(QuicSession* session) { } } // Exclude draining streams. - result -= session->GetNumDrainingStreams(); + result -= session->num_draining_streams_; // Add locally closed streams. result += session->locally_closed_streams_highest_offset_.size(); return result; } +// static +size_t QuicSessionPeer::GetNumDrainingStreams(QuicSession* session) { + return session->num_draining_streams_; +} + } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.h b/chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.h index ffb6a46446d..061f16da3a7 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.h @@ -82,6 +82,7 @@ class QuicSessionPeer { static void set_is_configured(QuicSession* session, bool value); static void SetPerspective(QuicSession* session, Perspective perspective); static size_t GetNumOpenDynamicStreams(QuicSession* session); + static size_t GetNumDrainingStreams(QuicSession* session); }; } // namespace test diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_client.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_client.cc index 22e65b822ee..503f58539b2 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_client.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_client.cc @@ -210,6 +210,22 @@ MockableQuicClient::MockableQuicClient( const ParsedQuicVersionVector& supported_versions, QuicEpollServer* epoll_server, std::unique_ptr<ProofVerifier> proof_verifier) + : MockableQuicClient(server_address, + server_id, + config, + supported_versions, + epoll_server, + std::move(proof_verifier), + nullptr) {} + +MockableQuicClient::MockableQuicClient( + QuicSocketAddress server_address, + const QuicServerId& server_id, + const QuicConfig& config, + const ParsedQuicVersionVector& supported_versions, + QuicEpollServer* epoll_server, + std::unique_ptr<ProofVerifier> proof_verifier, + std::unique_ptr<SessionCache> session_cache) : QuicClient( server_address, server_id, @@ -218,8 +234,8 @@ MockableQuicClient::MockableQuicClient( epoll_server, std::make_unique<MockableQuicClientEpollNetworkHelper>(epoll_server, this), - QuicWrapUnique( - new RecordingProofVerifier(std::move(proof_verifier)))), + QuicWrapUnique(new RecordingProofVerifier(std::move(proof_verifier))), + std::move(session_cache)), override_server_connection_id_(EmptyQuicConnectionId()), server_connection_id_overridden_(false), override_client_connection_id_(EmptyQuicConnectionId()), @@ -342,6 +358,24 @@ QuicTestClient::QuicTestClient( Initialize(); } +QuicTestClient::QuicTestClient( + QuicSocketAddress server_address, + const std::string& server_hostname, + const QuicConfig& config, + const ParsedQuicVersionVector& supported_versions, + std::unique_ptr<ProofVerifier> proof_verifier, + std::unique_ptr<SessionCache> session_cache) + : client_(new MockableQuicClient( + server_address, + QuicServerId(server_hostname, server_address.port(), false), + config, + supported_versions, + &epoll_server_, + std::move(proof_verifier), + std::move(session_cache))) { + Initialize(); +} + QuicTestClient::QuicTestClient() = default; QuicTestClient::~QuicTestClient() { @@ -390,13 +424,8 @@ ssize_t QuicTestClient::SendRequestAndRstTogether(const std::string& uri) { QuicStreamId stream_id = GetNthClientInitiatedBidirectionalStreamId( session->transport_version(), 0); QuicStream* stream = session->GetOrCreateStream(stream_id); - if (session->break_close_loop()) { - session->ResetStream(stream_id, QUIC_STREAM_CANCELLED, - stream->stream_bytes_written()); - } else { - session->SendRstStream(stream_id, QUIC_STREAM_CANCELLED, - stream->stream_bytes_written()); - } + session->ResetStream(stream_id, QUIC_STREAM_CANCELLED, + stream->stream_bytes_written()); return ret; } @@ -962,7 +991,7 @@ void QuicTestClient::WaitForDelayedAcks() { const QuicClock* clock = client()->client_session()->connection()->clock(); QuicTime wait_until = clock->ApproximateNow() + kWaitDuration; - while (clock->ApproximateNow() < wait_until) { + while (connected() && clock->ApproximateNow() < wait_until) { // This waits for up to 50 ms. client()->WaitForEvents(); } diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_client.h b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_client.h index f74974f4231..41e30b13dbb 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_client.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_client.h @@ -49,6 +49,14 @@ class MockableQuicClient : public QuicClient { const ParsedQuicVersionVector& supported_versions, QuicEpollServer* epoll_server, std::unique_ptr<ProofVerifier> proof_verifier); + + MockableQuicClient(QuicSocketAddress server_address, + const QuicServerId& server_id, + const QuicConfig& config, + const ParsedQuicVersionVector& supported_versions, + QuicEpollServer* epoll_server, + std::unique_ptr<ProofVerifier> proof_verifier, + std::unique_ptr<SessionCache> session_cache); MockableQuicClient(const MockableQuicClient&) = delete; MockableQuicClient& operator=(const MockableQuicClient&) = delete; @@ -100,6 +108,12 @@ class QuicTestClient : public QuicSpdyStream::Visitor, const QuicConfig& config, const ParsedQuicVersionVector& supported_versions, std::unique_ptr<ProofVerifier> proof_verifier); + QuicTestClient(QuicSocketAddress server_address, + const std::string& server_hostname, + const QuicConfig& config, + const ParsedQuicVersionVector& supported_versions, + std::unique_ptr<ProofVerifier> proof_verifier, + std::unique_ptr<SessionCache> session_cache); ~QuicTestClient() override; @@ -188,9 +202,10 @@ class QuicTestClient : public QuicSpdyStream::Visitor, void WaitForInitialResponse() { WaitForInitialResponseForMs(-1); } // Returns once at least one complete response or a connection close has been - // received from the server, or once the timeout expires. -1 means no timeout. - // If responses are received for multiple (say 2) streams, next - // WaitForResponseForMs will return immediately. + // received from the server, or once the timeout expires. + // Passing in a timeout value of -1 disables the timeout. If multiple + // responses are received while the client is waiting, subsequent calls to + // this function will return immediately. void WaitForResponseForMs(int timeout_ms) { WaitUntil(timeout_ms, [this]() { return !closed_stream_states_.empty(); }); if (response_complete()) { diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.cc index 7d88ccdaae7..41fb995e5e3 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.cc @@ -419,6 +419,11 @@ bool NoOpFramerVisitor::OnHandshakeDoneFrame( return true; } +bool NoOpFramerVisitor::OnAckFrequencyFrame( + const QuicAckFrequencyFrame& /*frame*/) { + return true; +} + bool NoOpFramerVisitor::IsValidStatelessResetToken( QuicUint128 /*token*/) const { return false; @@ -566,6 +571,7 @@ void PacketSavingConnection::SendOrQueuePacket(SerializedPacket packet) { clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10)); // Transfer ownership of the packet to the SentPacketManager and the // ack notifier to the AckNotifierManager. + OnPacketSent(packet.encryption_level, packet.transmission_type); QuicConnectionPeer::GetSentPacketManager(this)->OnPacketSent( &packet, clock_.ApproximateNow(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA); @@ -755,8 +761,8 @@ TestQuicSpdyClientSession::TestQuicSpdyClientSession( &push_promise_index_, config, supported_versions) { - // TODO(b/153726130): Consider adding OnApplicationState calls in tests and - // set |has_application_state| to true. + // TODO(b/153726130): Consider adding SetServerApplicationStateForResumption + // calls in tests and set |has_application_state| to true. crypto_stream_ = std::make_unique<QuicCryptoClientStream>( server_id, this, crypto_test_utils::ProofVerifyContextForTesting(), crypto_config, this, /*has_application_state = */ false); @@ -799,7 +805,7 @@ MockPacketWriter::MockPacketWriter() { .WillByDefault(testing::Return(kMaxOutgoingPacketSize)); ON_CALL(*this, IsBatchMode()).WillByDefault(testing::Return(false)); ON_CALL(*this, GetNextWriteLocation(_, _)) - .WillByDefault(testing::Return(nullptr)); + .WillByDefault(testing::Return(QuicPacketBuffer())); ON_CALL(*this, Flush()) .WillByDefault(testing::Return(WriteResult(WRITE_STATUS_OK, 0))); ON_CALL(*this, SupportsReleaseTime()).WillByDefault(testing::Return(false)); @@ -841,9 +847,9 @@ ParsedQuicVersion QuicVersionMin() { } void DisableQuicVersionsWithTls() { - SetQuicReloadableFlag(quic_enable_version_draft_27, false); - SetQuicReloadableFlag(quic_enable_version_draft_25_v3, false); - SetQuicReloadableFlag(quic_enable_version_t050_v2, false); + for (const ParsedQuicVersion& version : AllSupportedVersionsWithTls()) { + QuicDisableVersion(version); + } } QuicEncryptedPacket* ConstructEncryptedPacket( @@ -1255,12 +1261,12 @@ QuicStreamId GetNthClientInitiatedUnidirectionalStreamId( } StreamType DetermineStreamType(QuicStreamId id, - QuicTransportVersion version, + ParsedQuicVersion version, Perspective perspective, bool is_incoming, StreamType default_type) { - return VersionHasIetfQuicFrames(version) - ? QuicUtils::GetStreamType(id, perspective, is_incoming) + return version.HasIetfQuicFrames() + ? QuicUtils::GetStreamType(id, perspective, is_incoming, version) : default_type; } diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.h b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.h index 7d1d9db4459..2af8aeb3224 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.h @@ -15,6 +15,7 @@ #include "net/third_party/quiche/src/quic/core/congestion_control/loss_detection_interface.h" #include "net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_interface.h" +#include "net/third_party/quiche/src/quic/core/crypto/transport_parameters.h" #include "net/third_party/quiche/src/quic/core/http/quic_client_push_promise_index.h" #include "net/third_party/quiche/src/quic/core/http/quic_server_session_base.h" #include "net/third_party/quiche/src/quic/core/http/quic_spdy_session.h" @@ -395,6 +396,10 @@ class MockFramerVisitor : public QuicFramerVisitorInterface { OnHandshakeDoneFrame, (const QuicHandshakeDoneFrame& frame), (override)); + MOCK_METHOD(bool, + OnAckFrequencyFrame, + (const QuicAckFrequencyFrame& frame), + (override)); MOCK_METHOD(void, OnPacketComplete, (), (override)); MOCK_METHOD(bool, IsValidStatelessResetToken, @@ -459,6 +464,7 @@ class NoOpFramerVisitor : public QuicFramerVisitorInterface { bool OnBlockedFrame(const QuicBlockedFrame& frame) override; bool OnMessageFrame(const QuicMessageFrame& frame) override; bool OnHandshakeDoneFrame(const QuicHandshakeDoneFrame& frame) override; + bool OnAckFrequencyFrame(const QuicAckFrequencyFrame& frame) override; void OnPacketComplete() override {} bool IsValidStatelessResetToken(QuicUint128 token) const override; void OnAuthenticatedIetfStatelessResetPacket( @@ -498,14 +504,18 @@ class MockQuicConnectionVisitor : public QuicConnectionVisitorInterface { MOCK_METHOD(void, OnWriteBlocked, (), (override)); MOCK_METHOD(void, OnCanWrite, (), (override)); MOCK_METHOD(bool, SendProbingData, (), (override)); + MOCK_METHOD(bool, + ValidateStatelessReset, + (const quic::QuicSocketAddress&, const quic::QuicSocketAddress&), + (override)); MOCK_METHOD(void, OnCongestionWindowChange, (QuicTime now), (override)); MOCK_METHOD(void, OnConnectionMigration, (AddressChangeType type), (override)); MOCK_METHOD(void, OnPathDegrading, (), (override)); + MOCK_METHOD(void, OnForwardProgressMadeAfterPathDegrading, (), (override)); MOCK_METHOD(bool, WillingAndAbleToWrite, (), (const, override)); - MOCK_METHOD(bool, HasPendingHandshake, (), (const, override)); MOCK_METHOD(bool, ShouldKeepConnectionAlive, (), (const, override)); MOCK_METHOD(void, OnSuccessfulVersionNegotiation, @@ -521,7 +531,6 @@ class MockQuicConnectionVisitor : public QuicConnectionVisitorInterface { MOCK_METHOD(void, SendPing, (), (override)); MOCK_METHOD(bool, AllowSelfAddressChange, (), (const, override)); MOCK_METHOD(HandshakeState, GetHandshakeState, (), (const, override)); - MOCK_METHOD(void, OnForwardProgressConfirmed, (), (override)); MOCK_METHOD(bool, OnMaxStreamsFrame, (const QuicMaxStreamsFrame& frame), @@ -672,6 +681,8 @@ class MockQuicConnection : public QuicConnection { QuicConnection::OnError(framer); } + void ReallyOnCanWrite() { QuicConnection::OnCanWrite(); } + void ReallyCloseConnection( QuicErrorCode error, const std::string& details, @@ -738,6 +749,8 @@ class PacketSavingConnection : public MockQuicConnection { void SendOrQueuePacket(SerializedPacket packet) override; + MOCK_METHOD(void, OnPacketSent, (EncryptionLevel, TransmissionType)); + std::vector<std::unique_ptr<QuicEncryptedPacket>> encrypted_packets_; MockClock clock_; }; @@ -797,7 +810,6 @@ class MockQuicSession : public QuicSession { MOCK_METHOD(void, OnAlpnSelected, (quiche::QuicheStringPiece), (override)); using QuicSession::ActivateStream; - using QuicSession::GetNumDrainingStreams; // Returns a QuicConsumedData that indicates all of |write_length| (and |fin| // if set) has been consumed. @@ -834,6 +846,8 @@ class MockQuicCryptoStream : public QuicCryptoStream { void OnHandshakePacketSent() override {} void OnHandshakeDoneReceived() override {} HandshakeState GetHandshakeState() const override { return HANDSHAKE_START; } + void SetServerApplicationStateForResumption( + std::unique_ptr<ApplicationState> /*application_state*/) override {} private: QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params_; @@ -1182,7 +1196,7 @@ class MockPacketWriter : public QuicPacketWriter { (const, override)); MOCK_METHOD(bool, SupportsReleaseTime, (), (const, override)); MOCK_METHOD(bool, IsBatchMode, (), (const, override)); - MOCK_METHOD(char*, + MOCK_METHOD(QuicPacketBuffer, GetNextWriteLocation, (const QuicIpAddress& self_address, const QuicSocketAddress& peer_address), @@ -1285,6 +1299,7 @@ class MockLossAlgorithm : public LossDetectionInterface { MOCK_METHOD(void, OnConfigNegotiated, (), (override)); MOCK_METHOD(void, OnMinRttAvailable, (), (override)); + MOCK_METHOD(void, OnUserAgentIdKnown, (), (override)); MOCK_METHOD(void, OnConnectionClosed, (), (override)); }; @@ -1415,6 +1430,16 @@ class MockQuicConnectionDebugVisitor : public QuicConnectionDebugVisitor { OnVersionNegotiationPacket, (const QuicVersionNegotiationPacket&), (override)); + + MOCK_METHOD(void, + OnTransportParametersSent, + (const TransportParameters&), + (override)); + + MOCK_METHOD(void, + OnTransportParametersReceived, + (const TransportParameters&), + (override)); }; class MockReceivedPacketManager : public QuicReceivedPacketManager { @@ -1443,7 +1468,7 @@ class MockPacketCreatorDelegate : public QuicPacketCreator::DelegateInterface { delete; ~MockPacketCreatorDelegate() override; - MOCK_METHOD(char*, GetPacketBuffer, (), (override)); + MOCK_METHOD(QuicPacketBuffer, GetPacketBuffer, (), (override)); MOCK_METHOD(void, OnSerializedPacket, (SerializedPacket), (override)); MOCK_METHOD(void, OnUnrecoverableError, @@ -1600,7 +1625,7 @@ QuicStreamId GetNthClientInitiatedUnidirectionalStreamId( int n); StreamType DetermineStreamType(QuicStreamId id, - QuicTransportVersion version, + ParsedQuicVersion version, Perspective perspective, bool is_incoming, StreamType default_type); diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simple_quic_framer.cc b/chromium/net/third_party/quiche/src/quic/test_tools/simple_quic_framer.cc index 3d2652fa7ed..8ec56dc9ed8 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/simple_quic_framer.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/simple_quic_framer.cc @@ -204,6 +204,11 @@ class SimpleFramerVisitor : public QuicFramerVisitorInterface { return true; } + bool OnAckFrequencyFrame(const QuicAckFrequencyFrame& frame) override { + ack_frequency_frames_.push_back(frame); + return true; + } + void OnPacketComplete() override {} bool IsValidStatelessResetToken(QuicUint128 /*token*/) const override { @@ -295,6 +300,7 @@ class SimpleFramerVisitor : public QuicFramerVisitorInterface { std::vector<QuicNewTokenFrame> new_token_frames_; std::vector<QuicMessageFrame> message_frames_; std::vector<QuicHandshakeDoneFrame> handshake_done_frames_; + std::vector<QuicAckFrequencyFrame> ack_frequency_frames_; std::vector<std::unique_ptr<std::string>> stream_data_; std::vector<std::unique_ptr<std::string>> crypto_data_; EncryptionLevel last_decrypted_level_; diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_cache.cc b/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_cache.cc index 6a0cafb4177..94b8764a7bf 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_cache.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_cache.cc @@ -34,6 +34,12 @@ std::unique_ptr<QuicResumptionState> SimpleSessionCache::Lookup( if (it == cache_entries_.end()) { return nullptr; } + + if (!it->second.session) { + cache_entries_.erase(it); + return nullptr; + } + auto state = std::make_unique<QuicResumptionState>(); state->tls_session = std::move(it->second.session); state->application_state = it->second.application_state.get(); @@ -41,5 +47,10 @@ std::unique_ptr<QuicResumptionState> SimpleSessionCache::Lookup( return state; } +void SimpleSessionCache::ClearEarlyData(const QuicServerId& /*server_id*/) { + // The simple session cache only stores 1 SSL ticket per entry, so no need to + // do anything here. +} + } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_cache.h b/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_cache.h index cfe3f4a5454..6043a439e4d 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_cache.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_cache.h @@ -28,6 +28,7 @@ class SimpleSessionCache : public SessionCache { const ApplicationState* application_state) override; std::unique_ptr<QuicResumptionState> Lookup(const QuicServerId& server_id, const SSL_CTX* ctx) override; + void ClearEarlyData(const QuicServerId& server_id) override; private: struct Entry { diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_notifier.h b/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_notifier.h index 1237f424499..65afacebf3c 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_notifier.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_notifier.h @@ -78,6 +78,7 @@ class SimpleSessionNotifier : public SessionNotifierInterface { bool IsFrameOutstanding(const QuicFrame& frame) const override; bool HasUnackedCryptoData() const override; bool HasUnackedStreamData() const override; + bool HasLostStreamData() const; private: struct StreamState { @@ -124,8 +125,6 @@ class SimpleSessionNotifier : public SessionNotifierInterface { bool HasBufferedControlFrames() const; - bool HasLostStreamData() const; - bool StreamHasBufferedData(QuicStreamId id) const; QuicCircularDeque<QuicFrame> control_frames_; diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/queue.cc b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/queue.cc index 3816fd4b0c0..52f7fe683b7 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/queue.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/queue.cc @@ -20,6 +20,7 @@ Queue::Queue(Simulator* simulator, std::string name, QuicByteCount capacity) aggregation_timeout_(QuicTime::Delta::Infinite()), current_bundle_(0), current_bundle_bytes_(0), + tx_port_(nullptr), listener_(nullptr) { aggregation_timeout_alarm_.reset(simulator_->GetAlarmFactory()->CreateAlarm( new AggregationAlarmDelegate(this))); @@ -116,7 +117,12 @@ void Queue::ScheduleNextPacketDequeue() { return; } - Schedule(clock_->Now() + tx_port_->TimeUntilAvailable()); + QuicTime::Delta time_until_available = QuicTime::Delta::Zero(); + if (tx_port_) { + time_until_available = tx_port_->TimeUntilAvailable(); + } + + Schedule(clock_->Now() + time_until_available); } } // namespace simulator diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint.cc b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint.cc index c908f982abd..aba7b46a649 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint.cc @@ -11,6 +11,7 @@ #include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h" #include "net/third_party/quiche/src/quic/core/quic_data_writer.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test_output.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_config_peer.h" #include "net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h" #include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" #include "net/third_party/quiche/src/quic/test_tools/simulator/simulator.h" @@ -55,6 +56,7 @@ QuicEndpoint::QuicEndpoint(Simulator* simulator, // Skip version negotiation. test::QuicConnectionPeer::SetNegotiatedVersion(connection_.get()); } + test::QuicConnectionPeer::SetAddressValidated(connection_.get()); connection_->SetDataProducer(&producer_); connection_->SetSessionNotifier(this); notifier_ = std::make_unique<test::SimpleSessionNotifier>(connection_.get()); @@ -74,6 +76,17 @@ QuicEndpoint::QuicEndpoint(Simulator* simulator, peer_hello, perspective == Perspective::IS_CLIENT ? SERVER : CLIENT, &error); DCHECK_EQ(error_code, QUIC_NO_ERROR) << "Configuration failed: " << error; + if (connection_->version().AuthenticatesHandshakeConnectionIds()) { + if (connection_->perspective() == Perspective::IS_CLIENT) { + test::QuicConfigPeer::SetReceivedOriginalConnectionId( + &config, connection_->connection_id()); + test::QuicConfigPeer::SetReceivedInitialSourceConnectionId( + &config, connection_->connection_id()); + } else { + test::QuicConfigPeer::SetReceivedInitialSourceConnectionId( + &config, connection_->client_connection_id()); + } + } connection_->SetFromConfig(config); } @@ -153,9 +166,6 @@ bool QuicEndpoint::WillingAndAbleToWrite() const { } return bytes_to_transfer_ != 0; } -bool QuicEndpoint::HasPendingHandshake() const { - return false; -} bool QuicEndpoint::ShouldKeepConnectionAlive() const { return true; } diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint.h b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint.h index 8b9fd1f480d..cb3c38644f7 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint.h @@ -51,8 +51,12 @@ class QuicEndpoint : public QuicEndpointBase, void OnCryptoFrame(const QuicCryptoFrame& frame) override; void OnCanWrite() override; bool SendProbingData() override; + bool ValidateStatelessReset( + const quic::QuicSocketAddress& /*self_address*/, + const quic::QuicSocketAddress& /*peer_address*/) override { + return true; + } bool WillingAndAbleToWrite() const override; - bool HasPendingHandshake() const override; bool ShouldKeepConnectionAlive() const override; void OnWindowUpdateFrame(const QuicWindowUpdateFrame& /*frame*/) override {} @@ -72,11 +76,11 @@ class QuicEndpoint : public QuicEndpointBase, void OnCongestionWindowChange(QuicTime /*now*/) override {} void OnConnectionMigration(AddressChangeType /*type*/) override {} void OnPathDegrading() override {} + void OnForwardProgressMadeAfterPathDegrading() override {} void OnAckNeedsRetransmittableFrame() override {} void SendPing() override {} bool AllowSelfAddressChange() const override; HandshakeState GetHandshakeState() const override; - void OnForwardProgressConfirmed() override {} bool OnMaxStreamsFrame(const QuicMaxStreamsFrame& /*frame*/) override { return true; } diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint_base.cc b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint_base.cc index 21815d8fe31..c05740d6f00 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint_base.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint_base.cc @@ -178,10 +178,10 @@ bool QuicEndpointBase::Writer::IsBatchMode() const { return false; } -char* QuicEndpointBase::Writer::GetNextWriteLocation( +QuicPacketBuffer QuicEndpointBase::Writer::GetNextWriteLocation( const QuicIpAddress& /*self_address*/, const QuicSocketAddress& /*peer_address*/) { - return nullptr; + return {nullptr, nullptr}; } WriteResult QuicEndpointBase::Writer::Flush() { diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint_base.h b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint_base.h index f4fe33be429..c9be24eb089 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint_base.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint_base.h @@ -87,8 +87,9 @@ class QuicEndpointBase : public Endpoint, const QuicSocketAddress& peer_address) const override; bool SupportsReleaseTime() const override; bool IsBatchMode() const override; - char* GetNextWriteLocation(const QuicIpAddress& self_address, - const QuicSocketAddress& peer_address) override; + QuicPacketBuffer GetNextWriteLocation( + const QuicIpAddress& self_address, + const QuicSocketAddress& peer_address) override; WriteResult Flush() override; private: diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/test_certificates.cc b/chromium/net/third_party/quiche/src/quic/test_tools/test_certificates.cc index 2a733b43ae9..d179d006329 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/test_certificates.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/test_certificates.cc @@ -249,6 +249,34 @@ hTXMooR/wD7an6gtnXD8ixCh7bP0TyPiBhNsUb12WrvSEAm/UyciQbQlR7P+K0Z7 Cmn1Mj4hQ+pT0t+pw/DMOw== -----END CERTIFICATE-----)"; +QUIC_CONST_INIT const char kTestCertWithUnknownSanTypePem[] = + R"(-----BEGIN CERTIFICATE----- +MIIEYTCCA0mgAwIBAgIJAILStmLgUUcVMA0GCSqGSIb3DQEBCwUAMHYxCzAJBgNV +BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNp +c2NvMQ0wCwYDVQQKDARMeWZ0MRkwFwYDVQQLDBBMeWZ0IEVuZ2luZWVyaW5nMRAw +DgYDVQQDDAdUZXN0IENBMB4XDTE4MTIxNzIwMTgwMFoXDTIwMTIxNjIwMTgwMFow +gaYxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1T +YW4gRnJhbmNpc2NvMQ0wCwYDVQQKDARMeWZ0MRkwFwYDVQQLDBBMeWZ0IEVuZ2lu +ZWVyaW5nMRowGAYDVQQDDBFUZXN0IEJhY2tlbmQgVGVhbTEkMCIGCSqGSIb3DQEJ +ARYVYmFja2VuZC10ZWFtQGx5ZnQuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAuvPdQdmwZongPAgQho/Vipd3PZWrQ6BKxIb4l/RvqtVP321IUTLs +4vVwpXoYJ+12L+XOO3jCInszs53tHjFpTI1GE8/sasmgR6LRr2krwSoVRHPqUoc9 +tzkDG1SzKP2TRTi1MTI3FO+TnLFahntO9Zstxhv1Epz5GZ/xQLE0/LLoRYzcynL/ +iflk18iL1KM8i0Hy4cKjclOaUdnh2nh753iJfxCSb5wJfx4FH1qverYHHT6FopYR +V40Cg0yYXcYo8yNwrg+EBY8QAT2JOMDokXNKbZpmVKiBlh0QYMX6BBiW249v3sYl +3Ve+fZvCkle3W0xP0xJw8PdX0NRbvGOrBQIDAQABo4HAMIG9MAwGA1UdEwEB/wQC +MAAwCwYDVR0PBAQDAgXgMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATBB +BgNVHREEOjA4hh5zcGlmZmU6Ly9seWZ0LmNvbS9iYWNrZW5kLXRlYW2CCGx5ZnQu +Y29tggx3d3cubHlmdC5jb20wHQYDVR0OBBYEFLHmMm0DV9jCHJSWVRwyPYpBw62r +MB8GA1UdIwQYMBaAFBQz1vaSbPuePL++7GTMqLAMtk3kMA0GCSqGSIb3DQEBCwUA +A4IBAQAwx3/M2o00W8GlQ3OT4y/hQGb5K2aytxx8QeSmJaaZTJbvaHhe0x3/fLgq +uWrW3WEWFtwasilySjOrFOtB9UNmJmNOHSJD3Bslbv5htRaWnoFPCXdwZtVMdoTq +IHIQqLoos/xj3kVD5sJSYySrveMeKaeUILTkb5ZubSivye1X2yiJLR7AtuwuiMio +CdIOqhn6xJqYhT7z0IhdKpLNPk4w1tBZSKOXqzrXS4uoJgTC67hWslWWZ2VC6IvZ +FmKuuGZamCCj6F1QF2IjMVM8evl84hEnN0ajdkA/QWnil9kcWvBm15Ho+oTvvJ7s +M8MD3RDSq/90FSiME4vbyNEyTmj0 +-----END CERTIFICATE-----)"; + QUIC_CONST_INIT const char kTestCertificatePrivateKeyRaw[] = { '\x30', '\x82', '\x04', '\xbc', '\x02', '\x01', '\x00', '\x30', '\x0d', '\x06', '\x09', '\x2a', '\x86', '\x48', '\x86', '\xf7', '\x0d', '\x01', diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/test_certificates.h b/chromium/net/third_party/quiche/src/quic/test_tools/test_certificates.h index ec4a4d407d5..e7d3035a610 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/test_certificates.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/test_certificates.h @@ -20,6 +20,10 @@ QUIC_CONST_INIT extern const char kTestCertificatePem[]; // |kTestCertificatePem| with a PEM-encoded root appended to the end. QUIC_CONST_INIT extern const char kTestCertificateChainPem[]; +// PEM-encoded certificate that contains a subjectAltName with an +// unknown/unsupported type. +QUIC_CONST_INIT extern const char kTestCertWithUnknownSanTypePem[]; + // DER-encoded private key for |kTestCertificate|. QUIC_CONST_INIT extern const quiche::QuicheStringPiece kTestCertificatePrivateKey; diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_client_base.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_client_base.cc index 11edb195a9d..82b549faeef 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_client_base.cc +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_client_base.cc @@ -235,7 +235,7 @@ void QuicClientBase::WaitForStreamToClose(QuicStreamId id) { } } -bool QuicClientBase::WaitForCryptoHandshakeConfirmed() { +bool QuicClientBase::WaitForOneRttKeysAvailable() { DCHECK(connected()); while (connected() && !session_->OneRttKeysAvailable()) { @@ -247,6 +247,19 @@ bool QuicClientBase::WaitForCryptoHandshakeConfirmed() { return connected(); } +bool QuicClientBase::WaitForHandshakeConfirmed() { + if (!session_->connection()->version().HasHandshakeDone()) { + return WaitForOneRttKeysAvailable(); + } + while (connected() && session_->GetHandshakeState() < HANDSHAKE_CONFIRMED) { + WaitForEvents(); + } + + // If the handshake fails due to a timeout, the connection will be closed. + QUIC_LOG_IF(ERROR, !connected()) << "Handshake with server failed."; + return connected(); +} + bool QuicClientBase::connected() const { return session_.get() && session_->connection() && session_->connection()->connected(); @@ -290,21 +303,7 @@ QuicErrorCode QuicClientBase::connection_error() const { } QuicConnectionId QuicClientBase::GetNextConnectionId() { - QuicConnectionId server_designated_id = GetNextServerDesignatedConnectionId(); - return !server_designated_id.IsEmpty() ? server_designated_id - : GenerateNewConnectionId(); -} - -QuicConnectionId QuicClientBase::GetNextServerDesignatedConnectionId() { - QuicCryptoClientConfig::CachedState* cached = - crypto_config_.LookupOrCreate(server_id_); - // If the cached state indicates that we should use a server-designated - // connection ID, then return that connection ID. - CHECK(cached != nullptr) << "QuicClientCryptoConfig::LookupOrCreate returned " - << "unexpected nullptr."; - return cached->has_server_designated_connection_id() - ? cached->GetNextServerDesignatedConnectionId() - : EmptyQuicConnectionId(); + return GenerateNewConnectionId(); } QuicConnectionId QuicClientBase::GenerateNewConnectionId() { diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_client_base.h b/chromium/net/third_party/quiche/src/quic/tools/quic_client_base.h index 0a40b82d64a..842afc6f14c 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_client_base.h +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_client_base.h @@ -102,9 +102,14 @@ class QuicClientBase { // Wait for events until the stream with the given ID is closed. void WaitForStreamToClose(QuicStreamId id); - // Wait for events until the handshake is confirmed. - // Returns true if the crypto handshake succeeds, false otherwise. - QUIC_MUST_USE_RESULT bool WaitForCryptoHandshakeConfirmed(); + // Wait for 1-RTT keys become available. + // Returns true once 1-RTT keys are available, false otherwise. + QUIC_MUST_USE_RESULT bool WaitForOneRttKeysAvailable(); + + // Wait for handshake state proceeds to HANDSHAKE_CONFIRMED. + // In QUIC crypto, this does the same as WaitForOneRttKeysAvailable, while in + // TLS, this waits for HANDSHAKE_DONE frame is received. + QUIC_MUST_USE_RESULT bool WaitForHandshakeConfirmed(); // Wait up to 50ms, and handle any events which occur. // Returns true if there are any outstanding requests. @@ -271,10 +276,6 @@ class QuicClientBase { // returned. Otherwise, the next random ID will be returned. QuicConnectionId GetNextConnectionId(); - // Returns the next server-designated ConnectionId from the cached config for - // |server_id_|, if it exists. Otherwise, returns 0. - QuicConnectionId GetNextServerDesignatedConnectionId(); - // Generates a new, random connection ID (as opposed to a server-designated // connection ID). virtual QuicConnectionId GenerateNewConnectionId(); diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_client_interop_test_bin.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_client_interop_test_bin.cc index 803e313ea24..e6b9e73d473 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_client_interop_test_bin.cc +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_client_interop_test_bin.cc @@ -41,8 +41,13 @@ enum class Feature { kConnectionClose, // The connection was established using TLS resumption. kResumption, + // 0-RTT data is being sent and acted on. + kZeroRtt, // A RETRY packet was successfully processed. kRetry, + // A handshake using a ClientHello that spans multiple packets completed + // successfully. + kQuantum, // Second row of features (anything else protocol-related) // We switched to a different port and the server migrated to it. @@ -68,8 +73,12 @@ char MatrixLetter(Feature f) { return 'C'; case Feature::kResumption: return 'R'; + case Feature::kZeroRtt: + return 'Z'; case Feature::kRetry: return 'S'; + case Feature::kQuantum: + return 'Q'; case Feature::kRebinding: return 'B'; case Feature::kHttp3: @@ -90,14 +99,23 @@ class QuicClientInteropRunner : QuicConnectionDebugVisitor { // Attempts a resumption using |client| by disconnecting and reconnecting. If // resumption is successful, |features_| is modified to add // Feature::kResumption to it, otherwise it is left unmodified. - void AttemptResumption(QuicClient* client); + void AttemptResumption(QuicClient* client, const std::string& authority); void AttemptRequest(QuicSocketAddress addr, std::string authority, QuicServerId server_id, ParsedQuicVersion version, bool test_version_negotiation, - bool attempt_rebind); + bool attempt_rebind, + bool attempt_multi_packet_chlo); + + // Constructs a SpdyHeaderBlock containing the pseudo-headers needed to make a + // GET request to "/" on the hostname |authority|. + spdy::SpdyHeaderBlock ConstructHeaderBlock(const std::string& authority); + + // Sends an HTTP request represented by |header_block| using |client|. + void SendRequest(QuicClient* client, + const spdy::SpdyHeaderBlock& header_block); void OnConnectionCloseFrame(const QuicConnectionCloseFrame& frame) override { switch (frame.close_type) { @@ -134,20 +152,37 @@ class QuicClientInteropRunner : QuicConnectionDebugVisitor { std::set<Feature> features_; }; -void QuicClientInteropRunner::AttemptResumption(QuicClient* client) { +void QuicClientInteropRunner::AttemptResumption(QuicClient* client, + const std::string& authority) { client->Disconnect(); if (!client->Initialize()) { QUIC_LOG(ERROR) << "Failed to reinitialize client"; return; } - if (!client->Connect() || !client->session()->OneRttKeysAvailable()) { + if (!client->Connect()) { + return; + } + + bool zero_rtt_attempt = !client->session()->OneRttKeysAvailable(); + + spdy::SpdyHeaderBlock header_block = ConstructHeaderBlock(authority); + SendRequest(client, header_block); + + if (!client->session()->OneRttKeysAvailable()) { return; } + if (static_cast<QuicCryptoClientStream*>( test::QuicSessionPeer::GetMutableCryptoStream(client->session())) ->IsResumption()) { InsertFeature(Feature::kResumption); } + if (static_cast<QuicCryptoClientStream*>( + test::QuicSessionPeer::GetMutableCryptoStream(client->session())) + ->EarlyDataAccepted() && + zero_rtt_attempt && client->latest_response_code() != -1) { + InsertFeature(Feature::kZeroRtt); + } } void QuicClientInteropRunner::AttemptRequest(QuicSocketAddress addr, @@ -155,7 +190,8 @@ void QuicClientInteropRunner::AttemptRequest(QuicSocketAddress addr, QuicServerId server_id, ParsedQuicVersion version, bool test_version_negotiation, - bool attempt_rebind) { + bool attempt_rebind, + bool attempt_multi_packet_chlo) { ParsedQuicVersionVector versions = {version}; if (test_version_negotiation) { versions.insert(versions.begin(), QuicVersionReservedForNegotiation()); @@ -168,6 +204,15 @@ void QuicClientInteropRunner::AttemptRequest(QuicSocketAddress addr, QuicConfig config; QuicTime::Delta timeout = QuicTime::Delta::FromSeconds(20); config.SetIdleNetworkTimeout(timeout); + if (attempt_multi_packet_chlo) { + // Make the ClientHello span multiple packets by adding a custom transport + // parameter. + constexpr auto kCustomParameter = + static_cast<TransportParameters::TransportParameterId>(0x173E); + std::string custom_value(2000, '?'); + config.custom_transport_parameters_to_send()[kCustomParameter] = + custom_value; + } auto client = std::make_unique<QuicClient>( addr, server_id, versions, config, &epoll_server, std::move(proof_verifier), std::move(session_cache)); @@ -192,34 +237,28 @@ void QuicClientInteropRunner::AttemptRequest(QuicSocketAddress addr, if (test_version_negotiation && !connect_result) { // Failed to negotiate version, retry without version negotiation. AttemptRequest(addr, authority, server_id, version, - /*test_version_negotiation=*/false, attempt_rebind); + /*test_version_negotiation=*/false, attempt_rebind, + attempt_multi_packet_chlo); return; } if (!client->session()->OneRttKeysAvailable()) { + if (attempt_multi_packet_chlo) { + // Failed to handshake with multi-packet client hello, retry without it. + AttemptRequest(addr, authority, server_id, version, + test_version_negotiation, attempt_rebind, + /*attempt_multi_packet_chlo=*/false); + return; + } return; } InsertFeature(Feature::kHandshake); - - // Construct and send a request. - spdy::SpdyHeaderBlock header_block; - header_block[":method"] = "GET"; - header_block[":scheme"] = "https"; - header_block[":authority"] = authority; - header_block[":path"] = "/"; - client->set_store_response(true); - client->SendRequestAndWaitForResponse(header_block, "", /*fin=*/true); - - client_stats = connection->GetStats(); - QuicSentPacketManager* sent_packet_manager = - test::QuicConnectionPeer::GetSentPacketManager(connection); - const bool received_forward_secure_ack = - sent_packet_manager != nullptr && - sent_packet_manager->GetLargestAckedPacket(ENCRYPTION_FORWARD_SECURE) - .IsInitialized(); - if (client_stats.stream_bytes_received > 0 && received_forward_secure_ack) { - InsertFeature(Feature::kStreamData); + if (attempt_multi_packet_chlo) { + InsertFeature(Feature::kQuantum); } + spdy::SpdyHeaderBlock header_block = ConstructHeaderBlock(authority); + SendRequest(client.get(), header_block); + if (!client->connected()) { return; } @@ -238,7 +277,8 @@ void QuicClientInteropRunner::AttemptRequest(QuicSocketAddress addr, if (!client->connected()) { // Rebinding does not work, retry without attempting it. AttemptRequest(addr, authority, server_id, version, - test_version_negotiation, /*attempt_rebind=*/false); + test_version_negotiation, /*attempt_rebind=*/false, + attempt_multi_packet_chlo); return; } InsertFeature(Feature::kRebinding); @@ -259,7 +299,41 @@ void QuicClientInteropRunner::AttemptRequest(QuicSocketAddress addr, InsertFeature(Feature::kConnectionClose); } - AttemptResumption(client.get()); + AttemptResumption(client.get(), authority); +} + +spdy::SpdyHeaderBlock QuicClientInteropRunner::ConstructHeaderBlock( + const std::string& authority) { + // Construct and send a request. + spdy::SpdyHeaderBlock header_block; + header_block[":method"] = "GET"; + header_block[":scheme"] = "https"; + header_block[":authority"] = authority; + header_block[":path"] = "/"; + return header_block; +} + +void QuicClientInteropRunner::SendRequest( + QuicClient* client, + const spdy::SpdyHeaderBlock& header_block) { + client->set_store_response(true); + client->SendRequestAndWaitForResponse(header_block, "", /*fin=*/true); + + QuicConnection* connection = client->session()->connection(); + if (connection == nullptr) { + QUIC_LOG(ERROR) << "No QuicConnection object"; + return; + } + QuicConnectionStats client_stats = connection->GetStats(); + QuicSentPacketManager* sent_packet_manager = + test::QuicConnectionPeer::GetSentPacketManager(connection); + const bool received_forward_secure_ack = + sent_packet_manager != nullptr && + sent_packet_manager->GetLargestAckedPacket(ENCRYPTION_FORWARD_SECURE) + .IsInitialized(); + if (client_stats.stream_bytes_received > 0 && received_forward_secure_ack) { + InsertFeature(Feature::kStreamData); + } } std::set<Feature> ServerSupport(std::string dns_host, @@ -293,7 +367,8 @@ std::set<Feature> ServerSupport(std::string dns_host, runner.AttemptRequest(addr, authority, server_id, version, /*test_version_negotiation=*/true, - /*attempt_rebind=*/true); + /*attempt_rebind=*/true, + /*attempt_multi_packet_chlo=*/true); return runner.features(); } diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_epoll_client_factory.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_epoll_client_factory.cc index 1751f4173ed..38dc582c1f3 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_epoll_client_factory.cc +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_epoll_client_factory.cc @@ -22,6 +22,7 @@ std::unique_ptr<QuicSpdyClientBase> QuicEpollClientFactory::CreateClient( std::string host_for_lookup, uint16_t port, ParsedQuicVersionVector versions, + const QuicConfig& config, std::unique_ptr<ProofVerifier> verifier) { QuicSocketAddress addr = tools::LookupAddress(host_for_lookup, quiche::QuicheStrCat(port)); @@ -30,8 +31,9 @@ std::unique_ptr<QuicSpdyClientBase> QuicEpollClientFactory::CreateClient( return nullptr; } QuicServerId server_id(host_for_handshake, port, false); - return std::make_unique<QuicClient>(addr, server_id, versions, &epoll_server_, - std::move(verifier)); + return std::make_unique<QuicClient>(addr, server_id, versions, config, + &epoll_server_, std::move(verifier), + nullptr); } } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_epoll_client_factory.h b/chromium/net/third_party/quiche/src/quic/tools/quic_epoll_client_factory.h index 2ee26d9703c..392bd6cc47c 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_epoll_client_factory.h +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_epoll_client_factory.h @@ -18,6 +18,7 @@ class QuicEpollClientFactory : public QuicToyClient::ClientFactory { std::string host_for_lookup, uint16_t port, ParsedQuicVersionVector versions, + const QuicConfig& config, std::unique_ptr<ProofVerifier> verifier) override; private: diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_packet_printer_bin.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_packet_printer_bin.cc index 798b66e418e..3192d303c96 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_packet_printer_bin.cc +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_packet_printer_bin.cc @@ -207,6 +207,10 @@ class QuicPacketPrinter : public QuicFramerVisitorInterface { std::cerr << "OnHandshakeDoneFrame: " << frame; return true; } + bool OnAckFrequencyFrame(const QuicAckFrequencyFrame& frame) override { + std::cerr << "OnAckFrequencyFrame: " << frame; + return true; + } void OnPacketComplete() override { std::cerr << "OnPacketComplete\n"; } bool IsValidStatelessResetToken(QuicUint128 /*token*/) const override { std::cerr << "IsValidStatelessResetToken\n"; diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session.cc index f84a248cda8..387b3135d4d 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session.cc +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session.cc @@ -158,7 +158,7 @@ void QuicSimpleServerSession::HandleRstOnValidNonexistentStream( // index for it in promised_streams_ can be calculated. QuicStreamId next_stream_id = next_outgoing_unidirectional_stream_id(); if (VersionHasIetfQuicFrames(transport_version())) { - DCHECK(!QuicUtils::IsBidirectionalStreamId(frame.stream_id)); + DCHECK(!QuicUtils::IsBidirectionalStreamId(frame.stream_id, version())); } DCHECK_GE(frame.stream_id, next_stream_id); size_t index = (frame.stream_id - next_stream_id) / @@ -243,9 +243,9 @@ void QuicSimpleServerSession::OnCanCreateNewOutgoingStream( } void QuicSimpleServerSession::MaybeInitializeHttp3UnidirectionalStreams() { - size_t previous_static_stream_count = num_outgoing_static_streams(); + size_t previous_static_stream_count = num_static_streams(); QuicSpdySession::MaybeInitializeHttp3UnidirectionalStreams(); - size_t current_static_stream_count = num_outgoing_static_streams(); + size_t current_static_stream_count = num_static_streams(); DCHECK_GE(current_static_stream_count, previous_static_stream_count); highest_promised_stream_id_ += QuicUtils::StreamIdDelta(transport_version()) * diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream_test.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream_test.cc index 3dfaa1e3d22..5c8408428e7 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream_test.cc +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream_test.cc @@ -18,6 +18,7 @@ #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" #include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h" #include "net/third_party/quiche/src/quic/test_tools/quic_config_peer.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h" #include "net/third_party/quiche/src/quic/test_tools/quic_session_peer.h" #include "net/third_party/quiche/src/quic/test_tools/quic_spdy_session_peer.h" #include "net/third_party/quiche/src/quic/test_tools/quic_stream_peer.h" @@ -239,6 +240,9 @@ class QuicSimpleServerStreamTest : public QuicTestWithParam<ParsedQuicVersion> { session_.config()->SetInitialSessionFlowControlWindowToSend( kInitialSessionFlowControlWindowForTest); session_.Initialize(); + if (connection_->version().SupportsAntiAmplificationLimit()) { + QuicConnectionPeer::SetAddressValidated(connection_); + } stream_ = new StrictMock<TestStream>( GetNthClientInitiatedBidirectionalStreamId( connection_->transport_version(), 0), diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_tcp_like_trace_converter.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_tcp_like_trace_converter.cc index 3301ef5d014..1e6cc54043a 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_tcp_like_trace_converter.cc +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_tcp_like_trace_converter.cc @@ -5,6 +5,7 @@ #include "net/third_party/quiche/src/quic/tools/quic_tcp_like_trace_converter.h" #include "net/third_party/quiche/src/quic/core/quic_constants.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" namespace quic { @@ -24,20 +25,40 @@ QuicTcpLikeTraceConverter::StreamOffsetSegment::StreamOffsetSegment( QuicTcpLikeTraceConverter::StreamInfo::StreamInfo() : fin(false) {} +QuicIntervalSet<uint64_t> QuicTcpLikeTraceConverter::OnCryptoFrameSent( + EncryptionLevel level, + QuicStreamOffset offset, + QuicByteCount data_length) { + if (level >= NUM_ENCRYPTION_LEVELS) { + QUIC_BUG << "Invalid encryption level"; + return {}; + } + return OnFrameSent(offset, data_length, /*fin=*/false, + &crypto_frames_info_[level]); +} + QuicIntervalSet<uint64_t> QuicTcpLikeTraceConverter::OnStreamFrameSent( QuicStreamId stream_id, QuicStreamOffset offset, QuicByteCount data_length, bool fin) { + return OnFrameSent( + offset, data_length, fin, + &streams_info_.emplace(stream_id, StreamInfo()).first->second); +} + +QuicIntervalSet<uint64_t> QuicTcpLikeTraceConverter::OnFrameSent( + QuicStreamOffset offset, + QuicByteCount data_length, + bool fin, + StreamInfo* info) { QuicIntervalSet<uint64_t> connection_offsets; if (fin) { // Stream fin consumes a connection offset. ++data_length; } - StreamInfo* stream_info = - &streams_info_.emplace(stream_id, StreamInfo()).first->second; // Get connection offsets of retransmission data in this frame. - for (const auto& segment : stream_info->segments) { + for (const auto& segment : info->segments) { QuicInterval<QuicStreamOffset> retransmission(offset, offset + data_length); retransmission.IntersectWith(segment.stream_data); if (retransmission.Empty()) { @@ -50,15 +71,13 @@ QuicIntervalSet<uint64_t> QuicTcpLikeTraceConverter::OnStreamFrameSent( connection_offset + retransmission.Length()); } - if (stream_info->fin) { + if (info->fin) { return connection_offsets; } // Get connection offsets of new data in this frame. QuicStreamOffset least_unsent_offset = - stream_info->segments.empty() - ? 0 - : stream_info->segments.back().stream_data.max(); + info->segments.empty() ? 0 : info->segments.back().stream_data.max(); if (least_unsent_offset >= offset + data_length) { return connection_offsets; } @@ -68,20 +87,17 @@ QuicIntervalSet<uint64_t> QuicTcpLikeTraceConverter::OnStreamFrameSent( QuicByteCount new_data_length = offset + data_length - new_data_offset; connection_offsets.Add(connection_offset_, connection_offset_ + new_data_length); - if (!stream_info->segments.empty() && - new_data_offset == least_unsent_offset && - connection_offset_ == - stream_info->segments.back().connection_offset + - stream_info->segments.back().stream_data.Length()) { + if (!info->segments.empty() && new_data_offset == least_unsent_offset && + connection_offset_ == info->segments.back().connection_offset + + info->segments.back().stream_data.Length()) { // Extend the last segment if both stream and connection offsets are // contiguous. - stream_info->segments.back().stream_data.SetMax(new_data_offset + - new_data_length); + info->segments.back().stream_data.SetMax(new_data_offset + new_data_length); } else { - stream_info->segments.emplace_back(new_data_offset, connection_offset_, - new_data_length); + info->segments.emplace_back(new_data_offset, connection_offset_, + new_data_length); } - stream_info->fin = fin; + info->fin = fin; connection_offset_ += new_data_length; return connection_offsets; diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_tcp_like_trace_converter.h b/chromium/net/third_party/quiche/src/quic/tools/quic_tcp_like_trace_converter.h index 46dd7954a25..1380296e0ea 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_tcp_like_trace_converter.h +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_tcp_like_trace_converter.h @@ -37,6 +37,12 @@ class QuicTcpLikeTraceConverter { ~QuicTcpLikeTraceConverter() {} + // Called when a crypto frame is sent. Returns the corresponding connection + // offsets. + QuicIntervalSet<uint64_t> OnCryptoFrameSent(EncryptionLevel level, + QuicStreamOffset offset, + QuicByteCount data_length); + // Called when a stream frame is sent. Returns the corresponding connection // offsets. QuicIntervalSet<uint64_t> OnStreamFrameSent(QuicStreamId stream_id, @@ -59,6 +65,14 @@ class QuicTcpLikeTraceConverter { bool fin; }; + // Called when frame with |offset|, |data_length| and |fin| has been sent. + // Update |info| and returns connection offsets. + QuicIntervalSet<uint64_t> OnFrameSent(QuicStreamOffset offset, + QuicByteCount data_length, + bool fin, + StreamInfo* info); + + StreamInfo crypto_frames_info_[NUM_ENCRYPTION_LEVELS]; QuicHashMap<QuicStreamId, StreamInfo> streams_info_; QuicHashMap<QuicControlFrameId, QuicInterval<uint64_t>> control_frames_info_; diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_tcp_like_trace_converter_test.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_tcp_like_trace_converter_test.cc index a6ce81a8dcd..fa751ae885e 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_tcp_like_trace_converter_test.cc +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_tcp_like_trace_converter_test.cc @@ -98,6 +98,27 @@ TEST(QuicTcpLikeTraceConverterTest, FuzzerTest) { EXPECT_EQ(expected, converter.OnStreamFrameSent(1, 50, 600, false)); } +TEST(QuicTcpLikeTraceConverterTest, OnCryptoFrameSent) { + QuicTcpLikeTraceConverter converter; + + EXPECT_EQ(QuicIntervalSet<uint64_t>(0, 100), + converter.OnCryptoFrameSent(ENCRYPTION_INITIAL, 0, 100)); + EXPECT_EQ(QuicIntervalSet<uint64_t>(100, 200), + converter.OnStreamFrameSent(1, 0, 100, false)); + EXPECT_EQ(QuicIntervalSet<uint64_t>(200, 300), + converter.OnStreamFrameSent(1, 100, 100, false)); + EXPECT_EQ(QuicIntervalSet<uint64_t>(300, 400), + converter.OnCryptoFrameSent(ENCRYPTION_HANDSHAKE, 0, 100)); + EXPECT_EQ(QuicIntervalSet<uint64_t>(400, 500), + converter.OnCryptoFrameSent(ENCRYPTION_HANDSHAKE, 100, 100)); + + // Verify crypto frame retransmission works as intended. + EXPECT_EQ(QuicIntervalSet<uint64_t>(0, 100), + converter.OnCryptoFrameSent(ENCRYPTION_INITIAL, 0, 100)); + EXPECT_EQ(QuicIntervalSet<uint64_t>(400, 500), + converter.OnCryptoFrameSent(ENCRYPTION_HANDSHAKE, 100, 100)); +} + } // namespace } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_toy_client.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_toy_client.cc index 0018f0524b7..b42f967caf0 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_toy_client.cc +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_toy_client.cc @@ -109,6 +109,20 @@ DEFINE_QUIC_COMMAND_LINE_FLAG( "versions are offered in the handshake. Also supports wire versions " "such as Q043 or T099."); +DEFINE_QUIC_COMMAND_LINE_FLAG( + std::string, + connection_options, + "", + "Connection options as ASCII tags separated by commas, " + "e.g. \"ABCD,EFGH\""); + +DEFINE_QUIC_COMMAND_LINE_FLAG( + std::string, + client_connection_options, + "", + "Client connection options as ASCII tags separated by commas, " + "e.g. \"ABCD,EFGH\""); + DEFINE_QUIC_COMMAND_LINE_FLAG(bool, quic_ietf_draft, false, @@ -232,9 +246,22 @@ int QuicToyClient::SendRequestsAndPrintResponses( proof_verifier = quic::CreateDefaultProofVerifier(url.host()); } + QuicConfig config; + std::string connection_options_string = GetQuicFlag(FLAGS_connection_options); + if (!connection_options_string.empty()) { + config.SetConnectionOptionsToSend( + ParseQuicTagVector(connection_options_string)); + } + std::string client_connection_options_string = + GetQuicFlag(FLAGS_client_connection_options); + if (!client_connection_options_string.empty()) { + config.SetClientConnectionOptions( + ParseQuicTagVector(client_connection_options_string)); + } + // Build the client, and try to connect. std::unique_ptr<QuicSpdyClientBase> client = client_factory_->CreateClient( - url.host(), host, port, versions, std::move(proof_verifier)); + url.host(), host, port, versions, config, std::move(proof_verifier)); if (client == nullptr) { std::cerr << "Failed to create client." << std::endl; diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_toy_client.h b/chromium/net/third_party/quiche/src/quic/tools/quic_toy_client.h index 1a201225a58..d9d8ecaf87a 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_toy_client.h +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_toy_client.h @@ -26,6 +26,7 @@ class QuicToyClient { std::string host_for_lookup, uint16_t port, ParsedQuicVersionVector versions, + const QuicConfig& config, std::unique_ptr<ProofVerifier> verifier) = 0; }; diff --git a/chromium/net/third_party/quiche/src/spdy/core/fifo_write_scheduler.h b/chromium/net/third_party/quiche/src/spdy/core/fifo_write_scheduler.h index a2c69890459..7b318911007 100644 --- a/chromium/net/third_party/quiche/src/spdy/core/fifo_write_scheduler.h +++ b/chromium/net/third_party/quiche/src/spdy/core/fifo_write_scheduler.h @@ -29,6 +29,8 @@ class FifoWriteScheduler : public WriteScheduler<StreamIdType> { const StreamPrecedenceType& precedence) override; void UnregisterStream(StreamIdType stream_id) override; bool StreamRegistered(StreamIdType stream_id) const override; + // Stream precedence is available but note that it is not used for scheduling + // in this scheduler. StreamPrecedenceType GetStreamPrecedence( StreamIdType stream_id) const override; void UpdateStreamPrecedence(StreamIdType stream_id, @@ -51,20 +53,26 @@ class FifoWriteScheduler : public WriteScheduler<StreamIdType> { std::string DebugString() const override; private: + struct StreamInfo { + SpdyPriority priority; + int64_t event_time; // read/write event time (us since Unix epoch). + }; + std::set<StreamIdType> ready_streams_; - // This map maps stream ID to read/write event time (us since Unix epoch). - std::map<StreamIdType, int64_t> registered_streams_; + std::map<StreamIdType, StreamInfo> registered_streams_; }; template <typename StreamIdType> void FifoWriteScheduler<StreamIdType>::RegisterStream( StreamIdType stream_id, - const StreamPrecedenceType& /*precedence*/) { + const StreamPrecedenceType& precedence) { if (StreamRegistered(stream_id)) { SPDY_BUG << "Stream " << stream_id << " already registered"; return; } - registered_streams_.emplace_hint(registered_streams_.end(), stream_id, 0); + registered_streams_.emplace_hint( + registered_streams_.end(), stream_id, + StreamInfo{/*priority=*/precedence.spdy3_priority(), /*event_time=*/0}); } template <typename StreamIdType> @@ -88,14 +96,26 @@ bool FifoWriteScheduler<StreamIdType>::StreamRegistered( template <typename StreamIdType> typename FifoWriteScheduler<StreamIdType>::StreamPrecedenceType FifoWriteScheduler<StreamIdType>::GetStreamPrecedence( - StreamIdType /*stream_id*/) const { - return StreamPrecedenceType(kV3LowestPriority); + StreamIdType stream_id) const { + auto it = registered_streams_.find(stream_id); + if (it == registered_streams_.end()) { + SPDY_DVLOG(1) << "Stream " << stream_id << " not registered"; + return StreamPrecedenceType(kV3LowestPriority); + } + return StreamPrecedenceType(it->second.priority); } template <typename StreamIdType> void FifoWriteScheduler<StreamIdType>::UpdateStreamPrecedence( - StreamIdType /*stream_id*/, - const StreamPrecedenceType& /*precedence*/) {} + StreamIdType stream_id, + const StreamPrecedenceType& precedence) { + auto it = registered_streams_.find(stream_id); + if (it == registered_streams_.end()) { + SPDY_DVLOG(1) << "Stream " << stream_id << " not registered"; + return; + } + it->second.priority = precedence.spdy3_priority(); +} template <typename StreamIdType> std::vector<StreamIdType> FifoWriteScheduler<StreamIdType>::GetStreamChildren( @@ -109,7 +129,7 @@ void FifoWriteScheduler<StreamIdType>::RecordStreamEventTime( int64_t now_in_usec) { auto it = registered_streams_.find(stream_id); if (it != registered_streams_.end()) { - it->second = now_in_usec; + it->second.event_time = now_in_usec; } else { SPDY_BUG << "Stream " << stream_id << " is not registered"; } @@ -128,7 +148,8 @@ int64_t FifoWriteScheduler<StreamIdType>::GetLatestEventWithPrecedence( if (stream_id <= it->first) { break; } - latest_event_time_us = std::max(latest_event_time_us, it->second); + latest_event_time_us = + std::max(latest_event_time_us, it->second.event_time); } return latest_event_time_us; } diff --git a/chromium/net/third_party/quiche/src/spdy/core/fifo_write_scheduler_test.cc b/chromium/net/third_party/quiche/src/spdy/core/fifo_write_scheduler_test.cc index 950b6414d1d..d1dd066d6e9 100644 --- a/chromium/net/third_party/quiche/src/spdy/core/fifo_write_scheduler_test.cc +++ b/chromium/net/third_party/quiche/src/spdy/core/fifo_write_scheduler_test.cc @@ -80,6 +80,24 @@ TEST(FifoWriteSchedulerTest, GetLatestEventTest) { EXPECT_EQ(0, fifo.GetLatestEventWithPrecedence(1)); } +TEST(FifoWriteSchedulerTest, GetStreamPrecedence) { + FifoWriteScheduler<SpdyStreamId> fifo; + // Return lowest priority for unknown stream. + EXPECT_EQ(kV3LowestPriority, fifo.GetStreamPrecedence(1).spdy3_priority()); + + fifo.RegisterStream(1, SpdyStreamPrecedence(3)); + EXPECT_TRUE(fifo.GetStreamPrecedence(1).is_spdy3_priority()); + EXPECT_EQ(3, fifo.GetStreamPrecedence(1).spdy3_priority()); + + // Redundant registration shouldn't change stream priority. + EXPECT_SPDY_BUG(fifo.RegisterStream(1, SpdyStreamPrecedence(4)), + "Stream 1 already registered"); + EXPECT_EQ(3, fifo.GetStreamPrecedence(1).spdy3_priority()); + + fifo.UpdateStreamPrecedence(1, SpdyStreamPrecedence(5)); + EXPECT_EQ(5, fifo.GetStreamPrecedence(1).spdy3_priority()); +} + } // namespace test } // namespace spdy diff --git a/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_encoder.cc b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_encoder.cc index e3bf8f64c15..71b94a37f3f 100644 --- a/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_encoder.cc +++ b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_encoder.cc @@ -176,16 +176,9 @@ void HpackEncoder::EmitNonIndexedLiteral(const Representation& representation, SPDY_DVLOG(2) << "Emitting nonindexed literal: (" << representation.first << ", " << representation.second << ")"; output_stream_.AppendPrefix(kLiteralNoIndexOpcode); - if (GetSpdyReloadableFlag(spdy_hpack_use_indexed_name)) { - SPDY_CODE_COUNT(spdy_hpack_use_indexed_name); - const HpackEntry* name_entry = - header_table_.GetByName(representation.first); - if (enable_compression && name_entry != nullptr) { - output_stream_.AppendUint32(header_table_.IndexOf(name_entry)); - } else { - output_stream_.AppendUint32(0); - EmitString(representation.first); - } + const HpackEntry* name_entry = header_table_.GetByName(representation.first); + if (enable_compression && name_entry != nullptr) { + output_stream_.AppendUint32(header_table_.IndexOf(name_entry)); } else { output_stream_.AppendUint32(0); EmitString(representation.first); diff --git a/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_encoder_test.cc b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_encoder_test.cc index 2b1efe973b8..f6f9f87a1c0 100644 --- a/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_encoder_test.cc +++ b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_encoder_test.cc @@ -274,12 +274,8 @@ TEST_F(HpackEncoderTestBase, EncodeRepresentations) { {"accept", "text/html, text/plain,application/xml"}, {"cookie", "val4"}, {"withnul", quiche::QuicheStringPiece("one\0two", 7)}}; - if (GetSpdyReloadableFlag(spdy_hpack_use_indexed_name)) { - ExpectNonIndexedLiteralWithNameIndex(peer_.table()->GetByName(":path"), - "/home"); - } else { - ExpectNonIndexedLiteral(":path", "/home"); - } + ExpectNonIndexedLiteralWithNameIndex(peer_.table()->GetByName(":path"), + "/home"); ExpectIndexedLiteral(peer_.table()->GetByName("cookie"), "val1"); ExpectIndexedLiteral(peer_.table()->GetByName("cookie"), "val2"); ExpectIndexedLiteral(peer_.table()->GetByName("cookie"), "val3"); @@ -566,12 +562,8 @@ TEST_P(HpackEncoderTest, PseudoHeadersFirst) { // Headers are indexed in the order in which they were added. // This entry pushes "cookie: a=bb" back to 63. - if (GetSpdyReloadableFlag(spdy_hpack_use_indexed_name)) { - ExpectNonIndexedLiteralWithNameIndex(peer_.table()->GetByName(":path"), - "/spam/eggs.html"); - } else { - ExpectNonIndexedLiteral(":path", "/spam/eggs.html"); - } + ExpectNonIndexedLiteralWithNameIndex(peer_.table()->GetByName(":path"), + "/spam/eggs.html"); ExpectIndexedLiteral(peer_.table()->GetByName(":authority"), "www.example.com"); ExpectIndexedLiteral("-foo", "bar"); diff --git a/chromium/net/third_party/quiche/src/spdy/core/lifo_write_scheduler.h b/chromium/net/third_party/quiche/src/spdy/core/lifo_write_scheduler.h index 405ccf5387b..d2e7fcfb847 100644 --- a/chromium/net/third_party/quiche/src/spdy/core/lifo_write_scheduler.h +++ b/chromium/net/third_party/quiche/src/spdy/core/lifo_write_scheduler.h @@ -5,6 +5,7 @@ #ifndef QUICHE_SPDY_CORE_LIFO_WRITE_SCHEDULER_H_ #define QUICHE_SPDY_CORE_LIFO_WRITE_SCHEDULER_H_ +#include <cstdint> #include <map> #include <set> #include <string> @@ -40,15 +41,13 @@ class LifoWriteScheduler : public WriteScheduler<StreamIdType> { return registered_streams_.find(stream_id) != registered_streams_.end(); } - // Stream precedence is not supported by this scheduler. + // Stream precedence is available but note that it is not used for scheduling + // in this scheduler. StreamPrecedenceType GetStreamPrecedence( - StreamIdType /*stream_id*/) const override { - return StreamPrecedenceType(kV3LowestPriority); - } + StreamIdType stream_id) const override; - void UpdateStreamPrecedence( - StreamIdType /*stream_id*/, - const StreamPrecedenceType& /*precedence*/) override {} + void UpdateStreamPrecedence(StreamIdType stream_id, + const StreamPrecedenceType& precedence) override; std::vector<StreamIdType> GetStreamChildren( StreamIdType /*stream_id*/) const override { @@ -85,19 +84,26 @@ class LifoWriteScheduler : public WriteScheduler<StreamIdType> { private: friend class test::LifoWriteSchedulerPeer<StreamIdType>; + struct StreamInfo { + SpdyPriority priority; + int64_t event_time; // read/write event time (us since Unix epoch). + }; + std::set<StreamIdType> ready_streams_; - std::map<StreamIdType, int64_t> registered_streams_; + std::map<StreamIdType, StreamInfo> registered_streams_; }; template <typename StreamIdType> void LifoWriteScheduler<StreamIdType>::RegisterStream( StreamIdType stream_id, - const StreamPrecedenceType& /*precedence*/) { + const StreamPrecedenceType& precedence) { if (StreamRegistered(stream_id)) { SPDY_BUG << "Stream " << stream_id << " already registered"; return; } - registered_streams_.emplace_hint(registered_streams_.end(), stream_id, 0); + registered_streams_.emplace_hint( + registered_streams_.end(), stream_id, + StreamInfo{/*priority=*/precedence.spdy3_priority(), /*event_time=*/0}); } template <typename StreamIdType> @@ -112,12 +118,36 @@ void LifoWriteScheduler<StreamIdType>::UnregisterStream( } template <typename StreamIdType> +typename LifoWriteScheduler<StreamIdType>::StreamPrecedenceType +LifoWriteScheduler<StreamIdType>::GetStreamPrecedence( + StreamIdType stream_id) const { + auto it = registered_streams_.find(stream_id); + if (it == registered_streams_.end()) { + SPDY_DVLOG(1) << "Stream " << stream_id << " not registered"; + return StreamPrecedenceType(kV3LowestPriority); + } + return StreamPrecedenceType(it->second.priority); +} + +template <typename StreamIdType> +void LifoWriteScheduler<StreamIdType>::UpdateStreamPrecedence( + StreamIdType stream_id, + const StreamPrecedenceType& precedence) { + auto it = registered_streams_.find(stream_id); + if (it == registered_streams_.end()) { + SPDY_DVLOG(1) << "Stream " << stream_id << " not registered"; + return; + } + it->second.priority = precedence.spdy3_priority(); +} + +template <typename StreamIdType> void LifoWriteScheduler<StreamIdType>::RecordStreamEventTime( StreamIdType stream_id, int64_t now_in_usec) { auto it = registered_streams_.find(stream_id); if (it != registered_streams_.end()) { - it->second = now_in_usec; + it->second.event_time = now_in_usec; } else { SPDY_BUG << "Stream " << stream_id << " is not registered"; } @@ -134,8 +164,8 @@ int64_t LifoWriteScheduler<StreamIdType>::GetLatestEventWithPrecedence( for (auto it = registered_streams_.rbegin(); it != registered_streams_.rend(); ++it) { if (stream_id < it->first) { - if (it->second > latest_event_time_us) { - latest_event_time_us = it->second; + if (it->second.event_time > latest_event_time_us) { + latest_event_time_us = it->second.event_time; } } else { break; diff --git a/chromium/net/third_party/quiche/src/spdy/core/lifo_write_scheduler_test.cc b/chromium/net/third_party/quiche/src/spdy/core/lifo_write_scheduler_test.cc index 1d7ecbf8e32..744ee136521 100644 --- a/chromium/net/third_party/quiche/src/spdy/core/lifo_write_scheduler_test.cc +++ b/chromium/net/third_party/quiche/src/spdy/core/lifo_write_scheduler_test.cc @@ -151,6 +151,24 @@ TEST(LifoWriteSchedulerTest, GetLatestEventTest) { "Stream 11 is not registered"); } +TEST(LifoWriteSchedulerTest, GetStreamPrecedence) { + LifoWriteScheduler<SpdyStreamId> lifo; + // Return lowest priority for unknown stream. + EXPECT_EQ(kV3LowestPriority, lifo.GetStreamPrecedence(1).spdy3_priority()); + + lifo.RegisterStream(1, SpdyStreamPrecedence(3)); + EXPECT_TRUE(lifo.GetStreamPrecedence(1).is_spdy3_priority()); + EXPECT_EQ(3, lifo.GetStreamPrecedence(1).spdy3_priority()); + + // Redundant registration shouldn't change stream priority. + EXPECT_SPDY_BUG(lifo.RegisterStream(1, SpdyStreamPrecedence(4)), + "Stream 1 already registered"); + EXPECT_EQ(3, lifo.GetStreamPrecedence(1).spdy3_priority()); + + lifo.UpdateStreamPrecedence(1, SpdyStreamPrecedence(5)); + EXPECT_EQ(5, lifo.GetStreamPrecedence(1).spdy3_priority()); +} + } // namespace test } // namespace spdy diff --git a/chromium/net/tools/cert_verify_tool/cert_verify_tool_util.cc b/chromium/net/tools/cert_verify_tool/cert_verify_tool_util.cc index 95aa01c6e5a..f2b09c1551f 100644 --- a/chromium/net/tools/cert_verify_tool/cert_verify_tool_util.cc +++ b/chromium/net/tools/cert_verify_tool/cert_verify_tool_util.cc @@ -7,6 +7,7 @@ #include <iostream> #include "base/files/file_util.h" +#include "base/logging.h" #include "base/strings/stringprintf.h" #include "build/build_config.h" #include "net/cert/pem.h" diff --git a/chromium/net/tools/dns_fuzz_stub/dns_fuzz_stub.cc b/chromium/net/tools/dns_fuzz_stub/dns_fuzz_stub.cc index cd3f9a39d29..7abb217e250 100644 --- a/chromium/net/tools/dns_fuzz_stub/dns_fuzz_stub.cc +++ b/chromium/net/tools/dns_fuzz_stub/dns_fuzz_stub.cc @@ -14,6 +14,7 @@ #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/json/json_reader.h" +#include "base/logging.h" #include "base/time/time.h" #include "base/values.h" #include "net/base/address_list.h" diff --git a/chromium/net/tools/epoll_server/platform/impl/epoll_logging_impl.h b/chromium/net/tools/epoll_server/platform/impl/epoll_logging_impl.h index 9f9b8ab05b6..9487e1d2cbd 100644 --- a/chromium/net/tools/epoll_server/platform/impl/epoll_logging_impl.h +++ b/chromium/net/tools/epoll_server/platform/impl/epoll_logging_impl.h @@ -5,7 +5,9 @@ #ifndef NET_TOOLS_EPOLL_SERVER_PLATFORM_IMPL_EPOLL_LOGGING_IMPL_H_ #define NET_TOOLS_EPOLL_SERVER_PLATFORM_IMPL_EPOLL_LOGGING_IMPL_H_ +#include "base/check_op.h" #include "base/logging.h" +#include "base/notreached.h" #define EPOLL_CHROMIUM_LOG_INFO VLOG(1) #define EPOLL_CHROMIUM_LOG_WARNING DLOG(WARNING) diff --git a/chromium/net/tools/quic/quic_http_proxy_backend.h b/chromium/net/tools/quic/quic_http_proxy_backend.h index 0852d70a557..32d9d6bb4bf 100644 --- a/chromium/net/tools/quic/quic_http_proxy_backend.h +++ b/chromium/net/tools/quic/quic_http_proxy_backend.h @@ -26,7 +26,6 @@ #include "base/base64.h" #include "base/callback.h" -#include "base/logging.h" #include "base/macros.h" #include "base/single_thread_task_runner.h" #include "base/threading/thread.h" diff --git a/chromium/net/tools/quic/quic_http_proxy_backend_stream.h b/chromium/net/tools/quic/quic_http_proxy_backend_stream.h index 6d87391eb8a..80f8e2bc9a5 100644 --- a/chromium/net/tools/quic/quic_http_proxy_backend_stream.h +++ b/chromium/net/tools/quic/quic_http_proxy_backend_stream.h @@ -24,7 +24,6 @@ #include "base/bind.h" #include "base/callback.h" #include "base/location.h" -#include "base/logging.h" #include "base/macros.h" #include "net/base/request_priority.h" #include "net/base/upload_data_stream.h" diff --git a/chromium/net/tools/quic/quic_simple_client.cc b/chromium/net/tools/quic/quic_simple_client.cc index 5d8bf33b2a1..25fcab0a909 100644 --- a/chromium/net/tools/quic/quic_simple_client.cc +++ b/chromium/net/tools/quic/quic_simple_client.cc @@ -37,11 +37,12 @@ QuicSimpleClient::QuicSimpleClient( quic::QuicSocketAddress server_address, const quic::QuicServerId& server_id, const quic::ParsedQuicVersionVector& supported_versions, + const quic::QuicConfig& config, std::unique_ptr<quic::ProofVerifier> proof_verifier) : quic::QuicSpdyClientBase( server_id, supported_versions, - quic::QuicConfig(), + config, CreateQuicConnectionHelper(), CreateQuicAlarmFactory(), quic::QuicWrapUnique( diff --git a/chromium/net/tools/quic/quic_simple_client.h b/chromium/net/tools/quic/quic_simple_client.h index c791adefd75..3ac2841a68d 100644 --- a/chromium/net/tools/quic/quic_simple_client.h +++ b/chromium/net/tools/quic/quic_simple_client.h @@ -41,6 +41,7 @@ class QuicSimpleClient : public quic::QuicSpdyClientBase { QuicSimpleClient(quic::QuicSocketAddress server_address, const quic::QuicServerId& server_id, const quic::ParsedQuicVersionVector& supported_versions, + const quic::QuicConfig& config, std::unique_ptr<quic::ProofVerifier> proof_verifier); ~QuicSimpleClient() override; diff --git a/chromium/net/tools/quic/quic_simple_client_bin.cc b/chromium/net/tools/quic/quic_simple_client_bin.cc index dae728bc0a0..1de449b8af6 100644 --- a/chromium/net/tools/quic/quic_simple_client_bin.cc +++ b/chromium/net/tools/quic/quic_simple_client_bin.cc @@ -61,6 +61,7 @@ class QuicSimpleClientFactory : public quic::QuicToyClient::ClientFactory { std::string host_for_lookup, uint16_t port, quic::ParsedQuicVersionVector versions, + const quic::QuicConfig& config, std::unique_ptr<quic::ProofVerifier> verifier) override { net::AddressList addresses; int rv = net::SynchronousHostResolver::Resolve(host_for_lookup, &addresses); @@ -85,7 +86,7 @@ class QuicSimpleClientFactory : public quic::QuicToyClient::ClientFactory { quic::QuicServerId server_id(host_for_handshake, port, false); return std::make_unique<net::QuicSimpleClient>( - quic::QuicSocketAddress(ip_addr, port), server_id, versions, + quic::QuicSocketAddress(ip_addr, port), server_id, versions, config, std::move(verifier)); } }; diff --git a/chromium/net/tools/quic/quic_simple_client_test.cc b/chromium/net/tools/quic/quic_simple_client_test.cc index a36102e5ad9..b522460bcd3 100644 --- a/chromium/net/tools/quic/quic_simple_client_test.cc +++ b/chromium/net/tools/quic/quic_simple_client_test.cc @@ -19,7 +19,7 @@ TEST(QuicSimpleClientTest, Initialize) { quic::QuicServerId server_id("hostname", server_address.port(), false); quic::ParsedQuicVersionVector versions = quic::AllSupportedVersions(); QuicSimpleClient client( - server_address, server_id, versions, + server_address, server_id, versions, quic::QuicConfig(), quic::test::crypto_test_utils::ProofVerifierForTesting()); EXPECT_TRUE(client.Initialize()); } diff --git a/chromium/net/tools/quic/quic_simple_server.cc b/chromium/net/tools/quic/quic_simple_server.cc index 9c397b57c98..01c3e63a084 100644 --- a/chromium/net/tools/quic/quic_simple_server.cc +++ b/chromium/net/tools/quic/quic_simple_server.cc @@ -125,6 +125,7 @@ bool QuicSimpleServer::Listen(const IPEndPoint& address) { } void QuicSimpleServer::Shutdown() { + LOG(WARNING) << "QuicSimpleServer is shutting down"; // Before we shut down the epoll server, give all active sessions a chance to // notify clients that they're closing. dispatcher_->Shutdown(); @@ -177,20 +178,24 @@ void QuicSimpleServer::StartReading() { void QuicSimpleServer::OnReadComplete(int result) { read_pending_ = false; - if (result == 0) - result = ERR_CONNECTION_CLOSED; - if (result < 0) { + if (result > 0) { + quic::QuicReceivedPacket packet(read_buffer_->data(), result, + helper_->GetClock()->Now(), false); + dispatcher_->ProcessPacket(ToQuicSocketAddress(server_address_), + ToQuicSocketAddress(client_address_), packet); + } else { LOG(ERROR) << "QuicSimpleServer read failed: " << ErrorToString(result); - Shutdown(); - return; + // Do not act on ERR_MSG_TOO_BIG as that indicates that we received a UDP + // packet whose payload is larger than our receive buffer. Do not act on 0 + // as that indicates that we received a UDP packet with an empty payload. + // In both cases, the socket should still be usable. + if (result != ERR_MSG_TOO_BIG && result != 0) { + Shutdown(); + return; + } } - quic::QuicReceivedPacket packet(read_buffer_->data(), result, - helper_->GetClock()->Now(), false); - dispatcher_->ProcessPacket(ToQuicSocketAddress(server_address_), - ToQuicSocketAddress(client_address_), packet); - StartReading(); } diff --git a/chromium/net/tools/quic/quic_simple_server_packet_writer.cc b/chromium/net/tools/quic/quic_simple_server_packet_writer.cc index b4599eba584..5978b7922a8 100644 --- a/chromium/net/tools/quic/quic_simple_server_packet_writer.cc +++ b/chromium/net/tools/quic/quic_simple_server_packet_writer.cc @@ -88,10 +88,10 @@ bool QuicSimpleServerPacketWriter::IsBatchMode() const { return false; } -char* QuicSimpleServerPacketWriter::GetNextWriteLocation( +quic::QuicPacketBuffer QuicSimpleServerPacketWriter::GetNextWriteLocation( const quic::QuicIpAddress& self_address, const quic::QuicSocketAddress& peer_address) { - return nullptr; + return {nullptr, nullptr}; } quic::WriteResult QuicSimpleServerPacketWriter::Flush() { diff --git a/chromium/net/tools/quic/quic_simple_server_packet_writer.h b/chromium/net/tools/quic/quic_simple_server_packet_writer.h index 76f8b8e82f9..c8ba2227ba5 100644 --- a/chromium/net/tools/quic/quic_simple_server_packet_writer.h +++ b/chromium/net/tools/quic/quic_simple_server_packet_writer.h @@ -50,7 +50,7 @@ class QuicSimpleServerPacketWriter : public quic::QuicPacketWriter { const quic::QuicSocketAddress& peer_address) const override; bool SupportsReleaseTime() const override; bool IsBatchMode() const override; - char* GetNextWriteLocation( + quic::QuicPacketBuffer GetNextWriteLocation( const quic::QuicIpAddress& self_address, const quic::QuicSocketAddress& peer_address) override; quic::WriteResult Flush() override; diff --git a/chromium/net/tools/testserver/testserver_base.py b/chromium/net/tools/testserver/testserver_base.py index 7be34a3fac3..25cb7af9e8a 100644 --- a/chromium/net/tools/testserver/testserver_base.py +++ b/chromium/net/tools/testserver/testserver_base.py @@ -2,14 +2,14 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -import BaseHTTPServer +from six.moves import BaseHTTPServer import errno import json import optparse import os import re import socket -import SocketServer +from six.moves import socketserver as SocketServer import struct import sys import warnings @@ -74,7 +74,7 @@ class BrokenPipeHandlerMixIn: def handle_error(self, request, client_address): value = sys.exc_info()[1] if isinstance(value, tlslite.errors.TLSClosedConnectionError): - print "testserver.py: Closed connection" + print("testserver.py: Closed connection") return if isinstance(value, socket.error): err = value.args[0] @@ -84,10 +84,10 @@ class BrokenPipeHandlerMixIn: else: pipe_err = errno.EPIPE if err == pipe_err: - print "testserver.py: Broken pipe" + print("testserver.py: Broken pipe") return if err == errno.ECONNRESET: - print "testserver.py: Connection reset by peer" + print("testserver.py: Connection reset by peer") return SocketServer.BaseServer.handle_error(self, request, client_address) @@ -219,7 +219,7 @@ class TestServerRunner(object): try: self.server.serve_forever() except KeyboardInterrupt: - print 'shutting down server' + print('shutting down server') self.server.stop = True def add_options(self): @@ -256,15 +256,15 @@ class TestServerRunner(object): # Notify the parent that we've started. (BaseServer subclasses # bind their sockets on construction.) if self.options.startup_pipe is not None: - server_data_json = json.dumps(server_data) + server_data_json = json.dumps(server_data).encode() server_data_len = len(server_data_json) - print 'sending server_data: %s (%d bytes)' % ( - server_data_json, server_data_len) + print('sending server_data: %s (%d bytes)' % + (server_data_json, server_data_len)) if sys.platform == 'win32': fd = msvcrt.open_osfhandle(self.options.startup_pipe, 0) else: fd = self.options.startup_pipe - startup_pipe = os.fdopen(fd, "w") + startup_pipe = os.fdopen(fd, "wb") # First write the data length as an unsigned 4-byte value. This # is _not_ using network byte ordering since the other end of the # pipe is on the same machine. diff --git a/chromium/net/traffic_annotation/network_traffic_annotation.h b/chromium/net/traffic_annotation/network_traffic_annotation.h index 6319a81fd10..e91a4c6f29b 100644 --- a/chromium/net/traffic_annotation/network_traffic_annotation.h +++ b/chromium/net/traffic_annotation/network_traffic_annotation.h @@ -5,7 +5,10 @@ #ifndef NET_TRAFFIC_ANNOTATION_NETWORK_TRAFFIC_ANNOTATION_H_ #define NET_TRAFFIC_ANNOTATION_NETWORK_TRAFFIC_ANNOTATION_H_ -#include "base/logging.h" +#include <cstdint> + +#include "base/check.h" +#include "base/notreached.h" #include "build/build_config.h" namespace { diff --git a/chromium/net/url_request/url_fetcher_response_writer.cc b/chromium/net/url_request/url_fetcher_response_writer.cc index adfbcb1c370..7a96f12458a 100644 --- a/chromium/net/url_request/url_fetcher_response_writer.cc +++ b/chromium/net/url_request/url_fetcher_response_writer.cc @@ -166,8 +166,7 @@ void URLFetcherFileWriter::CloseAndDeleteFile() { file_stream_.reset(); DisownFile(); file_task_runner_->PostTask( - FROM_HERE, base::BindOnce(base::IgnoreResult(&base::DeleteFile), - file_path_, false /* recursive */)); + FROM_HERE, base::BindOnce(base::GetDeleteFileCallback(), file_path_)); } void URLFetcherFileWriter::DidCreateTempFile(base::FilePath* temp_file_path, diff --git a/chromium/net/url_request/url_request.cc b/chromium/net/url_request/url_request.cc index 40927b586fa..cbed158f16b 100644 --- a/chromium/net/url_request/url_request.cc +++ b/chromium/net/url_request/url_request.cc @@ -395,7 +395,7 @@ int URLRequest::GetResponseCode() const { return job_->GetResponseCode(); } -void URLRequest::set_maybe_sent_cookies(CookieStatusList cookies) { +void URLRequest::set_maybe_sent_cookies(CookieAccessResultList cookies) { maybe_sent_cookies_ = std::move(cookies); } @@ -983,13 +983,12 @@ void URLRequest::NotifySSLCertificateError(int net_error, delegate_->OnSSLCertificateError(this, net_error, ssl_info, fatal); } -bool URLRequest::CanGetCookies(const CookieList& cookie_list) const { +bool URLRequest::CanGetCookies() const { DCHECK(!(load_flags_ & LOAD_DO_NOT_SEND_COOKIES)); bool can_get_cookies = g_default_can_use_cookies; if (network_delegate_) { can_get_cookies = - network_delegate_->CanGetCookies(*this, cookie_list, - /*allowed_from_caller=*/true); + network_delegate_->CanGetCookies(*this, /*allowed_from_caller=*/true); } if (!can_get_cookies) @@ -1015,7 +1014,10 @@ net::PrivacyMode URLRequest::DeterminePrivacyMode() const { // Enable privacy mode if flags tell us not send or save cookies. if ((load_flags_ & LOAD_DO_NOT_SEND_COOKIES) || (load_flags_ & LOAD_DO_NOT_SAVE_COOKIES)) { - return PRIVACY_MODE_ENABLED; + // TODO(https://crbug.com/775438): Client certs should always be + // affirmatively omitted for these requests. + return send_client_certs_ ? PRIVACY_MODE_ENABLED + : PRIVACY_MODE_ENABLED_WITHOUT_CLIENT_CERTS; } // Otherwise, check with the delegate if present, or base it off of diff --git a/chromium/net/url_request/url_request.h b/chromium/net/url_request/url_request.h index e967a680d6e..643ab4ae8f0 100644 --- a/chromium/net/url_request/url_request.h +++ b/chromium/net/url_request/url_request.h @@ -11,8 +11,6 @@ #include <string> #include <vector> -#include "base/debug/leak_tracker.h" -#include "base/logging.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/optional.h" @@ -542,7 +540,7 @@ class NET_EXPORT URLRequest : public base::SupportsUserData { // Returns whether secure DNS should be disabled for the request. bool disable_secure_dns() { return disable_secure_dns_; } - void set_maybe_sent_cookies(CookieStatusList cookies); + void set_maybe_sent_cookies(CookieAccessResultList cookies); void set_maybe_stored_cookies(CookieAndLineStatusList cookies); // These lists contain a list of cookies that are associated with the given @@ -556,7 +554,7 @@ class NET_EXPORT URLRequest : public base::SupportsUserData { // and only contain the cookies relevant to the most recent roundtrip. // Populated while the http request is being built. - const CookieStatusList& maybe_sent_cookies() const { + const CookieAccessResultList& maybe_sent_cookies() const { return maybe_sent_cookies_; } // Populated after the response headers are received. @@ -724,6 +722,20 @@ class NET_EXPORT URLRequest : public base::SupportsUserData { } bool upgrade_if_insecure() const { return upgrade_if_insecure_; } + // By default, client certs will be sent (provided via + // Delegate::OnCertificateRequested) when cookies are disabled + // (LOAD_DO_NOT_SEND_COOKIES / LOAD_DO_NOT_SAVE_COOKIES). As described at + // https://crbug.com/775438, this is not the desired behavior. When + // |send_client_certs| is set to false, this will suppress the + // Delegate::OnCertificateRequested callback when cookies/credentials are also + // suppressed. This method has no effect if credentials are enabled (cookies + // saved and sent). + // TODO(https://crbug.com/775438): Remove this when the underlying + // issue is fixed. + void set_send_client_certs(bool send_client_certs) { + send_client_certs_ = send_client_certs; + } + base::WeakPtr<URLRequest> GetWeakPtr(); protected: @@ -815,7 +827,7 @@ class NET_EXPORT URLRequest : public base::SupportsUserData { // These functions delegate to |network_delegate_| if it is not NULL. // If |network_delegate_| is NULL, cookies can be used unless // SetDefaultCookiePolicyToBlock() has been called. - bool CanGetCookies(const CookieList& cookie_list) const; + bool CanGetCookies() const; bool CanSetCookie(const net::CanonicalCookie& cookie, CookieOptions* options) const; PrivacyMode DeterminePrivacyMode() const; @@ -865,7 +877,7 @@ class NET_EXPORT URLRequest : public base::SupportsUserData { PrivacyMode privacy_mode_; bool disable_secure_dns_; - CookieStatusList maybe_sent_cookies_; + CookieAccessResultList maybe_sent_cookies_; CookieAndLineStatusList maybe_stored_cookies_; #if BUILDFLAG(ENABLE_REPORTING) @@ -928,8 +940,6 @@ class NET_EXPORT URLRequest : public base::SupportsUserData { std::string blocked_by_; bool use_blocked_by_as_load_param_; - base::debug::LeakTracker<URLRequest> leak_tracker_; - // Safe-guard to ensure that we do not send multiple "I am completed" // messages to network delegate. // TODO(battre): Remove this. http://crbug.com/89049 @@ -959,6 +969,8 @@ class NET_EXPORT URLRequest : public base::SupportsUserData { bool upgrade_if_insecure_; + bool send_client_certs_ = true; + THREAD_CHECKER(thread_checker_); base::WeakPtrFactory<URLRequest> weak_factory_{this}; diff --git a/chromium/net/url_request/url_request_context_builder.cc b/chromium/net/url_request/url_request_context_builder.cc index 943423b3f81..4a71bd3364e 100644 --- a/chromium/net/url_request/url_request_context_builder.cc +++ b/chromium/net/url_request/url_request_context_builder.cc @@ -107,7 +107,6 @@ class BasicNetworkDelegate : public NetworkDelegateImpl { } bool OnCanGetCookies(const URLRequest& request, - const CookieList& cookie_list, bool allowed_from_caller) override { return allowed_from_caller; } diff --git a/chromium/net/url_request/url_request_context_builder_unittest.cc b/chromium/net/url_request/url_request_context_builder_unittest.cc index bb98fa97c86..3b1922c2fab 100644 --- a/chromium/net/url_request/url_request_context_builder_unittest.cc +++ b/chromium/net/url_request/url_request_context_builder_unittest.cc @@ -58,6 +58,7 @@ class MockHttpAuthHandlerFactory : public HttpAuthHandlerFactory { int CreateAuthHandler(HttpAuthChallengeTokenizer* challenge, HttpAuth::Target target, const SSLInfo& ssl_info, + const NetworkIsolationKey& network_isolation_key, const GURL& origin, CreateReason reason, int nonce_count, @@ -131,10 +132,11 @@ TEST_F(URLRequestContextBuilderTest, DefaultHttpAuthHandlerFactory) { SSLInfo null_ssl_info; // Verify that the default basic handler is present - EXPECT_EQ(OK, - context->http_auth_handler_factory()->CreateAuthHandlerFromString( - "basic", HttpAuth::AUTH_SERVER, null_ssl_info, gurl, - NetLogWithSource(), host_resolver_.get(), &handler)); + EXPECT_EQ( + OK, + context->http_auth_handler_factory()->CreateAuthHandlerFromString( + "basic", HttpAuth::AUTH_SERVER, null_ssl_info, NetworkIsolationKey(), + gurl, NetLogWithSource(), host_resolver_.get(), &handler)); } TEST_F(URLRequestContextBuilderTest, CustomHttpAuthHandlerFactory) { @@ -149,20 +151,23 @@ TEST_F(URLRequestContextBuilderTest, CustomHttpAuthHandlerFactory) { // Verify that a handler is returned for a custom scheme. EXPECT_EQ(kBasicReturnCode, context->http_auth_handler_factory()->CreateAuthHandlerFromString( - "ExtraScheme", HttpAuth::AUTH_SERVER, null_ssl_info, gurl, - NetLogWithSource(), host_resolver_.get(), &handler)); + "ExtraScheme", HttpAuth::AUTH_SERVER, null_ssl_info, + NetworkIsolationKey(), gurl, NetLogWithSource(), + host_resolver_.get(), &handler)); // Verify that the default basic handler isn't present - EXPECT_EQ(ERR_UNSUPPORTED_AUTH_SCHEME, - context->http_auth_handler_factory()->CreateAuthHandlerFromString( - "basic", HttpAuth::AUTH_SERVER, null_ssl_info, gurl, - NetLogWithSource(), host_resolver_.get(), &handler)); + EXPECT_EQ( + ERR_UNSUPPORTED_AUTH_SCHEME, + context->http_auth_handler_factory()->CreateAuthHandlerFromString( + "basic", HttpAuth::AUTH_SERVER, null_ssl_info, NetworkIsolationKey(), + gurl, NetLogWithSource(), host_resolver_.get(), &handler)); // Verify that a handler isn't returned for a bogus scheme. - EXPECT_EQ(ERR_UNSUPPORTED_AUTH_SCHEME, - context->http_auth_handler_factory()->CreateAuthHandlerFromString( - "Bogus", HttpAuth::AUTH_SERVER, null_ssl_info, gurl, - NetLogWithSource(), host_resolver_.get(), &handler)); + EXPECT_EQ( + ERR_UNSUPPORTED_AUTH_SCHEME, + context->http_auth_handler_factory()->CreateAuthHandlerFromString( + "Bogus", HttpAuth::AUTH_SERVER, null_ssl_info, NetworkIsolationKey(), + gurl, NetLogWithSource(), host_resolver_.get(), &handler)); } #if BUILDFLAG(ENABLE_REPORTING) @@ -226,7 +231,8 @@ TEST_F(URLRequestContextBuilderTest, ShutdownHostResolverWithPendingRequest) { std::unique_ptr<HostResolver::ResolveHostRequest> request = context->host_resolver()->CreateRequest( - HostPortPair("example.com", 1234), NetLogWithSource(), base::nullopt); + HostPortPair("example.com", 1234), NetworkIsolationKey(), + NetLogWithSource(), base::nullopt); TestCompletionCallback callback; int rv = request->Start(callback.callback()); ASSERT_TRUE(mock_host_resolver->has_pending_requests()); diff --git a/chromium/net/url_request/url_request_http_job.cc b/chromium/net/url_request/url_request_http_job.cc index 0e88cd83a0c..5590bd226c9 100644 --- a/chromium/net/url_request/url_request_http_job.cc +++ b/chromium/net/url_request/url_request_http_job.cc @@ -88,7 +88,7 @@ base::Value CookieInclusionStatusNetLogParams( const std::string& cookie_name, const std::string& cookie_domain, const std::string& cookie_path, - const net::CanonicalCookie::CookieInclusionStatus& status, + const net::CookieInclusionStatus& status, net::NetLogCaptureMode capture_mode) { base::Value dict(base::Value::Type::DICTIONARY); dict.SetStringKey("operation", operation); @@ -160,6 +160,58 @@ void RecordCTHistograms(const net::SSLInfo& ssl_info) { } } +template <typename CookieWithMetadata> +bool ShouldMarkSameSiteCompatPairs( + const std::vector<CookieWithMetadata>& cookie_list, + const net::CookieOptions& options) { + // If the context is same-site then there cannot be any SameSite-by-default + // warnings, so the compat pair warning is irrelevant. + if (options.same_site_cookie_context().GetContextForCookieInclusion() > + net::CookieOptions::SameSiteCookieContext::ContextType:: + SAME_SITE_LAX_METHOD_UNSAFE) { + return false; + } + return cookie_list.size() >= 2; +} + +void MarkSameSiteCompatPairs( + std::vector<net::CookieWithAccessResult>& cookie_list, + const net::CookieOptions& options) { + for (size_t i = 0; i < cookie_list.size() - 1; ++i) { + const net::CanonicalCookie& c1 = cookie_list[i].cookie; + for (size_t j = i + 1; j < cookie_list.size(); ++j) { + const net::CanonicalCookie& c2 = cookie_list[j].cookie; + if (net::cookie_util::IsSameSiteCompatPair(c1, c2, options)) { + cookie_list[i].access_result.status.AddWarningReason( + net::CookieInclusionStatus::WARN_SAMESITE_COMPAT_PAIR); + cookie_list[j].access_result.status.AddWarningReason( + net::CookieInclusionStatus::WARN_SAMESITE_COMPAT_PAIR); + } + } + } +} + +void MarkSameSiteCompatPairs( + std::vector<net::CookieAndLineWithStatus>& cookie_list, + const net::CookieOptions& options) { + for (size_t i = 0; i < cookie_list.size() - 1; ++i) { + if (!cookie_list[i].cookie.has_value()) + continue; + const net::CanonicalCookie& c1 = cookie_list[i].cookie.value(); + for (size_t j = i + 1; j < cookie_list.size(); ++j) { + if (!cookie_list[j].cookie.has_value()) + continue; + const net::CanonicalCookie& c2 = cookie_list[j].cookie.value(); + if (net::cookie_util::IsSameSiteCompatPair(c1, c2, options)) { + cookie_list[i].status.AddWarningReason( + net::CookieInclusionStatus::WARN_SAMESITE_COMPAT_PAIR); + cookie_list[j].status.AddWarningReason( + net::CookieInclusionStatus::WARN_SAMESITE_COMPAT_PAIR); + } + } + } +} + } // namespace namespace net { @@ -279,18 +331,10 @@ void URLRequestHttpJob::Start() { // plugin could set a referrer although sending the referrer is inhibited. request_info_.extra_headers.RemoveHeader(HttpRequestHeaders::kReferer); - // Our consumer should have made sure that this is a safe referrer. See for - // instance WebCore::FrameLoader::HideReferrer. + // Our consumer should have made sure that this is a safe referrer (e.g. via + // URLRequestJob::ComputeReferrerForPolicy). if (referrer.is_valid()) { std::string referer_value = referrer.spec(); - // We limit the `referer` header to 4k: see step 6 of - // https://w3c.github.io/webappsec-referrer-policy/#determine-requests-referrer - // and https://github.com/whatwg/fetch/issues/903. - if (referer_value.length() > 4096) { - // Strip the referrer down to its origin, but ensure that it's serialized - // as a URL (e.g. retaining a trailing `/` character). - referer_value = url::Origin::Create(referrer).GetURL().spec(); - } request_info_.extra_headers.SetHeader(HttpRequestHeaders::kReferer, referer_value); } @@ -552,21 +596,14 @@ void URLRequestHttpJob::AddCookieHeaderAndStart() { void URLRequestHttpJob::SetCookieHeaderAndStart( const CookieOptions& options, - const CookieStatusList& cookies_with_status_list, - const CookieStatusList& excluded_list) { + const CookieAccessResultList& cookies_with_access_result_list, + const CookieAccessResultList& excluded_list) { DCHECK(request_->maybe_sent_cookies().empty()); - // TODO(chlily): This is just for passing to CanGetCookies(), however the - // CookieList parameter of CanGetCookies(), which eventually gets passed to - // the NetworkDelegate, never actually gets used anywhere except in tests. The - // parameter should be removed. - CookieList cookie_list = - net::cookie_util::StripStatuses(cookies_with_status_list); - - bool can_get_cookies = CanGetCookies(cookie_list); - if (!cookies_with_status_list.empty() && can_get_cookies) { + bool can_get_cookies = CanGetCookies(); + if (!cookies_with_access_result_list.empty() && can_get_cookies) { std::string cookie_line = - CanonicalCookie::BuildCookieLine(cookies_with_status_list); + CanonicalCookie::BuildCookieLine(cookies_with_access_result_list); UMA_HISTOGRAM_COUNTS_10000("Cookie.HeaderLength", cookie_line.length()); request_info_.extra_headers.SetHeader(HttpRequestHeaders::kCookie, cookie_line); @@ -576,7 +613,7 @@ void URLRequestHttpJob::SetCookieHeaderAndStart( // TODO(crbug.com/1031664): Reduce the number of times the cookie list is // iterated over. Get metrics for every cookie which is included. - for (const auto& c : cookies_with_status_list) { + for (const auto& c : cookies_with_access_result_list) { bool request_is_secure = request_->url().SchemeIsCryptographic(); net::CookieSourceScheme cookie_scheme = c.cookie.SourceScheme(); CookieRequestScheme cookie_request_schemes; @@ -606,43 +643,49 @@ void URLRequestHttpJob::SetCookieHeaderAndStart( } } - // Report status for things in |excluded_list| and |cookies_with_status_list| + // Report status for things in |excluded_list| and + // |cookies_with_access_result_list| // after the delegate got a chance to block them. - CookieStatusList maybe_sent_cookies = excluded_list; - // CanGetCookies only looks at the fields of the URLRequest, not the cookies - // it is passed, so if CanGetCookies(cookie_list) is false, then - // CanGetCookies(excluded_list) would also be false, so tag also the - // excluded cookies as having been blocked by user preferences. + CookieAccessResultList maybe_sent_cookies = excluded_list; + if (!can_get_cookies) { - for (CookieStatusList::iterator it = maybe_sent_cookies.begin(); + for (CookieAccessResultList::iterator it = maybe_sent_cookies.begin(); it != maybe_sent_cookies.end(); ++it) { - it->status.AddExclusionReason( - CanonicalCookie::CookieInclusionStatus::EXCLUDE_USER_PREFERENCES); + it->access_result.status.AddExclusionReason( + CookieInclusionStatus::EXCLUDE_USER_PREFERENCES); } } - for (const auto& cookie_with_status : cookies_with_status_list) { - CanonicalCookie::CookieInclusionStatus status = cookie_with_status.status; + + for (const auto& cookie_with_access_result : + cookies_with_access_result_list) { + CookieAccessResult access_result = cookie_with_access_result.access_result; if (!can_get_cookies) { - status.AddExclusionReason( - CanonicalCookie::CookieInclusionStatus::EXCLUDE_USER_PREFERENCES); + access_result.status.AddExclusionReason( + CookieInclusionStatus::EXCLUDE_USER_PREFERENCES); } - maybe_sent_cookies.push_back({cookie_with_status.cookie, status}); + maybe_sent_cookies.push_back( + {cookie_with_access_result.cookie, access_result}); } if (request_->net_log().IsCapturing()) { - for (const auto& cookie_and_status : maybe_sent_cookies) { + for (const auto& cookie_with_access_result : maybe_sent_cookies) { request_->net_log().AddEvent( NetLogEventType::COOKIE_INCLUSION_STATUS, [&](NetLogCaptureMode capture_mode) { return CookieInclusionStatusNetLogParams( - "send", cookie_and_status.cookie.Name(), - cookie_and_status.cookie.Domain(), - cookie_and_status.cookie.Path(), cookie_and_status.status, - capture_mode); + "send", cookie_with_access_result.cookie.Name(), + cookie_with_access_result.cookie.Domain(), + cookie_with_access_result.cookie.Path(), + cookie_with_access_result.access_result.status, capture_mode); }); } } + // Mark the CookieInclusionStatuses of items in |maybe_sent_cookies| if they + // are part of a presumed SameSite compatibility pair. + if (ShouldMarkSameSiteCompatPairs(maybe_sent_cookies, options)) + MarkSameSiteCompatPairs(maybe_sent_cookies, options); + request_->set_maybe_sent_cookies(std::move(maybe_sent_cookies)); StartTransaction(); @@ -707,7 +750,7 @@ void URLRequestHttpJob::SaveCookiesAndNotifyHeadersComplete(int result) { // it reaches 0 in the callback itself. num_cookie_lines_left_ = 1; while (headers->EnumerateHeader(&iter, name, &cookie_string)) { - CanonicalCookie::CookieInclusionStatus returned_status; + CookieInclusionStatus returned_status; num_cookie_lines_left_++; @@ -723,7 +766,7 @@ void URLRequestHttpJob::SaveCookiesAndNotifyHeadersComplete(int result) { } if (cookie && !CanSetCookie(*cookie, &options)) { returned_status.AddExclusionReason( - CanonicalCookie::CookieInclusionStatus::EXCLUDE_USER_PREFERENCES); + CookieInclusionStatus::EXCLUDE_USER_PREFERENCES); } if (!returned_status.IsInclude()) { OnSetCookieResult(options, cookie_to_return, std::move(cookie_string), @@ -741,15 +784,21 @@ void URLRequestHttpJob::SaveCookiesAndNotifyHeadersComplete(int result) { // loop has been exited. num_cookie_lines_left_--; - if (num_cookie_lines_left_ == 0) + if (num_cookie_lines_left_ == 0) { + // Mark the CookieInclusionStatuses of items in |set_cookie_status_list_| if + // they are part of a presumed SameSite compatibility pair. + if (ShouldMarkSameSiteCompatPairs(set_cookie_status_list_, options)) + MarkSameSiteCompatPairs(set_cookie_status_list_, options); + NotifyHeadersComplete(); + } } void URLRequestHttpJob::OnSetCookieResult( const CookieOptions& options, base::Optional<CanonicalCookie> cookie, std::string cookie_string, - CanonicalCookie::CookieInclusionStatus status) { + CookieInclusionStatus status) { if (request_->net_log().IsCapturing()) { request_->net_log().AddEvent( NetLogEventType::COOKIE_INCLUSION_STATUS, @@ -768,8 +817,14 @@ void URLRequestHttpJob::OnSetCookieResult( // If all the cookie lines have been handled, |set_cookie_status_list_| now // reflects the result of all Set-Cookie lines, and the request can be // continued. - if (num_cookie_lines_left_ == 0) + if (num_cookie_lines_left_ == 0) { + // Mark the CookieInclusionStatuses of items in |set_cookie_status_list_| if + // they are part of a presumed SameSite compatibility pair. + if (ShouldMarkSameSiteCompatPairs(set_cookie_status_list_, options)) + MarkSameSiteCompatPairs(set_cookie_status_list_, options); + NotifyHeadersComplete(); + } } void URLRequestHttpJob::ProcessStrictTransportSecurityHeader() { @@ -817,7 +872,8 @@ void URLRequestHttpJob::ProcessExpectCTHeader() { std::string value; if (headers->GetNormalizedHeader("Expect-CT", &value)) { security_state->ProcessExpectCTHeader( - value, HostPortPair::FromURL(request_info_.url), ssl_info); + value, HostPortPair::FromURL(request_info_.url), ssl_info, + request_->isolation_info().network_isolation_key()); } } diff --git a/chromium/net/url_request/url_request_http_job.h b/chromium/net/url_request/url_request_http_job.h index f214aef293c..cc6eecb5b3e 100644 --- a/chromium/net/url_request/url_request_http_job.h +++ b/chromium/net/url_request/url_request_http_job.h @@ -22,6 +22,7 @@ #include "net/base/ip_endpoint.h" #include "net/base/net_error_details.h" #include "net/base/net_export.h" +#include "net/cookies/cookie_inclusion_status.h" #include "net/http/http_request_info.h" #include "net/socket/connection_attempts.h" #include "net/url_request/url_request_job.h" @@ -167,14 +168,14 @@ class NET_EXPORT_PRIVATE URLRequestHttpJob : public URLRequestJob { // Callback functions for Cookie Monster void SetCookieHeaderAndStart(const CookieOptions& options, - const CookieStatusList& cookie_list, - const CookieStatusList& excluded_list); + const CookieAccessResultList& cookie_list, + const CookieAccessResultList& excluded_list); // Another Cookie Monster callback void OnSetCookieResult(const CookieOptions& options, base::Optional<CanonicalCookie> cookie, std::string cookie_string, - CanonicalCookie::CookieInclusionStatus status); + CookieInclusionStatus status); int num_cookie_lines_left_; CookieAndLineStatusList set_cookie_status_list_; diff --git a/chromium/net/url_request/url_request_http_job_unittest.cc b/chromium/net/url_request/url_request_http_job_unittest.cc index f70cf685f69..65fc278295b 100644 --- a/chromium/net/url_request/url_request_http_job_unittest.cc +++ b/chromium/net/url_request/url_request_http_job_unittest.cc @@ -22,6 +22,7 @@ #include "base/test/metrics/histogram_tester.h" #include "net/base/auth.h" #include "net/base/isolation_info.h" +#include "net/base/network_isolation_key.h" #include "net/base/request_priority.h" #include "net/cert/ct_policy_status.h" #include "net/cookies/cookie_monster.h" @@ -1012,6 +1013,84 @@ TEST_F(URLRequestHttpJobWithMockSocketsTest, kGTSRootR3HistogramID, 1); } +namespace { + +// An ExpectCTReporter that records the number of times OnExpectCTFailed() was +// called. +class MockExpectCTReporter : public TransportSecurityState::ExpectCTReporter { + public: + MockExpectCTReporter() = default; + ~MockExpectCTReporter() override = default; + + void OnExpectCTFailed( + const HostPortPair& host_port_pair, + const GURL& report_uri, + base::Time expiration, + const X509Certificate* validated_certificate_chain, + const X509Certificate* served_certificate_chain, + const SignedCertificateTimestampAndStatusList& + signed_certificate_timestamps, + const NetworkIsolationKey& network_isolation_key) override { + num_failures_++; + network_isolation_key_ = network_isolation_key; + } + + int num_failures() const { return num_failures_; } + const NetworkIsolationKey& network_isolation_key() const { + return network_isolation_key_; + } + + private: + int num_failures_ = 0; + NetworkIsolationKey network_isolation_key_; +}; + +} // namespace + +TEST_F(URLRequestHttpJobWithMockSocketsTest, + TestHttpJobSendsNetworkIsolationKeyWhenProcessingExpectCTHeader) { + SSLSocketDataProvider ssl_socket_data(net::ASYNC, net::OK); + ssl_socket_data.ssl_info.cert = + ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem"); + ssl_socket_data.ssl_info.is_issued_by_known_root = true; + ssl_socket_data.ssl_info.ct_policy_compliance_required = false; + ssl_socket_data.ssl_info.ct_policy_compliance = + ct::CTPolicyCompliance::CT_POLICY_NOT_DIVERSE_SCTS; + + socket_factory_.AddSSLSocketDataProvider(&ssl_socket_data); + + MockWrite writes[] = {MockWrite(kSimpleGetMockWrite)}; + MockRead reads[] = { + MockRead( + "HTTP/1.1 200 OK\r\n" + "Expect-CT: max-age=100, enforce, report-uri=https://example.test\r\n" + "Content-Length: 12\r\n\r\n"), + MockRead("Test Content")}; + StaticSocketDataProvider socket_data(reads, writes); + socket_factory_.AddSocketDataProvider(&socket_data); + + base::HistogramTester histograms; + + MockExpectCTReporter reporter; + TransportSecurityState transport_security_state; + transport_security_state.SetExpectCTReporter(&reporter); + context_->set_transport_security_state(&transport_security_state); + + TestDelegate delegate; + std::unique_ptr<URLRequest> request = context_->CreateRequest( + GURL("https://www.example.com/"), DEFAULT_PRIORITY, &delegate, + TRAFFIC_ANNOTATION_FOR_TESTS); + IsolationInfo isolation_info = IsolationInfo::CreateTransient(); + request->set_isolation_info(isolation_info); + request->Start(); + delegate.RunUntilComplete(); + EXPECT_THAT(delegate.request_status(), IsOk()); + + ASSERT_EQ(1, reporter.num_failures()); + EXPECT_EQ(isolation_info.network_isolation_key(), + reporter.network_isolation_key()); +} + // Tests that the CT compliance histogram is recorded, even if CT is not // required. TEST_F(URLRequestHttpJobWithMockSocketsTest, @@ -1646,7 +1725,7 @@ TEST_F(URLRequestHttpJobWebSocketTest, CreateHelperPassedThrough) { bool SetAllCookies(CookieMonster* cm, const CookieList& list) { DCHECK(cm); - ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus> callback; + ResultSavingCookieCallback<CookieInclusionStatus> callback; cm->SetAllCookiesAsync(list, callback.MakeCallback()); callback.WaitUntilDone(); return callback.result().IsInclude(); @@ -1660,7 +1739,7 @@ bool CreateAndSetCookie(CookieStore* cs, if (!cookie) return false; DCHECK(cs); - ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus> callback; + ResultSavingCookieCallback<CookieInclusionStatus> callback; cs->SetCanonicalCookieAsync(std::move(cookie), url, CookieOptions::MakeAllInclusive(), callback.MakeCallback()); diff --git a/chromium/net/url_request/url_request_job.cc b/chromium/net/url_request/url_request_job.cc index 3430a8dd62f..e490bd69b85 100644 --- a/chromium/net/url_request/url_request_job.cc +++ b/chromium/net/url_request/url_request_job.cc @@ -16,6 +16,7 @@ #include "base/threading/thread_task_runner_handle.h" #include "base/values.h" #include "net/base/auth.h" +#include "net/base/features.h" #include "net/base/io_buffer.h" #include "net/base/load_flags.h" #include "net/base/load_states.h" @@ -271,49 +272,111 @@ void URLRequestJob::GetConnectionAttempts(ConnectionAttempts* out) const { out->clear(); } +namespace { + +// Assuming |url| has already been stripped for use as a referrer, if +// |should_strip_to_origin| is true, this method returns the output of the +// "Strip `url` for use as a referrer" algorithm from the Referrer Policy spec +// with its "origin-only" flag set to true: +// https://w3c.github.io/webappsec-referrer-policy/#strip-url +GURL MaybeStripToOrigin(GURL url, bool should_strip_to_origin) { + if (!should_strip_to_origin) + return url; + + return url.GetOrigin(); +} + +} // namespace + // static GURL URLRequestJob::ComputeReferrerForPolicy( URLRequest::ReferrerPolicy policy, const GURL& original_referrer, const GURL& destination, bool* same_origin_out_for_metrics) { + // Here and below, numbered lines are from the Referrer Policy spec's + // "Determine request's referrer" algorithm: + // https://w3c.github.io/webappsec-referrer-policy/#determine-requests-referrer + // + // 4. Let referrerURL be the result of stripping referrerSource for use as a + // referrer. + GURL stripped_referrer = original_referrer.GetAsReferrer(); + + // 5. Let referrerOrigin be the result of stripping referrerSource for use as + // a referrer, with the origin-only flag set to true. + // + // (We use a boolean instead of computing the URL right away in order to avoid + // constructing a new GURL when it's not necessary.) + bool should_strip_to_origin = false; + + // 6. If the result of serializing referrerURL is a string whose length is + // greater than 4096, set referrerURL to referrerOrigin. + if (stripped_referrer.spec().size() > 4096) + should_strip_to_origin = true; + + bool same_origin = url::Origin::Create(original_referrer) + .IsSameOriginWith(url::Origin::Create(destination)); + + if (same_origin_out_for_metrics) + *same_origin_out_for_metrics = same_origin; + + // 7. The user agent MAY alter referrerURL or referrerOrigin at this point to + // enforce arbitrary policy considerations in the interests of minimizing data + // leakage. For example, the user agent could strip the URL down to an origin, + // modify its host, replace it with an empty string, etc. + if (base::FeatureList::IsEnabled( + features::kCapReferrerToOriginOnCrossOrigin) && + !same_origin) { + should_strip_to_origin = true; + } + bool secure_referrer_but_insecure_destination = original_referrer.SchemeIsCryptographic() && !destination.SchemeIsCryptographic(); - url::Origin referrer_origin = url::Origin::Create(original_referrer); - bool same_origin = - referrer_origin.IsSameOriginWith(url::Origin::Create(destination)); - if (same_origin_out_for_metrics) - *same_origin_out_for_metrics = same_origin; + switch (policy) { case URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE: - return secure_referrer_but_insecure_destination ? GURL() - : original_referrer; + if (secure_referrer_but_insecure_destination) + return GURL(); + return MaybeStripToOrigin(std::move(stripped_referrer), + should_strip_to_origin); case URLRequest::REDUCE_REFERRER_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN: - if (same_origin) { - return original_referrer; - } else if (secure_referrer_but_insecure_destination) { + if (secure_referrer_but_insecure_destination) return GURL(); - } else { - return referrer_origin.GetURL(); - } + if (!same_origin) + should_strip_to_origin = true; + return MaybeStripToOrigin(std::move(stripped_referrer), + should_strip_to_origin); case URLRequest::ORIGIN_ONLY_ON_TRANSITION_CROSS_ORIGIN: - return same_origin ? original_referrer : referrer_origin.GetURL(); + if (!same_origin) + should_strip_to_origin = true; + return MaybeStripToOrigin(std::move(stripped_referrer), + should_strip_to_origin); case URLRequest::NEVER_CLEAR_REFERRER: - return original_referrer; + return MaybeStripToOrigin(std::move(stripped_referrer), + should_strip_to_origin); + case URLRequest::ORIGIN: - return referrer_origin.GetURL(); + should_strip_to_origin = true; + return MaybeStripToOrigin(std::move(stripped_referrer), + should_strip_to_origin); + case URLRequest::CLEAR_REFERRER_ON_TRANSITION_CROSS_ORIGIN: - if (same_origin) - return original_referrer; - return GURL(); + if (!same_origin) + return GURL(); + return MaybeStripToOrigin(std::move(stripped_referrer), + should_strip_to_origin); + case URLRequest::ORIGIN_CLEAR_ON_TRANSITION_FROM_SECURE_TO_INSECURE: if (secure_referrer_but_insecure_destination) return GURL(); - return referrer_origin.GetURL(); + should_strip_to_origin = true; + return MaybeStripToOrigin(std::move(stripped_referrer), + should_strip_to_origin); + case URLRequest::NO_REFERRER: return GURL(); } @@ -333,8 +396,8 @@ void URLRequestJob::NotifySSLCertificateError(int net_error, request_->NotifySSLCertificateError(net_error, ssl_info, fatal); } -bool URLRequestJob::CanGetCookies(const CookieList& cookie_list) const { - return request_->CanGetCookies(cookie_list); +bool URLRequestJob::CanGetCookies() const { + return request_->CanGetCookies(); } bool URLRequestJob::CanSetCookie(const net::CanonicalCookie& cookie, diff --git a/chromium/net/url_request/url_request_job.h b/chromium/net/url_request/url_request_job.h index caabaeab232..e7b13cc3942 100644 --- a/chromium/net/url_request/url_request_job.h +++ b/chromium/net/url_request/url_request_job.h @@ -265,7 +265,7 @@ class NET_EXPORT URLRequestJob { bool fatal); // Delegates to URLRequest. - bool CanGetCookies(const CookieList& cookie_list) const; + bool CanGetCookies() const; // Delegates to URLRequest. bool CanSetCookie(const net::CanonicalCookie& cookie, diff --git a/chromium/net/url_request/url_request_job_unittest.cc b/chromium/net/url_request/url_request_job_unittest.cc index 4056dd8742c..4f6ed2d87b3 100644 --- a/chromium/net/url_request/url_request_job_unittest.cc +++ b/chromium/net/url_request/url_request_job_unittest.cc @@ -7,6 +7,8 @@ #include <memory> #include "base/run_loop.h" +#include "base/test/scoped_feature_list.h" +#include "net/base/features.h" #include "net/base/request_priority.h" #include "net/http/http_transaction_test_util.h" #include "net/test/cert_test_util.h" @@ -18,6 +20,7 @@ #include "net/url_request/url_request_test_util.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +#include "url/url_util.h" using net::test::IsError; using net::test::IsOk; @@ -658,4 +661,116 @@ TEST(URLRequestJobComputeReferrer, AcceptsNullptrInput) { GURL(), nullptr); } +TEST(URLRequestJobComputeReferrer, FilesystemDestination) { + EXPECT_EQ( + URLRequestJob::ComputeReferrerForPolicy( + URLRequest::NEVER_CLEAR_REFERRER, GURL("https://referrer.example"), + GURL("filesystem:https://destination.example"), nullptr), + GURL("https://referrer.example")); +} + +TEST(URLRequestJobComputeReferrer, TruncatesLongReferrer) { + std::string original_spec = "https://referrer.example/"; + original_spec.resize(4097, 'a'); + const GURL kOriginalReferrer(original_spec); + + EXPECT_EQ(URLRequestJob::ComputeReferrerForPolicy( + URLRequest::NEVER_CLEAR_REFERRER, kOriginalReferrer, + GURL("https://google.com")), + GURL("https://referrer.example/")); +} + +TEST(URLRequestJobComputeReferrer, DoesntTruncateShortReferrer) { + std::string original_spec = "https://referrer.example/"; + original_spec.resize(4096, 'a'); + const GURL kOriginalReferrer(original_spec); + + EXPECT_EQ(URLRequestJob::ComputeReferrerForPolicy( + URLRequest::NEVER_CLEAR_REFERRER, kOriginalReferrer, + GURL("https://google.com")), + kOriginalReferrer); +} + +TEST(URLRequestJobComputeReferrer, DoesntTruncateEvenShorterReferrer) { + std::string original_spec = "https://referrer.example/"; + original_spec.resize(4095, 'a'); + const GURL kOriginalReferrer(original_spec); + + EXPECT_EQ(URLRequestJob::ComputeReferrerForPolicy( + URLRequest::NEVER_CLEAR_REFERRER, kOriginalReferrer, + GURL("https://google.com")), + kOriginalReferrer); +} + +TEST(URLRequestJobComputeReferrer, DoesntTruncateReferrerWithLongRef) { + // Because the "is the length greater than 4096?" check comes *after* + // stripping the ref in the Referrer Policy spec, a URL that is short except + // for having a very long ref should not be stripped to an origin by the "if + // the length is too long, strip to the origin" check. + EXPECT_EQ(URLRequestJob::ComputeReferrerForPolicy( + URLRequest::NEVER_CLEAR_REFERRER, + GURL(std::string("https://referrer.example/path#") + + std::string(5000, 'a')), + GURL("https://google.com")), + GURL("https://referrer.example/path")); +} + +TEST(URLRequestJobComputeReferrer, InvalidSchemeReferrer) { + const GURL kOriginalReferrer("about:blank"); + ASSERT_FALSE(url::IsReferrerScheme( + kOriginalReferrer.spec().data(), + kOriginalReferrer.parsed_for_possibly_invalid_spec().scheme)); + + EXPECT_EQ(URLRequestJob::ComputeReferrerForPolicy( + URLRequest::NEVER_CLEAR_REFERRER, kOriginalReferrer, + GURL("https://google.com")), + GURL()); + + EXPECT_EQ( + URLRequestJob::ComputeReferrerForPolicy( + URLRequest::ORIGIN, kOriginalReferrer, GURL("https://google.com")), + GURL()); +} + +TEST(URLRequestJobComputeReferrer, CapReferrerOnCrossOrigin) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature( + features::kCapReferrerToOriginOnCrossOrigin); + + const GURL kOriginalReferrer("https://boggle.com/path"); + + EXPECT_EQ(URLRequestJob::ComputeReferrerForPolicy( + URLRequest::NEVER_CLEAR_REFERRER, kOriginalReferrer, + GURL("https://google.com")), + GURL("https://boggle.com/")); +} + +TEST(URLRequestJobComputeReferrer, + CapReferrerOnCrossOriginRespectsStricterPolicy) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature( + features::kCapReferrerToOriginOnCrossOrigin); + + const GURL kOriginalReferrer("https://boggle.com/path"); + + EXPECT_EQ(URLRequestJob::ComputeReferrerForPolicy(URLRequest::NO_REFERRER, + kOriginalReferrer, + GURL("https://google.com")), + GURL()); +} + +TEST(URLRequestJobComputeReferrer, + CapReferrerOnCrossOriginDoesntCapOnSameOrigin) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature( + features::kCapReferrerToOriginOnCrossOrigin); + + const GURL kOriginalReferrer("https://boggle.com/path"); + + EXPECT_EQ(URLRequestJob::ComputeReferrerForPolicy( + URLRequest::NEVER_CLEAR_REFERRER, kOriginalReferrer, + GURL("https://boggle.com")), + kOriginalReferrer); +} + } // namespace net diff --git a/chromium/net/url_request/url_request_netlog_params.cc b/chromium/net/url_request/url_request_netlog_params.cc index 2a88f066683..d6473f26e52 100644 --- a/chromium/net/url_request/url_request_netlog_params.cc +++ b/chromium/net/url_request/url_request_netlog_params.cc @@ -16,6 +16,22 @@ namespace net { +namespace { + +std::string PrivacyModeDebugString(PrivacyMode privacy_mode) { + switch (privacy_mode) { + case PRIVACY_MODE_DISABLED: + return "disabled"; + case PRIVACY_MODE_ENABLED: + return "enabled"; + case PRIVACY_MODE_ENABLED_WITHOUT_CLIENT_CERTS: + return "enabled without client certs"; + } + return ""; +} + +} // namespace + base::Value NetLogURLRequestConstructorParams( const GURL& url, RequestPriority priority, @@ -40,7 +56,7 @@ base::Value NetLogURLRequestStartParams( dict.SetStringKey("url", url.possibly_invalid_spec()); dict.SetStringKey("method", method); dict.SetIntKey("load_flags", load_flags); - dict.SetIntKey("privacy_mode", privacy_mode == PRIVACY_MODE_ENABLED); + dict.SetStringKey("privacy_mode", PrivacyModeDebugString(privacy_mode)); dict.SetStringKey("network_isolation_key", network_isolation_key.ToDebugString()); dict.SetStringKey("site_for_cookies", site_for_cookies.ToDebugString()); diff --git a/chromium/net/url_request/url_request_quic_unittest.cc b/chromium/net/url_request/url_request_quic_unittest.cc index c282944895a..3860e68196d 100644 --- a/chromium/net/url_request/url_request_quic_unittest.cc +++ b/chromium/net/url_request/url_request_quic_unittest.cc @@ -11,11 +11,15 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" #include "base/test/bind_test_util.h" +#include "base/test/scoped_feature_list.h" #include "build/build_config.h" #include "net/base/features.h" #include "net/base/isolation_info.h" #include "net/base/load_timing_info.h" #include "net/base/network_delegate.h" +#include "net/base/network_isolation_key.h" +#include "net/cert/ct_policy_enforcer.h" +#include "net/cert/ct_policy_status.h" #include "net/cert/mock_cert_verifier.h" #include "net/dns/mapped_host_resolver.h" #include "net/dns/mock_host_resolver.h" @@ -64,6 +68,53 @@ const char kIndexPath[] = "/index2.html"; const char kIndexBodyValue[] = "Hello from QUIC Server"; const int kIndexStatus = 200; +class MockCTPolicyEnforcerNonCompliant : public CTPolicyEnforcer { + public: + MockCTPolicyEnforcerNonCompliant() = default; + ~MockCTPolicyEnforcerNonCompliant() override = default; + + ct::CTPolicyCompliance CheckCompliance( + X509Certificate* cert, + const ct::SCTList& verified_scts, + const NetLogWithSource& net_log) override { + return ct::CTPolicyCompliance::CT_POLICY_NOT_DIVERSE_SCTS; + } +}; + +// An ExpectCTReporter that records the number of times OnExpectCTFailed() was +// called. +class MockExpectCTReporter : public TransportSecurityState::ExpectCTReporter { + public: + MockExpectCTReporter() = default; + ~MockExpectCTReporter() override = default; + + void OnExpectCTFailed( + const HostPortPair& host_port_pair, + const GURL& report_uri, + base::Time expiration, + const X509Certificate* validated_certificate_chain, + const X509Certificate* served_certificate_chain, + const SignedCertificateTimestampAndStatusList& + signed_certificate_timestamps, + const NetworkIsolationKey& network_isolation_key) override { + num_failures_++; + report_uri_ = report_uri; + network_isolation_key_ = network_isolation_key; + } + + int num_failures() const { return num_failures_; } + const GURL& report_uri() const { return report_uri_; } + const NetworkIsolationKey& network_isolation_key() const { + return network_isolation_key_; + } + + private: + int num_failures_ = 0; + + GURL report_uri_; + NetworkIsolationKey network_isolation_key_; +}; + class URLRequestQuicTest : public TestWithTaskEnvironment, public ::testing::WithParamInterface<quic::ParsedQuicVersion> { @@ -78,8 +129,7 @@ class URLRequestQuicTest verify_result.verified_cert = ImportCertFromFile( GetTestCertsDirectory(), "quic-chain.pem"); cert_verifier_.AddResultForCertAndHost(verify_result.verified_cert.get(), - "test.example.com", verify_result, - OK); + kTestServerHost, verify_result, OK); // To simplify the test, and avoid the race with the HTTP request, we force // QUIC for these requests. context_->set_quic_context(&quic_context_); @@ -92,6 +142,8 @@ class URLRequestQuicTest context_->set_http_network_session_params(std::move(params)); context_->set_cert_verifier(&cert_verifier_); context_->set_net_log(&net_log_); + transport_security_state_.SetExpectCTReporter(&expect_ct_reporter_); + context_->set_transport_security_state(&transport_security_state_); } void TearDown() override { @@ -108,6 +160,10 @@ class URLRequestQuicTest context_->set_network_delegate(network_delegate); } + // Can be used to modify |context_|. Only safe to modify before Init() is + // called. + TestURLRequestContext* context() { return context_.get(); } + // Initializes the TestURLRequestContext |context_|. void Init() { context_->Init(); } @@ -155,6 +211,12 @@ class URLRequestQuicTest quic::ParsedQuicVersion version() { return GetParam(); } + MockExpectCTReporter* expect_ct_reporter() { return &expect_ct_reporter_; } + + TransportSecurityState* transport_security_state() { + return &transport_security_state_; + } + protected: // Returns a fully-qualified URL for |path| on the test server. std::string UrlFromPath(base::StringPiece path) { @@ -219,6 +281,9 @@ class URLRequestQuicTest return path.MaybeAsASCII(); } + MockExpectCTReporter expect_ct_reporter_; + TransportSecurityState transport_security_state_; + std::unique_ptr<MappedHostResolver> host_resolver_; std::unique_ptr<QuicSimpleServer> server_; std::unique_ptr<TestURLRequestContext> context_; @@ -513,9 +578,10 @@ TEST_P(URLRequestQuicTest, CancelPushIfCached_AllCached) { EXPECT_FALSE(end_entry_2->HasParams()); EXPECT_FALSE(GetOptionalNetErrorCodeFromParams(*end_entry_2)); -#if !defined(OS_FUCHSIA) && !defined(OS_IOS) +#if !defined(OS_FUCHSIA) && !defined(OS_IOS) && !defined(OS_MACOSX) // TODO(crbug.com/813631): Make this work on Fuchsia. // TODO(crbug.com/1032568): Make this work on iOS. + // TODO(crbug.com/1087378): Flaky on Mac. // Verify the reset error count received on the server side. EXPECT_LE(2u, GetRstErrorCountReceivedByServer(quic::QUIC_STREAM_CANCELLED)); #endif @@ -636,4 +702,42 @@ TEST_P(URLRequestQuicTest, RequestHeadersCallback) { EXPECT_EQ(OK, delegate.request_status()); } +// Tests that if there's an Expect-CT failure at the QUIC layer, a report is +// generated. +TEST_P(URLRequestQuicTest, ExpectCT) { + TransportSecurityState::SetRequireCTForTesting(true); + base::test::ScopedFeatureList feature_list; + feature_list.InitWithFeatures( + // enabled_features + {features::kPartitionConnectionsByNetworkIsolationKey, + features::kPartitionHttpServerPropertiesByNetworkIsolationKey, + features::kPartitionSSLSessionsByNetworkIsolationKey}, + // disabled_features + {}); + + MockCTPolicyEnforcerNonCompliant ct_enforcer; + context()->set_ct_policy_enforcer(&ct_enforcer); + Init(); + + GURL report_uri("https://report.test/"); + IsolationInfo isolation_info = IsolationInfo::CreateTransient(); + transport_security_state()->AddExpectCT( + kTestServerHost, base::Time::Now() + base::TimeDelta::FromDays(1), + true /* enforce */, report_uri, isolation_info.network_isolation_key()); + + base::RunLoop run_loop; + TestDelegate delegate; + std::unique_ptr<URLRequest> request = + CreateRequest(GURL(UrlFromPath(kHelloPath)), DEFAULT_PRIORITY, &delegate); + request->set_isolation_info(isolation_info); + request->Start(); + delegate.RunUntilComplete(); + + EXPECT_EQ(ERR_QUIC_PROTOCOL_ERROR, delegate.request_status()); + ASSERT_EQ(1, expect_ct_reporter()->num_failures()); + EXPECT_EQ(report_uri, expect_ct_reporter()->report_uri()); + EXPECT_EQ(isolation_info.network_isolation_key(), + expect_ct_reporter()->network_isolation_key()); +} + } // namespace net diff --git a/chromium/net/url_request/url_request_test_util.cc b/chromium/net/url_request/url_request_test_util.cc index 702f6a8d0de..b06d7924f46 100644 --- a/chromium/net/url_request/url_request_test_util.cc +++ b/chromium/net/url_request/url_request_test_util.cc @@ -594,7 +594,6 @@ void TestNetworkDelegate::OnPACScriptError(int line_number, } bool TestNetworkDelegate::OnCanGetCookies(const URLRequest& request, - const CookieList& cookie_list, bool allowed_from_caller) { bool allow = allowed_from_caller; if (cookie_options_bit_mask_ & NO_GET_COOKIES) diff --git a/chromium/net/url_request/url_request_test_util.h b/chromium/net/url_request/url_request_test_util.h index 064be87739f..5d6da89e066 100644 --- a/chromium/net/url_request/url_request_test_util.h +++ b/chromium/net/url_request/url_request_test_util.h @@ -342,7 +342,6 @@ class TestNetworkDelegate : public NetworkDelegateImpl { void OnURLRequestDestroyed(URLRequest* request) override; void OnPACScriptError(int line_number, const base::string16& error) override; bool OnCanGetCookies(const URLRequest& request, - const CookieList& cookie_list, bool allowed_from_caller) override; bool OnCanSetCookie(const URLRequest& request, const net::CanonicalCookie& cookie, diff --git a/chromium/net/url_request/url_request_unittest.cc b/chromium/net/url_request/url_request_unittest.cc index c9d24bfe0a3..e2ef3cadd5e 100644 --- a/chromium/net/url_request/url_request_unittest.cc +++ b/chromium/net/url_request/url_request_unittest.cc @@ -84,6 +84,7 @@ #include "net/cert/x509_util.h" #include "net/cert_net/cert_net_fetcher_url_request.h" #include "net/cookies/canonical_cookie_test_helpers.h" +#include "net/cookies/cookie_inclusion_status.h" #include "net/cookies/cookie_monster.h" #include "net/cookies/cookie_store_test_helpers.h" #include "net/cookies/test_cookie_access_delegate.h" @@ -115,6 +116,7 @@ #include "net/ssl/ssl_server_config.h" #include "net/ssl/test_ssl_config_service.h" #include "net/test/cert_test_util.h" +#include "net/test/embedded_test_server/default_handlers.h" #include "net/test/embedded_test_server/embedded_test_server.h" #include "net/test/embedded_test_server/embedded_test_server_connection_listener.h" #include "net/test/embedded_test_server/http_request.h" @@ -161,6 +163,7 @@ using net::test::IsError; using net::test::IsOk; +using net::test_server::RegisterDefaultHandlers; using testing::AnyOf; using base::ASCIIToUTF16; @@ -324,7 +327,7 @@ class HttpTestServer : public EmbeddedTestServer { AddDefaultHandlers(document_root); } - HttpTestServer() { AddDefaultHandlers(base::FilePath()); } + HttpTestServer() { RegisterDefaultHandlers(this); } }; // Job that allows monitoring of its priority. @@ -1569,7 +1572,6 @@ class FilteringTestNetworkDelegate : public TestNetworkDelegate { void ResetBlockedSetCookieCount() { blocked_set_cookie_count_ = 0; } bool OnCanGetCookies(const URLRequest& request, - const net::CookieList& cookie_list, bool allowed_from_caller) override { // Filter out cookies if |block_get_cookies_| is set and // combine with |allowed_from_caller|. @@ -1580,7 +1582,7 @@ class FilteringTestNetworkDelegate : public TestNetworkDelegate { if (!allowed) ++blocked_get_cookie_count_; - return TestNetworkDelegate::OnCanGetCookies(request, cookie_list, allowed); + return TestNetworkDelegate::OnCanGetCookies(request, allowed); } void set_block_get_cookies() { block_get_cookies_ = true; } @@ -2398,10 +2400,10 @@ TEST_F(URLRequestTest, SameSiteCookiesSpecialScheme) { url::AddStandardScheme("chrome", url::SchemeType::SCHEME_WITH_HOST); EmbeddedTestServer https_test_server(EmbeddedTestServer::TYPE_HTTPS); - https_test_server.AddDefaultHandlers(base::FilePath()); + RegisterDefaultHandlers(&https_test_server); ASSERT_TRUE(https_test_server.Start()); EmbeddedTestServer http_test_server(EmbeddedTestServer::TYPE_HTTP); - http_test_server.AddDefaultHandlers(base::FilePath()); + RegisterDefaultHandlers(&http_test_server); // Ensure they are on different ports. ASSERT_TRUE(http_test_server.Start(https_test_server.port() + 1)); // Both hostnames should be 127.0.0.1 (so that we can use the same set of @@ -2488,11 +2490,9 @@ TEST_F(URLRequestTest, SameSiteCookiesSpecialScheme) { // Tests that __Secure- cookies can't be set on non-secure origins. TEST_F(URLRequestTest, SecureCookiePrefixOnNonsecureOrigin) { EmbeddedTestServer http_server; - http_server.AddDefaultHandlers( - base::FilePath(FILE_PATH_LITERAL("net/data/ssl"))); + RegisterDefaultHandlers(&http_server); EmbeddedTestServer https_server(EmbeddedTestServer::TYPE_HTTPS); - https_server.AddDefaultHandlers( - base::FilePath(FILE_PATH_LITERAL("net/data/ssl"))); + RegisterDefaultHandlers(&https_server); ASSERT_TRUE(http_server.Start()); ASSERT_TRUE(https_server.Start()); @@ -2531,8 +2531,7 @@ TEST_F(URLRequestTest, SecureCookiePrefixOnNonsecureOrigin) { TEST_F(URLRequestTest, SecureCookiePrefixNonsecure) { EmbeddedTestServer https_server(EmbeddedTestServer::TYPE_HTTPS); - https_server.AddDefaultHandlers( - base::FilePath(FILE_PATH_LITERAL("net/data/ssl"))); + RegisterDefaultHandlers(&https_server); ASSERT_TRUE(https_server.Start()); TestNetworkDelegate network_delegate; @@ -2570,8 +2569,7 @@ TEST_F(URLRequestTest, SecureCookiePrefixNonsecure) { TEST_F(URLRequestTest, SecureCookiePrefixSecure) { EmbeddedTestServer https_server(EmbeddedTestServer::TYPE_HTTPS); - https_server.AddDefaultHandlers( - base::FilePath(FILE_PATH_LITERAL("net/data/ssl"))); + RegisterDefaultHandlers(&https_server); ASSERT_TRUE(https_server.Start()); TestNetworkDelegate network_delegate; @@ -2610,11 +2608,9 @@ TEST_F(URLRequestTest, SecureCookiePrefixSecure) { // cookies are enabled. TEST_F(URLRequestTest, StrictSecureCookiesOnNonsecureOrigin) { EmbeddedTestServer http_server; - http_server.AddDefaultHandlers( - base::FilePath(FILE_PATH_LITERAL("net/data/ssl"))); + RegisterDefaultHandlers(&http_server); EmbeddedTestServer https_server(EmbeddedTestServer::TYPE_HTTPS); - https_server.AddDefaultHandlers( - base::FilePath(FILE_PATH_LITERAL("net/data/ssl"))); + RegisterDefaultHandlers(&https_server); ASSERT_TRUE(http_server.Start()); ASSERT_TRUE(https_server.Start()); @@ -3728,76 +3724,132 @@ TEST_F(URLRequestTestHTTP, GetTestLoadTiming) { } } -// TODO(svaldez): Update tests to use EmbeddedTestServer. -#if !defined(OS_IOS) -TEST_F(URLRequestTestHTTP, GetZippedTest) { - SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTP, - base::FilePath(kTestFilePath)); +namespace { - ASSERT_TRUE(test_server.Start()); +// Sends the correct Content-Length matching the compressed length. +const char kZippedContentLengthCompressed[] = "C"; +// Sends an incorrect Content-Length matching the uncompressed length. +const char kZippedContentLengthUncompressed[] = "U"; +// Sends an incorrect Content-Length shorter than the compressed length. +const char kZippedContentLengthShort[] = "S"; +// Sends an incorrect Content-Length between the compressed and uncompressed +// lengths. +const char kZippedContentLengthMedium[] = "M"; +// Sends an incorrect Content-Length larger than both compressed and +// uncompressed lengths. +const char kZippedContentLengthLong[] = "L"; + +// Sends |compressed_content| which, when decoded with deflate, should have +// length |uncompressed_length|. The Content-Length header will be sent based on +// which of the constants above is sent in the query string. +std::unique_ptr<test_server::HttpResponse> HandleZippedRequest( + const std::string& compressed_content, + size_t uncompressed_length, + const test_server::HttpRequest& request) { + GURL url = request.GetURL(); + if (url.path_piece() != "/compressedfiles/BullRunSpeech.txt") + return nullptr; - // Parameter that specifies the Content-Length field in the response: - // C - Compressed length. - // U - Uncompressed length. - // L - Large length (larger than both C & U). - // M - Medium length (between C & U). - // S - Small length (smaller than both C & U). - const char test_parameters[] = "CULMS"; - const int num_tests = base::size(test_parameters) - 1; // Skip NULL. - // C & U should be OK. - // L & M are larger than the data sent, and show an error. - // S has too little data, but we seem to accept it. - const bool test_expect_success[num_tests] = - { true, true, false, false, true }; + size_t length; + if (url.query_piece() == kZippedContentLengthCompressed) { + length = compressed_content.size(); + } else if (url.query_piece() == kZippedContentLengthUncompressed) { + length = uncompressed_length; + } else if (url.query_piece() == kZippedContentLengthShort) { + length = compressed_content.size() / 2; + } else if (url.query_piece() == kZippedContentLengthMedium) { + length = (compressed_content.size() + uncompressed_length) / 2; + } else if (url.query_piece() == kZippedContentLengthLong) { + length = compressed_content.size() + uncompressed_length; + } else { + return nullptr; + } + + std::string headers = "HTTP/1.1 200 OK\r\n"; + headers += "Content-Encoding: deflate\r\n"; + base::StringAppendF(&headers, "Content-Length: %zu\r\n", length); + return std::make_unique<test_server::RawHttpResponse>(headers, + compressed_content); +} +} // namespace + +TEST_F(URLRequestTestHTTP, GetZippedTest) { base::FilePath file_path; base::PathService::Get(base::DIR_SOURCE_ROOT, &file_path); file_path = file_path.Append(kTestFilePath); - file_path = file_path.Append(FILE_PATH_LITERAL("BullRunSpeech.txt")); - std::string expected_content; - ASSERT_TRUE(base::ReadFileToString(file_path, &expected_content)); + std::string expected_content, compressed_content; + ASSERT_TRUE(base::ReadFileToString( + file_path.Append(FILE_PATH_LITERAL("BullRunSpeech.txt")), + &expected_content)); + // This file is the output of the Python zlib.compress function on + // |expected_content|. + ASSERT_TRUE(base::ReadFileToString( + file_path.Append(FILE_PATH_LITERAL("BullRunSpeech.txt.deflate")), + &compressed_content)); + + http_test_server()->RegisterRequestHandler(base::BindRepeating( + &HandleZippedRequest, compressed_content, expected_content.size())); + ASSERT_TRUE(http_test_server()->Start()); + + static const struct { + const char* parameter; + bool expect_success; + } kTests[] = { + // Sending the compressed Content-Length is correct. + {kZippedContentLengthCompressed, true}, + // Sending the uncompressed Content-Length is incorrect, but we accept it + // to workaround some broken servers. + {kZippedContentLengthUncompressed, true}, + // Sending too long of Content-Length is rejected. + {kZippedContentLengthLong, false}, + {kZippedContentLengthMedium, false}, + // Sending too short of Content-Length successfully fetches a response + // body, but it will be truncated. + {kZippedContentLengthShort, true}, + }; - for (int i = 0; i < num_tests; i++) { + for (const auto& test : kTests) { + SCOPED_TRACE(test.parameter); TestDelegate d; - { - std::string test_file = base::StringPrintf( - "compressedfiles/BullRunSpeech.txt?%c", test_parameters[i]); + std::string test_file = base::StringPrintf( + "/compressedfiles/BullRunSpeech.txt?%s", test.parameter); - TestNetworkDelegate network_delegate; // Must outlive URLRequest. - TestURLRequestContext context(true); - context.set_network_delegate(&network_delegate); - context.Init(); + TestNetworkDelegate network_delegate; // Must outlive URLRequest. + TestURLRequestContext context(true); + context.set_network_delegate(&network_delegate); + context.Init(); - std::unique_ptr<URLRequest> r( - context.CreateRequest(test_server.GetURL(test_file), DEFAULT_PRIORITY, - &d, TRAFFIC_ANNOTATION_FOR_TESTS)); - r->Start(); - EXPECT_TRUE(r->is_pending()); + std::unique_ptr<URLRequest> r(context.CreateRequest( + http_test_server()->GetURL(test_file), DEFAULT_PRIORITY, &d, + TRAFFIC_ANNOTATION_FOR_TESTS)); + r->Start(); + EXPECT_TRUE(r->is_pending()); - d.RunUntilComplete(); + d.RunUntilComplete(); - EXPECT_EQ(1, d.response_started_count()); - EXPECT_FALSE(d.received_data_before_response()); - VLOG(1) << " Received " << d.bytes_received() << " bytes" - << " error = " << d.request_status(); - if (test_expect_success[i]) { - EXPECT_EQ(OK, d.request_status()) << " Parameter = \"" << test_file - << "\""; - if (test_parameters[i] == 'S') { - // When content length is smaller than both compressed length and - // uncompressed length, HttpStreamParser might not read the full - // response body. - continue; - } - EXPECT_EQ(expected_content, d.data_received()); + EXPECT_EQ(1, d.response_started_count()); + EXPECT_FALSE(d.received_data_before_response()); + VLOG(1) << " Received " << d.bytes_received() << " bytes" + << " error = " << d.request_status(); + if (test.expect_success) { + EXPECT_EQ(OK, d.request_status()) + << " Parameter = \"" << test_file << "\""; + if (strcmp(test.parameter, kZippedContentLengthShort) == 0) { + // When content length is smaller than both compressed length and + // uncompressed length, HttpStreamParser might not read the full + // response body. + EXPECT_EQ(expected_content.substr(0, d.data_received().size()), + d.data_received()); } else { - EXPECT_EQ(ERR_CONTENT_LENGTH_MISMATCH, d.request_status()) - << " Parameter = \"" << test_file << "\""; + EXPECT_EQ(expected_content, d.data_received()); } + } else { + EXPECT_EQ(ERR_CONTENT_LENGTH_MISMATCH, d.request_status()) + << " Parameter = \"" << test_file << "\""; } } } -#endif // !defined(OS_IOS) TEST_F(URLRequestTestHTTP, RedirectLoadTiming) { ASSERT_TRUE(http_test_server()->Start()); @@ -4997,8 +5049,8 @@ TEST_F(URLRequestTestHTTP, ProcessSTS) { default_context().transport_security_state(); TransportSecurityState::STSState sts_state; TransportSecurityState::PKPState pkp_state; - EXPECT_TRUE(security_state->GetDynamicSTSState(test_server_hostname, - &sts_state, nullptr)); + EXPECT_TRUE( + security_state->GetDynamicSTSState(test_server_hostname, &sts_state)); EXPECT_FALSE( security_state->GetDynamicPKPState(test_server_hostname, &pkp_state)); EXPECT_EQ(TransportSecurityState::STSState::MODE_FORCE_HTTPS, @@ -5031,8 +5083,8 @@ TEST_F(URLRequestTestHTTP, STSNotProcessedOnIP) { TransportSecurityState* security_state = default_context().transport_security_state(); TransportSecurityState::STSState sts_state; - EXPECT_FALSE(security_state->GetDynamicSTSState(test_server_hostname, - &sts_state, nullptr)); + EXPECT_FALSE( + security_state->GetDynamicSTSState(test_server_hostname, &sts_state)); } namespace { @@ -5245,8 +5297,8 @@ TEST_F(URLRequestTestHTTP, ProcessSTSOnce) { TransportSecurityState* security_state = default_context().transport_security_state(); TransportSecurityState::STSState sts_state; - EXPECT_TRUE(security_state->GetDynamicSTSState(test_server_hostname, - &sts_state, nullptr)); + EXPECT_TRUE( + security_state->GetDynamicSTSState(test_server_hostname, &sts_state)); EXPECT_EQ(TransportSecurityState::STSState::MODE_FORCE_HTTPS, sts_state.upgrade_mode); EXPECT_FALSE(sts_state.include_subdomains); @@ -5260,13 +5312,15 @@ class MockExpectCTReporter : public TransportSecurityState::ExpectCTReporter { MockExpectCTReporter() : num_failures_(0) {} ~MockExpectCTReporter() override = default; - void OnExpectCTFailed(const HostPortPair& host_port_pair, - const GURL& report_uri, - base::Time expiration, - const X509Certificate* validated_certificate_chain, - const X509Certificate* served_certificate_chain, - const SignedCertificateTimestampAndStatusList& - signed_certificate_timestamps) override { + void OnExpectCTFailed( + const HostPortPair& host_port_pair, + const GURL& report_uri, + base::Time expiration, + const X509Certificate* validated_certificate_chain, + const X509Certificate* served_certificate_chain, + const SignedCertificateTimestampAndStatusList& + signed_certificate_timestamps, + const NetworkIsolationKey& network_isolation_key) override { num_failures_++; } @@ -5414,8 +5468,8 @@ TEST_F(URLRequestTestHTTP, ExpectCTHeader) { d.RunUntilComplete(); TransportSecurityState::ExpectCTState state; - ASSERT_TRUE( - transport_security_state.GetDynamicExpectCTState(url.host(), &state)); + ASSERT_TRUE(transport_security_state.GetDynamicExpectCTState( + url.host(), NetworkIsolationKey(), &state)); EXPECT_TRUE(state.enforce); EXPECT_EQ(GURL("https://example.test"), state.report_uri); } @@ -5476,8 +5530,8 @@ TEST_F(URLRequestTestHTTP, MultipleExpectCTHeaders) { d.RunUntilComplete(); TransportSecurityState::ExpectCTState state; - ASSERT_TRUE( - transport_security_state.GetDynamicExpectCTState(url.host(), &state)); + ASSERT_TRUE(transport_security_state.GetDynamicExpectCTState( + url.host(), NetworkIsolationKey(), &state)); EXPECT_TRUE(state.enforce); EXPECT_EQ(GURL("https://example.test"), state.report_uri); } @@ -5488,7 +5542,7 @@ TEST_F(URLRequestTestHTTP, MultipleExpectCTHeaders) { TEST_F(URLRequestTestHTTP, NetworkErrorLogging_DontReportIfNetworkNotAccessed) { EmbeddedTestServer https_test_server(net::EmbeddedTestServer::TYPE_HTTPS); - https_test_server.AddDefaultHandlers(base::FilePath(kTestFilePath)); + RegisterDefaultHandlers(&https_test_server); ASSERT_TRUE(https_test_server.Start()); GURL request_url = https_test_server.GetURL("/cachetime"); @@ -5552,7 +5606,7 @@ TEST_F(URLRequestTestHTTP, NetworkErrorLogging_BasicSuccess) { TEST_F(URLRequestTestHTTP, NetworkErrorLogging_BasicError) { EmbeddedTestServer https_test_server(net::EmbeddedTestServer::TYPE_HTTPS); - https_test_server.AddDefaultHandlers(base::FilePath(kTestFilePath)); + RegisterDefaultHandlers(&https_test_server); ASSERT_TRUE(https_test_server.Start()); GURL request_url = https_test_server.GetURL("/close-socket"); @@ -5636,7 +5690,7 @@ TEST_F(URLRequestTestHTTP, NetworkErrorLogging_RedirectWithoutLocationHeader) { TEST_F(URLRequestTestHTTP, NetworkErrorLogging_Auth) { EmbeddedTestServer https_test_server(net::EmbeddedTestServer::TYPE_HTTPS); - https_test_server.AddDefaultHandlers(base::FilePath(kTestFilePath)); + RegisterDefaultHandlers(&https_test_server); ASSERT_TRUE(https_test_server.Start()); GURL request_url = https_test_server.GetURL("/auth-basic"); @@ -5667,7 +5721,7 @@ TEST_F(URLRequestTestHTTP, NetworkErrorLogging_Auth) { TEST_F(URLRequestTestHTTP, NetworkErrorLogging_304Response) { EmbeddedTestServer https_test_server(net::EmbeddedTestServer::TYPE_HTTPS); - https_test_server.AddDefaultHandlers(base::FilePath(kTestFilePath)); + RegisterDefaultHandlers(&https_test_server); ASSERT_TRUE(https_test_server.Start()); GURL request_url = https_test_server.GetURL("/auth-basic"); @@ -6127,7 +6181,12 @@ TEST_F(URLRequestTestHTTP, CapRefererHeaderLength) { req->Start(); d.RunUntilComplete(); - EXPECT_EQ("http://example.com/", d.data_received()); + // The request's referrer will be stripped since (1) there will be a + // mismatch between the request's referrer and the output of + // URLRequestJob::ComputeReferrerForPolicy and (2) the delegate, when + // offered the opportunity to cancel the request for this reason, will + // decline. + EXPECT_EQ("None", d.data_received()); } { std::string original_header = "http://example.com/"; @@ -6729,8 +6788,7 @@ TEST_F(URLRequestTest, ReportCookieActivity) { req->maybe_stored_cookies()[0].cookie->Name()); EXPECT_TRUE(req->maybe_stored_cookies()[0] .status.HasExactlyExclusionReasonsForTesting( - {net::CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_USER_PREFERENCES})); + {CookieInclusionStatus::EXCLUDE_USER_PREFERENCES})); EXPECT_EQ("stored_cookie", req->maybe_stored_cookies()[1].cookie->Name()); EXPECT_TRUE(req->maybe_stored_cookies()[1].status.IsInclude()); EXPECT_EQ("stored_cookie", req->maybe_stored_cookies()[1].cookie->Name()); @@ -6769,17 +6827,16 @@ TEST_F(URLRequestTest, ReportCookieActivity) { ASSERT_EQ(2u, req->maybe_sent_cookies().size()); EXPECT_EQ("path_cookie", req->maybe_sent_cookies()[0].cookie.Name()); - EXPECT_TRUE(req->maybe_sent_cookies()[0] - .status.HasExactlyExclusionReasonsForTesting( - {net::CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_NOT_ON_PATH, - net::CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_USER_PREFERENCES})); + EXPECT_TRUE( + req->maybe_sent_cookies()[0] + .access_result.status.HasExactlyExclusionReasonsForTesting( + {net::CookieInclusionStatus::EXCLUDE_NOT_ON_PATH, + net::CookieInclusionStatus::EXCLUDE_USER_PREFERENCES})); EXPECT_EQ("stored_cookie", req->maybe_sent_cookies()[1].cookie.Name()); - EXPECT_TRUE(req->maybe_sent_cookies()[1] - .status.HasExactlyExclusionReasonsForTesting( - {net::CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_USER_PREFERENCES})); + EXPECT_TRUE( + req->maybe_sent_cookies()[1] + .access_result.status.HasExactlyExclusionReasonsForTesting( + {net::CookieInclusionStatus::EXCLUDE_USER_PREFERENCES})); auto entries = net_log.GetEntriesWithType(NetLogEventType::COOKIE_INCLUSION_STATUS); EXPECT_EQ(2u, entries.size()); @@ -6842,11 +6899,10 @@ TEST_F(URLRequestTest, ReportCookieActivity) { ASSERT_EQ(2u, req->maybe_sent_cookies().size()); EXPECT_EQ("path_cookie", req->maybe_sent_cookies()[0].cookie.Name()); EXPECT_TRUE(req->maybe_sent_cookies()[0] - .status.HasExactlyExclusionReasonsForTesting( - {net::CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_NOT_ON_PATH})); + .access_result.status.HasExactlyExclusionReasonsForTesting( + {net::CookieInclusionStatus::EXCLUDE_NOT_ON_PATH})); EXPECT_EQ("stored_cookie", req->maybe_sent_cookies()[1].cookie.Name()); - EXPECT_TRUE(req->maybe_sent_cookies()[1].status.IsInclude()); + EXPECT_TRUE(req->maybe_sent_cookies()[1].access_result.status.IsInclude()); auto entries = net_log.GetEntriesWithType(NetLogEventType::COOKIE_INCLUSION_STATUS); EXPECT_EQ(2u, entries.size()); @@ -6863,6 +6919,200 @@ TEST_F(URLRequestTest, ReportCookieActivity) { } } +// Test that CookieInclusionStatus warnings for SameSite cookie compatibility +// pairs are applied correctly. +TEST_F(URLRequestTest, SameSiteCookieCompatPairWarnings) { + EmbeddedTestServer https_test_server(EmbeddedTestServer::TYPE_HTTPS); + RegisterDefaultHandlers(&https_test_server); + ASSERT_TRUE(https_test_server.Start()); + + GURL set_pair_url = https_test_server.GetURL( + "/set-cookie?name=value;SameSite=None;Secure&" + "name_legacy=value"); + GURL set_httponly_pair_url = https_test_server.GetURL( + "/set-cookie?name=value;SameSite=None;Secure;HttpOnly&" + "name_legacy=value;HttpOnly"); + GURL set_pair_and_other_url = https_test_server.GetURL( + "/set-cookie?name=value;SameSite=None;Secure&" + "name_legacy=value&" + "name2=value;SameSite=None;Secure"); + GURL set_two_pairs_url = https_test_server.GetURL( + "/set-cookie?name=value;SameSite=None;Secure&" + "name_legacy=value&" + "name2=value;SameSite=None;Secure&" + "compat-name2=value"); + GURL get_cookies_url = https_test_server.GetURL("/echoheader?Cookie"); + + struct TestCase { + // URL used to set cookies. + // Note: This test works because each URL uses a superset of the cookies + // used by URLs before it. + GURL set_cookies_url; + // Names of cookies and whether they are expected to be included for a + // cross-site get/set. (All are expected for a same-site request.) + std::map<std::string, bool> expected_cookies; + // Names of cookies expected to have a compat pair warning for a cross-site + // request. + std::set<std::string> expected_compat_warning_cookies; + // Whether all cookies should be HttpOnly. + bool expected_httponly = false; + } kTestCases[] = { + // Basic case with a single compat pair. + {set_pair_url, + {{"name", true}, {"name_legacy", false}}, + {"name", "name_legacy"}}, + // Compat pair with HttpOnly cookies (should not change behavior because + // this is an HTTP request). + {set_httponly_pair_url, + {{"name", true}, {"name_legacy", false}}, + {"name", "name_legacy"}, + true}, + // Pair should be marked, but extra cookie (not part of a pair) should + // not. + {set_pair_and_other_url, + {{"name", true}, {"name_legacy", false}, {"name2", true}}, + {"name", "name_legacy"}}, + // Two separate pairs should all be marked. + {set_two_pairs_url, + {{"name", true}, + {"name_legacy", false}, + {"name2", true}, + {"compat-name2", false}}, + {"name", "name_legacy", "name2", "compat-name2"}}}; + + // For each test case, this exercises: + // 1. Set cookies in a cross-site context to trigger compat pair warnings. + // 2. Set cookies in a same-site context and check that no compat pair + // warnings are applied (and also make sure the cookies are actually + // present for the subsequent tests). + // 3. Get cookies in a same-site context and check that no compat pair + // warnings are applied. + // 4. Get cookies in a cross-site context to trigger compat pair warnings. + for (const auto& test : kTestCases) { + { + // Set cookies in a cross-site context. + TestDelegate d; + std::unique_ptr<URLRequest> req(default_context().CreateRequest( + test.set_cookies_url, DEFAULT_PRIORITY, &d, + TRAFFIC_ANNOTATION_FOR_TESTS)); + req->Start(); + d.RunUntilComplete(); + + ASSERT_EQ(test.expected_cookies.size(), + req->maybe_stored_cookies().size()); + for (const auto& cookie : req->maybe_stored_cookies()) { + ASSERT_TRUE(cookie.cookie.has_value()); + EXPECT_EQ(cookie.cookie->IsHttpOnly(), test.expected_httponly); + + const std::string& cookie_name = cookie.cookie->Name(); + auto it = test.expected_cookies.find(cookie_name); + ASSERT_NE(test.expected_cookies.end(), it); + bool included = cookie.status.IsInclude(); + EXPECT_EQ(it->second, included); + + std::vector<CookieInclusionStatus::ExclusionReason> exclusions; + std::vector<CookieInclusionStatus::WarningReason> warnings; + if (!included) { + exclusions.push_back(CookieInclusionStatus:: + EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX); + warnings.push_back(CookieInclusionStatus:: + WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT); + } + if (base::Contains(test.expected_compat_warning_cookies, cookie_name)) { + warnings.push_back(CookieInclusionStatus::WARN_SAMESITE_COMPAT_PAIR); + } + EXPECT_TRUE( + cookie.status.HasExactlyExclusionReasonsForTesting(exclusions)); + EXPECT_TRUE(cookie.status.HasExactlyWarningReasonsForTesting(warnings)); + } + } + { + // Set cookies in a same-site context. + TestDelegate d; + std::unique_ptr<URLRequest> req(default_context().CreateFirstPartyRequest( + test.set_cookies_url, DEFAULT_PRIORITY, &d, + TRAFFIC_ANNOTATION_FOR_TESTS)); + req->Start(); + d.RunUntilComplete(); + + ASSERT_EQ(test.expected_cookies.size(), + req->maybe_stored_cookies().size()); + for (const auto& cookie : req->maybe_stored_cookies()) { + ASSERT_TRUE(cookie.cookie.has_value()); + EXPECT_EQ(cookie.cookie->IsHttpOnly(), test.expected_httponly); + EXPECT_TRUE( + base::Contains(test.expected_cookies, cookie.cookie->Name())); + // Cookie was included and there are no warnings. + EXPECT_EQ(CookieInclusionStatus(), cookie.status); + } + } + { + // Get cookies in a same-site context. + TestDelegate d; + std::unique_ptr<URLRequest> req(default_context().CreateFirstPartyRequest( + get_cookies_url, DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS)); + req->Start(); + d.RunUntilComplete(); + + ASSERT_EQ(test.expected_cookies.size(), req->maybe_sent_cookies().size()); + for (const auto& cookie : req->maybe_sent_cookies()) { + EXPECT_EQ(cookie.cookie.IsHttpOnly(), test.expected_httponly); + EXPECT_TRUE( + base::Contains(test.expected_cookies, cookie.cookie.Name())); + EXPECT_THAT(d.data_received(), + ::testing::HasSubstr(cookie.cookie.Name() + "=value")); + // Cookie was included and there are no warnings. + EXPECT_EQ(CookieInclusionStatus(), cookie.access_result.status); + } + } + { + // Get cookies in a cross-site context. + TestDelegate d; + std::unique_ptr<URLRequest> req(default_context().CreateRequest( + get_cookies_url, DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS)); + req->Start(); + d.RunUntilComplete(); + + ASSERT_EQ(test.expected_cookies.size(), req->maybe_sent_cookies().size()); + for (const auto& cookie : req->maybe_sent_cookies()) { + EXPECT_EQ(cookie.cookie.IsHttpOnly(), test.expected_httponly); + + const std::string& cookie_name = cookie.cookie.Name(); + auto it = test.expected_cookies.find(cookie_name); + ASSERT_NE(test.expected_cookies.end(), it); + bool included = cookie.access_result.status.IsInclude(); + EXPECT_EQ(it->second, included); + + if (included) { + EXPECT_THAT(d.data_received(), + ::testing::HasSubstr(cookie.cookie.Name() + "=value")); + } else { + EXPECT_THAT(d.data_received(), ::testing::Not(::testing::HasSubstr( + cookie.cookie.Name() + "=value"))); + } + + std::vector<CookieInclusionStatus::ExclusionReason> exclusions; + std::vector<CookieInclusionStatus::WarningReason> warnings; + if (!included) { + exclusions.push_back(CookieInclusionStatus:: + EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX); + warnings.push_back(CookieInclusionStatus:: + WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT); + } + if (base::Contains(test.expected_compat_warning_cookies, cookie_name)) { + warnings.push_back(CookieInclusionStatus::WARN_SAMESITE_COMPAT_PAIR); + } + EXPECT_TRUE( + cookie.access_result.status.HasExactlyExclusionReasonsForTesting( + exclusions)); + EXPECT_TRUE( + cookie.access_result.status.HasExactlyWarningReasonsForTesting( + warnings)); + } + } + } +} + // Test that the SameSite-by-default CookieInclusionStatus warnings do not get // set if the cookie would have been rejected for other reasons. // Regression test for https://crbug.com/1027318. @@ -6908,8 +7158,7 @@ TEST_F(URLRequestTest, NoCookieInclusionStatusWarningIfWouldBeExcludedAnyway) { // doesn't even make it to the cookie store (it is filtered out beforehand). EXPECT_TRUE(req->maybe_stored_cookies()[0] .status.HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_USER_PREFERENCES})); + {CookieInclusionStatus::EXCLUDE_USER_PREFERENCES})); EXPECT_FALSE(req->maybe_stored_cookies()[0].status.ShouldWarn()); // Cookie that would be included had it not been for the new SameSite rules @@ -6918,22 +7167,21 @@ TEST_F(URLRequestTest, NoCookieInclusionStatusWarningIfWouldBeExcludedAnyway) { req->maybe_stored_cookies()[1].cookie->Name()); EXPECT_TRUE(req->maybe_stored_cookies()[1] .status.HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: + {CookieInclusionStatus:: EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX})); EXPECT_TRUE(req->maybe_stored_cookies()[1] .status.HasExactlyWarningReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: + {CookieInclusionStatus:: WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT})); // Cookie that is blocked because of invalid Secure attribute is not warned // about. EXPECT_EQ("invalidsecure", req->maybe_stored_cookies()[2].cookie->Name()); - EXPECT_TRUE( - req->maybe_stored_cookies()[2] - .status.HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus::EXCLUDE_SECURE_ONLY, - CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX})); + EXPECT_TRUE(req->maybe_stored_cookies()[2] + .status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_SECURE_ONLY, + CookieInclusionStatus:: + EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX})); EXPECT_FALSE(req->maybe_stored_cookies()[2].status.ShouldWarn()); } @@ -6944,14 +7192,13 @@ TEST_F(URLRequestTest, NoCookieInclusionStatusWarningIfWouldBeExcludedAnyway) { auto cookie1 = CanonicalCookie::Create(url, "cookienosamesite=1", base::Time::Now(), base::nullopt); base::RunLoop run_loop; - CanonicalCookie::CookieInclusionStatus status; + CookieInclusionStatus status; cm.SetCanonicalCookieAsync( std::move(cookie1), url, CookieOptions::MakeAllInclusive(), - base::BindLambdaForTesting( - [&](CanonicalCookie::CookieInclusionStatus result) { - status = result; - run_loop.Quit(); - })); + base::BindLambdaForTesting([&](CookieInclusionStatus result) { + status = result; + run_loop.Quit(); + })); run_loop.Run(); EXPECT_TRUE(status.IsInclude()); @@ -6970,14 +7217,14 @@ TEST_F(URLRequestTest, NoCookieInclusionStatusWarningIfWouldBeExcludedAnyway) { ASSERT_EQ(1u, req->maybe_sent_cookies().size()); EXPECT_EQ("cookienosamesite", req->maybe_sent_cookies()[0].cookie.Name()); EXPECT_TRUE(req->maybe_sent_cookies()[0] - .status.HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_USER_PREFERENCES, - CanonicalCookie::CookieInclusionStatus:: + .access_result.status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_USER_PREFERENCES, + CookieInclusionStatus:: EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX})); // Cookie should not be warned about because it was blocked because of user // preferences. - EXPECT_FALSE(req->maybe_sent_cookies()[0].status.ShouldWarn()); + EXPECT_FALSE( + req->maybe_sent_cookies()[0].access_result.status.ShouldWarn()); } network_delegate.unset_block_get_cookies(); @@ -6988,14 +7235,13 @@ TEST_F(URLRequestTest, NoCookieInclusionStatusWarningIfWouldBeExcludedAnyway) { base::Time::Now(), base::nullopt); base::RunLoop run_loop; // Note: cookie1 from the previous testcase is still in the cookie store. - CanonicalCookie::CookieInclusionStatus status; + CookieInclusionStatus status; cm.SetCanonicalCookieAsync( std::move(cookie2), url, CookieOptions::MakeAllInclusive(), - base::BindLambdaForTesting( - [&](CanonicalCookie::CookieInclusionStatus result) { - status = result; - run_loop.Quit(); - })); + base::BindLambdaForTesting([&](CookieInclusionStatus result) { + status = result; + run_loop.Quit(); + })); run_loop.Run(); EXPECT_TRUE(status.IsInclude()); @@ -7017,24 +7263,24 @@ TEST_F(URLRequestTest, NoCookieInclusionStatusWarningIfWouldBeExcludedAnyway) { // Note: this cookie is first because the cookies are sorted by path length // with longest first. See CookieSorter() in cookie_monster.cc. EXPECT_EQ("cookiewithpath", req->maybe_sent_cookies()[0].cookie.Name()); - EXPECT_TRUE( - req->maybe_sent_cookies()[0] - .status.HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus::EXCLUDE_NOT_ON_PATH, - CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX})); - EXPECT_FALSE(req->maybe_sent_cookies()[0].status.ShouldWarn()); + EXPECT_TRUE(req->maybe_sent_cookies()[0] + .access_result.status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_NOT_ON_PATH, + CookieInclusionStatus:: + EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX})); + EXPECT_FALSE( + req->maybe_sent_cookies()[0].access_result.status.ShouldWarn()); // Cookie that was only blocked because of unspecified SameSite should be // warned about. EXPECT_EQ("cookienosamesite", req->maybe_sent_cookies()[1].cookie.Name()); EXPECT_TRUE(req->maybe_sent_cookies()[1] - .status.HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: + .access_result.status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus:: EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX})); - EXPECT_TRUE( - req->maybe_sent_cookies()[1].status.HasExactlyWarningReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT})); + EXPECT_TRUE(req->maybe_sent_cookies()[1] + .access_result.status.HasExactlyWarningReasonsForTesting( + {CookieInclusionStatus:: + WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT})); } } @@ -7060,8 +7306,7 @@ TEST_F(URLRequestTestHTTP, AuthChallengeCancelCookieCollect) { ASSERT_EQ(1u, request->maybe_stored_cookies().size()); EXPECT_TRUE(request->maybe_stored_cookies()[0] .status.HasExactlyExclusionReasonsForTesting( - {net::CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_USER_PREFERENCES})); + {net::CookieInclusionStatus::EXCLUDE_USER_PREFERENCES})); EXPECT_EQ("got_challenged=true", request->maybe_stored_cookies()[0].cookie_string); @@ -7099,11 +7344,11 @@ TEST_F(URLRequestTestHTTP, AuthChallengeWithFilteredCookies) { // The number of cookies blocked from the most recent round trip. ASSERT_EQ(1u, request->maybe_stored_cookies().size()); - EXPECT_TRUE(request->maybe_stored_cookies() - .front() - .status.HasExactlyExclusionReasonsForTesting( - {net::CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_USER_PREFERENCES})); + EXPECT_TRUE( + request->maybe_stored_cookies() + .front() + .status.HasExactlyExclusionReasonsForTesting( + {net::CookieInclusionStatus::EXCLUDE_USER_PREFERENCES})); // Now check the second round trip request->SetAuth(AuthCredentials(kUser, kSecret)); @@ -7153,11 +7398,11 @@ TEST_F(URLRequestTestHTTP, AuthChallengeWithFilteredCookies) { EXPECT_EQ("another_cookie", request->maybe_sent_cookies().front().cookie.Name()); EXPECT_EQ("true", request->maybe_sent_cookies().front().cookie.Value()); - EXPECT_TRUE(request->maybe_sent_cookies() - .front() - .status.HasExactlyExclusionReasonsForTesting( - {net::CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_USER_PREFERENCES})); + EXPECT_TRUE( + request->maybe_sent_cookies() + .front() + .access_result.status.HasExactlyExclusionReasonsForTesting( + {net::CookieInclusionStatus::EXCLUDE_USER_PREFERENCES})); // Check maybe_sent_cookies on second roundtrip. request->set_maybe_sent_cookies({}); @@ -7188,11 +7433,11 @@ TEST_F(URLRequestTestHTTP, AuthChallengeWithFilteredCookies) { ASSERT_EQ(1u, request->maybe_sent_cookies().size()); EXPECT_EQ("one_more_cookie", request->maybe_sent_cookies().front().cookie.Name()); - EXPECT_TRUE(request->maybe_sent_cookies() - .front() - .status.HasExactlyExclusionReasonsForTesting( - {net::CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_USER_PREFERENCES})); + EXPECT_TRUE( + request->maybe_sent_cookies() + .front() + .access_result.status.HasExactlyExclusionReasonsForTesting( + {net::CookieInclusionStatus::EXCLUDE_USER_PREFERENCES})); } } @@ -7503,11 +7748,11 @@ TEST_F(URLRequestTestHTTP, RedirectWithFilteredCookies) { EXPECT_EQ("server-redirect", request->maybe_stored_cookies().front().cookie->Name()); EXPECT_EQ("true", request->maybe_stored_cookies().front().cookie->Value()); - EXPECT_TRUE(request->maybe_stored_cookies() - .front() - .status.HasExactlyExclusionReasonsForTesting( - {net::CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_USER_PREFERENCES})); + EXPECT_TRUE( + request->maybe_stored_cookies() + .front() + .status.HasExactlyExclusionReasonsForTesting( + {net::CookieInclusionStatus::EXCLUDE_USER_PREFERENCES})); // Check maybe_stored_cookies on second round trip (and clearing from the // first). @@ -7526,11 +7771,11 @@ TEST_F(URLRequestTestHTTP, RedirectWithFilteredCookies) { EXPECT_EQ("server-redirect", request->maybe_stored_cookies().front().cookie->Name()); EXPECT_EQ("other", request->maybe_stored_cookies().front().cookie->Value()); - EXPECT_TRUE(request->maybe_stored_cookies() - .front() - .status.HasExactlyExclusionReasonsForTesting( - {net::CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_USER_PREFERENCES})); + EXPECT_TRUE( + request->maybe_stored_cookies() + .front() + .status.HasExactlyExclusionReasonsForTesting( + {net::CookieInclusionStatus::EXCLUDE_USER_PREFERENCES})); } // Check maybe_sent_cookies on first round trip. @@ -7561,11 +7806,11 @@ TEST_F(URLRequestTestHTTP, RedirectWithFilteredCookies) { ASSERT_EQ(1u, request->maybe_sent_cookies().size()); EXPECT_EQ("another_cookie", request->maybe_sent_cookies().front().cookie.Name()); - EXPECT_TRUE(request->maybe_sent_cookies() - .front() - .status.HasExactlyExclusionReasonsForTesting( - {net::CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_USER_PREFERENCES})); + EXPECT_TRUE( + request->maybe_sent_cookies() + .front() + .access_result.status.HasExactlyExclusionReasonsForTesting( + {net::CookieInclusionStatus::EXCLUDE_USER_PREFERENCES})); // Check maybe_sent_cookies on second round trip request->set_maybe_sent_cookies({}); @@ -7592,11 +7837,11 @@ TEST_F(URLRequestTestHTTP, RedirectWithFilteredCookies) { EXPECT_EQ("one_more_cookie", request->maybe_sent_cookies().front().cookie.Name()); EXPECT_EQ("true", request->maybe_sent_cookies().front().cookie.Value()); - EXPECT_TRUE(request->maybe_sent_cookies() - .front() - .status.HasExactlyExclusionReasonsForTesting( - {net::CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_USER_PREFERENCES})); + EXPECT_TRUE( + request->maybe_sent_cookies() + .front() + .access_result.status.HasExactlyExclusionReasonsForTesting( + {net::CookieInclusionStatus::EXCLUDE_USER_PREFERENCES})); } } @@ -8123,34 +8368,19 @@ class URLRequestTestReferrerPolicy : public URLRequestTest { URLRequestTestReferrerPolicy() = default; void InstantiateSameOriginServers(net::EmbeddedTestServer::Type type) { - origin_server_.reset(new EmbeddedTestServer(type)); - if (type == net::EmbeddedTestServer::TYPE_HTTPS) { - origin_server_->AddDefaultHandlers( - base::FilePath(FILE_PATH_LITERAL("net/data/ssl"))); - } else { - origin_server_->AddDefaultHandlers(base::FilePath(kTestFilePath)); - } + origin_server_ = std::make_unique<EmbeddedTestServer>(type); + RegisterDefaultHandlers(origin_server_.get()); ASSERT_TRUE(origin_server_->Start()); } void InstantiateCrossOriginServers(net::EmbeddedTestServer::Type origin_type, net::EmbeddedTestServer::Type dest_type) { - origin_server_.reset(new EmbeddedTestServer(origin_type)); - if (origin_type == net::EmbeddedTestServer::TYPE_HTTPS) { - origin_server_->AddDefaultHandlers( - base::FilePath(FILE_PATH_LITERAL("net/data/ssl"))); - } else { - origin_server_->AddDefaultHandlers(base::FilePath(kTestFilePath)); - } + origin_server_ = std::make_unique<EmbeddedTestServer>(origin_type); + RegisterDefaultHandlers(origin_server_.get()); ASSERT_TRUE(origin_server_->Start()); - destination_server_.reset(new EmbeddedTestServer(dest_type)); - if (dest_type == net::EmbeddedTestServer::TYPE_HTTPS) { - destination_server_->AddDefaultHandlers( - base::FilePath(FILE_PATH_LITERAL("net/data/ssl"))); - } else { - destination_server_->AddDefaultHandlers(base::FilePath(kTestFilePath)); - } + destination_server_ = std::make_unique<EmbeddedTestServer>(dest_type); + RegisterDefaultHandlers(destination_server_.get()); ASSERT_TRUE(destination_server_->Start()); } @@ -8454,8 +8684,7 @@ class HTTPSRequestTest : public TestWithTaskEnvironment { TEST_F(HTTPSRequestTest, HTTPSGetTest) { EmbeddedTestServer test_server(net::EmbeddedTestServer::TYPE_HTTPS); - test_server.AddDefaultHandlers( - base::FilePath(FILE_PATH_LITERAL("net/data/ssl"))); + RegisterDefaultHandlers(&test_server); ASSERT_TRUE(test_server.Start()); TestDelegate d; @@ -8482,8 +8711,7 @@ TEST_F(HTTPSRequestTest, HTTPSGetTest) { TEST_F(HTTPSRequestTest, HTTPSMismatchedTest) { EmbeddedTestServer test_server(net::EmbeddedTestServer::TYPE_HTTPS); test_server.SetSSLConfig(net::EmbeddedTestServer::CERT_MISMATCHED_NAME); - test_server.AddDefaultHandlers( - base::FilePath(FILE_PATH_LITERAL("net/data/ssl"))); + RegisterDefaultHandlers(&test_server); ASSERT_TRUE(test_server.Start()); bool err_allowed = true; @@ -8516,8 +8744,7 @@ TEST_F(HTTPSRequestTest, HTTPSMismatchedTest) { TEST_F(HTTPSRequestTest, HTTPSExpiredTest) { EmbeddedTestServer test_server(net::EmbeddedTestServer::TYPE_HTTPS); test_server.SetSSLConfig(net::EmbeddedTestServer::CERT_EXPIRED); - test_server.AddDefaultHandlers( - base::FilePath(FILE_PATH_LITERAL("net/data/ssl"))); + RegisterDefaultHandlers(&test_server); ASSERT_TRUE(test_server.Start()); // Iterate from false to true, just so that we do the opposite of the @@ -8578,8 +8805,7 @@ class SSLNetErrorTestDelegate : public TestDelegate { TEST_F(HTTPSRequestTest, SSLNetErrorReportedToDelegate) { EmbeddedTestServer test_server(net::EmbeddedTestServer::TYPE_HTTPS); test_server.SetSSLConfig(net::EmbeddedTestServer::CERT_EXPIRED); - test_server.AddDefaultHandlers( - base::FilePath(FILE_PATH_LITERAL("net/data/ssl"))); + RegisterDefaultHandlers(&test_server); ASSERT_TRUE(test_server.Start()); SSLNetErrorTestDelegate d; @@ -8675,7 +8901,7 @@ TEST_F(HTTPSRequestTest, HTTPSErrorsNoClobberTSSTest) { TransportSecurityState::STSState dynamic_sts_state; TransportSecurityState::PKPState dynamic_pkp_state; EXPECT_FALSE(transport_security_state.GetDynamicSTSState( - "hsts-hpkp-preloaded.test", &dynamic_sts_state, nullptr)); + "hsts-hpkp-preloaded.test", &dynamic_sts_state)); EXPECT_FALSE(transport_security_state.GetDynamicPKPState( "hsts-hpkp-preloaded.test", &dynamic_pkp_state)); @@ -8704,7 +8930,7 @@ TEST_F(HTTPSRequestTest, HTTPSErrorsNoClobberTSSTest) { TransportSecurityState::STSState new_dynamic_sts_state; TransportSecurityState::PKPState new_dynamic_pkp_state; EXPECT_FALSE(transport_security_state.GetDynamicSTSState( - "hsts-hpkp-preloaded.test", &new_dynamic_sts_state, nullptr)); + "hsts-hpkp-preloaded.test", &new_dynamic_sts_state)); EXPECT_FALSE(transport_security_state.GetDynamicPKPState( "hsts-hpkp-preloaded.test", &new_dynamic_pkp_state)); @@ -8723,8 +8949,7 @@ TEST_F(HTTPSRequestTest, HSTSPreservesPosts) { static const char kData[] = "hello world"; EmbeddedTestServer test_server(net::EmbeddedTestServer::TYPE_HTTPS); - test_server.AddDefaultHandlers( - base::FilePath(FILE_PATH_LITERAL("net/data/ssl"))); + RegisterDefaultHandlers(&test_server); ASSERT_TRUE(test_server.Start()); @@ -8909,8 +9134,7 @@ TEST_F(HTTPSRequestTest, ClientAuthNoCertificate) { ssl_config.client_cert_type = SSLServerConfig::ClientCertType::OPTIONAL_CLIENT_CERT; test_server.SetSSLConfig(EmbeddedTestServer::CERT_OK, ssl_config); - test_server.AddDefaultHandlers( - base::FilePath(FILE_PATH_LITERAL("net/data/ssl"))); + RegisterDefaultHandlers(&test_server); ASSERT_TRUE(test_server.Start()); SSLClientAuthTestDelegate d; @@ -8956,8 +9180,7 @@ TEST_F(HTTPSRequestTest, ClientAuth) { ssl_config.client_cert_type = SSLServerConfig::ClientCertType::REQUIRE_CLIENT_CERT; test_server.SetSSLConfig(EmbeddedTestServer::CERT_OK, ssl_config); - test_server.AddDefaultHandlers( - base::FilePath(FILE_PATH_LITERAL("net/data/ssl"))); + RegisterDefaultHandlers(&test_server); ASSERT_TRUE(test_server.Start()); { @@ -9038,8 +9261,7 @@ TEST_F(HTTPSRequestTest, ClientAuthFailSigning) { ssl_config.client_cert_type = SSLServerConfig::ClientCertType::REQUIRE_CLIENT_CERT; test_server.SetSSLConfig(EmbeddedTestServer::CERT_OK, ssl_config); - test_server.AddDefaultHandlers( - base::FilePath(FILE_PATH_LITERAL("net/data/ssl"))); + RegisterDefaultHandlers(&test_server); ASSERT_TRUE(test_server.Start()); { @@ -9119,8 +9341,7 @@ TEST_F(HTTPSRequestTest, ClientAuthFailSigningRetry) { ssl_config.client_cert_type = SSLServerConfig::ClientCertType::REQUIRE_CLIENT_CERT; test_server.SetSSLConfig(EmbeddedTestServer::CERT_OK, ssl_config); - test_server.AddDefaultHandlers( - base::FilePath(FILE_PATH_LITERAL("net/data/ssl"))); + RegisterDefaultHandlers(&test_server); ASSERT_TRUE(test_server.Start()); // Connect with a client certificate to put it in the client auth cache. @@ -9587,8 +9808,7 @@ class HTTPSCertNetFetchingTest : public HTTPSRequestTest { EmbeddedTestServer test_server(EmbeddedTestServer::TYPE_HTTPS); test_server.SetSSLConfig(cert_config); - test_server.AddDefaultHandlers( - base::FilePath(FILE_PATH_LITERAL("net/data/ssl"))); + RegisterDefaultHandlers(&test_server); ASSERT_TRUE(test_server.Start()); delegate->set_allow_certificate_errors(true); @@ -10287,8 +10507,7 @@ TEST_F(HTTPSAIATest, AIAFetching) { EmbeddedTestServer::ServerCertificateConfig cert_config; cert_config.intermediate = EmbeddedTestServer::IntermediateType::kByAIA; test_server.SetSSLConfig(cert_config); - test_server.AddDefaultHandlers( - base::FilePath(FILE_PATH_LITERAL("net/data/ssl"))); + RegisterDefaultHandlers(&test_server); ASSERT_TRUE(test_server.Start()); TestDelegate d; @@ -10589,8 +10808,7 @@ TEST_F(HTTPSCRLSetTest, CRLSetRevoked) { {{OCSPRevocationStatus::GOOD, EmbeddedTestServer::OCSPConfig::SingleResponse::Date::kValid}}); test_server.SetSSLConfig(cert_config); - test_server.AddDefaultHandlers( - base::FilePath(FILE_PATH_LITERAL("net/data/ssl"))); + RegisterDefaultHandlers(&test_server); ASSERT_TRUE(test_server.Start()); CertVerifier::Config cert_verifier_config = GetCertVerifierConfig(); @@ -10629,8 +10847,7 @@ TEST_F(HTTPSCRLSetTest, CRLSetRevokedBySubject) { {{OCSPRevocationStatus::GOOD, EmbeddedTestServer::OCSPConfig::SingleResponse::Date::kValid}}); test_server.SetSSLConfig(cert_config); - test_server.AddDefaultHandlers( - base::FilePath(FILE_PATH_LITERAL("net/data/ssl"))); + RegisterDefaultHandlers(&test_server); ASSERT_TRUE(test_server.Start()); std::string common_name = test_server.GetCertificate()->subject().common_name; @@ -10705,8 +10922,7 @@ TEST_F(HTTPSLocalCRLSetTest, KnownInterceptionBlocked) { // Verify the connection succeeds without being flagged. EmbeddedTestServer https_server(EmbeddedTestServer::TYPE_HTTPS); - https_server.AddDefaultHandlers( - base::FilePath(FILE_PATH_LITERAL("net/data/ssl"))); + RegisterDefaultHandlers(&https_server); https_server.SetSSLConfig(EmbeddedTestServer::CERT_OK_BY_INTERMEDIATE); ASSERT_TRUE(https_server.Start()); @@ -11770,8 +11986,7 @@ class HTTPSEarlyDataTest : public TestWithTaskEnvironment { ssl_config_.version_max = SSL_PROTOCOL_VERSION_TLS1_3; ssl_config_.early_data_enabled = true; test_server_.SetSSLConfig(net::EmbeddedTestServer::CERT_OK, ssl_config_); - test_server_.AddDefaultHandlers( - base::FilePath(FILE_PATH_LITERAL("net/data/ssl"))); + RegisterDefaultHandlers(&test_server_); test_server_.RegisterRequestHandler( base::BindRepeating(&HandleZeroRTTRequest)); test_server_.SetConnectionListener(&listener_); diff --git a/chromium/net/websockets/websocket_channel.cc b/chromium/net/websockets/websocket_channel.cc index dea22fcf40c..67365d39c64 100644 --- a/chromium/net/websockets/websocket_channel.cc +++ b/chromium/net/websockets/websocket_channel.cc @@ -44,8 +44,6 @@ namespace { using base::StreamingUtf8Validator; -const int kDefaultSendQuotaLowWaterMark = 1 << 16; -const int kDefaultSendQuotaHighWaterMark = 1 << 17; const size_t kWebSocketCloseCodeLength = 2; // Timeout for waiting for the server to acknowledge a closing handshake. const int kClosingHandshakeTimeoutSeconds = 60; @@ -286,9 +284,6 @@ WebSocketChannel::WebSocketChannel( URLRequestContext* url_request_context) : event_interface_(std::move(event_interface)), url_request_context_(url_request_context), - send_quota_low_water_mark_(kDefaultSendQuotaLowWaterMark), - send_quota_high_water_mark_(kDefaultSendQuotaHighWaterMark), - current_send_quota_(0), closing_handshake_timeout_( base::TimeDelta::FromSeconds(kClosingHandshakeTimeoutSeconds)), underlying_connection_close_timeout_(base::TimeDelta::FromSeconds( @@ -354,12 +349,6 @@ WebSocketChannel::ChannelState WebSocketChannel::SendFrame( } DCHECK_EQ(state_, CONNECTED); - if (buffer_size > base::checked_cast<size_t>(current_send_quota_)) { - // TODO(ricea): Kill renderer. - FailChannel("Send quota exceeded", kWebSocketErrorGoingAway, ""); - return CHANNEL_DELETED; - // |this| has been deleted. - } DCHECK(WebSocketFrameHeader::IsKnownDataOpCode(op_code)) << "Got SendFrame with bogus op_code " << op_code << " fin=" << fin @@ -381,11 +370,7 @@ WebSocketChannel::ChannelState WebSocketChannel::SendFrame( sending_text_message_ = !fin; DCHECK(!fin || state == StreamingUtf8Validator::VALID_ENDPOINT); } - current_send_quota_ -= buffer_size; - // TODO(ricea): If current_send_quota_ has dropped below - // send_quota_low_water_mark_, it might be good to increase the "low - // water mark" and "high water mark", but only if the link to the WebSocket - // server is not saturated. + return SendFrameInternal(fin, op_code, std::move(buffer), buffer_size); // |this| may have been deleted. } @@ -519,12 +504,8 @@ void WebSocketChannel::OnConnectSuccess( // |stream_request_| is not used once the connection has succeeded. stream_request_.reset(); - // TODO(ricea): Get flow control information from the WebSocketStream once we - // have a multiplexing WebSocketStream. - current_send_quota_ = send_quota_high_water_mark_; event_interface_->OnAddChannelResponse( - std::move(response), stream_->GetSubProtocol(), stream_->GetExtensions(), - send_quota_high_water_mark_); + std::move(response), stream_->GetSubProtocol(), stream_->GetExtensions()); // |this| may have been deleted after OnAddChannelResponse. } @@ -599,21 +580,7 @@ ChannelState WebSocketChannel::OnWriteDone(bool synchronous, int result) { return WriteFrames(); } else { data_being_sent_.reset(); - if (current_send_quota_ < send_quota_low_water_mark_) { - // TODO(ricea): Increase low_water_mark and high_water_mark if - // throughput is high, reduce them if throughput is low. Low water - // mark needs to be >= the bandwidth delay product *of the IPC - // channel*. Because factors like context-switch time, thread wake-up - // time, and bus speed come into play it is complex and probably needs - // to be determined empirically. - DCHECK_LE(send_quota_low_water_mark_, send_quota_high_water_mark_); - // TODO(ricea): Truncate quota by the quota specified by the remote - // server, if the protocol in use supports quota. - int fresh_quota = send_quota_high_water_mark_ - current_send_quota_; - current_send_quota_ += fresh_quota; - event_interface_->OnSendFlowControlQuotaAdded(fresh_quota); - return CHANNEL_ALIVE; - } + event_interface_->OnSendDataFrameDone(); } return CHANNEL_ALIVE; @@ -961,8 +928,6 @@ ChannelState WebSocketChannel::SendFrameInternal( if (data_being_sent_) { // Either the link to the WebSocket server is saturated, or several messages // are being sent in a batch. - // TODO(ricea): Keep some statistics to work out the situation and adjust - // quota appropriately. if (!data_to_send_next_) data_to_send_next_ = std::make_unique<SendBuffer>(); data_to_send_next_->AddFrame(std::move(frame), std::move(buffer)); @@ -1016,6 +981,7 @@ ChannelState WebSocketChannel::SendClose(uint16_t code, std::copy( reason.begin(), reason.end(), body->data() + kWebSocketCloseCodeLength); } + return SendFrameInternal(true, WebSocketFrameHeader::kOpCodeClose, std::move(body), size); } diff --git a/chromium/net/websockets/websocket_channel.h b/chromium/net/websockets/websocket_channel.h index d05207e8bc3..d5e78537456 100644 --- a/chromium/net/websockets/websocket_channel.h +++ b/chromium/net/websockets/websocket_channel.h @@ -118,12 +118,6 @@ class NET_EXPORT WebSocketChannel { ChannelState StartClosingHandshake(uint16_t code, const std::string& reason) WARN_UNUSED_RESULT; - // Returns the current send quota. This value is unsafe to use outside of the - // browser IO thread because it changes asynchronously. The value is only - // valid for the execution of the current Task or until SendFrame() is called, - // whichever happens sooner. - int current_send_quota() const { return current_send_quota_; } - // Starts the connection process, using a specified creator callback rather // than the default. This is exposed for testing. void SendAddChannelRequestForTesting( @@ -359,17 +353,6 @@ class NET_EXPORT WebSocketChannel { // during the connection process. std::unique_ptr<WebSocketStreamRequest> stream_request_; - // If the renderer's send quota reaches this level, it is sent a quota - // refresh. "quota units" are currently bytes. TODO(ricea): Update the - // definition of quota units when necessary. - int send_quota_low_water_mark_; - // The level the quota is refreshed to when it reaches the low_water_mark - // (quota units). - int send_quota_high_water_mark_; - // The current amount of quota that the renderer has available for sending - // on this logical channel (quota units). - int current_send_quota_; - // Timer for the closing handshake. base::OneShotTimer close_timer_; diff --git a/chromium/net/websockets/websocket_channel_test.cc b/chromium/net/websockets/websocket_channel_test.cc index 07f90d5b23b..b0c3478692a 100644 --- a/chromium/net/websockets/websocket_channel_test.cc +++ b/chromium/net/websockets/websocket_channel_test.cc @@ -131,15 +131,6 @@ const char kBinaryBlob[] = {'\n', '\r', // BACKWARDS CRNL }; const size_t kBinaryBlobSize = base::size(kBinaryBlob); -// The amount of quota a new connection gets by default. -// TODO(ricea): If kDefaultSendQuotaHighWaterMark changes, then this value will -// need to be updated. -const size_t kDefaultInitialQuota = 1 << 17; -// The amount of bytes we need to send after the initial connection to trigger a -// quota refresh. TODO(ricea): Change this if kDefaultSendQuotaHighWaterMark or -// kDefaultSendQuotaLowWaterMark change. -const size_t kDefaultQuotaRefreshTrigger = (1 << 16) + 1; - const int kVeryBigTimeoutMillis = 60 * 60 * 24 * 1000; // TestTimeouts::tiny_timeout() is 100ms! I could run halfway around the world @@ -167,17 +158,16 @@ class MockWebSocketEventInterface : public WebSocketEventInterface { } MOCK_METHOD1(OnCreateURLRequest, void(URLRequest*)); - MOCK_METHOD4(OnAddChannelResponse, + MOCK_METHOD3(OnAddChannelResponse, void(std::unique_ptr<WebSocketHandshakeResponseInfo> response, const std::string&, - const std::string&, - int64_t)); // NOLINT + const std::string&)); // NOLINT MOCK_METHOD3(OnDataFrameVector, void(bool, WebSocketMessageType, const std::vector<char>&)); // NOLINT MOCK_METHOD0(HasPendingDataFrames, bool(void)); // NOLINT - MOCK_METHOD1(OnSendFlowControlQuotaAdded, void(int64_t)); // NOLINT + MOCK_METHOD0(OnSendDataFrameDone, void(void)); // NOLINT MOCK_METHOD0(OnClosingHandshake, void(void)); // NOLINT MOCK_METHOD1(OnFailChannel, void(const std::string&)); // NOLINT MOCK_METHOD3(OnDropChannel, @@ -225,13 +215,12 @@ class FakeWebSocketEventInterface : public WebSocketEventInterface { void OnAddChannelResponse( std::unique_ptr<WebSocketHandshakeResponseInfo> response, const std::string& selected_protocol, - const std::string& extensions, - int64_t send_flow_control_quota) override {} + const std::string& extensions) override {} void OnDataFrame(bool fin, WebSocketMessageType type, base::span<const char> data_span) override {} + void OnSendDataFrameDone() override {} bool HasPendingDataFrames() override { return false; } - void OnSendFlowControlQuotaAdded(int64_t quota) override {} void OnClosingHandshake() override {} void OnFailChannel(const std::string& message) override {} void OnDropChannel(bool was_clean, @@ -930,11 +919,12 @@ class WebSocketChannelStreamTest : public WebSocketChannelEventInterfaceTest { // whether these methods are called or not. EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber()); EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber()); - EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _, _)) + EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _)) .Times(AnyNumber()); EXPECT_CALL(*event_interface_, OnDataFrameVector(_, _, _)) .Times(AnyNumber()); EXPECT_CALL(*event_interface_, OnClosingHandshake()).Times(AnyNumber()); + EXPECT_CALL(*event_interface_, OnSendDataFrameDone()).Times(AnyNumber()); EXPECT_CALL(*event_interface_, OnFailChannel(_)).Times(AnyNumber()); EXPECT_CALL(*event_interface_, OnDropChannel(_, _, _)).Times(AnyNumber()); } @@ -961,8 +951,9 @@ class WebSocketChannelSendUtf8Test set_stream(std::make_unique<WriteableFakeWebSocketStream>()); // For the purpose of the tests using this fixture, it doesn't matter // whether these methods are called or not. - EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _, _)) + EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _)) .Times(AnyNumber()); + EXPECT_CALL(*event_interface_, OnSendDataFrameDone()).Times(AnyNumber()); } }; @@ -1006,7 +997,7 @@ TEST_F(WebSocketChannelTest, EverythingIsPassedToTheCreatorFunction) { TEST_F(WebSocketChannelEventInterfaceTest, ConnectSuccessReported) { // false means success. - EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, "", "", _)); + EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, "", "")); CreateChannelAndConnect(); @@ -1031,7 +1022,7 @@ TEST_F(WebSocketChannelEventInterfaceTest, NonWebSocketSchemeRejected) { } TEST_F(WebSocketChannelEventInterfaceTest, ProtocolPassed) { - EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, "Bob", "", _)); + EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, "Bob", "")); CreateChannelAndConnect(); @@ -1044,7 +1035,7 @@ TEST_F(WebSocketChannelEventInterfaceTest, ProtocolPassed) { TEST_F(WebSocketChannelEventInterfaceTest, ExtensionsPassed) { EXPECT_CALL(*event_interface_, - OnAddChannelResponse(_, "", "extension1, extension2", _)); + OnAddChannelResponse(_, "", "extension1, extension2")); CreateChannelAndConnect(); @@ -1066,7 +1057,7 @@ TEST_F(WebSocketChannelEventInterfaceTest, DataLeftFromHandshake) { set_stream(std::move(stream)); { InSequence s; - EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _, _)); + EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _)); EXPECT_CALL(*event_interface_, OnDataFrameVector(true, WebSocketFrameHeader::kOpCodeText, AsVector("HELLO"))); @@ -1088,7 +1079,7 @@ TEST_F(WebSocketChannelEventInterfaceTest, CloseAfterHandshake) { set_stream(std::move(stream)); { InSequence s; - EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _, _)); + EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _)); EXPECT_CALL(*event_interface_, OnClosingHandshake()); EXPECT_CALL( *event_interface_, @@ -1112,7 +1103,7 @@ TEST_F(WebSocketChannelEventInterfaceTest, ShouldCloseWhileNoDataFrames) { Checkpoint checkpoint; { InSequence s; - EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _, _)); + EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _)); EXPECT_CALL(*event_interface_, HasPendingDataFrames()) .WillOnce(Return(false)) .WillOnce(Return(true)) @@ -1142,7 +1133,7 @@ TEST_F(WebSocketChannelEventInterfaceTest, ConnectionCloseAfterHandshake) { set_stream(std::move(stream)); { InSequence s; - EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _, _)); + EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _)); EXPECT_CALL(*event_interface_, OnDropChannel(false, kWebSocketErrorAbnormalClosure, _)); } @@ -1161,7 +1152,7 @@ TEST_F(WebSocketChannelEventInterfaceTest, NormalAsyncRead) { set_stream(std::move(stream)); { InSequence s; - EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _, _)); + EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _)); EXPECT_CALL(checkpoint, Call(1)); EXPECT_CALL(*event_interface_, OnDataFrameVector(true, WebSocketFrameHeader::kOpCodeText, @@ -1188,7 +1179,7 @@ TEST_F(WebSocketChannelEventInterfaceTest, AsyncThenSyncRead) { set_stream(std::move(stream)); { InSequence s; - EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _, _)); + EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _)); EXPECT_CALL(*event_interface_, OnDataFrameVector(true, WebSocketFrameHeader::kOpCodeText, AsVector("HELLO"))); @@ -1226,7 +1217,7 @@ TEST_F(WebSocketChannelEventInterfaceTest, FragmentedMessage) { set_stream(std::move(stream)); { InSequence s; - EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _, _)); + EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _)); EXPECT_CALL(*event_interface_, OnDataFrameVector(false, WebSocketFrameHeader::kOpCodeText, AsVector("THREE"))); @@ -1259,7 +1250,7 @@ TEST_F(WebSocketChannelEventInterfaceTest, NullMessage) { {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, nullptr}}; stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames); set_stream(std::move(stream)); - EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _, _)); + EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _)); EXPECT_CALL( *event_interface_, OnDataFrameVector(true, WebSocketFrameHeader::kOpCodeText, AsVector(""))); @@ -1274,7 +1265,7 @@ TEST_F(WebSocketChannelEventInterfaceTest, AsyncAbnormalClosure) { set_stream(std::move(stream)); { InSequence s; - EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _, _)); + EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _)); EXPECT_CALL(*event_interface_, OnDropChannel(false, kWebSocketErrorAbnormalClosure, _)); } @@ -1291,7 +1282,7 @@ TEST_F(WebSocketChannelEventInterfaceTest, ConnectionReset) { set_stream(std::move(stream)); { InSequence s; - EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _, _)); + EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _)); EXPECT_CALL(*event_interface_, OnDropChannel(false, kWebSocketErrorAbnormalClosure, _)); } @@ -1310,7 +1301,7 @@ TEST_F(WebSocketChannelEventInterfaceTest, MaskedFramesAreRejected) { set_stream(std::move(stream)); { InSequence s; - EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _, _)); + EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _)); EXPECT_CALL( *event_interface_, OnFailChannel( @@ -1331,7 +1322,7 @@ TEST_F(WebSocketChannelEventInterfaceTest, UnknownOpCodeIsRejected) { set_stream(std::move(stream)); { InSequence s; - EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _, _)); + EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _)); EXPECT_CALL(*event_interface_, OnFailChannel("Unrecognized frame opcode: 4")); } @@ -1360,7 +1351,7 @@ TEST_F(WebSocketChannelEventInterfaceTest, ControlFrameInDataMessage) { set_stream(std::move(stream)); { InSequence s; - EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _, _)); + EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _)); EXPECT_CALL(*event_interface_, OnDataFrameVector(false, WebSocketFrameHeader::kOpCodeText, AsVector("SPLIT "))); @@ -1382,7 +1373,7 @@ TEST_F(WebSocketChannelEventInterfaceTest, PongWithNullData) { {FINAL_FRAME, WebSocketFrameHeader::kOpCodePong, NOT_MASKED, nullptr}}; stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames); set_stream(std::move(stream)); - EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _, _)); + EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _)); CreateChannelAndConnectSuccessfully(); base::RunLoop().RunUntilIdle(); @@ -1400,7 +1391,7 @@ TEST_F(WebSocketChannelEventInterfaceTest, FrameAfterInvalidFrame) { set_stream(std::move(stream)); { InSequence s; - EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _, _)); + EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _)); EXPECT_CALL( *event_interface_, OnFailChannel( @@ -1411,105 +1402,13 @@ TEST_F(WebSocketChannelEventInterfaceTest, FrameAfterInvalidFrame) { base::RunLoop().RunUntilIdle(); } -// If the renderer sends lots of small writes, we don't want to update the quota -// for each one. -TEST_F(WebSocketChannelEventInterfaceTest, SmallWriteDoesntUpdateQuota) { - set_stream(std::make_unique<WriteableFakeWebSocketStream>()); - { - InSequence s; - EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _, _)); - } - - CreateChannelAndConnectSuccessfully(); - EXPECT_EQ(channel_->SendFrame(true, WebSocketFrameHeader::kOpCodeText, - AsIOBuffer("B"), 1U), - WebSocketChannel::CHANNEL_ALIVE); -} - -// If we send enough to go below |send_quota_low_water_mark_| we should get our -// quota refreshed. -TEST_F(WebSocketChannelEventInterfaceTest, LargeWriteUpdatesQuota) { - set_stream(std::make_unique<WriteableFakeWebSocketStream>()); - // We use this checkpoint object to verify that the quota update comes after - // the write. - Checkpoint checkpoint; - { - InSequence s; - EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _, _)); - EXPECT_CALL(checkpoint, Call(1)); - EXPECT_CALL(*event_interface_, OnSendFlowControlQuotaAdded(_)); - EXPECT_CALL(checkpoint, Call(2)); - } - - CreateChannelAndConnectSuccessfully(); - checkpoint.Call(1); - EXPECT_EQ( - channel_->SendFrame(true, WebSocketFrameHeader::kOpCodeText, - AsIOBuffer(std::string(kDefaultInitialQuota, 'B')), - kDefaultInitialQuota), - WebSocketChannel::CHANNEL_ALIVE); - checkpoint.Call(2); -} - -// Verify that our quota actually is refreshed when we are told it is. -TEST_F(WebSocketChannelEventInterfaceTest, QuotaReallyIsRefreshed) { - set_stream(std::make_unique<WriteableFakeWebSocketStream>()); - Checkpoint checkpoint; - { - InSequence s; - EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _, _)); - EXPECT_CALL(checkpoint, Call(1)); - EXPECT_CALL(*event_interface_, OnSendFlowControlQuotaAdded(_)); - EXPECT_CALL(checkpoint, Call(2)); - // If quota was not really refreshed, we would get an OnDropChannel() - // message. - EXPECT_CALL(*event_interface_, OnSendFlowControlQuotaAdded(_)); - EXPECT_CALL(checkpoint, Call(3)); - } - - CreateChannelAndConnectSuccessfully(); - checkpoint.Call(1); - EXPECT_EQ(channel_->SendFrame( - true, WebSocketFrameHeader::kOpCodeText, - AsIOBuffer(std::string(kDefaultQuotaRefreshTrigger, 'D')), - kDefaultQuotaRefreshTrigger), - WebSocketChannel::CHANNEL_ALIVE); - checkpoint.Call(2); - // We should have received more quota at this point. - EXPECT_EQ(channel_->SendFrame( - true, WebSocketFrameHeader::kOpCodeText, - AsIOBuffer(std::string(kDefaultQuotaRefreshTrigger, 'E')), - kDefaultQuotaRefreshTrigger), - WebSocketChannel::CHANNEL_ALIVE); - checkpoint.Call(3); -} - -// If we send more than the available quota then the connection will be closed -// with an error. -TEST_F(WebSocketChannelEventInterfaceTest, WriteOverQuotaIsRejected) { - set_stream(std::make_unique<WriteableFakeWebSocketStream>()); - { - InSequence s; - EXPECT_CALL(*event_interface_, - OnAddChannelResponse(_, _, _, kDefaultInitialQuota)); - EXPECT_CALL(*event_interface_, OnFailChannel("Send quota exceeded")); - } - - CreateChannelAndConnectSuccessfully(); - EXPECT_EQ(channel_->SendFrame( - true, WebSocketFrameHeader::kOpCodeText, - AsIOBuffer(std::string(kDefaultInitialQuota + 1, 'C')), - kDefaultInitialQuota + 1), - WebSocketChannel::CHANNEL_DELETED); -} - // If a write fails, the channel is dropped. TEST_F(WebSocketChannelEventInterfaceTest, FailedWrite) { set_stream(std::make_unique<UnWriteableFakeWebSocketStream>()); Checkpoint checkpoint; { InSequence s; - EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _, _)); + EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _)); EXPECT_CALL(checkpoint, Call(1)); EXPECT_CALL(*event_interface_, OnDropChannel(false, kWebSocketErrorAbnormalClosure, _)); @@ -1530,7 +1429,8 @@ TEST_F(WebSocketChannelEventInterfaceTest, SendCloseDropsChannel) { set_stream(std::make_unique<EchoeyFakeWebSocketStream>()); { InSequence s; - EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _, _)); + EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _)); + EXPECT_CALL(*event_interface_, OnSendDataFrameDone()); EXPECT_CALL(*event_interface_, OnDropChannel(true, kWebSocketNormalClosure, "Fred")); } @@ -1557,7 +1457,7 @@ TEST_F(WebSocketChannelEventInterfaceTest, CloseDuringConnection) { // connection reset. TEST_F(WebSocketChannelEventInterfaceTest, OnDropChannelCalledOnce) { set_stream(std::make_unique<ResetOnWriteFakeWebSocketStream>()); - EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _, _)); + EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _)); EXPECT_CALL(*event_interface_, OnDropChannel(false, kWebSocketErrorAbnormalClosure, "")) @@ -1581,7 +1481,7 @@ TEST_F(WebSocketChannelEventInterfaceTest, CloseWithNoPayloadGivesStatus1005) { stream->PrepareReadFramesError(ReadableFakeWebSocketStream::SYNC, ERR_CONNECTION_CLOSED); set_stream(std::move(stream)); - EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _, _)); + EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _)); EXPECT_CALL(*event_interface_, OnClosingHandshake()); EXPECT_CALL(*event_interface_, OnDropChannel(true, kWebSocketErrorNoStatusReceived, _)); @@ -1599,7 +1499,7 @@ TEST_F(WebSocketChannelEventInterfaceTest, stream->PrepareReadFramesError(ReadableFakeWebSocketStream::SYNC, ERR_CONNECTION_CLOSED); set_stream(std::move(stream)); - EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _, _)); + EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _)); EXPECT_CALL(*event_interface_, OnClosingHandshake()); EXPECT_CALL(*event_interface_, OnDropChannel(true, kWebSocketErrorNoStatusReceived, _)); @@ -1614,7 +1514,7 @@ TEST_F(WebSocketChannelEventInterfaceTest, SyncProtocolErrorGivesStatus1002) { stream->PrepareReadFramesError(ReadableFakeWebSocketStream::SYNC, ERR_WS_PROTOCOL_ERROR); set_stream(std::move(stream)); - EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _, _)); + EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _)); EXPECT_CALL(*event_interface_, OnFailChannel("Invalid frame header")); @@ -1627,7 +1527,7 @@ TEST_F(WebSocketChannelEventInterfaceTest, AsyncProtocolErrorGivesStatus1002) { stream->PrepareReadFramesError(ReadableFakeWebSocketStream::ASYNC, ERR_WS_PROTOCOL_ERROR); set_stream(std::move(stream)); - EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _, _)); + EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _)); EXPECT_CALL(*event_interface_, OnFailChannel("Invalid frame header")); CreateChannelAndConnectSuccessfully(); @@ -1637,7 +1537,7 @@ TEST_F(WebSocketChannelEventInterfaceTest, AsyncProtocolErrorGivesStatus1002) { TEST_F(WebSocketChannelEventInterfaceTest, StartHandshakeRequest) { { InSequence s; - EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _, _)); + EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _)); EXPECT_CALL(*event_interface_, OnStartOpeningHandshakeCalled()); } @@ -1685,7 +1585,7 @@ TEST_F(WebSocketChannelEventInterfaceTest, DataAfterCloseIsRejected) { {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "Payload"}}; stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames); set_stream(std::move(stream)); - EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _, _)); + EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _)); { InSequence s; @@ -1705,7 +1605,7 @@ TEST_F(WebSocketChannelEventInterfaceTest, OneByteClosePayloadMessage) { {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, NOT_MASKED, "\x03"}}; stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames); set_stream(std::move(stream)); - EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _, _)); + EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _)); EXPECT_CALL( *event_interface_, OnFailChannel( @@ -1723,7 +1623,7 @@ TEST_F(WebSocketChannelEventInterfaceTest, ClosePayloadReservedStatusMessage) { NOT_MASKED, CLOSE_DATA(ABNORMAL_CLOSURE, "Not valid on wire")}}; stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames); set_stream(std::move(stream)); - EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _, _)); + EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _)); EXPECT_CALL( *event_interface_, OnFailChannel( @@ -1741,7 +1641,7 @@ TEST_F(WebSocketChannelEventInterfaceTest, ClosePayloadInvalidReason) { NOT_MASKED, CLOSE_DATA(NORMAL_CLOSURE, "\xFF")}}; stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames); set_stream(std::move(stream)); - EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _, _)); + EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _)); EXPECT_CALL( *event_interface_, OnFailChannel( @@ -1765,7 +1665,7 @@ TEST_F(WebSocketChannelEventInterfaceTest, ReservedBitsMustNotBeSet) { stream->PrepareRawReadFrames(ReadableFakeWebSocketStream::SYNC, OK, std::move(raw_frames)); set_stream(std::move(stream)); - EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _, _)); + EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _)); EXPECT_CALL(*event_interface_, OnFailChannel( "One or more reserved bits are on: reserved1 = 1, " @@ -1782,7 +1682,7 @@ TEST_F(WebSocketChannelEventInterfaceTest, stream->PrepareReadFramesError(ReadableFakeWebSocketStream::SYNC, ERR_IO_PENDING); set_stream(std::move(stream)); - EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _, _)); + EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _)); // This checkpoint object verifies that the OnDropChannel message comes after // the timeout. Checkpoint checkpoint; @@ -1818,7 +1718,7 @@ TEST_F(WebSocketChannelEventInterfaceTest, NOT_MASKED, CLOSE_DATA(NORMAL_CLOSURE, "OK")}}; stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames); set_stream(std::move(stream)); - EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _, _)); + EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _)); Checkpoint checkpoint; TestClosure completion; { @@ -1877,7 +1777,7 @@ TEST_F(WebSocketChannelEventInterfaceTest, SingleFrameMessage) { set_stream(std::move(stream)); { InSequence s; - EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _, _)); + EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _)); EXPECT_CALL(*event_interface_, OnDataFrameVector(true, WebSocketFrameHeader::kOpCodeText, AsVector("FOUR"))); @@ -1899,7 +1799,7 @@ TEST_F(WebSocketChannelEventInterfaceTest, EmptyMessage) { set_stream(std::move(stream)); { InSequence s; - EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _, _)); + EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _)); EXPECT_CALL(*event_interface_, OnDataFrameVector(true, WebSocketFrameHeader::kOpCodeText, AsVector("FIRST MESSAGE"))); @@ -1933,7 +1833,7 @@ TEST_F(WebSocketChannelEventInterfaceTest, set_stream(std::move(stream)); Checkpoint checkpoint; InSequence s; - EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _, _)); + EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _)); EXPECT_CALL(*event_interface_, HasPendingDataFrames()).WillOnce(Return(true)); EXPECT_CALL(checkpoint, Call(1)); EXPECT_CALL(*event_interface_, HasPendingDataFrames()) @@ -2283,26 +2183,6 @@ TEST_F(WebSocketChannelStreamTest, WaitingMessagesAreBatched) { std::move(write_callback).Run(OK); } -// When the renderer sends more on a channel than it has quota for, we send the -// remote server a kWebSocketErrorGoingAway error code. -TEST_F(WebSocketChannelStreamTest, SendGoingAwayOnRendererQuotaExceeded) { - static const InitFrame expected[] = { - {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, - MASKED, CLOSE_DATA(GOING_AWAY, "")}}; - EXPECT_CALL(*mock_stream_, ReadFramesInternal(_, _)) - .WillOnce(Return(ERR_IO_PENDING)); - EXPECT_CALL(*mock_stream_, WriteFramesInternal(EqualsFrames(expected), _)) - .WillOnce(Return(OK)); - EXPECT_CALL(*mock_stream_, Close()); - - CreateChannelAndConnectSuccessfully(); - EXPECT_EQ(channel_->SendFrame( - true, WebSocketFrameHeader::kOpCodeText, - AsIOBuffer(std::string(kDefaultInitialQuota + 1, 'C')), - kDefaultInitialQuota + 1), - WebSocketChannel::CHANNEL_DELETED); -} - // For convenience, most of these tests use Text frames. However, the WebSocket // protocol also has Binary frames and those need to be 8-bit clean. For the // sake of completeness, this test verifies that they are. @@ -2345,7 +2225,7 @@ TEST_F(WebSocketChannelEventInterfaceTest, ReadBinaryFramesAre8BitClean) { stream->PrepareRawReadFrames(ReadableFakeWebSocketStream::SYNC, OK, std::move(frames)); set_stream(std::move(stream)); - EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _, _)); + EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _)); EXPECT_CALL( *event_interface_, OnDataFrameVector( @@ -2477,8 +2357,7 @@ TEST_F(WebSocketChannelEventInterfaceTest, ReceivedInvalidUtf8) { stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames); set_stream(std::move(stream)); - EXPECT_CALL(*event_interface_, - OnAddChannelResponse(_, _, _, kDefaultInitialQuota)); + EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _)); EXPECT_CALL(*event_interface_, OnFailChannel("Could not decode a text frame as UTF-8.")); @@ -2667,8 +2546,7 @@ TEST_F(WebSocketChannelEventInterfaceTest, BogusContinuation) { stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames); set_stream(std::move(stream)); - EXPECT_CALL(*event_interface_, - OnAddChannelResponse(_, _, _, kDefaultInitialQuota)); + EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _)); EXPECT_CALL(*event_interface_, OnDataFrameVector(false, WebSocketFrameHeader::kOpCodeBinary, AsVector("frame1"))); @@ -2689,8 +2567,7 @@ TEST_F(WebSocketChannelEventInterfaceTest, MessageStartingWithContinuation) { stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames); set_stream(std::move(stream)); - EXPECT_CALL(*event_interface_, - OnAddChannelResponse(_, _, _, kDefaultInitialQuota)); + EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _)); EXPECT_CALL(*event_interface_, OnFailChannel("Received unexpected continuation frame.")); @@ -2709,8 +2586,7 @@ TEST_F(WebSocketChannelEventInterfaceTest, DataFramesNonEmptyOrFinal) { stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames); set_stream(std::move(stream)); - EXPECT_CALL(*event_interface_, - OnAddChannelResponse(_, _, _, kDefaultInitialQuota)); + EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _)); EXPECT_CALL( *event_interface_, OnDataFrameVector(true, WebSocketFrameHeader::kOpCodeText, AsVector(""))); @@ -2925,30 +2801,5 @@ TEST_F(WebSocketChannelStreamTimeoutTest, ConnectionCloseTimesOut) { completion.WaitForResult(); } -// Verify that current_send_quota() returns a non-zero value for a newly -// connected channel. -TEST_F(WebSocketChannelTest, CurrentSendQuotaNonZero) { - CreateChannelAndConnectSuccessfully(); - EXPECT_GT(channel_->current_send_quota(), 0); -} - -// Verify that current_send_quota() is updated when SendFrame() is called. -TEST_F(WebSocketChannelTest, CurrentSendQuotaUpdated) { - const int kMessageSize = 5; - set_stream(std::make_unique<WriteableFakeWebSocketStream>()); - CreateChannelAndConnectSuccessfully(); - - int initial_send_quota = channel_->current_send_quota(); - EXPECT_GE(initial_send_quota, kMessageSize); - - EXPECT_EQ(channel_->SendFrame( - true, WebSocketFrameHeader::kOpCodeText, - AsIOBuffer(std::string(static_cast<size_t>(kMessageSize), 'a')), - static_cast<size_t>(kMessageSize)), - WebSocketChannel::CHANNEL_ALIVE); - int new_send_quota = channel_->current_send_quota(); - EXPECT_EQ(kMessageSize, initial_send_quota - new_send_quota); -} - } // namespace } // namespace net diff --git a/chromium/net/websockets/websocket_deflate_parameters.h b/chromium/net/websockets/websocket_deflate_parameters.h index 1898e1d7a12..f5653e28006 100644 --- a/chromium/net/websockets/websocket_deflate_parameters.h +++ b/chromium/net/websockets/websocket_deflate_parameters.h @@ -9,7 +9,7 @@ #include <string> -#include "base/logging.h" +#include "base/check.h" #include "net/base/net_export.h" #include "net/websockets/websocket_deflater.h" #include "net/websockets/websocket_extension.h" diff --git a/chromium/net/websockets/websocket_end_to_end_test.cc b/chromium/net/websockets/websocket_end_to_end_test.cc index caf50d9e26d..27e9cc34aa0 100644 --- a/chromium/net/websockets/websocket_end_to_end_test.cc +++ b/chromium/net/websockets/websocket_end_to_end_test.cc @@ -100,8 +100,7 @@ class ConnectTestingEventInterface : public WebSocketEventInterface { void OnAddChannelResponse( std::unique_ptr<WebSocketHandshakeResponseInfo> response, const std::string& selected_subprotocol, - const std::string& extensions, - int64_t send_flow_control_quota) override; + const std::string& extensions) override; void OnDataFrame(bool fin, WebSocketMessageType type, @@ -109,7 +108,7 @@ class ConnectTestingEventInterface : public WebSocketEventInterface { bool HasPendingDataFrames() override { return false; } - void OnSendFlowControlQuotaAdded(int64_t quota) override; + void OnSendDataFrameDone() override; void OnClosingHandshake() override; @@ -170,8 +169,7 @@ std::string ConnectTestingEventInterface::extensions() const { void ConnectTestingEventInterface::OnAddChannelResponse( std::unique_ptr<WebSocketHandshakeResponseInfo> response, const std::string& selected_subprotocol, - const std::string& extensions, - int64_t send_flow_control_quota) { + const std::string& extensions) { selected_subprotocol_ = selected_subprotocol; extensions_ = extensions; QuitNestedEventLoop(); @@ -182,7 +180,7 @@ void ConnectTestingEventInterface::OnDataFrame(bool fin, base::span<const char> payload) { } -void ConnectTestingEventInterface::OnSendFlowControlQuotaAdded(int64_t quota) {} +void ConnectTestingEventInterface::OnSendDataFrameDone() {} void ConnectTestingEventInterface::OnClosingHandshake() {} diff --git a/chromium/net/websockets/websocket_event_interface.h b/chromium/net/websockets/websocket_event_interface.h index 63eb1b4fa4b..df55472067e 100644 --- a/chromium/net/websockets/websocket_event_interface.h +++ b/chromium/net/websockets/websocket_event_interface.h @@ -48,8 +48,7 @@ class NET_EXPORT WebSocketEventInterface { virtual void OnAddChannelResponse( std::unique_ptr<WebSocketHandshakeResponseInfo> response, const std::string& selected_subprotocol, - const std::string& extensions, - int64_t send_flow_control_quota) = 0; + const std::string& extensions) = 0; // Called when a data frame has been received from the remote host and needs // to be forwarded to the renderer process. @@ -64,9 +63,9 @@ class NET_EXPORT WebSocketEventInterface { // out. The network service should not read more from network until that. virtual bool HasPendingDataFrames() = 0; - // Called to provide more send quota for this channel to the renderer - // process. - virtual void OnSendFlowControlQuotaAdded(int64_t quota) = 0; + // Called once for each call to SendFrame() once the frame has been passed to + // the OS. + virtual void OnSendDataFrameDone() = 0; // Called when the remote server has Started the WebSocket Closing // Handshake. The client should not attempt to send any more messages after diff --git a/chromium/net/websockets/websocket_stream_cookie_test.cc b/chromium/net/websockets/websocket_stream_cookie_test.cc index d1e9aca194d..f2e105f23d2 100644 --- a/chromium/net/websockets/websocket_stream_cookie_test.cc +++ b/chromium/net/websockets/websocket_stream_cookie_test.cc @@ -15,6 +15,7 @@ #include "net/base/isolation_info.h" #include "net/cookies/canonical_cookie.h" #include "net/cookies/canonical_cookie_test_helpers.h" +#include "net/cookies/cookie_inclusion_status.h" #include "net/cookies/cookie_store.h" #include "net/cookies/cookie_util.h" #include "net/http/http_request_headers.h" @@ -85,11 +86,10 @@ class WebSocketStreamClientUseCookieTest base::RunLoop().RunUntilIdle(); } - static void SetCookieHelperFunction( - const base::RepeatingClosure& task, - base::WeakPtr<bool> weak_is_called, - base::WeakPtr<bool> weak_result, - CanonicalCookie::CookieInclusionStatus status) { + static void SetCookieHelperFunction(const base::RepeatingClosure& task, + base::WeakPtr<bool> weak_is_called, + base::WeakPtr<bool> weak_result, + CookieInclusionStatus status) { *weak_is_called = true; *weak_result = status.IsInclude(); base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, task); @@ -122,10 +122,10 @@ class WebSocketStreamServerSetCookieTest base::OnceClosure task, base::WeakPtr<bool> weak_is_called, base::WeakPtr<CookieList> weak_result, - const CookieStatusList& cookie_list, - const CookieStatusList& excluded_cookies) { + const CookieAccessResultList& cookie_list, + const CookieAccessResultList& excluded_cookies) { *weak_is_called = true; - *weak_result = cookie_util::StripStatuses(cookie_list); + *weak_result = cookie_util::StripAccessResults(cookie_list); base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(task)); } }; diff --git a/chromium/net/websockets/websocket_stream_test.cc b/chromium/net/websockets/websocket_stream_test.cc index d4dfb6f582b..7784392afa2 100644 --- a/chromium/net/websockets/websocket_stream_test.cc +++ b/chromium/net/websockets/websocket_stream_test.cc @@ -1749,5 +1749,45 @@ TEST_P(WebSocketStreamCreateTest, ContinueSSLRequestAfterDelete) { ssl_error_callbacks_->ContinueSSLRequest(); } +TEST_P(WebSocketStreamCreateTest, HandleConnectionCloseInFirstSegment) { + std::string request = + WebSocketStandardRequest("/", "www.example.org", Origin(), "", ""); + + // The response headers are immediately followed by a close frame, length 11, + // code 1013, reason "Try Again". + std::string close_body = "\x03\xf5Try Again"; + std::string response = WebSocketStandardResponse(std::string()) + "\x88" + + static_cast<char>(close_body.size()) + close_body; + MockRead reads[] = { + MockRead(SYNCHRONOUS, response.data(), response.size(), 1), + MockRead(SYNCHRONOUS, ERR_CONNECTION_CLOSED, 2), + }; + MockWrite writes[] = {MockWrite(SYNCHRONOUS, 0, request.c_str())}; + std::unique_ptr<SequencedSocketData> socket_data( + BuildSocketData(reads, writes)); + socket_data->set_connect_data(MockConnect(SYNCHRONOUS, OK)); + CreateAndConnectRawExpectations("ws://www.example.org/", NoSubProtocols(), + HttpRequestHeaders(), std::move(socket_data)); + WaitUntilConnectDone(); + ASSERT_TRUE(stream_); + + std::vector<std::unique_ptr<WebSocketFrame>> frames; + TestCompletionCallback callback1; + int rv1 = stream_->ReadFrames(&frames, callback1.callback()); + rv1 = callback1.GetResult(rv1); + ASSERT_THAT(rv1, IsOk()); + ASSERT_EQ(1U, frames.size()); + EXPECT_EQ(frames[0]->header.opcode, WebSocketFrameHeader::kOpCodeClose); + EXPECT_TRUE(frames[0]->header.final); + EXPECT_EQ(close_body, + std::string(frames[0]->payload, frames[0]->header.payload_length)); + + std::vector<std::unique_ptr<WebSocketFrame>> empty_frames; + TestCompletionCallback callback2; + int rv2 = stream_->ReadFrames(&empty_frames, callback2.callback()); + rv2 = callback2.GetResult(rv2); + ASSERT_THAT(rv2, IsError(ERR_CONNECTION_CLOSED)); +} + } // namespace } // namespace net |
