diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2018-01-31 16:33:43 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2018-02-06 16:33:22 +0000 |
commit | da51f56cc21233c2d30f0fe0d171727c3102b2e0 (patch) | |
tree | 4e579ab70ce4b19bee7984237f3ce05a96d59d83 /chromium/net | |
parent | c8c2d1901aec01e934adf561a9fdf0cc776cdef8 (diff) | |
download | qtwebengine-chromium-da51f56cc21233c2d30f0fe0d171727c3102b2e0.tar.gz |
BASELINE: Update Chromium to 65.0.3525.40
Also imports missing submodules
Change-Id: I36901b7c6a325cda3d2c10cedb2186c25af3b79b
Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'chromium/net')
865 files changed, 25093 insertions, 13721 deletions
diff --git a/chromium/net/BUILD.gn b/chromium/net/BUILD.gn index cda37cb455f..7676ff4cbf8 100644 --- a/chromium/net/BUILD.gn +++ b/chromium/net/BUILD.gn @@ -82,15 +82,9 @@ net_configs = [ ":net_internal_config", "//build/config:precompiled_headers", - # TODO(jschuh): crbug.com/167187 fix size_t to int truncations. - "//build/config/compiler:no_size_t_to_int_warning", "//build/config/compiler:wexit_time_destructors", ] -if (use_glib && use_gconf && !is_chromeos) { - net_configs += [ "//build/config/linux/gconf" ] -} - if (is_linux) { net_configs += [ "//build/config/linux:libresolv" ] } @@ -1051,6 +1045,7 @@ component("net") { "proxy/multi_threaded_proxy_resolver.h", "proxy/network_delegate_error_observer.cc", "proxy/network_delegate_error_observer.h", + "proxy/pac_js_library.h", "proxy/polling_proxy_config_service.cc", "proxy/polling_proxy_config_service.h", "proxy/proxy_bypass_rules.cc", @@ -1082,7 +1077,6 @@ component("net") { "proxy/proxy_resolver_factory.h", "proxy/proxy_resolver_mac.cc", "proxy/proxy_resolver_mac.h", - "proxy/proxy_resolver_script.h", "proxy/proxy_resolver_script_data.cc", "proxy/proxy_resolver_script_data.h", "proxy/proxy_resolver_winhttp.cc", @@ -1148,8 +1142,6 @@ component("net") { "quic/core/congestion_control/bandwidth_sampler.h", "quic/core/congestion_control/bbr_sender.cc", "quic/core/congestion_control/bbr_sender.h", - "quic/core/congestion_control/cubic.cc", - "quic/core/congestion_control/cubic.h", "quic/core/congestion_control/cubic_bytes.cc", "quic/core/congestion_control/cubic_bytes.h", "quic/core/congestion_control/general_loss_algorithm.cc", @@ -1165,8 +1157,6 @@ component("net") { "quic/core/congestion_control/rtt_stats.h", "quic/core/congestion_control/send_algorithm_interface.cc", "quic/core/congestion_control/send_algorithm_interface.h", - "quic/core/congestion_control/tcp_cubic_sender_base.cc", - "quic/core/congestion_control/tcp_cubic_sender_base.h", "quic/core/congestion_control/tcp_cubic_sender_bytes.cc", "quic/core/congestion_control/tcp_cubic_sender_bytes.h", "quic/core/congestion_control/windowed_filter.h", @@ -1436,6 +1426,7 @@ component("net") { "quic/http/quic_http_structures.cc", "quic/http/quic_http_structures.h", "quic/platform/api/quic_aligned.h", + "quic/platform/api/quic_arraysize.h", "quic/platform/api/quic_bug_tracker.h", "quic/platform/api/quic_clock.cc", "quic/platform/api/quic_clock.h", @@ -1459,6 +1450,7 @@ component("net") { "quic/platform/api/quic_mutex.h", "quic/platform/api/quic_optional.h", "quic/platform/api/quic_pcc_sender.h", + "quic/platform/api/quic_prefetch.h", "quic/platform/api/quic_ptr_util.h", "quic/platform/api/quic_reconstruct_object.h", "quic/platform/api/quic_reference_counted.h", @@ -1474,6 +1466,7 @@ component("net") { "quic/platform/api/quic_url_utils.cc", "quic/platform/api/quic_url_utils.h", "quic/platform/impl/quic_aligned_impl.h", + "quic/platform/impl/quic_arraysize_impl.h", "quic/platform/impl/quic_bug_tracker_impl.h", "quic/platform/impl/quic_chromium_clock.cc", "quic/platform/impl/quic_chromium_clock.h", @@ -1499,6 +1492,7 @@ component("net") { "quic/platform/impl/quic_mutex_impl.h", "quic/platform/impl/quic_optional_impl.h", "quic/platform/impl/quic_pcc_sender_impl.h", + "quic/platform/impl/quic_prefetch_impl.h", "quic/platform/impl/quic_ptr_util_impl.h", "quic/platform/impl/quic_reconstruct_object_impl.h", "quic/platform/impl/quic_reference_counted_impl.h", @@ -1833,8 +1827,6 @@ component("net") { "reporting/reporting_network_change_observer.h", "reporting/reporting_observer.cc", "reporting/reporting_observer.h", - "reporting/reporting_persister.cc", - "reporting/reporting_persister.h", "reporting/reporting_policy.cc", "reporting/reporting_policy.h", "reporting/reporting_report.cc", @@ -1908,7 +1900,7 @@ component("net") { } if (use_gio) { - deps += [ "//build/linux/libgio" ] + configs += [ "//build/linux:gio_config" ] } if (!use_nss_certs) { @@ -2308,10 +2300,7 @@ static_library("http_server") { "server/web_socket_encoder.cc", "server/web_socket_encoder.h", ] - configs += [ - "//build/config/compiler:no_size_t_to_int_warning", - "//build/config/compiler:wexit_time_destructors", - ] + configs += [ "//build/config/compiler:wexit_time_destructors" ] deps = [ ":net", "//base", @@ -2327,9 +2316,6 @@ if (!is_ios) { "tools/dump_cache/dump_files.h", ] - # TODO(jschuh): crbug.com/167187 fix size_t to int truncations. - configs += [ "//build/config/compiler:no_size_t_to_int_warning" ] - deps = [ ":net", ":test_support", @@ -2407,10 +2393,14 @@ bundle_data("test_support_bundle_data") { "data/ssl/certificates/client_6.pk8", "data/ssl/certificates/client_6_ca.pem", "data/ssl/certificates/client_root_ca.pem", + "data/ssl/certificates/common_name_only.pem", "data/ssl/certificates/crit-codeSigning-chain.pem", "data/ssl/certificates/crlset_by_intermediate_serial.raw", "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_subject.raw", + "data/ssl/certificates/crlset_by_root_subject_no_spki.raw", "data/ssl/certificates/cross-signed-leaf.pem", "data/ssl/certificates/cross-signed-root-md5.pem", "data/ssl/certificates/cross-signed-root-sha256.pem", @@ -2418,6 +2408,7 @@ bundle_data("test_support_bundle_data") { "data/ssl/certificates/ct-test-embedded-with-intermediate-chain.pem", "data/ssl/certificates/ct-test-embedded-with-intermediate-preca-chain.pem", "data/ssl/certificates/ct-test-embedded-with-preca-chain.pem", + "data/ssl/certificates/dec_2017.pem", "data/ssl/certificates/diginotar_cyber_ca.pem", "data/ssl/certificates/diginotar_pkioverheid.pem", "data/ssl/certificates/diginotar_pkioverheid_g2.pem", @@ -2487,19 +2478,11 @@ bundle_data("test_support_bundle_data") { "data/ssl/certificates/prime256v1-ecdsa-ee-by-prime256v1-ecdsa-intermediate.pem", "data/ssl/certificates/prime256v1-ecdsa-intermediate.pem", "data/ssl/certificates/punycodetest.pem", - "data/ssl/certificates/quic_chain.crt", - "data/ssl/certificates/quic_intermediate.crt", - "data/ssl/certificates/quic_intermediate.key", - "data/ssl/certificates/quic_root.crt", - "data/ssl/certificates/quic_root.key", - "data/ssl/certificates/quic_test.example.com.crt", - "data/ssl/certificates/quic_test.example.com.key", - "data/ssl/certificates/quic_test.example.com.key.pkcs8", - "data/ssl/certificates/quic_test.example.com.key.pkcs8.pem", - "data/ssl/certificates/quic_test.example.com.key.sct", - "data/ssl/certificates/quic_test_ecc.example.com.crt", - "data/ssl/certificates/quic_test_ecc.example.com.key", - "data/ssl/certificates/quic_test_ecc.example.com.sct", + "data/ssl/certificates/quic-chain.pem", + "data/ssl/certificates/quic-leaf-cert.key", + "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/redundant-server-chain.pem", "data/ssl/certificates/redundant-validated-chain-root.pem", "data/ssl/certificates/redundant-validated-chain.pem", @@ -2511,6 +2494,7 @@ bundle_data("test_support_bundle_data") { "data/ssl/certificates/sha1_2016.pem", "data/ssl/certificates/sha1_dec_2015.pem", "data/ssl/certificates/sha1_jan_2016.pem", + "data/ssl/certificates/sha1_leaf.pem", "data/ssl/certificates/spdy_pooling.pem", "data/ssl/certificates/start_after_expiry.pem", "data/ssl/certificates/subjectAltName_sanity_check.pem", @@ -2665,12 +2649,7 @@ static_library("test_support") { "url_request/url_request_test_util.h", ] - configs += [ - "//build/config:precompiled_headers", - - # TODO(jschuh): crbug.com/167187 fix size_t to int truncations. - "//build/config/compiler:no_size_t_to_int_warning", - ] + configs += [ "//build/config:precompiled_headers" ] public_deps = [ ":traffic_annotation", @@ -2776,7 +2755,6 @@ if (use_v8_in_net) { defines = [ "NET_IMPLEMENTATION" ] configs += [ - "//build/config/compiler:no_size_t_to_int_warning", "//build/config/compiler:wexit_time_destructors", "//v8:external_startup_data", ] @@ -2841,8 +2819,6 @@ if (!is_ios && !is_android) { "tools/cert_verify_tool/verify_using_path_builder.h", ] - # TODO(jschuh): crbug.com/167187 fix size_t to int truncations. - configs += [ "//build/config/compiler:no_size_t_to_int_warning" ] deps = [ ":net", ":test_support", @@ -2862,8 +2838,6 @@ if (!is_ios && !is_android) { "tools/crash_cache/crash_cache.cc", ] - # TODO(jschuh): crbug.com/167187 fix size_t to int truncations. - configs += [ "//build/config/compiler:no_size_t_to_int_warning" ] deps = [ ":net", ":test_support", @@ -2879,8 +2853,6 @@ if (!is_ios && !is_android) { "tools/crl_set_dump/crl_set_dump.cc", ] - # TODO(jschuh): crbug.com/167187 fix size_t to int truncations. - configs += [ "//build/config/compiler:no_size_t_to_int_warning" ] deps = [ ":net", "//base", @@ -2895,8 +2867,6 @@ if (!is_ios && !is_android) { "tools/dns_fuzz_stub/dns_fuzz_stub.cc", ] - # TODO(jschuh): crbug.com/167187 fix size_t to int truncations. - configs += [ "//build/config/compiler:no_size_t_to_int_warning" ] deps = [ ":net", "//base", @@ -2926,8 +2896,6 @@ if (!is_ios && !is_android) { "tools/get_server_time/get_server_time.cc", ] - # TODO(jschuh): crbug.com/167187 fix size_t to int truncations. - configs += [ "//build/config/compiler:no_size_t_to_int_warning" ] deps = [ ":net", "//base", @@ -2944,8 +2912,6 @@ if (!is_ios && !is_android) { "spdy/core/fuzzing/hpack_example_generator.cc", ] - # TODO(jschuh): crbug.com/167187 fix size_t to int truncations. - configs += [ "//build/config/compiler:no_size_t_to_int_warning" ] deps = [ ":net", "//base", @@ -2991,8 +2957,6 @@ if (!is_ios && !is_android) { "tools/stress_cache/stress_cache.cc", ] - # TODO(jschuh): crbug.com/167187 fix size_t to int truncations. - configs += [ "//build/config/compiler:no_size_t_to_int_warning" ] deps = [ ":net", ":test_support", @@ -3007,8 +2971,6 @@ if (!is_ios && !is_android) { "tools/tld_cleanup/tld_cleanup.cc", ] - # TODO(jschuh): crbug.com/167187 fix size_t to int truncations. - configs += [ "//build/config/compiler:no_size_t_to_int_warning" ] deps = [ "//base", "//base:i18n", @@ -3290,6 +3252,8 @@ source_set("quic_test_tools") { if (is_linux) { sources += [ + "tools/quic/test_tools/bad_packet_writer.cc", + "tools/quic/test_tools/bad_packet_writer.h", "tools/quic/test_tools/limited_mtu_test_writer.cc", "tools/quic/test_tools/limited_mtu_test_writer.h", "tools/quic/test_tools/mock_epoll_server.cc", @@ -4036,6 +4000,7 @@ bundle_data("net_unittests_bundle_data") { "data/verify_name_match_unittest/names/ascii-UTF8-unmangled.pem", "data/verify_name_match_unittest/names/ascii-mixed-rdn_dupetype_sorting_1.pem", "data/verify_name_match_unittest/names/ascii-mixed-rdn_dupetype_sorting_2.pem", + "data/verify_name_match_unittest/names/custom-custom-normalized.pem", "data/verify_name_match_unittest/names/invalid-AttributeTypeAndValue-badAttributeType.pem", "data/verify_name_match_unittest/names/invalid-AttributeTypeAndValue-empty.pem", "data/verify_name_match_unittest/names/invalid-AttributeTypeAndValue-extradata.pem", @@ -4887,6 +4852,7 @@ test("net_unittests") { "http/http_network_transaction_ssl_unittest.cc", "http/http_network_transaction_unittest.cc", "http/http_proxy_client_socket_pool_unittest.cc", + "http/http_proxy_client_socket_unittest.cc", "http/http_proxy_client_socket_wrapper_unittest.cc", "http/http_request_headers_unittest.cc", "http/http_response_body_drainer_unittest.cc", @@ -5059,7 +5025,6 @@ test("net_unittests") { "quic/core/congestion_control/bandwidth_sampler_test.cc", "quic/core/congestion_control/bbr_sender_test.cc", "quic/core/congestion_control/cubic_bytes_test.cc", - "quic/core/congestion_control/cubic_test.cc", "quic/core/congestion_control/general_loss_algorithm_test.cc", "quic/core/congestion_control/hybrid_slow_start_test.cc", "quic/core/congestion_control/pacing_sender_test.cc", @@ -5332,12 +5297,7 @@ test("net_unittests") { ] net_unfiltered_sources = [] - configs += [ - "//build/config:precompiled_headers", - - # TODO(jschuh): crbug.com/167187 fix size_t to int truncations. - "//build/config/compiler:no_size_t_to_int_warning", - ] + configs += [ "//build/config:precompiled_headers" ] defines = [] deps = [ @@ -5364,6 +5324,7 @@ test("net_unittests") { if (enable_reporting) { sources += [ + "network_error_logging/network_error_logging_end_to_end_test.cc", "network_error_logging/network_error_logging_service_unittest.cc", "reporting/reporting_browsing_data_remover_unittest.cc", "reporting/reporting_cache_unittest.cc", @@ -5372,7 +5333,6 @@ test("net_unittests") { "reporting/reporting_garbage_collector_unittest.cc", "reporting/reporting_header_parser_unittest.cc", "reporting/reporting_network_change_observer_unittest.cc", - "reporting/reporting_persister_unittest.cc", "reporting/reporting_service_unittest.cc", "reporting/reporting_test_util.cc", "reporting/reporting_test_util.h", @@ -5768,8 +5728,6 @@ if (!is_ios && !is_proto_quic) { "url_request/url_request_quic_perftest.cc", ] - # TODO(jschuh): crbug.com/167187 fix size_t to int truncations. - configs += [ "//build/config/compiler:no_size_t_to_int_warning" ] deps = [ ":extras", ":net", diff --git a/chromium/net/android/network_library.cc b/chromium/net/android/network_library.cc index e2cadfdc39a..494288fc696 100644 --- a/chromium/net/android/network_library.cc +++ b/chromium/net/android/network_library.cc @@ -62,22 +62,6 @@ void ClearTestRootCertificates() { Java_AndroidNetworkLibrary_clearTestRootCertificates(env); } -bool StoreKeyPair(const uint8_t* public_key, - size_t public_len, - const uint8_t* private_key, - size_t private_len) { - JNIEnv* env = AttachCurrentThread(); - ScopedJavaLocalRef<jbyteArray> public_array = - ToJavaByteArray(env, public_key, public_len); - ScopedJavaLocalRef<jbyteArray> private_array = - ToJavaByteArray(env, private_key, private_len); - jboolean ret = - Java_AndroidNetworkLibrary_storeKeyPair(env, public_array, private_array); - LOG_IF(WARNING, !ret) << - "Call to Java_AndroidNetworkLibrary_storeKeyPair failed"; - return ret; -} - bool IsCleartextPermitted(const std::string& host) { JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef<jstring> host_string = ConvertUTF8ToJavaString(env, host); diff --git a/chromium/net/base/fuzzer_test_support.cc b/chromium/net/base/fuzzer_test_support.cc index 8e10957bfc5..f2a54d51686 100644 --- a/chromium/net/base/fuzzer_test_support.cc +++ b/chromium/net/base/fuzzer_test_support.cc @@ -6,7 +6,6 @@ #include "base/command_line.h" #include "base/i18n/icu_util.h" #include "base/logging.h" -#include "base/metrics/statistics_recorder.h" #include "base/test/scoped_task_environment.h" namespace { @@ -26,10 +25,6 @@ struct InitGlobals { // asserting when handling non-ASCII urls. CHECK(base::i18n::InitializeICU()); - // Prevent every call to get a Histogram* from leaking memory. Instead, only - // the fist call to get each Histogram* leaks memory. - base::StatisticsRecorder::Initialize(); - // Disable noisy logging as per "libFuzzer in Chrome" documentation: // testing/libfuzzer/getting_started.md#Disable-noisy-error-message-logging. logging::SetMinLogLevel(logging::LOG_FATAL); diff --git a/chromium/net/base/hash_value.cc b/chromium/net/base/hash_value.cc index 7a2dbd4c7ec..80d8eecdda6 100644 --- a/chromium/net/base/hash_value.cc +++ b/chromium/net/base/hash_value.cc @@ -22,12 +22,12 @@ namespace { // SHA256HashValues. struct SHA256ToHashValueComparator { bool operator()(const SHA256HashValue& lhs, const HashValue& rhs) const { - DCHECK_EQ(HASH_VALUE_SHA256, rhs.tag); + DCHECK_EQ(HASH_VALUE_SHA256, rhs.tag()); return memcmp(lhs.data, rhs.data(), rhs.size()) < 0; } bool operator()(const HashValue& lhs, const SHA256HashValue& rhs) const { - DCHECK_EQ(HASH_VALUE_SHA256, lhs.tag); + DCHECK_EQ(HASH_VALUE_SHA256, lhs.tag()); return memcmp(lhs.data(), rhs.data, lhs.size()) < 0; } }; @@ -43,7 +43,7 @@ HashValue::HashValue(const SHA256HashValue& hash) bool HashValue::FromString(const base::StringPiece value) { base::StringPiece base64_str; if (value.starts_with("sha256/")) { - tag = HASH_VALUE_SHA256; + tag_ = HASH_VALUE_SHA256; base64_str = value.substr(7); } else { return false; @@ -61,26 +61,26 @@ std::string HashValue::ToString() const { std::string base64_str; base::Base64Encode(base::StringPiece(reinterpret_cast<const char*>(data()), size()), &base64_str); - switch (tag) { - case HASH_VALUE_SHA256: - return std::string("sha256/") + base64_str; - default: - NOTREACHED() << "Unknown HashValueTag " << tag; - return std::string("unknown/" + base64_str); + switch (tag_) { + case HASH_VALUE_SHA256: + return std::string("sha256/") + base64_str; } + + NOTREACHED() << "Unknown HashValueTag " << tag_; + return std::string("unknown/" + base64_str); } size_t HashValue::size() const { - switch (tag) { + switch (tag_) { case HASH_VALUE_SHA256: return sizeof(fingerprint.sha256.data); - default: - NOTREACHED() << "Unknown HashValueTag " << tag; - // While an invalid tag should not happen, return a non-zero length - // to avoid compiler warnings when the result of size() is - // used with functions like memset. - return sizeof(fingerprint.sha256.data); } + + NOTREACHED() << "Unknown HashValueTag " << tag_; + // While an invalid tag should not happen, return a non-zero length + // to avoid compiler warnings when the result of size() is + // used with functions like memset. + return sizeof(fingerprint.sha256.data); } unsigned char* HashValue::data() { @@ -88,13 +88,55 @@ unsigned char* HashValue::data() { } const unsigned char* HashValue::data() const { - switch (tag) { + switch (tag_) { case HASH_VALUE_SHA256: return fingerprint.sha256.data; - default: - NOTREACHED() << "Unknown HashValueTag " << tag; - return NULL; } + + NOTREACHED() << "Unknown HashValueTag " << tag_; + return nullptr; +} + +bool operator==(const HashValue& lhs, const HashValue& rhs) { + if (lhs.tag_ != rhs.tag_) + return false; + + switch (lhs.tag_) { + case HASH_VALUE_SHA256: + return lhs.fingerprint.sha256 == rhs.fingerprint.sha256; + } + + NOTREACHED(); + return false; +} + +bool operator!=(const HashValue& lhs, const HashValue& rhs) { + return !(lhs == rhs); +} + +bool operator<(const HashValue& lhs, const HashValue& rhs) { + if (lhs.tag_ != rhs.tag_) + return lhs.tag_ < rhs.tag_; + + switch (lhs.tag_) { + case HASH_VALUE_SHA256: + return lhs.fingerprint.sha256 < rhs.fingerprint.sha256; + } + + NOTREACHED(); + return false; +} + +bool operator>(const HashValue& lhs, const HashValue& rhs) { + return rhs < lhs; +} + +bool operator<=(const HashValue& lhs, const HashValue& rhs) { + return !(lhs > rhs); +} + +bool operator>=(const HashValue& lhs, const HashValue& rhs) { + return !(lhs < rhs); } bool IsSHA256HashInSortedArray(const HashValue& hash, @@ -108,7 +150,7 @@ bool IsAnySHA256HashInSortedArray(const HashValueVector& hashes, const SHA256HashValue* list, size_t list_length) { for (const auto& hash : hashes) { - if (hash.tag != HASH_VALUE_SHA256) + if (hash.tag() != HASH_VALUE_SHA256) continue; if (IsSHA256HashInSortedArray(hash, list, list_length)) diff --git a/chromium/net/base/hash_value.h b/chromium/net/base/hash_value.h index 52732ebd5d7..f01181d1cba 100644 --- a/chromium/net/base/hash_value.h +++ b/chromium/net/base/hash_value.h @@ -27,7 +27,23 @@ inline bool operator==(const SHA256HashValue& lhs, const SHA256HashValue& rhs) { } inline bool operator!=(const SHA256HashValue& lhs, const SHA256HashValue& rhs) { - return !(lhs == rhs); + return memcmp(lhs.data, rhs.data, sizeof(lhs.data)) != 0; +} + +inline bool operator<(const SHA256HashValue& lhs, const SHA256HashValue& rhs) { + return memcmp(lhs.data, rhs.data, sizeof(lhs.data)) < 0; +} + +inline bool operator>(const SHA256HashValue& lhs, const SHA256HashValue& rhs) { + return memcmp(lhs.data, rhs.data, sizeof(lhs.data)) > 0; +} + +inline bool operator<=(const SHA256HashValue& lhs, const SHA256HashValue& rhs) { + return memcmp(lhs.data, rhs.data, sizeof(lhs.data)) <= 0; +} + +inline bool operator>=(const SHA256HashValue& lhs, const SHA256HashValue& rhs) { + return memcmp(lhs.data, rhs.data, sizeof(lhs.data)) >= 0; } enum HashValueTag { @@ -37,8 +53,8 @@ enum HashValueTag { class NET_EXPORT HashValue { public: explicit HashValue(const SHA256HashValue& hash); - explicit HashValue(HashValueTag tag) : tag(tag) {} - HashValue() : tag(HASH_VALUE_SHA256) {} + explicit HashValue(HashValueTag tag) : tag_(tag) {} + HashValue() : tag_(HASH_VALUE_SHA256) {} // Serializes/Deserializes hashes in the form of // <hash-name>"/"<base64-hash-value> @@ -63,33 +79,26 @@ class NET_EXPORT HashValue { unsigned char* data(); const unsigned char* data() const; - HashValueTag tag; + HashValueTag tag() const { return tag_; } + + NET_EXPORT friend bool operator==(const HashValue& lhs, const HashValue& rhs); + NET_EXPORT friend bool operator!=(const HashValue& lhs, const HashValue& rhs); + NET_EXPORT friend bool operator<(const HashValue& lhs, const HashValue& rhs); + NET_EXPORT friend bool operator>(const HashValue& lhs, const HashValue& rhs); + NET_EXPORT friend bool operator<=(const HashValue& lhs, const HashValue& rhs); + NET_EXPORT friend bool operator>=(const HashValue& lhs, const HashValue& rhs); private: + HashValueTag tag_; + union { SHA256HashValue sha256; } fingerprint; }; -inline bool operator==(const HashValue& lhs, const HashValue& rhs) { - return lhs.tag == rhs.tag && memcmp(lhs.data(), rhs.data(), lhs.size()) == 0; -} - -inline bool operator!=(const HashValue& lhs, const HashValue& rhs) { - return !(lhs == rhs); -} - typedef std::vector<HashValue> HashValueVector; -class SHA256HashValueLessThan { - public: - bool operator()(const SHA256HashValue& lhs, - const SHA256HashValue& rhs) const { - return memcmp(lhs.data, rhs.data, sizeof(lhs.data)) < 0; - } -}; - // IsSHA256HashInSortedArray returns true iff |hash| is in |array|, a sorted // array of SHA256 hashes. bool IsSHA256HashInSortedArray(const HashValue& hash, diff --git a/chromium/net/base/hex_utils.cc b/chromium/net/base/hex_utils.cc index 62cdb637255..f6efcbefe16 100644 --- a/chromium/net/base/hex_utils.cc +++ b/chromium/net/base/hex_utils.cc @@ -16,7 +16,7 @@ namespace net { std::string HexDecode(base::StringPiece input) { std::vector<uint8_t> output; std::string result; - if (base::HexStringToBytes(input.as_string(), &output)) + if (base::HexStringToBytes(input, &output)) result.assign(reinterpret_cast<const char*>(&output[0]), output.size()); return result; } diff --git a/chromium/net/base/mime_sniffer_fuzzer.cc b/chromium/net/base/mime_sniffer_fuzzer.cc index fec7feaf677..66bb264f0b2 100644 --- a/chromium/net/base/mime_sniffer_fuzzer.cc +++ b/chromium/net/base/mime_sniffer_fuzzer.cc @@ -7,6 +7,7 @@ #include <stddef.h> #include <stdint.h> +#include <algorithm> #include <string> #include "base/strings/string_piece.h" @@ -37,14 +38,28 @@ std::string GetNextArgument(base::StringPiece* input) { // own line, and content is everything after them. Since neither URLs nor // content-encoding headers can have line breaks, this doesn't reduce coverage. extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - base::StringPiece input(reinterpret_cast<const char*>(data), size); - GURL url(GetNextArgument(&input)); + // net::SniffMimeType DCHECKs if passed an input buffer that's too large, + // since it's meant to be used only on the first chunk of a file that's bing + // fed into a stream. Set a max size of the input to avoid running into that + // DCHECK. Use 64k because that's twice the size of a typical read attempt. + constexpr size_t kMaxSniffLength = 64 * 1024; + static_assert(kMaxSniffLength >= net::kMaxBytesToSniff, + "kMaxSniffLength is too small."); + base::StringPiece input(reinterpret_cast<const char*>(data), size); + // Divide up the input. It's important not to pass |url_string| to the GURL + // constructor until after the length check, to prevent the fuzzer from + // exploring GURL space with invalid inputs. + std::string url_string = GetNextArgument(&input); std::string mime_type_hint = GetNextArgument(&input); + // Do nothing if input is too long. + if (input.length() > kMaxSniffLength) + return 0; + std::string result; - net::SniffMimeType(input.data(), input.length(), url, mime_type_hint, - &result); + net::SniffMimeType(input.data(), input.length(), GURL(url_string), + mime_type_hint, &result); net::SniffMimeTypeFromLocalData(input.data(), input.length(), &result); diff --git a/chromium/net/base/net_error_list.h b/chromium/net/base/net_error_list.h index 8b7e5b4b9e3..d1857c25feb 100644 --- a/chromium/net/base/net_error_list.h +++ b/chromium/net/base/net_error_list.h @@ -729,6 +729,13 @@ NET_ERROR(CONTENT_DECODING_INIT_FAILED, -371) // SpdyStream layer. NET_ERROR(SPDY_RST_STREAM_NO_ERROR_RECEIVED, -372) +// The pushed stream claimed by the request is no longer available. +NET_ERROR(SPDY_PUSHED_STREAM_NOT_AVAILABLE, -373) + +// A pushed stream was claimed and later reset by the server. When this happens, +// the request should be retried. +NET_ERROR(SPDY_CLAIMED_PUSHED_STREAM_RESET_BY_SERVER, -374) + // The cache does not have the requested entry. NET_ERROR(CACHE_MISS, -400) diff --git a/chromium/net/base/network_change_notifier.cc b/chromium/net/base/network_change_notifier.cc index 190b420f9f1..573ec3a23db 100644 --- a/chromium/net/base/network_change_notifier.cc +++ b/chromium/net/base/network_change_notifier.cc @@ -21,7 +21,7 @@ #include "url/gurl.h" #if defined(OS_ANDROID) -#include "base/metrics/sparse_histogram.h" +#include "base/metrics/histogram_functions.h" #include "base/strings/string_number_conversions.h" #include "net/android/network_library.h" #endif @@ -296,8 +296,7 @@ class NetworkChangeNotifier::HistogramWatcher : public ConnectionTypeObserver, // from the network thread. void NotifyDataReceived(const URLRequest& request, int bytes_read) { DCHECK(thread_checker_.CalledOnValidThread()); - if (IsLocalhost(request.url().host()) || - !request.url().SchemeIsHTTPOrHTTPS()) { + if (IsLocalhost(request.url()) || !request.url().SchemeIsHTTPOrHTTPS()) { return; } @@ -500,6 +499,11 @@ NetworkChangeNotifier::~NetworkChangeNotifier() { } // static +NetworkChangeNotifierFactory* NetworkChangeNotifier::GetFactory() { + return g_network_change_notifier_factory; +} + +// static void NetworkChangeNotifier::SetFactory( NetworkChangeNotifierFactory* factory) { CHECK(!g_network_change_notifier_factory); @@ -760,7 +764,7 @@ void NetworkChangeNotifier::LogOperatorCodeHistogram(ConnectionType type) { mcc_mnc = 0; } } - UMA_HISTOGRAM_SPARSE_SLOWLY("NCN.NetworkOperatorMCCMNC", mcc_mnc); + base::UmaHistogramSparse("NCN.NetworkOperatorMCCMNC", mcc_mnc); #endif } diff --git a/chromium/net/base/network_change_notifier.h b/chromium/net/base/network_change_notifier.h index 3fa2d360c6d..62d064b55cf 100644 --- a/chromium/net/base/network_change_notifier.h +++ b/chromium/net/base/network_change_notifier.h @@ -253,6 +253,9 @@ class NET_EXPORT NetworkChangeNotifier { virtual ~NetworkChangeNotifier(); + // Returns the factory or nullptr if it is not set. + static NetworkChangeNotifierFactory* GetFactory(); + // Replaces the default class factory instance of NetworkChangeNotifier class. // The method will take over the ownership of |factory| object. static void SetFactory(NetworkChangeNotifierFactory* factory); diff --git a/chromium/net/base/network_throttle_manager_impl.cc b/chromium/net/base/network_throttle_manager_impl.cc index 4c96573b02d..52e1fcffc58 100644 --- a/chromium/net/base/network_throttle_manager_impl.cc +++ b/chromium/net/base/network_throttle_manager_impl.cc @@ -156,7 +156,7 @@ NetworkThrottleManagerImpl::NetworkThrottleManagerImpl() outstanding_recomputation_timer_( std::make_unique<base::Timer>(false /* retain_user_task */, false /* is_repeating */)), - tick_clock_(new base::DefaultTickClock()), + tick_clock_(base::DefaultTickClock::GetInstance()), weak_ptr_factory_(this) {} NetworkThrottleManagerImpl::~NetworkThrottleManagerImpl() = default; @@ -188,12 +188,11 @@ NetworkThrottleManagerImpl::CreateThrottle( } void NetworkThrottleManagerImpl::SetTickClockForTesting( - std::unique_ptr<base::TickClock> tick_clock) { - tick_clock_ = std::move(tick_clock); + base::TickClock* tick_clock) { + tick_clock_ = tick_clock; DCHECK(!outstanding_recomputation_timer_->IsRunning()); outstanding_recomputation_timer_ = std::make_unique<base::Timer>( - false /* retain_user_task */, false /* is_repeating */, - tick_clock_.get()); + false /* retain_user_task */, false /* is_repeating */, tick_clock_); } bool NetworkThrottleManagerImpl::ConditionallyTriggerTimerForTesting() { diff --git a/chromium/net/base/network_throttle_manager_impl.h b/chromium/net/base/network_throttle_manager_impl.h index a388032d90c..620da459931 100644 --- a/chromium/net/base/network_throttle_manager_impl.h +++ b/chromium/net/base/network_throttle_manager_impl.h @@ -71,7 +71,7 @@ class NET_EXPORT NetworkThrottleManagerImpl : public NetworkThrottleManager { RequestPriority priority, bool ignore_limits) override; - void SetTickClockForTesting(std::unique_ptr<base::TickClock> tick_clock); + void SetTickClockForTesting(base::TickClock* tick_clock); // If the |NowTicks()| value of |tick_clock_| is greater than the // time the outstanding_recomputation_timer_ has set to go off, Stop() @@ -140,7 +140,7 @@ class NET_EXPORT NetworkThrottleManagerImpl : public NetworkThrottleManager { ThrottleList blocked_throttles_; // For testing. - std::unique_ptr<base::TickClock> tick_clock_; + base::TickClock* tick_clock_; base::WeakPtrFactory<NetworkThrottleManagerImpl> weak_ptr_factory_; diff --git a/chromium/net/base/network_throttle_manager_impl_unittest.cc b/chromium/net/base/network_throttle_manager_impl_unittest.cc index 16ad54ceb3a..713b2680d13 100644 --- a/chromium/net/base/network_throttle_manager_impl_unittest.cc +++ b/chromium/net/base/network_throttle_manager_impl_unittest.cc @@ -47,14 +47,12 @@ class NetworkThrottleManagerTest : public testing::Test, NetworkThrottleManager::ThrottleDelegate { public: NetworkThrottleManagerTest() - : clock_(new base::SimpleTestTickClock), - now_(base::TimeTicks::Now()), + : now_(base::TimeTicks::Now()), throttle_state_change_count_(0), last_throttle_to_change_state_(nullptr), throttle_manager_(new NetworkThrottleManagerImpl) { - clock_->SetNowTicks(now_); - throttle_manager_->SetTickClockForTesting( - std::unique_ptr<base::TickClock>(clock_)); + clock_.SetNowTicks(now_); + throttle_manager_->SetTickClockForTesting(&clock_); } protected: @@ -67,7 +65,7 @@ class NetworkThrottleManagerTest : public testing::Test, // Set the offset of the test clock from now_. void SetClockDelta(base::TimeDelta time_delta) { - clock_->SetNowTicks(now_ + time_delta); + clock_.SetNowTicks(now_ + time_delta); } // Throttle creation @@ -108,7 +106,7 @@ class NetworkThrottleManagerTest : public testing::Test, base::ResetAndReturn(&throttle_state_changed_callback_).Run(); } - base::SimpleTestTickClock* clock_; + base::SimpleTestTickClock clock_; base::TimeTicks now_; int throttle_state_change_count_; NetworkThrottleManager::Throttle* last_throttle_to_change_state_; diff --git a/chromium/net/base/platform_mime_util_win.cc b/chromium/net/base/platform_mime_util_win.cc index d68aa8cba8b..89b36ececbd 100644 --- a/chromium/net/base/platform_mime_util_win.cc +++ b/chromium/net/base/platform_mime_util_win.cc @@ -9,6 +9,8 @@ #include "base/strings/utf_string_conversions.h" #include "base/win/registry.h" +#include <windows.h> + namespace net { bool PlatformMimeUtil::GetPlatformMimeTypeFromExtension( diff --git a/chromium/net/base/port_util.cc b/chromium/net/base/port_util.cc index 543d9db9435..83c98213988 100644 --- a/chromium/net/base/port_util.cc +++ b/chromium/net/base/port_util.cc @@ -90,10 +90,9 @@ const int kRestrictedPorts[] = { // KURL::port()) }; -// FTP overrides the following restricted ports. +// FTP overrides the following restricted port. const int kAllowedFtpPorts[] = { 21, // ftp data - 22, // ssh }; base::LazyInstance<std::multiset<int>>::Leaky g_explicitly_allowed_ports = diff --git a/chromium/net/base/prioritized_dispatcher_unittest.cc b/chromium/net/base/prioritized_dispatcher_unittest.cc index 7d0b90ea58f..3970ff4d5dc 100644 --- a/chromium/net/base/prioritized_dispatcher_unittest.cc +++ b/chromium/net/base/prioritized_dispatcher_unittest.cc @@ -177,7 +177,8 @@ TEST_F(PrioritizedDispatcherTest, GetLimits) { // Get current limits, make sure the original limits are returned. PrioritizedDispatcher::Limits retrieved_limits = dispatcher_->GetLimits(); ASSERT_EQ(original_limits.total_jobs, retrieved_limits.total_jobs); - ASSERT_EQ(NUM_PRIORITIES, retrieved_limits.reserved_slots.size()); + ASSERT_EQ(static_cast<size_t>(NUM_PRIORITIES), + retrieved_limits.reserved_slots.size()); for (size_t priority = MINIMUM_PRIORITY; priority <= MAXIMUM_PRIORITY; ++priority) { EXPECT_EQ(original_limits.reserved_slots[priority], @@ -193,7 +194,8 @@ TEST_F(PrioritizedDispatcherTest, GetLimits) { // Get current limits, make sure the new limits are returned. retrieved_limits = dispatcher_->GetLimits(); ASSERT_EQ(new_limits.total_jobs, retrieved_limits.total_jobs); - ASSERT_EQ(NUM_PRIORITIES, retrieved_limits.reserved_slots.size()); + ASSERT_EQ(static_cast<size_t>(NUM_PRIORITIES), + retrieved_limits.reserved_slots.size()); for (size_t priority = MINIMUM_PRIORITY; priority <= MAXIMUM_PRIORITY; ++priority) { EXPECT_EQ(new_limits.reserved_slots[priority], diff --git a/chromium/net/base/proxy_delegate.h b/chromium/net/base/proxy_delegate.h index efcc347ffd4..356717b30b2 100644 --- a/chromium/net/base/proxy_delegate.h +++ b/chromium/net/base/proxy_delegate.h @@ -15,12 +15,8 @@ class GURL; namespace net { -class HttpRequestHeaders; -class HttpResponseHeaders; -class HostPortPair; class ProxyInfo; class ProxyServer; -class ProxyService; // Delegate for setting up a connection. class NET_EXPORT ProxyDelegate { @@ -48,36 +44,9 @@ class NET_EXPORT ProxyDelegate { virtual void OnFallback(const ProxyServer& bad_proxy, int net_error) = 0; - // Called immediately before a proxy tunnel request is sent. - // Provides the embedder an opportunity to add extra request headers. - virtual void OnBeforeTunnelRequest(const HostPortPair& proxy_server, - HttpRequestHeaders* extra_headers) = 0; - - // Called when the connect attempt to a CONNECT proxy has completed. - virtual void OnTunnelConnectCompleted(const HostPortPair& endpoint, - const HostPortPair& proxy_server, - int net_error) = 0; - - // Called after the response headers for the tunnel request are received. - virtual void OnTunnelHeadersReceived( - const HostPortPair& origin, - const HostPortPair& proxy_server, - const HttpResponseHeaders& response_headers) = 0; - // Returns true if |proxy_server| is a trusted SPDY/HTTP2 proxy that is // allowed to push cross-origin resources. - virtual bool IsTrustedSpdyProxy(const net::ProxyServer& proxy_server) = 0; - - // Called after the proxy is resolved but before the connection is - // established. |resolved_proxy_server| is the proxy server resolved by the - // proxy service for fetching |url|. Sets |alternative_proxy_server| to an - // alternative proxy server, if one is available to fetch |url|. - // |alternative_proxy_server| is owned by the caller, and is guaranteed to be - // non-null. - virtual void GetAlternativeProxy( - const GURL& url, - const ProxyServer& resolved_proxy_server, - ProxyServer* alternative_proxy_server) const = 0; + virtual bool IsTrustedSpdyProxy(const ProxyServer& proxy_server) = 0; // Notifies the ProxyDelegate that |alternative_proxy_server| is broken. virtual void OnAlternativeProxyBroken( diff --git a/chromium/net/base/test_proxy_delegate.cc b/chromium/net/base/test_proxy_delegate.cc index 35d7f6438b7..66e98cb0d1d 100644 --- a/chromium/net/base/test_proxy_delegate.cc +++ b/chromium/net/base/test_proxy_delegate.cc @@ -4,93 +4,30 @@ #include "net/base/test_proxy_delegate.h" -#include "net/http/http_request_headers.h" -#include "net/http/http_response_headers.h" +#include "net/proxy/proxy_info.h" #include "testing/gtest/include/gtest/gtest.h" namespace net { -TestProxyDelegate::TestProxyDelegate() - : on_before_tunnel_request_called_(false), - on_tunnel_request_completed_called_(false), - on_tunnel_headers_received_called_(false), - get_alternative_proxy_invocations_(0) {} +TestProxyDelegate::TestProxyDelegate() = default; TestProxyDelegate::~TestProxyDelegate() = default; -void TestProxyDelegate::VerifyOnTunnelRequestCompleted( - const std::string& endpoint, - const std::string& proxy_server) const { - EXPECT_TRUE(on_tunnel_request_completed_called_); - EXPECT_TRUE(HostPortPair::FromString(endpoint).Equals( - on_tunnel_request_completed_endpoint_)); - EXPECT_TRUE(HostPortPair::FromString(proxy_server) - .Equals(on_tunnel_request_completed_proxy_server_)); -} - -void TestProxyDelegate::VerifyOnTunnelHeadersReceived( - const std::string& origin, - const std::string& proxy_server, - const std::string& status_line) const { - EXPECT_TRUE(on_tunnel_headers_received_called_); - EXPECT_TRUE(HostPortPair::FromString(origin).Equals( - on_tunnel_headers_received_origin_)); - EXPECT_TRUE(HostPortPair::FromString(proxy_server) - .Equals(on_tunnel_headers_received_proxy_server_)); - EXPECT_EQ(status_line, on_tunnel_headers_received_status_line_); -} - void TestProxyDelegate::OnResolveProxy( const GURL& url, const std::string& method, const ProxyRetryInfoMap& proxy_retry_info, - ProxyInfo* result) {} - -void TestProxyDelegate::OnTunnelConnectCompleted( - const HostPortPair& endpoint, - const HostPortPair& proxy_server, - int net_error) { - on_tunnel_request_completed_called_ = true; - on_tunnel_request_completed_endpoint_ = endpoint; - on_tunnel_request_completed_proxy_server_ = proxy_server; + ProxyInfo* result) { + result->SetAlternativeProxy(alternative_proxy_server_); } void TestProxyDelegate::OnFallback(const ProxyServer& bad_proxy, int net_error) {} -void TestProxyDelegate::OnBeforeTunnelRequest( - const HostPortPair& proxy_server, - HttpRequestHeaders* extra_headers) { - on_before_tunnel_request_called_ = true; - if (extra_headers) - extra_headers->SetHeader("Foo", proxy_server.ToString()); -} - -void TestProxyDelegate::OnTunnelHeadersReceived( - const HostPortPair& origin, - const HostPortPair& proxy_server, - const HttpResponseHeaders& response_headers) { - on_tunnel_headers_received_called_ = true; - on_tunnel_headers_received_origin_ = origin; - on_tunnel_headers_received_proxy_server_ = proxy_server; - on_tunnel_headers_received_status_line_ = response_headers.GetStatusLine(); -} - -bool TestProxyDelegate::IsTrustedSpdyProxy( - const net::ProxyServer& proxy_server) { +bool TestProxyDelegate::IsTrustedSpdyProxy(const ProxyServer& proxy_server) { return proxy_server.is_valid() && trusted_spdy_proxy_ == proxy_server; } -void TestProxyDelegate::GetAlternativeProxy( - const GURL& url, - const ProxyServer& resolved_proxy_server, - ProxyServer* alternative_proxy_server) const { - EXPECT_TRUE(resolved_proxy_server.is_valid()); - EXPECT_FALSE(alternative_proxy_server->is_valid()); - *alternative_proxy_server = alternative_proxy_server_; - get_alternative_proxy_invocations_++; -} - void TestProxyDelegate::OnAlternativeProxyBroken( const ProxyServer& alternative_proxy_server) { EXPECT_TRUE(alternative_proxy_server.is_valid()); diff --git a/chromium/net/base/test_proxy_delegate.h b/chromium/net/base/test_proxy_delegate.h index 08c2caa1eb4..073e4da6f8d 100644 --- a/chromium/net/base/test_proxy_delegate.h +++ b/chromium/net/base/test_proxy_delegate.h @@ -7,7 +7,6 @@ #include <string> -#include "net/base/host_port_pair.h" #include "net/base/proxy_delegate.h" #include "net/proxy/proxy_server.h" @@ -15,8 +14,6 @@ class GURL; namespace net { -class HttpRequestHeaders; -class HttpResponseHeaders; class ProxyInfo; class TestProxyDelegate : public ProxyDelegate { @@ -24,49 +21,17 @@ class TestProxyDelegate : public ProxyDelegate { TestProxyDelegate(); ~TestProxyDelegate() override; - bool on_before_tunnel_request_called() const { - return on_before_tunnel_request_called_; - } - - bool on_tunnel_request_completed_called() const { - return on_tunnel_request_completed_called_; - } - - bool on_tunnel_headers_received_called() const { - return on_tunnel_headers_received_called_; - } - - void set_trusted_spdy_proxy(const net::ProxyServer& proxy_server) { + void set_trusted_spdy_proxy(const ProxyServer& proxy_server) { trusted_spdy_proxy_ = proxy_server; } - void VerifyOnTunnelRequestCompleted(const std::string& endpoint, - const std::string& proxy_server) const; - - void VerifyOnTunnelHeadersReceived(const std::string& origin, - const std::string& proxy_server, - const std::string& status_line) const; - // ProxyDelegate implementation: void OnResolveProxy(const GURL& url, const std::string& method, const ProxyRetryInfoMap& proxy_retry_info, ProxyInfo* result) override; - void OnTunnelConnectCompleted(const HostPortPair& endpoint, - const HostPortPair& proxy_server, - int net_error) override; void OnFallback(const ProxyServer& bad_proxy, int net_error) override; - void OnBeforeTunnelRequest(const HostPortPair& proxy_server, - HttpRequestHeaders* extra_headers) override; - void OnTunnelHeadersReceived( - const HostPortPair& origin, - const HostPortPair& proxy_server, - const HttpResponseHeaders& response_headers) override; - bool IsTrustedSpdyProxy(const net::ProxyServer& proxy_server) override; - void GetAlternativeProxy( - const GURL& url, - const ProxyServer& resolved_proxy_server, - ProxyServer* alternative_proxy_server) const override; + bool IsTrustedSpdyProxy(const ProxyServer& proxy_server) override; void OnAlternativeProxyBroken( const ProxyServer& alternative_proxy_server) override; @@ -78,24 +43,9 @@ class TestProxyDelegate : public ProxyDelegate { return alternative_proxy_server_; } - int get_alternative_proxy_invocations() const { - return get_alternative_proxy_invocations_; - } - private: - bool on_before_tunnel_request_called_; - bool on_tunnel_request_completed_called_; - bool on_tunnel_headers_received_called_; - net::ProxyServer trusted_spdy_proxy_; - HostPortPair on_tunnel_request_completed_endpoint_; - HostPortPair on_tunnel_request_completed_proxy_server_; - HostPortPair on_tunnel_headers_received_origin_; - HostPortPair on_tunnel_headers_received_proxy_server_; - std::string on_tunnel_headers_received_status_line_; + ProxyServer trusted_spdy_proxy_; ProxyServer alternative_proxy_server_; - - // Number of times GetAlternativeProxy() method has been called. - mutable int get_alternative_proxy_invocations_; }; } // namespace net diff --git a/chromium/net/base/upload_element_reader.h b/chromium/net/base/upload_element_reader.h index 08353f48089..32751dae03f 100644 --- a/chromium/net/base/upload_element_reader.h +++ b/chromium/net/base/upload_element_reader.h @@ -33,8 +33,9 @@ class NET_EXPORT UploadElementReader { // This function must be called before calling any other method. It is not // valid to call any method (other than the destructor) if Init() fails. - // This method can be called multiple times. Calling this method after an - // Init() success results in resetting the state (i.e. the stream is rewound). + // This method can be called multiple times. Calling this results in resetting + // the state (i.e. the stream is rewound), and any previously pending Init() + // or Read() calls are aborted. // // Initializes the instance synchronously when possible, otherwise does // initialization aynschronously, returns ERR_IO_PENDING and runs callback. diff --git a/chromium/net/base/url_util.cc b/chromium/net/base/url_util.cc index 565788b3b13..3bd93aa4006 100644 --- a/chromium/net/base/url_util.cc +++ b/chromium/net/base/url_util.cc @@ -346,7 +346,11 @@ bool IsHostnameNonUnique(const std::string& hostname) { registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES); } -bool IsLocalhost(base::StringPiece host) { +bool IsLocalhost(const GURL& url) { + return HostStringIsLocalhost(url.HostNoBracketsPiece()); +} + +bool HostStringIsLocalhost(base::StringPiece host) { if (IsLocalHostname(host, nullptr)) return true; diff --git a/chromium/net/base/url_util.h b/chromium/net/base/url_util.h index 2eb6d384112..97e7724cfd3 100644 --- a/chromium/net/base/url_util.h +++ b/chromium/net/base/url_util.h @@ -142,13 +142,19 @@ NET_EXPORT bool IsCanonicalizedHostCompliant(const std::string& host); // that falls in an IANA-reserved range. NET_EXPORT bool IsHostnameNonUnique(const std::string& hostname); +// Returns true if the host part of |url| is a local host name according to +// HostStringIsLocalhost. +NET_EXPORT bool IsLocalhost(const GURL& url); + // Returns true if |host| is one of the local hostnames // (e.g. "localhost") or IP addresses (IPv4 127.0.0.0/8 or IPv6 ::1). +// "[::1]" is not detected as a local hostname. Do not use this method to check +// whether the host part of a URL is a local host name; use IsLocalhost instead. // // Note that this function does not check for IP addresses other than // the above, although other IP addresses may point to the local // machine. -NET_EXPORT bool IsLocalhost(base::StringPiece host); +NET_EXPORT bool HostStringIsLocalhost(base::StringPiece host); // Strip the portions of |url| that aren't core to the network request. // - user name / password diff --git a/chromium/net/base/url_util_unittest.cc b/chromium/net/base/url_util_unittest.cc index cee4bb22d71..67acfd2381b 100644 --- a/chromium/net/base/url_util_unittest.cc +++ b/chromium/net/base/url_util_unittest.cc @@ -388,47 +388,51 @@ INSTANTIATE_TEST_CASE_P(, UrlUtilNonUniqueNameTest, testing::ValuesIn(kNonUniqueNameTestData)); TEST(UrlUtilTest, IsLocalhost) { - EXPECT_TRUE(IsLocalhost("localhost")); - EXPECT_TRUE(IsLocalhost("localHosT")); - EXPECT_TRUE(IsLocalhost("localhost.")); - EXPECT_TRUE(IsLocalhost("localHost.")); - EXPECT_TRUE(IsLocalhost("localhost.localdomain")); - EXPECT_TRUE(IsLocalhost("localhost.localDOMain")); - EXPECT_TRUE(IsLocalhost("localhost.localdomain.")); - EXPECT_TRUE(IsLocalhost("localhost6")); - EXPECT_TRUE(IsLocalhost("localhost6.")); - EXPECT_TRUE(IsLocalhost("localhost6.localdomain6")); - EXPECT_TRUE(IsLocalhost("localhost6.localdomain6.")); - EXPECT_TRUE(IsLocalhost("127.0.0.1")); - EXPECT_TRUE(IsLocalhost("127.0.1.0")); - EXPECT_TRUE(IsLocalhost("127.1.0.0")); - EXPECT_TRUE(IsLocalhost("127.0.0.255")); - EXPECT_TRUE(IsLocalhost("127.0.255.0")); - EXPECT_TRUE(IsLocalhost("127.255.0.0")); - EXPECT_TRUE(IsLocalhost("::1")); - EXPECT_TRUE(IsLocalhost("0:0:0:0:0:0:0:1")); - EXPECT_TRUE(IsLocalhost("foo.localhost")); - EXPECT_TRUE(IsLocalhost("foo.localhost.")); - EXPECT_TRUE(IsLocalhost("foo.localhoST")); - EXPECT_TRUE(IsLocalhost("foo.localhoST.")); - - EXPECT_FALSE(IsLocalhost("localhostx")); - EXPECT_FALSE(IsLocalhost("localhost.x")); - EXPECT_FALSE(IsLocalhost("foo.localdomain")); - EXPECT_FALSE(IsLocalhost("foo.localdomain.x")); - EXPECT_FALSE(IsLocalhost("localhost6x")); - EXPECT_FALSE(IsLocalhost("localhost.localdomain6")); - EXPECT_FALSE(IsLocalhost("localhost6.localdomain")); - EXPECT_FALSE(IsLocalhost("127.0.0.1.1")); - EXPECT_FALSE(IsLocalhost(".127.0.0.255")); - EXPECT_FALSE(IsLocalhost("::2")); - EXPECT_FALSE(IsLocalhost("::1:1")); - EXPECT_FALSE(IsLocalhost("0:0:0:0:1:0:0:1")); - EXPECT_FALSE(IsLocalhost("::1:1")); - EXPECT_FALSE(IsLocalhost("0:0:0:0:0:0:0:0:1")); - EXPECT_FALSE(IsLocalhost("foo.localhost.com")); - EXPECT_FALSE(IsLocalhost("foo.localhoste")); - EXPECT_FALSE(IsLocalhost("foo.localhos")); + EXPECT_TRUE(HostStringIsLocalhost("localhost")); + EXPECT_TRUE(HostStringIsLocalhost("localHosT")); + EXPECT_TRUE(HostStringIsLocalhost("localhost.")); + EXPECT_TRUE(HostStringIsLocalhost("localHost.")); + EXPECT_TRUE(HostStringIsLocalhost("localhost.localdomain")); + EXPECT_TRUE(HostStringIsLocalhost("localhost.localDOMain")); + EXPECT_TRUE(HostStringIsLocalhost("localhost.localdomain.")); + EXPECT_TRUE(HostStringIsLocalhost("localhost6")); + EXPECT_TRUE(HostStringIsLocalhost("localhost6.")); + EXPECT_TRUE(HostStringIsLocalhost("localhost6.localdomain6")); + EXPECT_TRUE(HostStringIsLocalhost("localhost6.localdomain6.")); + EXPECT_TRUE(HostStringIsLocalhost("127.0.0.1")); + EXPECT_TRUE(HostStringIsLocalhost("127.0.1.0")); + EXPECT_TRUE(HostStringIsLocalhost("127.1.0.0")); + EXPECT_TRUE(HostStringIsLocalhost("127.0.0.255")); + EXPECT_TRUE(HostStringIsLocalhost("127.0.255.0")); + EXPECT_TRUE(HostStringIsLocalhost("127.255.0.0")); + EXPECT_TRUE(HostStringIsLocalhost("::1")); + EXPECT_TRUE(HostStringIsLocalhost("0:0:0:0:0:0:0:1")); + EXPECT_TRUE(HostStringIsLocalhost("foo.localhost")); + EXPECT_TRUE(HostStringIsLocalhost("foo.localhost.")); + EXPECT_TRUE(HostStringIsLocalhost("foo.localhoST")); + EXPECT_TRUE(HostStringIsLocalhost("foo.localhoST.")); + + EXPECT_FALSE(HostStringIsLocalhost("localhostx")); + EXPECT_FALSE(HostStringIsLocalhost("localhost.x")); + EXPECT_FALSE(HostStringIsLocalhost("foo.localdomain")); + EXPECT_FALSE(HostStringIsLocalhost("foo.localdomain.x")); + EXPECT_FALSE(HostStringIsLocalhost("localhost6x")); + EXPECT_FALSE(HostStringIsLocalhost("localhost.localdomain6")); + EXPECT_FALSE(HostStringIsLocalhost("localhost6.localdomain")); + EXPECT_FALSE(HostStringIsLocalhost("127.0.0.1.1")); + EXPECT_FALSE(HostStringIsLocalhost(".127.0.0.255")); + EXPECT_FALSE(HostStringIsLocalhost("::2")); + EXPECT_FALSE(HostStringIsLocalhost("::1:1")); + EXPECT_FALSE(HostStringIsLocalhost("0:0:0:0:1:0:0:1")); + EXPECT_FALSE(HostStringIsLocalhost("::1:1")); + EXPECT_FALSE(HostStringIsLocalhost("0:0:0:0:0:0:0:0:1")); + EXPECT_FALSE(HostStringIsLocalhost("foo.localhost.com")); + EXPECT_FALSE(HostStringIsLocalhost("foo.localhoste")); + EXPECT_FALSE(HostStringIsLocalhost("foo.localhos")); + EXPECT_FALSE(HostStringIsLocalhost("[::1]")); + + GURL localhost6("http://[::1]/"); + EXPECT_TRUE(IsLocalhost(localhost6)); } TEST(UrlUtilTest, SimplifyUrlForRequest) { diff --git a/chromium/net/cert/asn1_util.cc b/chromium/net/cert/asn1_util.cc index 6b45f1651f1..abba2d55559 100644 --- a/chromium/net/cert/asn1_util.cc +++ b/chromium/net/cert/asn1_util.cc @@ -15,10 +15,10 @@ namespace asn1 { namespace { // Parses input |in| which should point to the beginning of a Certificate, and -// sets |*tbs_certificate| ready to parse the SubjectPublicKeyInfo. If parsing +// sets |*tbs_certificate| ready to parse the Subject. If parsing // fails, this function returns false and |*tbs_certificate| is left in an // undefined state. -bool SeekToSPKI(der::Input in, der::Parser* tbs_certificate) { +bool SeekToSubject(der::Input in, der::Parser* tbs_certificate) { // From RFC 5280, section 4.1 // Certificate ::= SEQUENCE { // tbsCertificate TBSCertificate, @@ -65,12 +65,19 @@ bool SeekToSPKI(der::Input in, der::Parser* tbs_certificate) { // validity if (!tbs_certificate->SkipTag(der::kSequence)) return false; - // subject - if (!tbs_certificate->SkipTag(der::kSequence)) - return false; return true; } +// Parses input |in| which should point to the beginning of a Certificate, and +// sets |*tbs_certificate| ready to parse the SubjectPublicKeyInfo. If parsing +// fails, this function returns false and |*tbs_certificate| is left in an +// undefined state. +bool SeekToSPKI(der::Input in, der::Parser* tbs_certificate) { + return SeekToSubject(in, tbs_certificate) && + // Skip over Subject. + tbs_certificate->SkipTag(der::kSequence); +} + // Parses input |in| which should point to the beginning of a // Certificate. If parsing fails, this function returns false, with // |*extensions_present| and |*extensions_parser| left in an undefined @@ -142,6 +149,18 @@ bool SeekToExtensions(der::Input in, } // namespace +bool ExtractSubjectFromDERCert(base::StringPiece cert, + base::StringPiece* subject_out) { + der::Parser parser; + if (!SeekToSubject(der::Input(cert), &parser)) + return false; + der::Input subject; + if (!parser.ReadRawTLV(&subject)) + return false; + *subject_out = subject.AsStringPiece(); + return true; +} + bool ExtractSPKIFromDERCert(base::StringPiece cert, base::StringPiece* spki_out) { der::Parser parser; diff --git a/chromium/net/cert/asn1_util.h b/chromium/net/cert/asn1_util.h index 30ccc766333..96f3d2ab663 100644 --- a/chromium/net/cert/asn1_util.h +++ b/chromium/net/cert/asn1_util.h @@ -14,6 +14,13 @@ namespace net { namespace asn1 { +// ExtractSubjectFromDERCert parses the DER encoded certificate in |cert| and +// extracts the bytes of the X.501 Subject. On successful return, |subject_out| +// is set to contain the Subject, pointing into |cert|. +NET_EXPORT_PRIVATE bool ExtractSubjectFromDERCert( + base::StringPiece cert, + base::StringPiece* subject_out); + // ExtractSPKIFromDERCert parses the DER encoded certificate in |cert| and // extracts the bytes of the SubjectPublicKeyInfo. On successful return, // |spki_out| is set to contain the SPKI, pointing into |cert|. diff --git a/chromium/net/cert/caching_cert_verifier_unittest.cc b/chromium/net/cert/caching_cert_verifier_unittest.cc index 354059f17e2..11e0917fe2d 100644 --- a/chromium/net/cert/caching_cert_verifier_unittest.cc +++ b/chromium/net/cert/caching_cert_verifier_unittest.cc @@ -12,6 +12,7 @@ #include "net/cert/cert_verify_result.h" #include "net/cert/mock_cert_verifier.h" #include "net/cert/x509_certificate.h" +#include "net/cert/x509_util.h" #include "net/log/net_log_with_source.h" #include "net/test/cert_test_util.h" #include "net/test/gtest_util.h" @@ -234,18 +235,22 @@ TEST_F(CachingCertVerifierTest, DifferentCACerts) { ImportCertFromFile(certs_dir, "verisign_intermediate_ca_2016.pem"); ASSERT_TRUE(intermediate_cert2); - X509Certificate::OSCertHandles intermediates; - intermediates.push_back(intermediate_cert1->os_cert_handle()); + std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates; + intermediates.push_back( + x509_util::DupCryptoBuffer(intermediate_cert1->cert_buffer())); scoped_refptr<X509Certificate> cert_chain1 = - X509Certificate::CreateFromHandle(server_cert->os_cert_handle(), - intermediates); + X509Certificate::CreateFromBuffer( + x509_util::DupCryptoBuffer(server_cert->cert_buffer()), + std::move(intermediates)); ASSERT_TRUE(cert_chain1); intermediates.clear(); - intermediates.push_back(intermediate_cert2->os_cert_handle()); + intermediates.push_back( + x509_util::DupCryptoBuffer(intermediate_cert2->cert_buffer())); scoped_refptr<X509Certificate> cert_chain2 = - X509Certificate::CreateFromHandle(server_cert->os_cert_handle(), - intermediates); + X509Certificate::CreateFromBuffer( + x509_util::DupCryptoBuffer(server_cert->cert_buffer()), + std::move(intermediates)); ASSERT_TRUE(cert_chain2); int error; diff --git a/chromium/net/cert/cert_verifier.cc b/chromium/net/cert/cert_verifier.cc index 5742ee16d25..f8e6a7f9711 100644 --- a/chromium/net/cert/cert_verifier.cc +++ b/chromium/net/cert/cert_verifier.cc @@ -9,6 +9,7 @@ #include "base/strings/string_util.h" #include "build/build_config.h" #include "net/cert/cert_verify_proc.h" +#include "third_party/boringssl/src/include/openssl/pool.h" #include "third_party/boringssl/src/include/openssl/sha.h" #if defined(OS_NACL) @@ -37,19 +38,18 @@ CertVerifier::RequestParams::RequestParams( // sake. SHA256_CTX ctx; SHA256_Init(&ctx); - std::string cert_der; - X509Certificate::GetDEREncoded(certificate_->os_cert_handle(), &cert_der); - SHA256_Update(&ctx, cert_der.data(), cert_der.size()); - for (auto* cert_handle : certificate_->GetIntermediateCertificates()) { - X509Certificate::GetDEREncoded(cert_handle, &cert_der); - SHA256_Update(&ctx, cert_der.data(), cert_der.size()); + SHA256_Update(&ctx, CRYPTO_BUFFER_data(certificate_->cert_buffer()), + CRYPTO_BUFFER_len(certificate_->cert_buffer())); + for (const auto& cert_handle : certificate_->intermediate_buffers()) { + SHA256_Update(&ctx, CRYPTO_BUFFER_data(cert_handle.get()), + CRYPTO_BUFFER_len(cert_handle.get())); } SHA256_Update(&ctx, hostname_.data(), hostname.size()); SHA256_Update(&ctx, &flags, sizeof(flags)); SHA256_Update(&ctx, ocsp_response.data(), ocsp_response.size()); for (const auto& trust_anchor : additional_trust_anchors_) { - X509Certificate::GetDEREncoded(trust_anchor->os_cert_handle(), &cert_der); - SHA256_Update(&ctx, cert_der.data(), cert_der.size()); + SHA256_Update(&ctx, CRYPTO_BUFFER_data(trust_anchor->cert_buffer()), + CRYPTO_BUFFER_len(trust_anchor->cert_buffer())); } SHA256_Final(reinterpret_cast<uint8_t*>( base::WriteInto(&key_, SHA256_DIGEST_LENGTH + 1)), diff --git a/chromium/net/cert/cert_verifier.h b/chromium/net/cert/cert_verifier.h index 50cc8334902..2745942ed6f 100644 --- a/chromium/net/cert/cert_verifier.h +++ b/chromium/net/cert/cert_verifier.h @@ -84,6 +84,10 @@ class NET_EXPORT CertVerifier { // match against the commonName of the certificate, but only if they are // issued by non-public trust anchors. VERIFY_ENABLE_COMMON_NAME_FALLBACK_LOCAL_ANCHORS = 1 << 6, + + // If set, disables the policy enforcement described at + // https://security.googleblog.com/2017/09/chromes-plan-to-distrust-symantec.html + VERIFY_DISABLE_SYMANTEC_ENFORCEMENT = 1 << 7, }; // Parameters to verify |certificate| against the supplied diff --git a/chromium/net/cert/cert_verifier_unittest.cc b/chromium/net/cert/cert_verifier_unittest.cc index 73e7c9f8c88..b54f00fa3ab 100644 --- a/chromium/net/cert/cert_verifier_unittest.cc +++ b/chromium/net/cert/cert_verifier_unittest.cc @@ -7,6 +7,7 @@ #include "base/files/file_path.h" #include "base/memory/ref_counted.h" #include "net/cert/x509_certificate.h" +#include "net/cert/x509_util.h" #include "net/test/cert_test_util.h" #include "net/test/test_data_directory.h" #include "testing/gtest/include/gtest/gtest.h" @@ -28,10 +29,11 @@ TEST(CertVerifierTest, RequestParamsComparators) { // Create a certificate that contains both a leaf and an // intermediate/root. - X509Certificate::OSCertHandles chain; - chain.push_back(root_cert->os_cert_handle()); + std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> chain; + chain.push_back(x509_util::DupCryptoBuffer(root_cert->cert_buffer())); const scoped_refptr<X509Certificate> combined_cert = - X509Certificate::CreateFromHandle(ok_cert->os_cert_handle(), chain); + X509Certificate::CreateFromBuffer( + x509_util::DupCryptoBuffer(ok_cert->cert_buffer()), std::move(chain)); ASSERT_TRUE(combined_cert.get()); const CertificateList empty_list; diff --git a/chromium/net/cert/cert_verify_proc.cc b/chromium/net/cert/cert_verify_proc.cc index 47562afd75d..181590b6606 100644 --- a/chromium/net/cert/cert_verify_proc.cc +++ b/chromium/net/cert/cert_verify_proc.cc @@ -9,6 +9,7 @@ #include <algorithm> #include "base/metrics/histogram.h" +#include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" #include "base/sha1.h" #include "base/strings/string_util.h" @@ -29,7 +30,9 @@ #include "net/cert/internal/signature_algorithm.h" #include "net/cert/known_roots.h" #include "net/cert/ocsp_revocation_status.h" +#include "net/cert/symantec_certs.h" #include "net/cert/x509_certificate.h" +#include "net/cert/x509_util.h" #include "net/der/encode_values.h" #include "url/url_canon.h" @@ -152,7 +155,7 @@ bool ExaminePublicKeys(const scoped_refptr<X509Certificate>& cert, cert->valid_start() >= kBaselineEffectiveDate && cert->valid_expiry() >= kBaselineKeysizeEffectiveDate; - X509Certificate::GetPublicKeyInfo(cert->os_cert_handle(), &size_bits, &type); + X509Certificate::GetPublicKeyInfo(cert->cert_buffer(), &size_bits, &type); if (should_histogram) { RecordPublicKeyHistogram(kLeafCert, baseline_keysize_applies, size_bits, type); @@ -160,10 +163,11 @@ bool ExaminePublicKeys(const scoped_refptr<X509Certificate>& cert, if (IsWeakKey(type, size_bits)) weak_key = true; - const X509Certificate::OSCertHandles& intermediates = - cert->GetIntermediateCertificates(); + const std::vector<bssl::UniquePtr<CRYPTO_BUFFER>>& intermediates = + cert->intermediate_buffers(); for (size_t i = 0; i < intermediates.size(); ++i) { - X509Certificate::GetPublicKeyInfo(intermediates[i], &size_bits, &type); + X509Certificate::GetPublicKeyInfo(intermediates[i].get(), &size_bits, + &type); if (should_histogram) { RecordPublicKeyHistogram( (i < intermediates.size() - 1) ? kIntermediateCert : kRootCert, @@ -190,6 +194,23 @@ bool IsPastSHA1DeprecationDate(const X509Certificate& cert) { return start >= kSHA1DeprecationDate; } +// See +// https://security.googleblog.com/2017/09/chromes-plan-to-distrust-symantec.html +// for more details. +bool IsUntrustedSymantecCert(const X509Certificate& cert) { + const base::Time& start = cert.valid_start(); + if (start.is_max() || start.is_null()) + return true; + // Certificates issued on/after 2017-12-01 00:00:00 UTC are no longer + // trusted. + const base::Time kSymantecDeprecationDate = + base::Time::UnixEpoch() + base::TimeDelta::FromSeconds(1512086400); + if (start >= kSymantecDeprecationDate) + return true; + + return false; +} + void BestEffortCheckOCSP(const std::string& raw_response, const X509Certificate& certificate, OCSPVerifyResult* verify_result) { @@ -199,31 +220,24 @@ void BestEffortCheckOCSP(const std::string& raw_response, return; } - std::string cert_der; - if (!X509Certificate::GetDEREncoded(certificate.os_cert_handle(), - &cert_der)) { - *verify_result = OCSPVerifyResult(); - return; - } + base::StringPiece cert_der = + x509_util::CryptoBufferAsStringPiece(certificate.cert_buffer()); // Try to get the certificate that signed |certificate|. This will run into // problems if the CertVerifyProc implementation doesn't return the ordered // certificates. If that happens the OCSP verification may be incorrect. - std::string issuer_der; - const X509Certificate::OSCertHandles& intermediates = - certificate.GetIntermediateCertificates(); - if (intermediates.empty()) { - if (X509Certificate::IsSelfSigned(certificate.os_cert_handle())) { + base::StringPiece issuer_der; + if (certificate.intermediate_buffers().empty()) { + if (X509Certificate::IsSelfSigned(certificate.cert_buffer())) { issuer_der = cert_der; } else { // A valid cert chain wasn't provided. *verify_result = OCSPVerifyResult(); return; } - } else if (!X509Certificate::GetDEREncoded(intermediates.front(), - &issuer_der)) { - *verify_result = OCSPVerifyResult(); - return; + } else { + issuer_der = x509_util::CryptoBufferAsStringPiece( + certificate.intermediate_buffers().front().get()); } verify_result->revocation_status = @@ -238,16 +252,13 @@ void BestEffortCheckOCSP(const std::string& raw_response, void RecordTLSFeatureExtensionWithPrivateRoot( X509Certificate* cert, const OCSPVerifyResult& ocsp_result) { - std::string cert_der; - if (!X509Certificate::GetDEREncoded(cert->os_cert_handle(), &cert_der)) - return; - // This checks only for the presence of the TLS Feature Extension, but // does not check the feature list, and in particular does not verify that // its value is 'status_request' or 'status_request2'. In practice the // only use of the TLS feature extension is for OCSP stapling, so // don't bother to check the value. - bool has_extension = asn1::HasTLSFeatureExtension(cert_der); + bool has_extension = asn1::HasTLSFeatureExtension( + x509_util::CryptoBufferAsStringPiece(cert->cert_buffer())); UMA_HISTOGRAM_BOOLEAN("Net.Certificate.TLSFeatureExtensionWithPrivateRoot", has_extension); @@ -279,7 +290,7 @@ void RecordTrustAnchorHistogram(const HashValueVector& spki_hashes) { if (id != 0) break; } - UMA_HISTOGRAM_SPARSE_SLOWLY("Net.Certificate.TrustAnchor.Verify", id); + base::UmaHistogramSparse("Net.Certificate.TrustAnchor.Verify", id); } // Comparison functor used for binary searching whether a given HashValue, @@ -345,16 +356,15 @@ void MapAlgorithmToBool(DigestAlgorithm hash, CertVerifyResult* verify_result) { // // Returns false if the signature algorithm was unknown or mismatched. WARN_UNUSED_RESULT bool InspectSignatureAlgorithmForCert( - X509Certificate::OSCertHandle cert, + const CRYPTO_BUFFER* cert, CertVerifyResult* verify_result) { - std::string cert_der; base::StringPiece cert_algorithm_sequence; base::StringPiece tbs_algorithm_sequence; // Extract the AlgorithmIdentifier SEQUENCEs - if (!X509Certificate::GetDEREncoded(cert, &cert_der) || - !asn1::ExtractSignatureAlgorithmsFromDERCert( - cert_der, &cert_algorithm_sequence, &tbs_algorithm_sequence)) { + if (!asn1::ExtractSignatureAlgorithmsFromDERCert( + x509_util::CryptoBufferAsStringPiece(cert), &cert_algorithm_sequence, + &tbs_algorithm_sequence)) { return false; } @@ -412,8 +422,8 @@ WARN_UNUSED_RESULT bool InspectSignatureAlgorithmForCert( // in order to prevent such confusion. WARN_UNUSED_RESULT bool InspectSignatureAlgorithmsInChain( CertVerifyResult* verify_result) { - const X509Certificate::OSCertHandles& intermediates = - verify_result->verified_cert->GetIntermediateCertificates(); + const std::vector<bssl::UniquePtr<CRYPTO_BUFFER>>& intermediates = + verify_result->verified_cert->intermediate_buffers(); // If there are no intermediates, then the leaf is trusted or verification // failed. @@ -424,7 +434,7 @@ WARN_UNUSED_RESULT bool InspectSignatureAlgorithmsInChain( // Fill in hash algorithms for the leaf certificate. if (!InspectSignatureAlgorithmForCert( - verify_result->verified_cert->os_cert_handle(), verify_result)) { + verify_result->verified_cert->cert_buffer(), verify_result)) { return false; } @@ -434,7 +444,8 @@ WARN_UNUSED_RESULT bool InspectSignatureAlgorithmsInChain( // final one (which is presumably the trust anchor; may be incorrect for // partial chains). for (size_t i = 0; i + 1 < intermediates.size(); ++i) { - if (!InspectSignatureAlgorithmForCert(intermediates[i], verify_result)) + if (!InspectSignatureAlgorithmForCert(intermediates[i].get(), + verify_result)) return false; } @@ -589,6 +600,17 @@ int CertVerifyProc::Verify(X509Certificate* cert, rv = MapCertStatusToNetError(verify_result->cert_status); } + // Distrust Symantec-issued certificates, as described at + // https://security.googleblog.com/2017/09/chromes-plan-to-distrust-symantec.html + if (!(flags & CertVerifier::VERIFY_DISABLE_SYMANTEC_ENFORCEMENT) && + IsLegacySymantecCert(verify_result->public_key_hashes)) { + if (IsUntrustedSymantecCert(*verify_result->verified_cert)) { + verify_result->cert_status |= CERT_STATUS_AUTHORITY_INVALID; + if (rv == OK || IsCertificateError(rv)) + rv = MapCertStatusToNetError(verify_result->cert_status); + } + } + // Flag certificates from publicly-trusted CAs that are issued to intranet // hosts. While the CA/Browser Forum Baseline Requirements (v1.1) permit // these to be issued until 1 November 2015, they represent a real risk for @@ -649,7 +671,7 @@ bool CertVerifyProc::IsPublicKeyBlacklisted( // Defines kBlacklistedSPKIs. #include "net/cert/cert_verify_proc_blacklist.inc" for (const auto& hash : public_key_hashes) { - if (hash.tag != HASH_VALUE_SHA256) + if (hash.tag() != HASH_VALUE_SHA256) continue; if (std::binary_search(std::begin(kBlacklistedSPKIs), std::end(kBlacklistedSPKIs), hash, @@ -806,7 +828,7 @@ bool CertVerifyProc::HasNameConstraintsViolation( for (unsigned i = 0; i < arraysize(kLimits); ++i) { for (HashValueVector::const_iterator j = public_key_hashes.begin(); j != public_key_hashes.end(); ++j) { - if (j->tag == HASH_VALUE_SHA256 && + if (j->tag() == HASH_VALUE_SHA256 && memcmp(j->data(), kLimits[i].public_key, crypto::kSHA256Length) == 0) { if (dns_names.empty() && ip_addrs.empty()) { diff --git a/chromium/net/cert/cert_verify_proc_android.cc b/chromium/net/cert/cert_verify_proc_android.cc index cdf87d3d829..e9c62318dee 100644 --- a/chromium/net/cert/cert_verify_proc_android.cc +++ b/chromium/net/cert/cert_verify_proc_android.cc @@ -8,6 +8,7 @@ #include <vector> #include "base/logging.h" +#include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" #include "base/sha1.h" #include "base/strings/string_piece.h" @@ -103,8 +104,8 @@ bool PerformAIAFetchAndAddResultToVector(scoped_refptr<CertNetFetcher> fetcher, Error error; std::vector<uint8_t> aia_fetch_bytes; request->WaitForResult(&error, &aia_fetch_bytes); - UMA_HISTOGRAM_SPARSE_SLOWLY("Net.Certificate.AndroidAIAFetchError", - std::abs(error)); + base::UmaHistogramSparse("Net.Certificate.AndroidAIAFetchError", + std::abs(error)); if (error != OK) return false; CertErrors errors; @@ -317,12 +318,12 @@ bool VerifyFromAndroidTrustManager( void GetChainDEREncodedBytes(X509Certificate* cert, std::vector<std::string>* chain_bytes) { - chain_bytes->reserve(1 + cert->GetIntermediateCertificates().size()); + chain_bytes->reserve(1 + cert->intermediate_buffers().size()); chain_bytes->emplace_back( - net::x509_util::CryptoBufferAsStringPiece(cert->os_cert_handle())); - for (auto* handle : cert->GetIntermediateCertificates()) { + net::x509_util::CryptoBufferAsStringPiece(cert->cert_buffer())); + for (const auto& handle : cert->intermediate_buffers()) { chain_bytes->emplace_back( - net::x509_util::CryptoBufferAsStringPiece(handle)); + net::x509_util::CryptoBufferAsStringPiece(handle.get())); } } diff --git a/chromium/net/cert/cert_verify_proc_android_unittest.cc b/chromium/net/cert/cert_verify_proc_android_unittest.cc index 4f8c42431eb..cc5e0ec4069 100644 --- a/chromium/net/cert/cert_verify_proc_android_unittest.cc +++ b/chromium/net/cert/cert_verify_proc_android_unittest.cc @@ -13,6 +13,7 @@ #include "net/cert/internal/test_helpers.h" #include "net/cert/test_root_certs.h" #include "net/cert/x509_certificate.h" +#include "net/cert/x509_util.h" #include "net/test/cert_test_util.h" #include "net/test/test_certificate_data.h" #include "net/test/test_data_directory.h" @@ -64,8 +65,8 @@ class MockCertNetFetcher : public CertNetFetcher { std::unique_ptr<CertNetFetcher::Request> CreateMockRequestFromX509Certificate( Error error, const scoped_refptr<X509Certificate>& cert) { - std::string der; - EXPECT_TRUE(X509Certificate::GetDEREncoded(cert->os_cert_handle(), &der)); + base::StringPiece der = + x509_util::CryptoBufferAsStringPiece(cert->cert_buffer()); return std::make_unique<TestCertNetFetcherRequest>( error, std::vector<uint8_t>(der.data(), der.data() + der.length())); } @@ -121,18 +122,18 @@ CreateMockRequestWithInvalidCertificate() { ::testing::AssertionResult r = ReadTestCert(files[0], &leaf); if (!r) return r; - CertificateList intermediates; - X509Certificate::OSCertHandles intermediate_os_cert_handles; + std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediate_buffers; for (size_t i = 1; i < files.size(); i++) { scoped_refptr<X509Certificate> intermediate; r = ReadTestCert(files[i], &intermediate); if (!r) return r; - intermediates.push_back(intermediate); - intermediate_os_cert_handles.push_back(intermediate->os_cert_handle()); + intermediate_buffers.push_back( + x509_util::DupCryptoBuffer(intermediate->cert_buffer())); } - *result = X509Certificate::CreateFromHandle(leaf->os_cert_handle(), - intermediate_os_cert_handles); + *result = X509Certificate::CreateFromBuffer( + x509_util::DupCryptoBuffer(leaf->cert_buffer()), + std::move(intermediate_buffers)); return ::testing::AssertionSuccess(); } diff --git a/chromium/net/cert/cert_verify_proc_builtin.cc b/chromium/net/cert/cert_verify_proc_builtin.cc index a8220270333..dc565ea73b5 100644 --- a/chromium/net/cert/cert_verify_proc_builtin.cc +++ b/chromium/net/cert/cert_verify_proc_builtin.cc @@ -293,25 +293,20 @@ bool CertVerifyProcBuiltin::SupportsOCSPStapling() const { return true; } -scoped_refptr<ParsedCertificate> ParseCertificateFromOSHandle( - X509Certificate::OSCertHandle cert_handle, +scoped_refptr<ParsedCertificate> ParseCertificateFromBuffer( + CRYPTO_BUFFER* cert_handle, CertErrors* errors) { - std::string cert_bytes; - if (!X509Certificate::GetDEREncoded(cert_handle, &cert_bytes)) - return nullptr; - return ParsedCertificate::Create(x509_util::CreateCryptoBuffer(cert_bytes), + return ParsedCertificate::Create(x509_util::DupCryptoBuffer(cert_handle), x509_util::DefaultParseCertificateOptions(), errors); } void AddIntermediatesToIssuerSource(X509Certificate* x509_cert, CertIssuerSourceStatic* intermediates) { - const X509Certificate::OSCertHandles& cert_handles = - x509_cert->GetIntermediateCertificates(); CertErrors errors; - for (auto it = cert_handles.begin(); it != cert_handles.end(); ++it) { + for (const auto& intermediate : x509_cert->intermediate_buffers()) { scoped_refptr<ParsedCertificate> cert = - ParseCertificateFromOSHandle(*it, &errors); + ParseCertificateFromBuffer(intermediate.get(), &errors); if (cert) intermediates->AddCert(std::move(cert)); // TODO(crbug.com/634443): Surface these parsing errors? @@ -371,9 +366,9 @@ void MapPathBuilderErrorsToCertStatus(const CertPathErrors& errors, *cert_status |= CERT_STATUS_INVALID; } -X509Certificate::OSCertHandle CreateOSCertHandle( +bssl::UniquePtr<CRYPTO_BUFFER> CreateCertBuffers( const scoped_refptr<ParsedCertificate>& certificate) { - return X509Certificate::CreateOSCertHandleFromBytes( + return X509Certificate::CreateCertBufferFromBytes( reinterpret_cast<const char*>(certificate->der_cert().UnsafeData()), certificate->der_cert().Length()); } @@ -386,20 +381,18 @@ X509Certificate::OSCertHandle CreateOSCertHandle( scoped_refptr<X509Certificate> CreateVerifiedCertChain( X509Certificate* target_cert, const CertPathBuilderResultPath& path) { - X509Certificate::OSCertHandles intermediates; + std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates; // Skip the first certificate in the path as that is the target certificate for (size_t i = 1; i < path.certs.size(); ++i) - intermediates.push_back(CreateOSCertHandle(path.certs[i])); + intermediates.push_back(CreateCertBuffers(path.certs[i])); - scoped_refptr<X509Certificate> result = X509Certificate::CreateFromHandle( - target_cert->os_cert_handle(), intermediates); + scoped_refptr<X509Certificate> result = X509Certificate::CreateFromBuffer( + x509_util::DupCryptoBuffer(target_cert->cert_buffer()), + std::move(intermediates)); // |target_cert| was already successfully parsed, so this should never fail. DCHECK(result); - for (const X509Certificate::OSCertHandle handle : intermediates) - X509Certificate::FreeOSCertHandle(handle); - return result; } @@ -534,8 +527,8 @@ int CertVerifyProcBuiltin::VerifyInternal( base::Time verification_time = base::Time::Now(); // Parse the target certificate. - scoped_refptr<ParsedCertificate> target = ParseCertificateFromOSHandle( - input_cert->os_cert_handle(), &parsing_errors); + scoped_refptr<ParsedCertificate> target = + ParseCertificateFromBuffer(input_cert->cert_buffer(), &parsing_errors); if (!target) { // TODO(crbug.com/634443): Surface these parsing errors? verify_result->cert_status |= CERT_STATUS_INVALID; @@ -551,8 +544,8 @@ int CertVerifyProcBuiltin::VerifyInternal( CreateSslSystemTrustStore(); for (const auto& x509_cert : additional_trust_anchors) { - scoped_refptr<ParsedCertificate> cert = ParseCertificateFromOSHandle( - x509_cert->os_cert_handle(), &parsing_errors); + scoped_refptr<ParsedCertificate> cert = + ParseCertificateFromBuffer(x509_cert->cert_buffer(), &parsing_errors); if (cert) ssl_trust_store->AddTrustAnchor(cert); // TODO(eroman): Surface parsing errors of additional trust anchor. diff --git a/chromium/net/cert/cert_verify_proc_mac.cc b/chromium/net/cert/cert_verify_proc_mac.cc index 539d27e0f47..4dd8715c686 100644 --- a/chromium/net/cert/cert_verify_proc_mac.cc +++ b/chromium/net/cert/cert_verify_proc_mac.cc @@ -309,14 +309,8 @@ void GetCandidateEVPolicy(const X509Certificate* cert_input, std::string* ev_policy_oid) { ev_policy_oid->clear(); - std::string der_cert; - if (!X509Certificate::GetDEREncoded(cert_input->os_cert_handle(), - &der_cert)) { - return; - } - scoped_refptr<ParsedCertificate> cert(ParsedCertificate::Create( - x509_util::CreateCryptoBuffer(der_cert), {}, nullptr)); + x509_util::DupCryptoBuffer(cert_input->cert_buffer()), {}, nullptr)); if (!cert) return; @@ -342,27 +336,24 @@ void GetCandidateEVPolicy(const X509Certificate* cert_input, bool CheckCertChainEV(const X509Certificate* cert, const std::string& ev_policy_oid_string) { der::Input ev_policy_oid(&ev_policy_oid_string); - X509Certificate::OSCertHandles os_cert_chain = - cert->GetIntermediateCertificates(); + const std::vector<bssl::UniquePtr<CRYPTO_BUFFER>>& cert_chain = + cert->intermediate_buffers(); // Root should have matching policy in EVRootCAMetadata. - if (os_cert_chain.empty()) + if (cert_chain.empty()) return false; SHA256HashValue fingerprint = - X509Certificate::CalculateFingerprint256(os_cert_chain.back()); + X509Certificate::CalculateFingerprint256(cert_chain.back().get()); EVRootCAMetadata* metadata = EVRootCAMetadata::GetInstance(); if (!metadata->HasEVPolicyOID(fingerprint, ev_policy_oid)) return false; // Intermediates should have Certificate Policies extension with the EV policy // or AnyPolicy. - for (size_t i = 0; i < os_cert_chain.size() - 1; ++i) { - std::string der_cert; - if (!X509Certificate::GetDEREncoded(os_cert_chain[i], &der_cert)) - return false; + for (size_t i = 0; i < cert_chain.size() - 1; ++i) { scoped_refptr<ParsedCertificate> intermediate_cert( - ParsedCertificate::Create(x509_util::CreateCryptoBuffer(der_cert), {}, - nullptr)); + ParsedCertificate::Create( + x509_util::DupCryptoBuffer(cert_chain[i].get()), {}, nullptr)); if (!intermediate_cert) return false; if (!HasPolicyOrAnyPolicy(intermediate_cert.get(), ev_policy_oid)) @@ -440,8 +431,9 @@ CRLSetResult CheckRevocationWithCRLSet(CFArrayRef chain, CRLSet* crl_set) { } base::StringPiece der_bytes(reinterpret_cast<const char*>(cert_data.Data), cert_data.Length); - base::StringPiece spki; - if (!asn1::ExtractSPKIFromDERCert(der_bytes, &spki)) { + base::StringPiece spki, subject; + if (!asn1::ExtractSPKIFromDERCert(der_bytes, &spki) || + !asn1::ExtractSubjectFromDERCert(der_bytes, &subject)) { NOTREACHED(); error = true; continue; @@ -468,6 +460,8 @@ CRLSetResult CheckRevocationWithCRLSet(CFArrayRef chain, CRLSet* crl_set) { CRLSet::Result result = crl_set->CheckSPKI(spki_hash); + if (result != CRLSet::REVOKED) + result = crl_set->CheckSubject(subject, spki_hash); if (result != CRLSet::REVOKED && !issuer_spki_hash.empty()) result = crl_set->CheckSerial(serial, issuer_spki_hash); diff --git a/chromium/net/cert/cert_verify_proc_mac_unittest.cc b/chromium/net/cert/cert_verify_proc_mac_unittest.cc index 71200c0b37d..24ced3f3b42 100644 --- a/chromium/net/cert/cert_verify_proc_mac_unittest.cc +++ b/chromium/net/cert/cert_verify_proc_mac_unittest.cc @@ -19,6 +19,7 @@ #include "net/cert/test_keychain_search_list_mac.h" #include "net/cert/test_root_certs.h" #include "net/cert/x509_certificate.h" +#include "net/cert/x509_util.h" #include "net/test/cert_test_util.h" #include "net/test/gtest_util.h" #include "net/test/test_data_directory.h" @@ -69,11 +70,14 @@ TEST(CertVerifyProcMacTest, MacCRLIntermediate) { // Add E as trust anchor. ScopedTestRoot test_root_E(path_3_certs[3].get()); // E-by-E - X509Certificate::OSCertHandles intermediates; - intermediates.push_back(path_2_certs[1]->os_cert_handle()); // B-by-C - intermediates.push_back(path_2_certs[2]->os_cert_handle()); // C-by-E - scoped_refptr<X509Certificate> cert = X509Certificate::CreateFromHandle( - path_3_certs[0]->os_cert_handle(), intermediates); + std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates; + intermediates.push_back( + x509_util::DupCryptoBuffer(path_2_certs[1]->cert_buffer())); // B-by-C + intermediates.push_back( + x509_util::DupCryptoBuffer(path_2_certs[2]->cert_buffer())); // C-by-E + scoped_refptr<X509Certificate> cert = X509Certificate::CreateFromBuffer( + x509_util::DupCryptoBuffer(path_3_certs[0]->cert_buffer()), + std::move(intermediates)); ASSERT_TRUE(cert); std::unique_ptr<TestKeychainSearchList> test_keychain_search_list( @@ -113,13 +117,13 @@ TEST(CertVerifyProcMacTest, MacCRLIntermediate) { ASSERT_EQ(0U, verify_result.cert_status); ASSERT_TRUE(verify_result.verified_cert.get()); - const X509Certificate::OSCertHandles& verified_intermediates = - verify_result.verified_cert->GetIntermediateCertificates(); + const auto& verified_intermediates = + verify_result.verified_cert->intermediate_buffers(); ASSERT_EQ(3U, verified_intermediates.size()); scoped_refptr<X509Certificate> intermediate = - X509Certificate::CreateFromHandle(verified_intermediates[1], - X509Certificate::OSCertHandles()); + X509Certificate::CreateFromBuffer( + x509_util::DupCryptoBuffer(verified_intermediates[1].get()), {}); ASSERT_TRUE(intermediate); scoped_refptr<X509Certificate> expected_intermediate = path_3_certs[2]; @@ -171,8 +175,8 @@ TEST(CertVerifyProcMacTest, MacKeychainReordering) { EXPECT_FALSE(verify_result.has_sha1); ASSERT_TRUE(verify_result.verified_cert.get()); - const X509Certificate::OSCertHandles& verified_intermediates = - verify_result.verified_cert->GetIntermediateCertificates(); + const auto& verified_intermediates = + verify_result.verified_cert->intermediate_buffers(); ASSERT_EQ(2U, verified_intermediates.size()); } diff --git a/chromium/net/cert/cert_verify_proc_nss.cc b/chromium/net/cert/cert_verify_proc_nss.cc index dc9a449083c..a137d5eaa72 100644 --- a/chromium/net/cert/cert_verify_proc_nss.cc +++ b/chromium/net/cert/cert_verify_proc_nss.cc @@ -17,6 +17,8 @@ #include "base/logging.h" #include "base/macros.h" +#include "base/memory/protected_memory.h" +#include "base/memory/protected_memory_cfi.h" #include "build/build_config.h" #include "crypto/nss_util.h" #include "crypto/scoped_nss_types.h" @@ -38,6 +40,28 @@ namespace net { namespace { +using CacheOCSPResponseFunction = SECStatus (*)(CERTCertDBHandle* handle, + CERTCertificate* cert, + PRTime time, + const SECItem* encodedResponse, + void* pwArg); + +static PROTECTED_MEMORY_SECTION base::ProtectedMemory<CacheOCSPResponseFunction> + g_cache_ocsp_response; + +// The function pointer for CERT_CacheOCSPResponseFromSideChannel is saved to +// read-only memory after being dynamically resolved as a security mitigation to +// prevent the pointer from being tampered with. See crbug.com/771365 for +// details. +const base::ProtectedMemory<CacheOCSPResponseFunction>& +ResolveCacheOCSPResponse() { + static base::ProtectedMemory<CacheOCSPResponseFunction>::Initializer init( + &g_cache_ocsp_response, + reinterpret_cast<CacheOCSPResponseFunction>( + dlsym(RTLD_DEFAULT, "CERT_CacheOCSPResponseFromSideChannel"))); + return g_cache_ocsp_response; +} + typedef std::unique_ptr< CERTCertificatePolicies, crypto::NSSDestroyer<CERTCertificatePolicies, @@ -270,8 +294,9 @@ CRLSetResult CheckRevocationWithCRLSet(const CERTCertList* cert_list, base::StringPiece der(reinterpret_cast<char*>(cert->derCert.data), cert->derCert.len); - base::StringPiece spki; - if (!asn1::ExtractSPKIFromDERCert(der, &spki)) { + base::StringPiece spki, subject; + if (!asn1::ExtractSPKIFromDERCert(der, &spki) || + !asn1::ExtractSubjectFromDERCert(der, &subject)) { NOTREACHED(); error = true; continue; @@ -284,6 +309,8 @@ CRLSetResult CheckRevocationWithCRLSet(const CERTCertList* cert_list, CRLSet::Result result = crl_set->CheckSPKI(spki_hash); + if (result != CRLSet::REVOKED) + result = crl_set->CheckSubject(subject, spki_hash); if (result != CRLSet::REVOKED && !issuer_spki_hash.empty()) result = crl_set->CheckSerial(serial_number, issuer_spki_hash); @@ -754,12 +781,7 @@ ScopedCERTCertList CertificateListToCERTCertListIgnoringErrors( } // namespace -CertVerifyProcNSS::CertVerifyProcNSS() - : cache_ocsp_response_from_side_channel_( - reinterpret_cast<CacheOCSPResponseFromSideChannelFunction>( - dlsym(RTLD_DEFAULT, "CERT_CacheOCSPResponseFromSideChannel"))) -{ -} +CertVerifyProcNSS::CertVerifyProcNSS() = default; CertVerifyProcNSS::~CertVerifyProcNSS() = default; @@ -768,7 +790,7 @@ bool CertVerifyProcNSS::SupportsAdditionalTrustAnchors() const { } bool CertVerifyProcNSS::SupportsOCSPStapling() const { - return cache_ocsp_response_from_side_channel_; + return *ResolveCacheOCSPResponse() != nullptr; } int CertVerifyProcNSS::VerifyInternalImpl( @@ -793,7 +815,7 @@ int CertVerifyProcNSS::VerifyInternalImpl( } CERTCertificate* cert_handle = input_chain[0].get(); - if (!ocsp_response.empty() && cache_ocsp_response_from_side_channel_) { + if (!ocsp_response.empty() && SupportsOCSPStapling()) { // Note: NSS uses a thread-safe global hash table, so this call will // affect any concurrent verification operations on |cert| or copies of // the same certificate. This is an unavoidable limitation of NSS's OCSP @@ -802,9 +824,9 @@ int CertVerifyProcNSS::VerifyInternalImpl( ocsp_response_item.data = reinterpret_cast<unsigned char*>( const_cast<char*>(ocsp_response.data())); ocsp_response_item.len = ocsp_response.size(); - cache_ocsp_response_from_side_channel_(CERT_GetDefaultCertDB(), cert_handle, - PR_Now(), &ocsp_response_item, - nullptr); + UnsanitizedCfiCall(ResolveCacheOCSPResponse())( + CERT_GetDefaultCertDB(), cert_handle, PR_Now(), &ocsp_response_item, + nullptr); } // Setup a callback to call into CheckChainRevocationWithCRLSet with the diff --git a/chromium/net/cert/cert_verify_proc_nss.h b/chromium/net/cert/cert_verify_proc_nss.h index c7b90b72b7a..bd18e03c119 100644 --- a/chromium/net/cert/cert_verify_proc_nss.h +++ b/chromium/net/cert/cert_verify_proc_nss.h @@ -43,15 +43,6 @@ class NET_EXPORT_PRIVATE CertVerifyProcNSS : public CertVerifyProc { CRLSet* crl_set, const CertificateList& additional_trust_anchors, CertVerifyResult* verify_result) override; - - using CacheOCSPResponseFromSideChannelFunction = - SECStatus (*)(CERTCertDBHandle* handle, - CERTCertificate* cert, - PRTime time, - const SECItem* encodedResponse, - void* pwArg); - const CacheOCSPResponseFromSideChannelFunction - cache_ocsp_response_from_side_channel_; }; } // namespace net diff --git a/chromium/net/cert/cert_verify_proc_unittest.cc b/chromium/net/cert/cert_verify_proc_unittest.cc index e7a8a9cc174..9199b892f36 100644 --- a/chromium/net/cert/cert_verify_proc_unittest.cc +++ b/chromium/net/cert/cert_verify_proc_unittest.cc @@ -333,15 +333,16 @@ TEST_P(CertVerifyProcInternalTest, EVVerificationMultipleOID) { // // This way CRLSet coverage will be sufficient for EV revocation checking, // so this test does not depend on online revocation checking. - ASSERT_EQ(1u, chain->GetIntermediateCertificates().size()); - std::string der_bytes; - ASSERT_TRUE(X509Certificate::GetDEREncoded( - chain->GetIntermediateCertificates()[0], &der_bytes)); + ASSERT_EQ(1u, chain->intermediate_buffers().size()); base::StringPiece spki; - ASSERT_TRUE(asn1::ExtractSPKIFromDERCert(der_bytes, &spki)); + ASSERT_TRUE( + asn1::ExtractSPKIFromDERCert(x509_util::CryptoBufferAsStringPiece( + chain->intermediate_buffers()[0].get()), + &spki)); SHA256HashValue spki_sha256; crypto::SHA256HashString(spki, spki_sha256.data, sizeof(spki_sha256.data)); - scoped_refptr<CRLSet> crl_set(CRLSet::ForTesting(false, &spki_sha256, "")); + scoped_refptr<CRLSet> crl_set( + CRLSet::ForTesting(false, &spki_sha256, "", "", {})); CertVerifyResult verify_result; int flags = CertVerifier::VERIFY_EV_CERT; @@ -375,8 +376,7 @@ TEST_P(CertVerifyProcInternalTest, TrustedTargetCertWithEVPolicy) { } else if (ScopedTestRootCanTrustTargetCert(verify_proc_type())) { EXPECT_THAT(error, IsOk()); ASSERT_TRUE(verify_result.verified_cert); - EXPECT_TRUE( - verify_result.verified_cert->GetIntermediateCertificates().empty()); + EXPECT_TRUE(verify_result.verified_cert->intermediate_buffers().empty()); } else { EXPECT_THAT(error, IsError(ERR_CERT_AUTHORITY_INVALID)); } @@ -416,8 +416,7 @@ TEST_P(CertVerifyProcInternalTest, } else if (ScopedTestRootCanTrustTargetCert(verify_proc_type())) { EXPECT_THAT(error, IsOk()); ASSERT_TRUE(verify_result.verified_cert); - EXPECT_TRUE( - verify_result.verified_cert->GetIntermediateCertificates().empty()); + EXPECT_TRUE(verify_result.verified_cert->intermediate_buffers().empty()); } else { EXPECT_THAT(error, IsError(ERR_CERT_AUTHORITY_INVALID)); } @@ -442,7 +441,7 @@ TEST_P(CertVerifyProcInternalTest, DISABLED_PaypalNullCertParsing) { ASSERT_NE(static_cast<X509Certificate*>(NULL), paypal_null_cert.get()); EXPECT_EQ(paypal_null_fingerprint, X509Certificate::CalculateFingerprint256( - paypal_null_cert->os_cert_handle())); + paypal_null_cert->cert_buffer())); int flags = 0; CertVerifyResult verify_result; @@ -488,11 +487,14 @@ TEST_P(CertVerifyProcInternalTest, InvalidTarget) { ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem")); ASSERT_TRUE(ok_cert); + std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates; + intermediates.push_back(x509_util::DupCryptoBuffer(ok_cert->cert_buffer())); scoped_refptr<X509Certificate> cert_with_bad_target( - X509Certificate::CreateFromHandle(bad_cert->os_cert_handle(), - {ok_cert->os_cert_handle()})); + X509Certificate::CreateFromBuffer( + x509_util::DupCryptoBuffer(bad_cert->cert_buffer()), + std::move(intermediates))); ASSERT_TRUE(cert_with_bad_target); - EXPECT_EQ(1U, cert_with_bad_target->GetIntermediateCertificates().size()); + EXPECT_EQ(1U, cert_with_bad_target->intermediate_buffers().size()); int flags = 0; CertVerifyResult verify_result; @@ -521,12 +523,14 @@ TEST_P(CertVerifyProcInternalTest, UnnecessaryInvalidIntermediate) { ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem")); ASSERT_TRUE(ok_cert); + std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates; + intermediates.push_back(std::move(bad_cert)); scoped_refptr<X509Certificate> cert_with_bad_intermediate( - X509Certificate::CreateFromHandle(ok_cert->os_cert_handle(), - {bad_cert.get()})); + X509Certificate::CreateFromBuffer( + x509_util::DupCryptoBuffer(ok_cert->cert_buffer()), + std::move(intermediates))); ASSERT_TRUE(cert_with_bad_intermediate); - EXPECT_EQ(1U, - cert_with_bad_intermediate->GetIntermediateCertificates().size()); + EXPECT_EQ(1U, cert_with_bad_intermediate->intermediate_buffers().size()); int flags = 0; CertVerifyResult verify_result; @@ -552,11 +556,12 @@ TEST_P(CertVerifyProcInternalTest, IntermediateCARequireExplicitPolicy) { certs_dir, "explicit-policy-chain.pem", X509Certificate::FORMAT_AUTO); ASSERT_EQ(3U, certs.size()); - X509Certificate::OSCertHandles intermediates; - intermediates.push_back(certs[1]->os_cert_handle()); + std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates; + intermediates.push_back(x509_util::DupCryptoBuffer(certs[1]->cert_buffer())); - scoped_refptr<X509Certificate> cert = X509Certificate::CreateFromHandle( - certs[0]->os_cert_handle(), intermediates); + scoped_refptr<X509Certificate> cert = X509Certificate::CreateFromBuffer( + x509_util::DupCryptoBuffer(certs[0]->cert_buffer()), + std::move(intermediates)); ASSERT_TRUE(cert.get()); ScopedTestRoot scoped_root(certs[2].get()); @@ -579,7 +584,7 @@ TEST_P(CertVerifyProcInternalTest, RejectExpiredCert) { scoped_refptr<X509Certificate> cert = CreateCertificateChainFromFile( certs_dir, "expired_cert.pem", X509Certificate::FORMAT_AUTO); ASSERT_TRUE(cert); - ASSERT_EQ(0U, cert->GetIntermediateCertificates().size()); + ASSERT_EQ(0U, cert->intermediate_buffers().size()); int flags = 0; CertVerifyResult verify_result; @@ -642,11 +647,13 @@ TEST_P(CertVerifyProcInternalTest, RejectWeakKeys) { ImportCertFromFile(certs_dir, basename); ASSERT_NE(static_cast<X509Certificate*>(NULL), intermediate.get()); - X509Certificate::OSCertHandles intermediates; - intermediates.push_back(intermediate->os_cert_handle()); + std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates; + intermediates.push_back( + x509_util::DupCryptoBuffer(intermediate->cert_buffer())); scoped_refptr<X509Certificate> cert_chain = - X509Certificate::CreateFromHandle(ee_cert->os_cert_handle(), - intermediates); + X509Certificate::CreateFromBuffer( + x509_util::DupCryptoBuffer(ee_cert->cert_buffer()), + std::move(intermediates)); ASSERT_TRUE(cert_chain); CertVerifyResult verify_result; @@ -699,10 +706,12 @@ TEST_P(CertVerifyProcInternalTest, ExtraneousMD5RootCert) { ScopedTestRoot scoped_root(root_cert.get()); - X509Certificate::OSCertHandles intermediates; - intermediates.push_back(extra_cert->os_cert_handle()); - scoped_refptr<X509Certificate> cert_chain = X509Certificate::CreateFromHandle( - server_cert->os_cert_handle(), intermediates); + std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates; + intermediates.push_back( + x509_util::DupCryptoBuffer(extra_cert->cert_buffer())); + scoped_refptr<X509Certificate> cert_chain = X509Certificate::CreateFromBuffer( + x509_util::DupCryptoBuffer(server_cert->cert_buffer()), + std::move(intermediates)); ASSERT_TRUE(cert_chain); CertVerifyResult verify_result; @@ -713,11 +722,10 @@ TEST_P(CertVerifyProcInternalTest, ExtraneousMD5RootCert) { // The extra MD5 root should be discarded ASSERT_TRUE(verify_result.verified_cert.get()); - ASSERT_EQ(1u, - verify_result.verified_cert->GetIntermediateCertificates().size()); - EXPECT_TRUE(X509Certificate::IsSameOSCert( - verify_result.verified_cert->GetIntermediateCertificates().front(), - root_cert->os_cert_handle())); + ASSERT_EQ(1u, verify_result.verified_cert->intermediate_buffers().size()); + EXPECT_TRUE(x509_util::CryptoBufferEqual( + verify_result.verified_cert->intermediate_buffers().front().get(), + root_cert->cert_buffer())); EXPECT_FALSE(verify_result.has_md5); } @@ -734,10 +742,12 @@ TEST_P(CertVerifyProcInternalTest, GoogleDigiNotarTest) { ImportCertFromFile(certs_dir, "diginotar_public_ca_2025.pem"); ASSERT_NE(static_cast<X509Certificate*>(NULL), intermediate_cert.get()); - X509Certificate::OSCertHandles intermediates; - intermediates.push_back(intermediate_cert->os_cert_handle()); - scoped_refptr<X509Certificate> cert_chain = X509Certificate::CreateFromHandle( - server_cert->os_cert_handle(), intermediates); + std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates; + intermediates.push_back( + x509_util ::DupCryptoBuffer(intermediate_cert->cert_buffer())); + scoped_refptr<X509Certificate> cert_chain = X509Certificate::CreateFromBuffer( + x509_util::DupCryptoBuffer(server_cert->cert_buffer()), + std::move(intermediates)); ASSERT_TRUE(cert_chain); CertVerifyResult verify_result; @@ -778,12 +788,10 @@ TEST(CertVerifyProcTest, DigiNotarCerts) { for (size_t i = 0; kDigiNotarFilenames[i]; i++) { scoped_refptr<X509Certificate> diginotar_cert = ImportCertFromFile(certs_dir, kDigiNotarFilenames[i]); - std::string der_bytes; - ASSERT_TRUE(X509Certificate::GetDEREncoded(diginotar_cert->os_cert_handle(), - &der_bytes)); - base::StringPiece spki; - ASSERT_TRUE(asn1::ExtractSPKIFromDERCert(der_bytes, &spki)); + ASSERT_TRUE(asn1::ExtractSPKIFromDERCert( + x509_util::CryptoBufferAsStringPiece(diginotar_cert->cert_buffer()), + &spki)); std::string spki_sha256 = crypto::SHA256HashString(spki); @@ -809,7 +817,7 @@ TEST_P(CertVerifyProcInternalTest, NameConstraintsOk) { GetTestCertsDirectory(), "name_constraint_good.pem", X509Certificate::FORMAT_AUTO); ASSERT_TRUE(leaf); - ASSERT_EQ(0U, leaf->GetIntermediateCertificates().size()); + ASSERT_EQ(0U, leaf->intermediate_buffers().size()); int flags = 0; CertVerifyResult verify_result; @@ -1004,13 +1012,10 @@ class CertVerifyProcInspectSignatureAlgorithmsTest : public ::testing::Test { return nullptr; } - // Start with the DER bytes of a valid certificate. This will be the basis - // for building a modified certificate. - std::string cert_der; - if (!X509Certificate::GetDEREncoded(cert->os_cert_handle(), &cert_der)) { - ADD_FAILURE() << "Failed getting DER bytes"; - return nullptr; - } + // Start with the DER bytes of a valid certificate. The der data is copied + // to a new std::string as it will modified to create a new certificate. + std::string cert_der( + x509_util::CryptoBufferAsStringPiece(cert->cert_buffer())); // Parse the certificate and identify the locations of interest within // |cert_der|. @@ -1061,12 +1066,14 @@ class CertVerifyProcInspectSignatureAlgorithmsTest : public ::testing::Test { return nullptr; } - X509Certificate::OSCertHandles intermediates; + std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates; for (size_t i = 1; i < certs.size(); ++i) - intermediates.push_back(certs[i]->os_cert_handle()); + intermediates.push_back( + x509_util::DupCryptoBuffer(certs[i]->cert_buffer())); - return X509Certificate::CreateFromHandle(certs[0]->os_cert_handle(), - intermediates); + return X509Certificate::CreateFromBuffer( + x509_util::DupCryptoBuffer(certs[0]->cert_buffer()), + std::move(intermediates)); } }; @@ -1205,9 +1212,8 @@ TEST_P(CertVerifyProcInternalTest, NameConstraintsFailure) { X509Certificate::FORMAT_AUTO); ASSERT_EQ(1U, cert_list.size()); - X509Certificate::OSCertHandles intermediates; - scoped_refptr<X509Certificate> leaf = X509Certificate::CreateFromHandle( - cert_list[0]->os_cert_handle(), intermediates); + scoped_refptr<X509Certificate> leaf = X509Certificate::CreateFromBuffer( + x509_util::DupCryptoBuffer(cert_list[0]->cert_buffer()), {}); ASSERT_TRUE(leaf); int flags = 0; @@ -1261,11 +1267,12 @@ TEST_P(CertVerifyProcInternalTest, DISABLED_TestKnownRoot) { certs_dir, "twitter-chain.pem", X509Certificate::FORMAT_AUTO); ASSERT_EQ(3U, certs.size()); - X509Certificate::OSCertHandles intermediates; - intermediates.push_back(certs[1]->os_cert_handle()); + std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates; + intermediates.push_back(x509_util::DupCryptoBuffer(certs[1]->cert_buffer())); - scoped_refptr<X509Certificate> cert_chain = X509Certificate::CreateFromHandle( - certs[0]->os_cert_handle(), intermediates); + scoped_refptr<X509Certificate> cert_chain = X509Certificate::CreateFromBuffer( + x509_util::DupCryptoBuffer(certs[0]->cert_buffer()), + std::move(intermediates)); ASSERT_TRUE(cert_chain); int flags = 0; @@ -1292,15 +1299,16 @@ TEST_P(CertVerifyProcInternalTest, PublicKeyHashes) { certs_dir, "x509_verify_results.chain.pem", X509Certificate::FORMAT_AUTO); ASSERT_EQ(3U, certs.size()); - X509Certificate::OSCertHandles intermediates; - intermediates.push_back(certs[1]->os_cert_handle()); - intermediates.push_back(certs[2]->os_cert_handle()); + std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates; + intermediates.push_back(x509_util::DupCryptoBuffer(certs[1]->cert_buffer())); + intermediates.push_back(x509_util::DupCryptoBuffer(certs[2]->cert_buffer())); ScopedTestRoot scoped_root(certs[2].get()); - scoped_refptr<X509Certificate> cert_chain = X509Certificate::CreateFromHandle( - certs[0]->os_cert_handle(), intermediates); + scoped_refptr<X509Certificate> cert_chain = X509Certificate::CreateFromBuffer( + x509_util::DupCryptoBuffer(certs[0]->cert_buffer()), + std::move(intermediates)); ASSERT_TRUE(cert_chain); - ASSERT_EQ(2U, cert_chain->GetIntermediateCertificates().size()); + ASSERT_EQ(2U, cert_chain->intermediate_buffers().size()); int flags = 0; CertVerifyResult verify_result; @@ -1384,17 +1392,18 @@ TEST_P(CertVerifyProcInternalTest, VerifyReturnChainBasic) { certs_dir, "x509_verify_results.chain.pem", X509Certificate::FORMAT_AUTO); ASSERT_EQ(3U, certs.size()); - X509Certificate::OSCertHandles intermediates; - intermediates.push_back(certs[1]->os_cert_handle()); - intermediates.push_back(certs[2]->os_cert_handle()); + std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates; + intermediates.push_back(x509_util::DupCryptoBuffer(certs[1]->cert_buffer())); + intermediates.push_back(x509_util::DupCryptoBuffer(certs[2]->cert_buffer())); ScopedTestRoot scoped_root(certs[2].get()); scoped_refptr<X509Certificate> google_full_chain = - X509Certificate::CreateFromHandle(certs[0]->os_cert_handle(), - intermediates); + X509Certificate::CreateFromBuffer( + x509_util::DupCryptoBuffer(certs[0]->cert_buffer()), + std::move(intermediates)); ASSERT_NE(static_cast<X509Certificate*>(NULL), google_full_chain.get()); - ASSERT_EQ(2U, google_full_chain->GetIntermediateCertificates().size()); + ASSERT_EQ(2U, google_full_chain->intermediate_buffers().size()); CertVerifyResult verify_result; EXPECT_EQ(static_cast<X509Certificate*>(NULL), @@ -1406,16 +1415,16 @@ TEST_P(CertVerifyProcInternalTest, VerifyReturnChainBasic) { verify_result.verified_cert.get()); EXPECT_NE(google_full_chain, verify_result.verified_cert); - EXPECT_TRUE(X509Certificate::IsSameOSCert( - google_full_chain->os_cert_handle(), - verify_result.verified_cert->os_cert_handle())); - const X509Certificate::OSCertHandles& return_intermediates = - verify_result.verified_cert->GetIntermediateCertificates(); + EXPECT_TRUE( + x509_util::CryptoBufferEqual(google_full_chain->cert_buffer(), + verify_result.verified_cert->cert_buffer())); + const auto& return_intermediates = + verify_result.verified_cert->intermediate_buffers(); ASSERT_EQ(2U, return_intermediates.size()); - EXPECT_TRUE(X509Certificate::IsSameOSCert(return_intermediates[0], - certs[1]->os_cert_handle())); - EXPECT_TRUE(X509Certificate::IsSameOSCert(return_intermediates[1], - certs[2]->os_cert_handle())); + EXPECT_TRUE(x509_util::CryptoBufferEqual(return_intermediates[0].get(), + certs[1]->cert_buffer())); + EXPECT_TRUE(x509_util::CryptoBufferEqual(return_intermediates[1].get(), + certs[2]->cert_buffer())); } // Test that certificates issued for 'intranet' names (that is, containing no @@ -1452,6 +1461,63 @@ TEST(CertVerifyProcTest, IntranetHostsRejected) { EXPECT_FALSE(verify_result.cert_status & CERT_STATUS_NON_UNIQUE_NAME); } +// Tests that certificates issued by Symantec's legacy infrastructure +// are rejected according to the policies outlined in +// https://security.googleblog.com/2017/09/chromes-plan-to-distrust-symantec.html +// unless the caller has explicitly disabled that enforcement. +TEST(CertVerifyProcTest, SymantecCertsRejected) { + constexpr SHA256HashValue kSymantecHashValue = { + {0xb2, 0xde, 0xf5, 0x36, 0x2a, 0xd3, 0xfa, 0xcd, 0x04, 0xbd, 0x29, + 0x04, 0x7a, 0x43, 0x84, 0x4f, 0x76, 0x70, 0x34, 0xea, 0x48, 0x92, + 0xf8, 0x0e, 0x56, 0xbe, 0xe6, 0x90, 0x24, 0x3e, 0x25, 0x02}}; + constexpr SHA256HashValue kGoogleHashValue = { + {0xec, 0x72, 0x29, 0x69, 0xcb, 0x64, 0x20, 0x0a, 0xb6, 0x63, 0x8f, + 0x68, 0xac, 0x53, 0x8e, 0x40, 0xab, 0xab, 0x5b, 0x19, 0xa6, 0x48, + 0x56, 0x61, 0x04, 0x2a, 0x10, 0x61, 0xc4, 0x61, 0x27, 0x76}}; + + scoped_refptr<X509Certificate> cert = CreateCertificateChainFromFile( + GetTestCertsDirectory(), "dec_2017.pem", X509Certificate::FORMAT_AUTO); + ASSERT_TRUE(cert); + + scoped_refptr<CertVerifyProc> verify_proc; + int error = 0; + + // Test that a Symantec certificate is rejected if issued after 2017-12-01. + CertVerifyResult symantec_result; + symantec_result.verified_cert = cert; + symantec_result.public_key_hashes.push_back(HashValue(kSymantecHashValue)); + symantec_result.is_issued_by_known_root = true; + verify_proc = base::MakeRefCounted<MockCertVerifyProc>(symantec_result); + + CertVerifyResult test_result_1; + error = verify_proc->Verify(cert.get(), "127.0.0.1", std::string(), 0, + nullptr, CertificateList(), &test_result_1); + EXPECT_THAT(error, IsError(ERR_CERT_AUTHORITY_INVALID)); + EXPECT_TRUE(test_result_1.cert_status & CERT_STATUS_AUTHORITY_INVALID); + + // ... Unless the Symantec cert chains through a whitelisted intermediate. + CertVerifyResult whitelisted_result; + whitelisted_result.verified_cert = cert; + whitelisted_result.public_key_hashes.push_back(HashValue(kSymantecHashValue)); + whitelisted_result.public_key_hashes.push_back(HashValue(kGoogleHashValue)); + whitelisted_result.is_issued_by_known_root = true; + verify_proc = base::MakeRefCounted<MockCertVerifyProc>(whitelisted_result); + + CertVerifyResult test_result_2; + error = verify_proc->Verify(cert.get(), "127.0.0.1", std::string(), 0, + nullptr, CertificateList(), &test_result_2); + EXPECT_THAT(error, IsOk()); + EXPECT_FALSE(test_result_2.cert_status & CERT_STATUS_AUTHORITY_INVALID); + + // ... Or the caller disabled enforcement of Symantec policies. + CertVerifyResult test_result_3; + error = verify_proc->Verify(cert.get(), "127.0.0.1", std::string(), + CertVerifier::VERIFY_DISABLE_SYMANTEC_ENFORCEMENT, + nullptr, CertificateList(), &test_result_3); + EXPECT_THAT(error, IsOk()); + EXPECT_FALSE(test_result_3.cert_status & CERT_STATUS_AUTHORITY_INVALID); +} + // While all SHA-1 certificates should be rejected, in the event that there // emerges some unexpected bug, test that the 'legacy' behaviour works // correctly - rejecting all SHA-1 certificates from publicly trusted CAs @@ -1554,38 +1620,37 @@ TEST_P(CertVerifyProcInternalTest, VerifyReturnChainProperlyOrdered) { ASSERT_EQ(3U, certs.size()); // Construct the chain out of order. - X509Certificate::OSCertHandles intermediates; - intermediates.push_back(certs[2]->os_cert_handle()); - intermediates.push_back(certs[1]->os_cert_handle()); + std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates; + intermediates.push_back(x509_util::DupCryptoBuffer(certs[2]->cert_buffer())); + intermediates.push_back(x509_util::DupCryptoBuffer(certs[1]->cert_buffer())); ScopedTestRoot scoped_root(certs[2].get()); scoped_refptr<X509Certificate> google_full_chain = - X509Certificate::CreateFromHandle(certs[0]->os_cert_handle(), - intermediates); - ASSERT_NE(static_cast<X509Certificate*>(NULL), google_full_chain.get()); - ASSERT_EQ(2U, google_full_chain->GetIntermediateCertificates().size()); + X509Certificate::CreateFromBuffer( + x509_util::DupCryptoBuffer(certs[0]->cert_buffer()), + std::move(intermediates)); + ASSERT_TRUE(google_full_chain); + ASSERT_EQ(2U, google_full_chain->intermediate_buffers().size()); CertVerifyResult verify_result; - EXPECT_EQ(static_cast<X509Certificate*>(NULL), - verify_result.verified_cert.get()); + EXPECT_FALSE(verify_result.verified_cert); int error = Verify(google_full_chain.get(), "127.0.0.1", 0, NULL, CertificateList(), &verify_result); EXPECT_THAT(error, IsOk()); - ASSERT_NE(static_cast<X509Certificate*>(NULL), - verify_result.verified_cert.get()); + ASSERT_TRUE(verify_result.verified_cert); EXPECT_NE(google_full_chain, verify_result.verified_cert); - EXPECT_TRUE(X509Certificate::IsSameOSCert( - google_full_chain->os_cert_handle(), - verify_result.verified_cert->os_cert_handle())); - const X509Certificate::OSCertHandles& return_intermediates = - verify_result.verified_cert->GetIntermediateCertificates(); + EXPECT_TRUE( + x509_util::CryptoBufferEqual(google_full_chain->cert_buffer(), + verify_result.verified_cert->cert_buffer())); + const auto& return_intermediates = + verify_result.verified_cert->intermediate_buffers(); ASSERT_EQ(2U, return_intermediates.size()); - EXPECT_TRUE(X509Certificate::IsSameOSCert(return_intermediates[0], - certs[1]->os_cert_handle())); - EXPECT_TRUE(X509Certificate::IsSameOSCert(return_intermediates[1], - certs[2]->os_cert_handle())); + EXPECT_TRUE(x509_util::CryptoBufferEqual(return_intermediates[0].get(), + certs[1]->cert_buffer())); + EXPECT_TRUE(x509_util::CryptoBufferEqual(return_intermediates[1].get(), + certs[2]->cert_buffer())); } // Test that Verify() filters out certificates which are not related to @@ -1610,38 +1675,39 @@ TEST_P(CertVerifyProcInternalTest, VerifyReturnChainFiltersUnrelatedCerts) { ASSERT_NE(static_cast<X509Certificate*>(NULL), unrelated_certificate2.get()); // Interject unrelated certificates into the list of intermediates. - X509Certificate::OSCertHandles intermediates; - intermediates.push_back(unrelated_certificate->os_cert_handle()); - intermediates.push_back(certs[1]->os_cert_handle()); - intermediates.push_back(unrelated_certificate2->os_cert_handle()); - intermediates.push_back(certs[2]->os_cert_handle()); + std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates; + intermediates.push_back( + x509_util::DupCryptoBuffer(unrelated_certificate->cert_buffer())); + intermediates.push_back(x509_util::DupCryptoBuffer(certs[1]->cert_buffer())); + intermediates.push_back( + x509_util::DupCryptoBuffer(unrelated_certificate2->cert_buffer())); + intermediates.push_back(x509_util::DupCryptoBuffer(certs[2]->cert_buffer())); scoped_refptr<X509Certificate> google_full_chain = - X509Certificate::CreateFromHandle(certs[0]->os_cert_handle(), - intermediates); - ASSERT_NE(static_cast<X509Certificate*>(NULL), google_full_chain.get()); - ASSERT_EQ(4U, google_full_chain->GetIntermediateCertificates().size()); + X509Certificate::CreateFromBuffer( + x509_util::DupCryptoBuffer(certs[0]->cert_buffer()), + std::move(intermediates)); + ASSERT_TRUE(google_full_chain); + ASSERT_EQ(4U, google_full_chain->intermediate_buffers().size()); CertVerifyResult verify_result; - EXPECT_EQ(static_cast<X509Certificate*>(NULL), - verify_result.verified_cert.get()); + EXPECT_FALSE(verify_result.verified_cert); int error = Verify(google_full_chain.get(), "127.0.0.1", 0, NULL, CertificateList(), &verify_result); EXPECT_THAT(error, IsOk()); - ASSERT_NE(static_cast<X509Certificate*>(NULL), - verify_result.verified_cert.get()); + ASSERT_TRUE(verify_result.verified_cert); EXPECT_NE(google_full_chain, verify_result.verified_cert); - EXPECT_TRUE(X509Certificate::IsSameOSCert( - google_full_chain->os_cert_handle(), - verify_result.verified_cert->os_cert_handle())); - const X509Certificate::OSCertHandles& return_intermediates = - verify_result.verified_cert->GetIntermediateCertificates(); + EXPECT_TRUE( + x509_util::CryptoBufferEqual(google_full_chain->cert_buffer(), + verify_result.verified_cert->cert_buffer())); + const auto& return_intermediates = + verify_result.verified_cert->intermediate_buffers(); ASSERT_EQ(2U, return_intermediates.size()); - EXPECT_TRUE(X509Certificate::IsSameOSCert(return_intermediates[0], - certs[1]->os_cert_handle())); - EXPECT_TRUE(X509Certificate::IsSameOSCert(return_intermediates[1], - certs[2]->os_cert_handle())); + EXPECT_TRUE(x509_util::CryptoBufferEqual(return_intermediates[0].get(), + certs[1]->cert_buffer())); + EXPECT_TRUE(x509_util::CryptoBufferEqual(return_intermediates[1].get(), + certs[2]->cert_buffer())); } TEST_P(CertVerifyProcInternalTest, AdditionalTrustAnchors) { @@ -1780,16 +1846,18 @@ TEST_P(CertVerifyProcInternalTest, CRLSetLeafSerial) { GetTestCertsDirectory(), "intermediate_ca_cert.pem", X509Certificate::FORMAT_AUTO); ASSERT_EQ(1U, intermediate_cert_list.size()); - X509Certificate::OSCertHandles intermediates; - intermediates.push_back(intermediate_cert_list[0]->os_cert_handle()); + std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates; + intermediates.push_back( + x509_util::DupCryptoBuffer(intermediate_cert_list[0]->cert_buffer())); CertificateList cert_list = CreateCertificateListFromFile( GetTestCertsDirectory(), "ok_cert_by_intermediate.pem", X509Certificate::FORMAT_AUTO); ASSERT_EQ(1U, cert_list.size()); - scoped_refptr<X509Certificate> leaf = X509Certificate::CreateFromHandle( - cert_list[0]->os_cert_handle(), intermediates); + scoped_refptr<X509Certificate> leaf = X509Certificate::CreateFromBuffer( + x509_util::DupCryptoBuffer(cert_list[0]->cert_buffer()), + std::move(intermediates)); ASSERT_TRUE(leaf); int flags = 0; @@ -1811,6 +1879,67 @@ TEST_P(CertVerifyProcInternalTest, CRLSetLeafSerial) { EXPECT_THAT(error, IsError(ERR_CERT_REVOKED)); } +// Tests that CertVerifyProc implementations apply CRLSet revocations by +// subject. +TEST_P(CertVerifyProcInternalTest, CRLSetRevokedBySubject) { + if (!SupportsCRLSet()) { + LOG(INFO) << "Skipping test as verifier doesn't support CRLSet"; + return; + } + + scoped_refptr<X509Certificate> root( + ImportCertFromFile(GetTestCertsDirectory(), "root_ca_cert.pem")); + ASSERT_TRUE(root); + + scoped_refptr<X509Certificate> leaf( + ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem")); + ASSERT_TRUE(leaf); + + ScopedTestRoot scoped_root(root.get()); + + int flags = 0; + CertVerifyResult verify_result; + + // Confirm that verifying the certificate chain with an empty CRLSet succeeds. + scoped_refptr<CRLSet> crl_set = CRLSet::EmptyCRLSetForTesting(); + int error = Verify(leaf.get(), "127.0.0.1", flags, crl_set.get(), + CertificateList(), &verify_result); + EXPECT_THAT(error, IsOk()); + + std::string crl_set_bytes; + + // Revoke the leaf by subject. Verification should now fail. + ASSERT_TRUE(base::ReadFileToString( + GetTestCertsDirectory().AppendASCII("crlset_by_leaf_subject_no_spki.raw"), + &crl_set_bytes)); + ASSERT_TRUE(CRLSetStorage::Parse(crl_set_bytes, &crl_set)); + + error = Verify(leaf.get(), "127.0.0.1", flags, crl_set.get(), + CertificateList(), &verify_result); + EXPECT_THAT(error, IsError(ERR_CERT_REVOKED)); + + // Revoke the root by subject. Verification should now fail. + ASSERT_TRUE(base::ReadFileToString( + GetTestCertsDirectory().AppendASCII("crlset_by_root_subject_no_spki.raw"), + &crl_set_bytes)); + ASSERT_TRUE(CRLSetStorage::Parse(crl_set_bytes, &crl_set)); + + error = Verify(leaf.get(), "127.0.0.1", flags, crl_set.get(), + CertificateList(), &verify_result); + EXPECT_THAT(error, IsError(ERR_CERT_REVOKED)); + + // Revoke the leaf by subject, but only if the SPKI doesn't match the given + // one. Verification should pass when using the certificate's actual SPKI. + ASSERT_TRUE(base::ReadFileToString( + GetTestCertsDirectory().AppendASCII("crlset_by_root_subject.raw"), + &crl_set_bytes)); + ASSERT_TRUE(CRLSetStorage::Parse(crl_set_bytes, &crl_set)); + + error = Verify(leaf.get(), "127.0.0.1", flags, crl_set.get(), + CertificateList(), &verify_result); + EXPECT_THAT(error, IsOk()); +} + // Tests that CRLSets participate in path building functions, and that as // long as a valid path exists within the verification graph, verification // succeeds. @@ -1859,14 +1988,20 @@ TEST_P(CertVerifyProcInternalTest, CRLSetDuringPathBuilding) { // that they're ignored if not necessary. // This is to avoid relying on AIA or internal object caches when // interacting with the underlying library. - X509Certificate::OSCertHandles intermediates; - intermediates.push_back(path_1_certs[1]->os_cert_handle()); // B-by-C - intermediates.push_back(path_1_certs[2]->os_cert_handle()); // C-by-D - intermediates.push_back(path_2_certs[2]->os_cert_handle()); // C-by-E - intermediates.push_back(path_3_certs[1]->os_cert_handle()); // B-by-F - intermediates.push_back(path_3_certs[2]->os_cert_handle()); // F-by-E - scoped_refptr<X509Certificate> cert = X509Certificate::CreateFromHandle( - path_1_certs[0]->os_cert_handle(), intermediates); + std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates; + intermediates.push_back( + x509_util::DupCryptoBuffer(path_1_certs[1]->cert_buffer())); // B-by-C + intermediates.push_back( + x509_util::DupCryptoBuffer(path_1_certs[2]->cert_buffer())); // C-by-D + intermediates.push_back( + x509_util::DupCryptoBuffer(path_2_certs[2]->cert_buffer())); // C-by-E + intermediates.push_back( + x509_util::DupCryptoBuffer(path_3_certs[1]->cert_buffer())); // B-by-F + intermediates.push_back( + x509_util::DupCryptoBuffer(path_3_certs[2]->cert_buffer())); // F-by-E + scoped_refptr<X509Certificate> cert = X509Certificate::CreateFromBuffer( + x509_util::DupCryptoBuffer(path_1_certs[0]->cert_buffer()), + std::move(intermediates)); ASSERT_TRUE(cert); struct TestPermutations { @@ -1906,13 +2041,13 @@ TEST_P(CertVerifyProcInternalTest, CRLSetDuringPathBuilding) { if (!testcase.expected_intermediate) continue; - const X509Certificate::OSCertHandles& verified_intermediates = - verify_result.verified_cert->GetIntermediateCertificates(); + const auto& verified_intermediates = + verify_result.verified_cert->intermediate_buffers(); ASSERT_EQ(3U, verified_intermediates.size()); scoped_refptr<X509Certificate> intermediate = - X509Certificate::CreateFromHandle(verified_intermediates[1], - X509Certificate::OSCertHandles()); + X509Certificate::CreateFromBuffer( + x509_util::DupCryptoBuffer(verified_intermediates[1].get()), {}); ASSERT_TRUE(intermediate); EXPECT_TRUE(testcase.expected_intermediate->Equals(intermediate.get())) @@ -2112,31 +2247,32 @@ TEST_P(CertVerifyProcWeakDigestTest, VerifyDetectsAlgorithm) { WeakDigestTestData data = GetParam(); base::FilePath certs_dir = GetTestCertsDirectory(); - scoped_refptr<X509Certificate> intermediate_cert; - scoped_refptr<X509Certificate> root_cert; - // Build |intermediates| as the full chain (including trust anchor). - X509Certificate::OSCertHandles intermediates; + std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates; if (data.intermediate_cert_filename) { - intermediate_cert = + scoped_refptr<X509Certificate> intermediate_cert = ImportCertFromFile(certs_dir, data.intermediate_cert_filename); ASSERT_TRUE(intermediate_cert); - intermediates.push_back(intermediate_cert->os_cert_handle()); + intermediates.push_back( + x509_util::DupCryptoBuffer(intermediate_cert->cert_buffer())); } if (data.root_cert_filename) { - root_cert = ImportCertFromFile(certs_dir, data.root_cert_filename); + scoped_refptr<X509Certificate> root_cert = + ImportCertFromFile(certs_dir, data.root_cert_filename); ASSERT_TRUE(root_cert); - intermediates.push_back(root_cert->os_cert_handle()); + intermediates.push_back( + x509_util::DupCryptoBuffer(root_cert->cert_buffer())); } scoped_refptr<X509Certificate> ee_cert = ImportCertFromFile(certs_dir, data.ee_cert_filename); ASSERT_TRUE(ee_cert); - scoped_refptr<X509Certificate> ee_chain = X509Certificate::CreateFromHandle( - ee_cert->os_cert_handle(), intermediates); + scoped_refptr<X509Certificate> ee_chain = X509Certificate::CreateFromBuffer( + x509_util::DupCryptoBuffer(ee_cert->cert_buffer()), + std::move(intermediates)); ASSERT_TRUE(ee_chain); int flags = 0; diff --git a/chromium/net/cert/cert_verify_proc_win.cc b/chromium/net/cert/cert_verify_proc_win.cc index 8318f8c90aa..a606da9dc32 100644 --- a/chromium/net/cert/cert_verify_proc_win.cc +++ b/chromium/net/cert/cert_verify_proc_win.cc @@ -375,6 +375,12 @@ bool HashSPKI(PCCERT_CONTEXT cert, std::string* hash) { return true; } +bool GetSubject(PCCERT_CONTEXT cert, base::StringPiece* out_subject) { + base::StringPiece der_bytes( + reinterpret_cast<const char*>(cert->pbCertEncoded), cert->cbCertEncoded); + return asn1::ExtractSubjectFromDERCert(der_bytes, out_subject); +} + enum CRLSetResult { // Indicates an error happened while attempting to determine CRLSet status. // For example, if the certificate's SPKI could not be extracted. @@ -422,18 +428,20 @@ CRLSetResult CheckRevocationWithCRLSet(CRLSet* crl_set, DCHECK(crl_set); DCHECK(subject_cert); - // Check to see if |subject_cert|'s SPKI is revoked. The actual revocation - // is handled by the SHA-256 hash of the SPKI, so compute that. + // Check to see if |subject_cert|'s SPKI or Subject is revoked. std::string subject_hash; - if (!HashSPKI(subject_cert, &subject_hash)) { + base::StringPiece subject_name; + if (!HashSPKI(subject_cert, &subject_hash) || + !GetSubject(subject_cert, &subject_name)) { NOTREACHED(); // Indicates Windows accepted something irrecoverably bad. previous_hash->clear(); return kCRLSetError; } - CRLSet::Result result = crl_set->CheckSPKI(subject_hash); - if (result == CRLSet::REVOKED) + if (crl_set->CheckSPKI(subject_hash) == CRLSet::REVOKED || + crl_set->CheckSubject(subject_name, subject_hash) == CRLSet::REVOKED) { return kCRLSetRevoked; + } // If no issuer cert is provided, nor a hash of the issuer's SPKI, no // further checks can be done. @@ -468,7 +476,7 @@ CRLSetResult CheckRevocationWithCRLSet(CRLSet* crl_set, } // Look up by serial & issuer SPKI. - result = crl_set->CheckSerial(serial, *issuer_hash); + const CRLSet::Result result = crl_set->CheckSerial(serial, *issuer_hash); if (result == CRLSet::REVOKED) return kCRLSetRevoked; diff --git a/chromium/net/cert/cert_verify_result.h b/chromium/net/cert/cert_verify_result.h index 5077e2fd349..43c88b9c203 100644 --- a/chromium/net/cert/cert_verify_result.h +++ b/chromium/net/cert/cert_verify_result.h @@ -31,7 +31,7 @@ class NET_EXPORT CertVerifyResult { // The certificate chain that was constructed during verification. // // Note: Although |verified_cert| will match the originally supplied - // certificate to be validated, the results of GetIntermediateCertificates() + // certificate to be validated, the results of intermediate_buffers() // may be substantially different, both in order and in content, then the // originally supplied intermediates. // @@ -40,9 +40,9 @@ class NET_EXPORT CertVerifyResult { // the implementation. // // In the event of validation success, the trust anchor will be - // |verified_cert->GetIntermediateCertificates().back()| if + // |verified_cert->intermediate_buffers().back()| if // there was a certificate chain to the trust anchor, and will - // be |verified_cert->os_cert_handle()| if the certificate was + // be |verified_cert->cert_buffer()| if the certificate was // the trust anchor. scoped_refptr<X509Certificate> verified_cert; diff --git a/chromium/net/cert/crl_set.cc b/chromium/net/cert/crl_set.cc index a6f3e0ed2b2..da71f4bca40 100644 --- a/chromium/net/cert/crl_set.cc +++ b/chromium/net/cert/crl_set.cc @@ -6,6 +6,9 @@ #include "base/logging.h" #include "base/time/time.h" +#include "crypto/sha2.h" +#include "third_party/boringssl/src/include/openssl/bytestring.h" +#include "third_party/boringssl/src/include/openssl/mem.h" namespace net { @@ -28,6 +31,23 @@ CRLSet::Result CRLSet::CheckSPKI(const base::StringPiece& spki_hash) const { return GOOD; } +CRLSet::Result CRLSet::CheckSubject(const base::StringPiece& encoded_subject, + const base::StringPiece& spki_hash) const { + const std::string digest(crypto::SHA256HashString(encoded_subject)); + const auto i = limited_subjects_.find(digest); + if (i == limited_subjects_.end()) { + return GOOD; + } + + for (const auto& j : i->second) { + if (spki_hash == j) { + return GOOD; + } + } + + return REVOKED; +} + CRLSet::Result CRLSet::CheckSerial( const base::StringPiece& serial_number, const base::StringPiece& issuer_spki_hash) const { @@ -75,21 +95,54 @@ const CRLSet::CRLList& CRLSet::crls() const { } // static -CRLSet* CRLSet::EmptyCRLSetForTesting() { - return ForTesting(false, NULL, ""); +scoped_refptr<CRLSet> CRLSet::EmptyCRLSetForTesting() { + return ForTesting(false, NULL, "", "", {}); } -CRLSet* CRLSet::ExpiredCRLSetForTesting() { - return ForTesting(true, NULL, ""); +scoped_refptr<CRLSet> CRLSet::ExpiredCRLSetForTesting() { + return ForTesting(true, NULL, "", "", {}); } // static -CRLSet* CRLSet::ForTesting(bool is_expired, - const SHA256HashValue* issuer_spki, - const std::string& serial_number) { - CRLSet* crl_set = new CRLSet; +scoped_refptr<CRLSet> CRLSet::ForTesting( + bool is_expired, + const SHA256HashValue* issuer_spki, + const std::string& serial_number, + const std::string common_name, + const std::vector<std::string> acceptable_spki_hashes_for_cn) { + std::string subject_hash; + if (!common_name.empty()) { + CBB cbb, top_level, set, inner_seq, oid, cn; + uint8_t* x501_data; + size_t x501_len; + static const uint8_t kCommonNameOID[] = {0x55, 0x04, 0x03}; // 2.5.4.3 + + CBB_zero(&cbb); + + if (!CBB_init(&cbb, 32) || + !CBB_add_asn1(&cbb, &top_level, CBS_ASN1_SEQUENCE) || + !CBB_add_asn1(&top_level, &set, CBS_ASN1_SET) || + !CBB_add_asn1(&set, &inner_seq, CBS_ASN1_SEQUENCE) || + !CBB_add_asn1(&inner_seq, &oid, CBS_ASN1_OBJECT) || + !CBB_add_bytes(&oid, kCommonNameOID, sizeof(kCommonNameOID)) || + !CBB_add_asn1(&inner_seq, &cn, CBS_ASN1_PRINTABLESTRING) || + !CBB_add_bytes(&cn, + reinterpret_cast<const uint8_t*>(common_name.data()), + common_name.size()) || + !CBB_finish(&cbb, &x501_data, &x501_len)) { + CBB_cleanup(&cbb); + return nullptr; + } + + subject_hash.assign(crypto::SHA256HashString( + base::StringPiece(reinterpret_cast<char*>(x501_data), x501_len))); + OPENSSL_free(x501_data); + } + + scoped_refptr<CRLSet> crl_set(new CRLSet); if (is_expired) crl_set->not_after_ = 1; + if (issuer_spki != NULL) { const std::string spki(reinterpret_cast<const char*>(issuer_spki->data), sizeof(issuer_spki->data)); @@ -100,6 +153,9 @@ CRLSet* CRLSet::ForTesting(bool is_expired, if (!serial_number.empty()) crl_set->crls_[0].second.push_back(serial_number); + if (!subject_hash.empty()) + crl_set->limited_subjects_[subject_hash] = acceptable_spki_hashes_for_cn; + return crl_set; } diff --git a/chromium/net/cert/crl_set.h b/chromium/net/cert/crl_set.h index d32faed654c..8cb293fbcd9 100644 --- a/chromium/net/cert/crl_set.h +++ b/chromium/net/cert/crl_set.h @@ -45,6 +45,12 @@ class NET_EXPORT CRLSet : public base::RefCountedThreadSafe<CRLSet> { const base::StringPiece& serial_number, const base::StringPiece& issuer_spki_hash) const; + // CheckSubject returns the information contained in the set for a given, + // encoded subject name and SPKI hash. The subject name is encoded as a DER + // X.501 Name (see https://tools.ietf.org/html/rfc5280#section-4.1.2.4). + Result CheckSubject(const base::StringPiece& asn1_subject, + const base::StringPiece& spki_hash) const; + // IsExpired returns true iff the current time is past the NotAfter time // specified in the CRLSet. bool IsExpired() const; @@ -64,19 +70,25 @@ class NET_EXPORT CRLSet : public base::RefCountedThreadSafe<CRLSet> { const CRLList& crls() const; // EmptyCRLSetForTesting returns a valid, but empty, CRLSet for unit tests. - static CRLSet* EmptyCRLSetForTesting(); + static scoped_refptr<CRLSet> EmptyCRLSetForTesting(); // ExpiredCRLSetForTesting returns a expired, empty CRLSet for unit tests. - static CRLSet* ExpiredCRLSetForTesting(); + static scoped_refptr<CRLSet> ExpiredCRLSetForTesting(); // ForTesting returns a CRLSet for testing. If |is_expired| is true, calling // IsExpired on the result will return true. If |issuer_spki| is not NULL, // the CRLSet will cover certificates issued by that SPKI. If |serial_number| // is not empty, then that big-endian serial number will be considered to - // have been revoked by |issuer_spki|. - static CRLSet* ForTesting(bool is_expired, - const SHA256HashValue* issuer_spki, - const std::string& serial_number); + // have been revoked by |issuer_spki|. If |common_name| is not empty then the + // CRLSet will consider certificates with a subject consisting only of that + // common name to be revoked unless they match an SPKI hash from + // |acceptable_spki_hashes_for_cn|. + static scoped_refptr<CRLSet> ForTesting( + bool is_expired, + const SHA256HashValue* issuer_spki, + const std::string& serial_number, + const std::string common_name, + const std::vector<std::string> acceptable_spki_hashes_for_cn); private: CRLSet(); @@ -98,6 +110,13 @@ class NET_EXPORT CRLSet : public base::RefCountedThreadSafe<CRLSet> { // blocked_spkis_ contains the SHA256 hashes of SPKIs which are to be blocked // no matter where in a certificate chain they might appear. std::vector<std::string> blocked_spkis_; + // limited_subjects_ is a map from the SHA256 hash of an X.501 subject name + // to a list of allowed SPKI hashes for certificates with that subject name. + std::unordered_map<std::string, std::vector<std::string>> limited_subjects_; + // limited_subjects_ordered_ contains the keys of |limited_subjects_|, + // ordered in the same order as they were found when parsing. This allows + // exact reserialisation. + std::vector<std::string> limited_subjects_ordered_; }; } // namespace net diff --git a/chromium/net/cert/crl_set_storage.cc b/chromium/net/cert/crl_set_storage.cc index 007cf3c1f47..0ca26779fde 100644 --- a/chromium/net/cert/crl_set_storage.cc +++ b/chromium/net/cert/crl_set_storage.cc @@ -133,7 +133,7 @@ static base::DictionaryValue* ReadHeader(base::StringPiece* data) { if (header.get() == NULL) return NULL; - if (!header->IsType(base::Value::Type::DICTIONARY)) + if (!header->is_dict()) return NULL; return static_cast<base::DictionaryValue*>(header.release()); } @@ -179,31 +179,32 @@ static bool ReadCRL(base::StringPiece* data, std::string* out_parent_spki_hash, return true; } -// static -bool CRLSetStorage::CopyBlockedSPKIsFromHeader( - CRLSet* crl_set, - base::DictionaryValue* header_dict) { - base::ListValue* blocked_spkis_list = NULL; - if (!header_dict->GetList("BlockedSPKIs", &blocked_spkis_list)) { - // BlockedSPKIs is optional, so it's fine if we don't find it. +// CopyHashListFromHeader parses a list of base64-encoded, SHA-256 hashes from +// the given |key| in |header_dict| and sets |*out| to the decoded values. It's +// not an error if |key| is not found in |header_dict|. +static bool CopyHashListFromHeader(base::DictionaryValue* header_dict, + const char* key, + std::vector<std::string>* out) { + base::ListValue* list = nullptr; + if (!header_dict->GetList(key, &list)) { + // Hash lists are optional so it's not an error if not present. return true; } - crl_set->blocked_spkis_.clear(); - crl_set->blocked_spkis_.reserve(blocked_spkis_list->GetSize()); + out->clear(); + out->reserve(list->GetSize()); - std::string spki_sha256_base64; + std::string sha256_base64; - for (size_t i = 0; i < blocked_spkis_list->GetSize(); ++i) { - spki_sha256_base64.clear(); + for (size_t i = 0; i < list->GetSize(); ++i) { + sha256_base64.clear(); - if (!blocked_spkis_list->GetString(i, &spki_sha256_base64)) + if (!list->GetString(i, &sha256_base64)) return false; - crl_set->blocked_spkis_.push_back(std::string()); - if (!base::Base64Decode(spki_sha256_base64, - &crl_set->blocked_spkis_.back())) { - crl_set->blocked_spkis_.pop_back(); + out->push_back(std::string()); + if (!base::Base64Decode(sha256_base64, &out->back())) { + out->pop_back(); return false; } } @@ -211,6 +212,51 @@ bool CRLSetStorage::CopyBlockedSPKIsFromHeader( return true; } +// CopyHashToHashesMapFromHeader parse a map from base64-encoded, SHA-256 +// hashes to lists of the same, from the given |key| in |header_dict|. It +// copies the map data into |out| (after base64-decoding) and writes the order +// of map keys into |out_key_order|. +static bool CopyHashToHashesMapFromHeader( + base::DictionaryValue* header_dict, + const char* key, + std::unordered_map<std::string, std::vector<std::string>>* out, + std::vector<std::string>* out_key_order) { + out->clear(); + out_key_order->clear(); + + base::Value* const dict = + header_dict->FindKeyOfType(key, base::Value::Type::DICTIONARY); + if (dict == nullptr) { + // Maps are optional so it's not an error if not present. + return true; + } + + for (const auto& i : dict->DictItems()) { + if (!i.second.is_list()) { + return false; + } + + std::vector<std::string> allowed_spkis; + for (const auto& j : i.second.GetList()) { + allowed_spkis.push_back(std::string()); + if (!j.is_string() || + !base::Base64Decode(j.GetString(), &allowed_spkis.back())) { + return false; + } + } + + std::string subject_hash; + if (!base::Base64Decode(i.first, &subject_hash)) { + return false; + } + + out_key_order->push_back(subject_hash); + (*out)[subject_hash] = allowed_spkis; + } + + return true; +} + // kMaxUncompressedChangesLength is the largest changes array that we'll // accept. This bounds the number of CRLs in the CRLSet as well as the number // of serial numbers in a given CRL. @@ -356,8 +402,13 @@ bool CRLSetStorage::Parse(base::StringPiece data, crl_set->crls_index_by_issuer_[back_pair->first] = crl_index; } - if (!CopyBlockedSPKIsFromHeader(crl_set.get(), header_dict.get())) + if (!CopyHashListFromHeader(header_dict.get(), "BlockedSPKIs", + &crl_set->blocked_spkis_) || + !CopyHashToHashesMapFromHeader(header_dict.get(), "LimitedSubjects", + &crl_set->limited_subjects_, + &crl_set->limited_subjects_ordered_)) { return false; + } *out_crl_set = crl_set; return true; @@ -403,8 +454,13 @@ bool CRLSetStorage::ApplyDelta(const CRLSet* in_crl_set, crl_set->sequence_ = static_cast<uint32_t>(sequence); crl_set->not_after_ = static_cast<uint64_t>(not_after); - if (!CopyBlockedSPKIsFromHeader(crl_set.get(), header_dict.get())) + if (!CopyHashListFromHeader(header_dict.get(), "BlockedSPKIs", + &crl_set->blocked_spkis_) || + !CopyHashToHashesMapFromHeader(header_dict.get(), "LimitedSubjects", + &crl_set->limited_subjects_, + &crl_set->limited_subjects_ordered_)) { return false; + } std::vector<uint8_t> crl_changes; @@ -505,9 +561,41 @@ std::string CRLSetStorage::Serialize(const CRLSet* crl_set) { header += ","; header += "\"" + spki_hash_base64 + "\""; } + header += "]"; if (crl_set->not_after_ != 0) header += base::StringPrintf(",\"NotAfter\":%" PRIu64, crl_set->not_after_); + + if (!crl_set->limited_subjects_ordered_.empty()) { + header += ",LimitedSubjects:{"; + bool first = true; + + for (const auto& i : crl_set->limited_subjects_ordered_) { + if (!first) + header += ","; + first = false; + + std::string subject_hash_base64; + base::Base64Encode(i, &subject_hash_base64); + header += "\"" + subject_hash_base64 + "\":["; + + bool first_hash = true; + for (const auto& j : crl_set->limited_subjects_.find(i)->second) { + if (!first_hash) + header += ","; + first_hash = false; + + std::string spki_hash_base64; + base::Base64Encode(j, &spki_hash_base64); + header += "\"" + spki_hash_base64 + "\""; + } + + header += "]"; + } + + header += "}"; + } + header += "}"; size_t len = 2 /* header len */ + header.size(); diff --git a/chromium/net/cert/crl_set_storage.h b/chromium/net/cert/crl_set_storage.h index dd15796aa5b..92659931420 100644 --- a/chromium/net/cert/crl_set_storage.h +++ b/chromium/net/cert/crl_set_storage.h @@ -13,10 +13,6 @@ #include "net/base/net_export.h" #include "net/cert/crl_set.h" -namespace base { -class DictionaryValue; -} - namespace net { // Static helpers to save and load CRLSet. @@ -42,12 +38,6 @@ class NET_EXPORT CRLSetStorage { // and serializing a CRLSet is a lossless operation - the resulting bytes // will be equal. static std::string Serialize(const CRLSet* crl_set); - - private: - // CopyBlockedSPKIsFromHeader sets |blocked_spkis_| to the list of values - // from "BlockedSPKIs" in |header_dict|. - static bool CopyBlockedSPKIsFromHeader(CRLSet* crl_set, - base::DictionaryValue* header_dict); }; } // namespace net diff --git a/chromium/net/cert/crl_set_unittest.cc b/chromium/net/cert/crl_set_unittest.cc index 6e154d3e5ce..88c072038fa 100644 --- a/chromium/net/cert/crl_set_unittest.cc +++ b/chromium/net/cert/crl_set_unittest.cc @@ -3,7 +3,15 @@ // found in the LICENSE file. #include "net/cert/crl_set.h" + +#include "base/files/file_util.h" +#include "crypto/sha2.h" +#include "net/cert/asn1_util.h" #include "net/cert/crl_set_storage.h" +#include "net/cert/x509_certificate.h" +#include "net/cert/x509_util.h" +#include "net/test/cert_test_util.h" +#include "net/test/test_data_directory.h" #include "testing/gtest/include/gtest/gtest.h" namespace net { @@ -202,9 +210,8 @@ TEST(CRLSetTest, Parse) { EXPECT_EQ(std::string("\x64\x63\x49\xD2\x00\x03\x00\x00\x1D\x77", 10), serials[kExpectedNumSerials - 1]); - const std::string gia_spki_hash( - reinterpret_cast<const char*>(kGIASPKISHA256), - sizeof(kGIASPKISHA256)); + const std::string gia_spki_hash(reinterpret_cast<const char*>(kGIASPKISHA256), + sizeof(kGIASPKISHA256)); EXPECT_EQ(CRLSet::REVOKED, set->CheckSerial( std::string("\x16\x7D\x75\x9D\x00\x03\x00\x00\x14\x55", 10), @@ -318,6 +325,48 @@ TEST(CRLSetTest, BlockedSPKIs) { set->CheckSPKI(reinterpret_cast<const char*>(spki_hash))); } +TEST(CRLSetTest, BlockedSubjects) { + std::string crl_set_bytes; + EXPECT_TRUE(base::ReadFileToString( + GetTestCertsDirectory().AppendASCII("crlset_by_root_subject.raw"), + &crl_set_bytes)); + scoped_refptr<CRLSet> set; + EXPECT_TRUE(CRLSetStorage::Parse(crl_set_bytes, &set)); + ASSERT_TRUE(set.get() != NULL); + + scoped_refptr<X509Certificate> root = CreateCertificateChainFromFile( + GetTestCertsDirectory(), "root_ca_cert.pem", + X509Certificate::FORMAT_AUTO); + base::StringPiece root_der = + net::x509_util::CryptoBufferAsStringPiece(root->cert_buffer()); + + base::StringPiece spki; + ASSERT_TRUE(asn1::ExtractSPKIFromDERCert(root_der, &spki)); + SHA256HashValue spki_sha256; + crypto::SHA256HashString(spki, spki_sha256.data, sizeof(spki_sha256.data)); + + base::StringPiece subject; + ASSERT_TRUE(asn1::ExtractSubjectFromDERCert(root_der, &subject)); + + // Unrelated subjects are unaffected. + EXPECT_EQ(CRLSet::GOOD, set->CheckSubject("abcdef", "")); + + // The subject in question is considered revoked if used with an unknown SPKI + // hash. + EXPECT_EQ(CRLSet::REVOKED, + set->CheckSubject( + subject, + base::StringPiece(reinterpret_cast<const char*>(kGIASPKISHA256), + sizeof(kGIASPKISHA256)))); + + // When used with the correct hash, that subject should be accepted. + EXPECT_EQ(CRLSet::GOOD, + set->CheckSubject( + subject, base::StringPiece( + reinterpret_cast<const char*>(spki_sha256.data), + sizeof(spki_sha256.data)))); +} + TEST(CRLSetTest, Expired) { // This CRLSet has an expiry value set to one second past midnight, 1st Jan, // 1970. diff --git a/chromium/net/cert/ct_log_response_parser.cc b/chromium/net/cert/ct_log_response_parser.cc index b6067d14f38..81e0f0a8015 100644 --- a/chromium/net/cert/ct_log_response_parser.cc +++ b/chromium/net/cert/ct_log_response_parser.cc @@ -33,7 +33,7 @@ struct JsonSignedTreeHead { base::JSONValueConverter<JsonSignedTreeHead>* converted); }; -bool ConvertSHA256RootHash(const base::StringPiece& s, std::string* result) { +bool ConvertSHA256RootHash(base::StringPiece s, std::string* result) { if (!base::Base64Decode(s, result)) { DVLOG(1) << "Failed decoding sha256_root_hash"; return false; @@ -48,8 +48,7 @@ bool ConvertSHA256RootHash(const base::StringPiece& s, std::string* result) { return true; } -bool ConvertTreeHeadSignature(const base::StringPiece& s, - DigitallySigned* result) { +bool ConvertTreeHeadSignature(base::StringPiece s, DigitallySigned* result) { std::string tree_head_signature; if (!base::Base64Decode(s, &tree_head_signature)) { DVLOG(1) << "Failed decoding tree_head_signature"; diff --git a/chromium/net/cert/ct_objects_extractor.cc b/chromium/net/cert/ct_objects_extractor.cc index 25c8219fb5e..055fbdb1728 100644 --- a/chromium/net/cert/ct_objects_extractor.cc +++ b/chromium/net/cert/ct_objects_extractor.cc @@ -12,6 +12,7 @@ #include "crypto/sha2.h" #include "net/cert/asn1_util.h" #include "net/cert/signed_certificate_timestamp.h" +#include "net/cert/x509_util.h" #include "third_party/boringssl/src/include/openssl/bytestring.h" #include "third_party/boringssl/src/include/openssl/mem.h" @@ -174,15 +175,12 @@ bool ParseSCTListFromExtensions(const CBS& extensions, // |*out_single_response| to the body of the SingleResponse starting at the // |certStatus| field. bool FindMatchingSingleResponse(CBS* responses, - X509Certificate::OSCertHandle issuer, + const CRYPTO_BUFFER* issuer, const std::string& cert_serial_number, CBS* out_single_response) { - std::string issuer_der; - if (!X509Certificate::GetDEREncoded(issuer, &issuer_der)) - return false; - base::StringPiece issuer_spki; - if (!asn1::ExtractSPKIFromDERCert(issuer_der, &issuer_spki)) + if (!asn1::ExtractSPKIFromDERCert( + x509_util::CryptoBufferAsStringPiece(issuer), &issuer_spki)) return false; // In OCSP, only the key itself is under hash. @@ -245,13 +243,9 @@ bool FindMatchingSingleResponse(CBS* responses, } // namespace -bool ExtractEmbeddedSCTList(X509Certificate::OSCertHandle cert, - std::string* sct_list) { - std::string der; - if (!X509Certificate::GetDEREncoded(cert, &der)) - return false; +bool ExtractEmbeddedSCTList(const CRYPTO_BUFFER* cert, std::string* sct_list) { CBS cert_cbs; - CBS_init(&cert_cbs, reinterpret_cast<const uint8_t*>(der.data()), der.size()); + CBS_init(&cert_cbs, CRYPTO_BUFFER_data(cert), CRYPTO_BUFFER_len(cert)); CBS cert_body, tbs_cert, extensions_wrap, extensions; if (!CBS_get_asn1(&cert_cbs, &cert_body, CBS_ASN1_SEQUENCE) || CBS_len(&cert_cbs) != 0 || @@ -269,19 +263,14 @@ bool ExtractEmbeddedSCTList(X509Certificate::OSCertHandle cert, sizeof(kEmbeddedSCTOid), sct_list); } -bool GetPrecertSignedEntry(X509Certificate::OSCertHandle leaf, - X509Certificate::OSCertHandle issuer, +bool GetPrecertSignedEntry(const CRYPTO_BUFFER* leaf, + const CRYPTO_BUFFER* issuer, SignedEntryData* result) { result->Reset(); - std::string leaf_der; - if (!X509Certificate::GetDEREncoded(leaf, &leaf_der)) - return false; - // Parse the TBSCertificate. CBS cert_cbs; - CBS_init(&cert_cbs, reinterpret_cast<const uint8_t*>(leaf_der.data()), - leaf_der.size()); + CBS_init(&cert_cbs, CRYPTO_BUFFER_data(leaf), CRYPTO_BUFFER_len(leaf)); CBS cert_body, tbs_cert; if (!CBS_get_asn1(&cert_cbs, &cert_body, CBS_ASN1_SEQUENCE) || CBS_len(&cert_cbs) != 0 || @@ -336,10 +325,9 @@ bool GetPrecertSignedEntry(X509Certificate::OSCertHandle leaf, bssl::UniquePtr<uint8_t> scoped_new_tbs_cert_der(new_tbs_cert_der); // Extract the issuer's public key. - std::string issuer_der; base::StringPiece issuer_key; - if (!X509Certificate::GetDEREncoded(issuer, &issuer_der) || - !asn1::ExtractSPKIFromDERCert(issuer_der, &issuer_key)) { + if (!asn1::ExtractSPKIFromDERCert( + x509_util::CryptoBufferAsStringPiece(issuer), &issuer_key)) { return false; } @@ -353,21 +341,17 @@ bool GetPrecertSignedEntry(X509Certificate::OSCertHandle leaf, return true; } -bool GetX509SignedEntry(X509Certificate::OSCertHandle leaf, - SignedEntryData* result) { +bool GetX509SignedEntry(const CRYPTO_BUFFER* leaf, SignedEntryData* result) { DCHECK(leaf); - std::string encoded; - if (!X509Certificate::GetDEREncoded(leaf, &encoded)) - return false; - result->Reset(); result->type = ct::SignedEntryData::LOG_ENTRY_TYPE_X509; - result->leaf_certificate.swap(encoded); + result->leaf_certificate = + std::string(x509_util::CryptoBufferAsStringPiece(leaf)); return true; } -bool ExtractSCTListFromOCSPResponse(X509Certificate::OSCertHandle issuer, +bool ExtractSCTListFromOCSPResponse(const CRYPTO_BUFFER* issuer, const std::string& cert_serial_number, base::StringPiece ocsp_response, std::string* sct_list) { diff --git a/chromium/net/cert/ct_objects_extractor.h b/chromium/net/cert/ct_objects_extractor.h index 469e315dadd..e18a84a5ac5 100644 --- a/chromium/net/cert/ct_objects_extractor.h +++ b/chromium/net/cert/ct_objects_extractor.h @@ -22,9 +22,8 @@ struct SignedEntryData; // If the extension is present, returns true, updating |*sct_list| to contain // the encoded list, minus the DER encoding necessary for the extension. // |*sct_list| can then be further decoded with ct::DecodeSCTList -NET_EXPORT_PRIVATE bool ExtractEmbeddedSCTList( - X509Certificate::OSCertHandle cert, - std::string* sct_list); +NET_EXPORT_PRIVATE bool ExtractEmbeddedSCTList(const CRYPTO_BUFFER* cert, + std::string* sct_list); // Obtains a PrecertChain log entry for |leaf|, an X.509v3 certificate that // contains an X.509v3 extension with the OID 1.3.6.1.4.1.11129.2.4.2. On @@ -33,10 +32,9 @@ NET_EXPORT_PRIVATE bool ExtractEmbeddedSCTList( // The filled |*result| should be verified using ct::CTLogVerifier::Verify // Note: If |leaf| does not contain the required extension, it is treated as // a failure. -NET_EXPORT_PRIVATE bool GetPrecertSignedEntry( - X509Certificate::OSCertHandle leaf, - X509Certificate::OSCertHandle issuer, - SignedEntryData* result); +NET_EXPORT_PRIVATE bool GetPrecertSignedEntry(const CRYPTO_BUFFER* leaf, + const CRYPTO_BUFFER* issuer, + SignedEntryData* result); // Obtains an X509Chain log entry for |leaf|, an X.509v3 certificate that // is not expected to contain an X.509v3 extension with the OID @@ -44,7 +42,7 @@ NET_EXPORT_PRIVATE bool GetPrecertSignedEntry( // On success, fills |result| with the data for an X509Chain log entry and // returns true. // The filled |*result| should be verified using ct::CTLogVerifier::Verify -NET_EXPORT_PRIVATE bool GetX509SignedEntry(X509Certificate::OSCertHandle leaf, +NET_EXPORT_PRIVATE bool GetX509SignedEntry(const CRYPTO_BUFFER* leaf, SignedEntryData* result); // Extracts a SignedCertificateTimestampList that has been embedded within @@ -54,7 +52,7 @@ NET_EXPORT_PRIVATE bool GetX509SignedEntry(X509Certificate::OSCertHandle leaf, // the encoded list, minus the DER encoding necessary for the extension. // |*sct_list| can then be further decoded with ct::DecodeSCTList. NET_EXPORT_PRIVATE bool ExtractSCTListFromOCSPResponse( - X509Certificate::OSCertHandle issuer, + const CRYPTO_BUFFER* issuer, const std::string& cert_serial_number, base::StringPiece ocsp_response, std::string* sct_list); diff --git a/chromium/net/cert/ct_objects_extractor_unittest.cc b/chromium/net/cert/ct_objects_extractor_unittest.cc index 846dd62cf20..8152d023191 100644 --- a/chromium/net/cert/ct_objects_extractor_unittest.cc +++ b/chromium/net/cert/ct_objects_extractor_unittest.cc @@ -40,7 +40,7 @@ class CTObjectsExtractorTest : public ::testing::Test { void ExtractEmbeddedSCT(scoped_refptr<X509Certificate> cert, scoped_refptr<SignedCertificateTimestamp>* sct) { std::string sct_list; - ASSERT_TRUE(ExtractEmbeddedSCTList(cert->os_cert_handle(), &sct_list)); + ASSERT_TRUE(ExtractEmbeddedSCTList(cert->cert_buffer(), &sct_list)); std::vector<base::StringPiece> parsed_scts; // Make sure the SCT list can be decoded properly @@ -73,9 +73,8 @@ TEST_F(CTObjectsExtractorTest, ExtractEmbeddedSCT) { TEST_F(CTObjectsExtractorTest, ExtractPrecert) { SignedEntryData entry; - ASSERT_TRUE(GetPrecertSignedEntry(precert_chain_[0]->os_cert_handle(), - precert_chain_[1]->os_cert_handle(), - &entry)); + ASSERT_TRUE(GetPrecertSignedEntry(precert_chain_[0]->cert_buffer(), + precert_chain_[1]->cert_buffer(), &entry)); ASSERT_EQ(ct::SignedEntryData::LOG_ENTRY_TYPE_PRECERT, entry.type); // Should have empty leaf cert for this log entry type. @@ -88,7 +87,7 @@ TEST_F(CTObjectsExtractorTest, ExtractPrecert) { TEST_F(CTObjectsExtractorTest, ExtractOrdinaryX509Cert) { SignedEntryData entry; - ASSERT_TRUE(GetX509SignedEntry(test_cert_->os_cert_handle(), &entry)); + ASSERT_TRUE(GetX509SignedEntry(test_cert_->cert_buffer(), &entry)); ASSERT_EQ(ct::SignedEntryData::LOG_ENTRY_TYPE_X509, entry.type); // Should have empty tbs_certificate for this log entry type. @@ -104,9 +103,8 @@ TEST_F(CTObjectsExtractorTest, ExtractedSCTVerifies) { ExtractEmbeddedSCT(precert_chain_[0], &sct); SignedEntryData entry; - ASSERT_TRUE(GetPrecertSignedEntry(precert_chain_[0]->os_cert_handle(), - precert_chain_[1]->os_cert_handle(), - &entry)); + ASSERT_TRUE(GetPrecertSignedEntry(precert_chain_[0]->cert_buffer(), + precert_chain_[1]->cert_buffer(), &entry)); EXPECT_TRUE(log_->Verify(entry, *sct.get())); } @@ -119,7 +117,7 @@ TEST_F(CTObjectsExtractorTest, ComplementarySCTVerifies) { GetX509CertSCT(&sct); SignedEntryData entry; - ASSERT_TRUE(GetX509SignedEntry(test_cert_->os_cert_handle(), &entry)); + ASSERT_TRUE(GetX509SignedEntry(test_cert_->cert_buffer(), &entry)); EXPECT_TRUE(log_->Verify(entry, *sct.get())); } @@ -143,8 +141,8 @@ TEST_F(CTObjectsExtractorTest, ExtractSCTListFromOCSPResponse) { std::string extracted_sct_list; EXPECT_TRUE(ct::ExtractSCTListFromOCSPResponse( - issuer_cert->os_cert_handle(), subject_cert->serial_number(), - ocsp_response, &extracted_sct_list)); + issuer_cert->cert_buffer(), subject_cert->serial_number(), ocsp_response, + &extracted_sct_list)); EXPECT_EQ(extracted_sct_list, fake_sct_list); } @@ -160,8 +158,8 @@ TEST_F(CTObjectsExtractorTest, ExtractSCTListFromOCSPResponseMatchesSerial) { std::string extracted_sct_list; EXPECT_FALSE(ct::ExtractSCTListFromOCSPResponse( - issuer_cert->os_cert_handle(), test_cert_->serial_number(), - ocsp_response, &extracted_sct_list)); + issuer_cert->cert_buffer(), test_cert_->serial_number(), ocsp_response, + &extracted_sct_list)); } // Test that the extractor honours issuer ID. @@ -177,8 +175,8 @@ TEST_F(CTObjectsExtractorTest, ExtractSCTListFromOCSPResponseMatchesIssuer) { std::string extracted_sct_list; // Use test_cert_ for issuer - it is not the correct issuer of |subject_cert|. EXPECT_FALSE(ct::ExtractSCTListFromOCSPResponse( - test_cert_->os_cert_handle(), subject_cert->serial_number(), - ocsp_response, &extracted_sct_list)); + test_cert_->cert_buffer(), subject_cert->serial_number(), ocsp_response, + &extracted_sct_list)); } } // namespace ct diff --git a/chromium/net/cert/ct_verifier.h b/chromium/net/cert/ct_verifier.h index b5b1c79045f..0368044f4fd 100644 --- a/chromium/net/cert/ct_verifier.h +++ b/chromium/net/cert/ct_verifier.h @@ -21,12 +21,14 @@ class NET_EXPORT CTVerifier { public: // Called for each Signed Certificate Timestamp from a known log that vas // verified successfully (i.e. the signature verifies). |sct| is the - // Signed Certificate Timestamp, |cert| is the certificate it applies to. - // The certificate is needed to calculate the hash of the log entry, - // necessary for checking inclusion in the log. + // Signed Certificate Timestamp, |cert| is the certificate it applies to and + // |hostname| is the server that presented the certificate (DNS name or IP + // address literal). The certificate is needed to calculate the hash of the + // log entry, necessary for checking inclusion in the log. // Note: The observer (whose implementation is expected to exist outside // net/) may store the observed |cert| and |sct|. - virtual void OnSCTVerified(X509Certificate* cert, + virtual void OnSCTVerified(base::StringPiece hostname, + X509Certificate* cert, const ct::SignedCertificateTimestamp* sct) = 0; protected: @@ -45,7 +47,11 @@ class NET_EXPORT CTVerifier { // TLS extension was negotiated, |sct_list_from_tls_extension| should be an // empty string. |output_scts| will be cleared and filled with the SCTs // present, if any, along with their verification results. - virtual void Verify(X509Certificate* cert, + // The |hostname| (or IP address literal) of the server that presented |cert| + // must be provided so that inclusion checks for |cert| are able to avoid + // leaking information about which servers have been visited. + virtual void Verify(base::StringPiece hostname, + X509Certificate* cert, base::StringPiece stapled_ocsp_response, base::StringPiece sct_list_from_tls_extension, SignedCertificateTimestampAndStatusList* output_scts, @@ -56,6 +62,10 @@ class NET_EXPORT CTVerifier { // URLRequests which have to be cancelled before this object is destroyed. // Setting |observer| to nullptr has the effect of stopping all notifications. virtual void SetObserver(Observer* observer) = 0; + + // Gets the Observer, if any, that is currently receiving notifications of + // validated SCTs. + virtual Observer* GetObserver() const = 0; }; } // namespace net diff --git a/chromium/net/cert/do_nothing_ct_verifier.cc b/chromium/net/cert/do_nothing_ct_verifier.cc index 0429d86e765..63b9c0ae306 100644 --- a/chromium/net/cert/do_nothing_ct_verifier.cc +++ b/chromium/net/cert/do_nothing_ct_verifier.cc @@ -12,6 +12,7 @@ DoNothingCTVerifier::DoNothingCTVerifier() = default; DoNothingCTVerifier::~DoNothingCTVerifier() = default; void DoNothingCTVerifier::Verify( + base::StringPiece hostname, X509Certificate* cert, base::StringPiece stapled_ocsp_response, base::StringPiece sct_list_from_tls_extension, @@ -22,4 +23,8 @@ void DoNothingCTVerifier::Verify( void DoNothingCTVerifier::SetObserver(Observer* observer) {} +CTVerifier::Observer* DoNothingCTVerifier::GetObserver() const { + return nullptr; +} + } // namespace net diff --git a/chromium/net/cert/do_nothing_ct_verifier.h b/chromium/net/cert/do_nothing_ct_verifier.h index 025ffd11be8..1aad260088a 100644 --- a/chromium/net/cert/do_nothing_ct_verifier.h +++ b/chromium/net/cert/do_nothing_ct_verifier.h @@ -50,13 +50,15 @@ class NET_EXPORT DoNothingCTVerifier : public CTVerifier { DoNothingCTVerifier(); ~DoNothingCTVerifier() override; - void Verify(X509Certificate* cert, + void Verify(base::StringPiece hostname, + X509Certificate* cert, base::StringPiece stapled_ocsp_response, base::StringPiece sct_list_from_tls_extension, SignedCertificateTimestampAndStatusList* output_scts, const NetLogWithSource& net_log) override; void SetObserver(Observer* observer) override; + Observer* GetObserver() const override; private: DISALLOW_COPY_AND_ASSIGN(DoNothingCTVerifier); diff --git a/chromium/net/cert/ev_root_ca_metadata.cc b/chromium/net/cert/ev_root_ca_metadata.cc index 85c84e1a52d..8880c1c3ea5 100644 --- a/chromium/net/cert/ev_root_ca_metadata.cc +++ b/chromium/net/cert/ev_root_ca_metadata.cc @@ -18,9 +18,9 @@ #include "net/der/input.h" #if defined(USE_NSS_CERTS) #include "crypto/nss_util.h" -#elif defined(PLATFORM_USES_CHROMIUM_EV_METADATA) -#include "third_party/boringssl/src/include/openssl/asn1.h" -#include "third_party/boringssl/src/include/openssl/obj.h" +#elif defined(PLATFORM_USES_CHROMIUM_EV_METADATA) || defined(OS_WIN) +#include "third_party/boringssl/src/include/openssl/bytestring.h" +#include "third_party/boringssl/src/include/openssl/mem.h" #endif namespace net { @@ -836,20 +836,13 @@ namespace { bool ConvertBytesToDottedString(const der::Input& policy_oid, std::string* dotted) { - ASN1_OBJECT obj; - memset(&obj, 0, sizeof(obj)); - obj.data = policy_oid.UnsafeData(); - obj.length = policy_oid.Length(); - - // Determine the length of the dotted string. - int len = OBJ_obj2txt(nullptr, 0, &obj, 1 /* dont_search_names */); - if (len == -1) + CBS cbs; + CBS_init(&cbs, policy_oid.UnsafeData(), policy_oid.Length()); + bssl::UniquePtr<char> text(CBS_asn1_oid_to_text(&cbs)); + if (!text) return false; - - // Write the dotted string into |*dotted|. - dotted->resize(len + 1); - return len == OBJ_obj2txt(&(*dotted)[0], static_cast<int>(dotted->size()), - &obj, 1 /* dont_search_names */); + dotted->assign(text.get()); + return true; } } // namespace @@ -938,12 +931,16 @@ bool EVRootCAMetadata::RemoveEVCA(const SHA256HashValue& fingerprint) { namespace { std::string OIDStringToDER(const char* policy) { - bssl::UniquePtr<ASN1_OBJECT> obj( - OBJ_txt2obj(policy, 1 /* dont_search_names */)); - if (!obj) + uint8_t* der; + size_t len; + bssl::ScopedCBB cbb; + if (!CBB_init(cbb.get(), 32) || + !CBB_add_asn1_oid_from_text(cbb.get(), policy, strlen(policy)) || + !CBB_finish(cbb.get(), &der, &len)) { return std::string(); - - return std::string(reinterpret_cast<const char*>(obj->data), obj->length); + } + bssl::UniquePtr<uint8_t> delete_der(der); + return std::string(reinterpret_cast<const char*>(der), len); } } // namespace diff --git a/chromium/net/cert/ev_root_ca_metadata.h b/chromium/net/cert/ev_root_ca_metadata.h index e69dbd7979d..42daddbd8bd 100644 --- a/chromium/net/cert/ev_root_ca_metadata.h +++ b/chromium/net/cert/ev_root_ca_metadata.h @@ -91,8 +91,7 @@ class NET_EXPORT_PRIVATE EVRootCAMetadata { ~EVRootCAMetadata(); #if defined(USE_NSS_CERTS) - using PolicyOIDMap = std:: - map<SHA256HashValue, std::vector<PolicyOID>, SHA256HashValueLessThan>; + 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. @@ -101,14 +100,12 @@ class NET_EXPORT_PRIVATE EVRootCAMetadata { PolicyOIDMap ev_policy_; std::set<PolicyOID> policy_oids_; #elif defined(OS_WIN) - using ExtraEVCAMap = - std::map<SHA256HashValue, std::string, SHA256HashValueLessThan>; + using ExtraEVCAMap = std::map<SHA256HashValue, std::string>; // extra_cas_ contains any EV CA metadata that was added at runtime. ExtraEVCAMap extra_cas_; #elif defined(PLATFORM_USES_CHROMIUM_EV_METADATA) - using PolicyOIDMap = std:: - map<SHA256HashValue, std::vector<std::string>, SHA256HashValueLessThan>; + using PolicyOIDMap = std::map<SHA256HashValue, std::vector<std::string>>; PolicyOIDMap ev_policy_; std::set<std::string> policy_oids_; diff --git a/chromium/net/cert/internal/revocation_checker.cc b/chromium/net/cert/internal/revocation_checker.cc index a8333e24781..e33f8e9fd9a 100644 --- a/chromium/net/cert/internal/revocation_checker.cc +++ b/chromium/net/cert/internal/revocation_checker.cc @@ -242,6 +242,12 @@ CRLSet::Result CheckChainRevocationUsingCRLSet( crypto::SHA256HashString(cert->tbs().spki_tlv.AsStringPiece()); CRLSet::Result result = crl_set->CheckSPKI(spki_hash); + // Check for revocation using the certificate's Subject. + if (result != CRLSet::REVOKED) { + result = crl_set->CheckSubject(cert->tbs().subject_tlv.AsStringPiece(), + spki_hash); + } + // Check for revocation using the certificate's serial number and issuer's // SPKI. if (result != CRLSet::REVOKED && !is_root) { diff --git a/chromium/net/cert/internal/system_trust_store.cc b/chromium/net/cert/internal/system_trust_store.cc index 5f0c724f7a0..f5c2b5fae3a 100644 --- a/chromium/net/cert/internal/system_trust_store.cc +++ b/chromium/net/cert/internal/system_trust_store.cc @@ -175,8 +175,7 @@ class FuchsiaSystemCerts { for (const auto& cert : certs) { CertErrors errors; auto parsed = ParsedCertificate::Create( - bssl::UniquePtr<CRYPTO_BUFFER>( - X509Certificate::DupOSCertHandle(cert->os_cert_handle())), + x509_util::DupCryptoBuffer(cert->cert_buffer()), x509_util::DefaultParseCertificateOptions(), &errors); CHECK(parsed) << errors.ToDebugString(); system_trust_store_.AddTrustAnchor(parsed); diff --git a/chromium/net/cert/internal/trust_store_mac.cc b/chromium/net/cert/internal/trust_store_mac.cc index 0d78dd0b7ad..01b505d259d 100644 --- a/chromium/net/cert/internal/trust_store_mac.cc +++ b/chromium/net/cert/internal/trust_store_mac.cc @@ -347,7 +347,7 @@ base::ScopedCFTypeRef<CFDataRef> TrustStoreMac::GetMacNormalizedIssuer( x509_util::CreateSecCertificateFromBytes(cert->der_cert().UnsafeData(), cert->der_cert().Length())); if (!cert_handle) { - LOG(ERROR) << "CreateOSCertHandleFromBytes"; + LOG(ERROR) << "CreateCertBufferFromBytes"; return name_data; } { diff --git a/chromium/net/cert/internal/trust_store_mac_unittest.cc b/chromium/net/cert/internal/trust_store_mac_unittest.cc index 70a3775ae66..04b3fbbc960 100644 --- a/chromium/net/cert/internal/trust_store_mac_unittest.cc +++ b/chromium/net/cert/internal/trust_store_mac_unittest.cc @@ -273,7 +273,7 @@ TEST(TrustStoreMacTest, SystemCerts) { x509_util::CreateSecCertificateFromBytes(cert->der_cert().UnsafeData(), cert->der_cert().Length())); if (!cert_handle) { - ADD_FAILURE() << "CreateOSCertHandleFromBytes " << hash_text; + ADD_FAILURE() << "CreateCertBufferFromBytes " << hash_text; continue; } base::ScopedCFTypeRef<SecTrustRef> trust; diff --git a/chromium/net/cert/internal/verify_name_match_unittest.cc b/chromium/net/cert/internal/verify_name_match_unittest.cc index 25bdd1ab7b8..e706d9c488c 100644 --- a/chromium/net/cert/internal/verify_name_match_unittest.cc +++ b/chromium/net/cert/internal/verify_name_match_unittest.cc @@ -597,4 +597,16 @@ TEST(NameNormalizationTest, TestEverything) { EXPECT_EQ(normalized_der, renormalized_der); } +// Unknown AttributeValue types normalize as-is, even non-primitive tags. +TEST(NameNormalizationTest, NormalizeCustom) { + std::string raw_der; + ASSERT_TRUE(LoadTestData("custom", "custom", "normalized", &raw_der)); + + std::string normalized_der; + CertErrors errors; + ASSERT_TRUE(NormalizeName(SequenceValueFromString(&raw_der), &normalized_der, + &errors)); + EXPECT_EQ(SequenceValueFromString(&raw_der), der::Input(&normalized_der)); +} + } // namespace net diff --git a/chromium/net/cert/known_roots.cc b/chromium/net/cert/known_roots.cc index 191923c8929..1a59ec5dde5 100644 --- a/chromium/net/cert/known_roots.cc +++ b/chromium/net/cert/known_roots.cc @@ -19,12 +19,12 @@ namespace { // RootCertData to a HashValue struct HashValueToRootCertDataComp { bool operator()(const HashValue& hash, const RootCertData& root_cert) { - DCHECK_EQ(HASH_VALUE_SHA256, hash.tag); + DCHECK_EQ(HASH_VALUE_SHA256, hash.tag()); return memcmp(hash.data(), root_cert.sha256_spki_hash, 32) < 0; } bool operator()(const RootCertData& root_cert, const HashValue& hash) { - DCHECK_EQ(HASH_VALUE_SHA256, hash.tag); + DCHECK_EQ(HASH_VALUE_SHA256, hash.tag()); return memcmp(root_cert.sha256_spki_hash, hash.data(), 32) < 0; } }; @@ -32,7 +32,7 @@ struct HashValueToRootCertDataComp { } // namespace int32_t GetNetTrustAnchorHistogramIdForSPKI(const HashValue& spki_hash) { - if (spki_hash.tag != HASH_VALUE_SHA256) + if (spki_hash.tag() != HASH_VALUE_SHA256) return 0; auto* it = std::lower_bound(std::begin(kRootCerts), std::end(kRootCerts), diff --git a/chromium/net/cert/known_roots_mac.cc b/chromium/net/cert/known_roots_mac.cc index 475dda6e9cf..c4c7c64575f 100644 --- a/chromium/net/cert/known_roots_mac.cc +++ b/chromium/net/cert/known_roots_mac.cc @@ -60,7 +60,7 @@ class OSXKnownRootHelper { ~OSXKnownRootHelper() {} - std::set<SHA256HashValue, SHA256HashValueLessThan> known_roots_; + std::set<SHA256HashValue> known_roots_; }; base::LazyInstance<OSXKnownRootHelper>::Leaky g_known_roots = diff --git a/chromium/net/cert/known_roots_nss.cc b/chromium/net/cert/known_roots_nss.cc index 34f3896d183..1e4b45ae1e7 100644 --- a/chromium/net/cert/known_roots_nss.cc +++ b/chromium/net/cert/known_roots_nss.cc @@ -5,18 +5,87 @@ #include "net/cert/known_roots_nss.h" #include <cert.h> +#include <dlfcn.h> #include <pk11pub.h> +#include <secmod.h> #include <memory> +#include "base/memory/protected_memory.h" +#include "base/memory/protected_memory_cfi.h" +#include "crypto/nss_util_internal.h" +#include "net/base/hash_value.h" +#include "net/cert/x509_util_nss.h" + namespace net { +namespace { + +// This can be removed once the minimum NSS version to build is >= 3.30. +#if !defined(CKA_NSS_MOZILLA_CA_POLICY) +#define CKA_NSS_MOZILLA_CA_POLICY (CKA_NSS + 34) +#endif + +using PK11HasAttributeSetFunction = CK_BBOOL (*)(PK11SlotInfo* slot, + CK_OBJECT_HANDLE id, + CK_ATTRIBUTE_TYPE type, + PRBool haslock); +static PROTECTED_MEMORY_SECTION + base::ProtectedMemory<PK11HasAttributeSetFunction> + g_pk11_has_attribute_set; + +// The function pointer for PK11_HasAttributeSet is saved to read-only memory +// after being dynamically resolved as a security mitigation to prevent the +// pointer from being tampered with. See https://crbug.com/771365 for details. +const base::ProtectedMemory<PK11HasAttributeSetFunction>& +ResolvePK11HasAttributeSet() { + static base::ProtectedMemory<PK11HasAttributeSetFunction>::Initializer init( + &g_pk11_has_attribute_set, + reinterpret_cast<PK11HasAttributeSetFunction>( + dlsym(RTLD_DEFAULT, "PK11_HasAttributeSet"))); + return g_pk11_has_attribute_set; +} + +} // namespace + // IsKnownRoot returns true if the given certificate is one that we believe // is a standard (as opposed to user-installed) root. bool IsKnownRoot(CERTCertificate* root) { if (!root || !root->slot) return false; + if (*ResolvePK11HasAttributeSet() != nullptr) { + // Historically, the set of root certs was determined based on whether or + // not it was part of nssckbi.[so,dll], the read-only PKCS#11 module that + // exported the certs with trust settings. However, some distributions, + // notably those in the Red Hat family, replace nssckbi with a redirect to + // their own store, such as from p11-kit, which can support more robust + // trust settings, like per-system trust, admin-defined, and user-defined + // trust. + // + // As a given certificate may exist in multiple modules and slots, scan + // through all of the available modules, all of the (connected) slots on + // those modules, and check to see if it has the CKA_NSS_MOZILLA_CA_POLICY + // attribute set. This attribute indicates it's from the upstream Mozilla + // trust store, and these distributions preserve the attribute as a flag. + crypto::AutoSECMODListReadLock lock_id; + for (const SECMODModuleList* item = SECMOD_GetDefaultModuleList(); + item != nullptr; item = item->next) { + for (int i = 0; i < item->module->slotCount; ++i) { + PK11SlotInfo* slot = item->module->slots[i]; + if (PK11_IsPresent(slot) && PK11_HasRootCerts(slot)) { + CK_OBJECT_HANDLE handle = PK11_FindCertInSlot(slot, root, nullptr); + if (handle != CK_INVALID_HANDLE && + UnsanitizedCfiCall(ResolvePK11HasAttributeSet())( + root->slot, handle, CKA_NSS_MOZILLA_CA_POLICY, PR_FALSE) == + CK_TRUE) { + return true; + } + } + } + } + } + // This magic name is taken from // http://bonsai.mozilla.org/cvsblame.cgi?file=mozilla/security/nss/lib/ckfw/builtins/constants.c&rev=1.13&mark=86,89#79 return 0 == strcmp(PK11_GetSlotName(root->slot), "NSS Builtin Objects"); diff --git a/chromium/net/cert/merkle_tree_leaf.cc b/chromium/net/cert/merkle_tree_leaf.cc index 07cd4692da4..1030213ac25 100644 --- a/chromium/net/cert/merkle_tree_leaf.cc +++ b/chromium/net/cert/merkle_tree_leaf.cc @@ -35,14 +35,14 @@ bool GetMerkleTreeLeaf(const X509Certificate* cert, const SignedCertificateTimestamp* sct, MerkleTreeLeaf* merkle_tree_leaf) { if (sct->origin == SignedCertificateTimestamp::SCT_EMBEDDED) { - if (cert->GetIntermediateCertificates().empty() || - !GetPrecertSignedEntry(cert->os_cert_handle(), - cert->GetIntermediateCertificates().front(), + if (cert->intermediate_buffers().empty() || + !GetPrecertSignedEntry(cert->cert_buffer(), + cert->intermediate_buffers().front().get(), &merkle_tree_leaf->signed_entry)) { return false; } } else { - if (!GetX509SignedEntry(cert->os_cert_handle(), + if (!GetX509SignedEntry(cert->cert_buffer(), &merkle_tree_leaf->signed_entry)) { return false; } diff --git a/chromium/net/cert/merkle_tree_leaf_unittest.cc b/chromium/net/cert/merkle_tree_leaf_unittest.cc index 59ac7dceb6e..691c1102e5e 100644 --- a/chromium/net/cert/merkle_tree_leaf_unittest.cc +++ b/chromium/net/cert/merkle_tree_leaf_unittest.cc @@ -59,7 +59,7 @@ class MerkleTreeLeafTest : public ::testing::Test { GetTestCertsDirectory(), "ct-test-embedded-cert.pem", X509Certificate::FORMAT_AUTO); ASSERT_TRUE(test_precert_); - ASSERT_EQ(1u, test_precert_->GetIntermediateCertificates().size()); + ASSERT_EQ(1u, test_precert_->intermediate_buffers().size()); GetPrecertSCT(&precert_sct_); precert_sct_->origin = SignedCertificateTimestamp::SCT_EMBEDDED; } diff --git a/chromium/net/cert/multi_log_ct_verifier.cc b/chromium/net/cert/multi_log_ct_verifier.cc index 784924a55d2..791ddca2102 100644 --- a/chromium/net/cert/multi_log_ct_verifier.cc +++ b/chromium/net/cert/multi_log_ct_verifier.cc @@ -81,7 +81,12 @@ void MultiLogCTVerifier::SetObserver(Observer* observer) { observer_ = observer; } +CTVerifier::Observer* MultiLogCTVerifier::GetObserver() const { + return observer_; +} + void MultiLogCTVerifier::Verify( + base::StringPiece hostname, X509Certificate* cert, base::StringPiece stapled_ocsp_response, base::StringPiece sct_list_from_tls_extension, @@ -93,26 +98,23 @@ void MultiLogCTVerifier::Verify( output_scts->clear(); std::string embedded_scts; - if (!cert->GetIntermediateCertificates().empty() && - ct::ExtractEmbeddedSCTList( - cert->os_cert_handle(), - &embedded_scts)) { + if (!cert->intermediate_buffers().empty() && + ct::ExtractEmbeddedSCTList(cert->cert_buffer(), &embedded_scts)) { ct::SignedEntryData precert_entry; - if (ct::GetPrecertSignedEntry(cert->os_cert_handle(), - cert->GetIntermediateCertificates().front(), + if (ct::GetPrecertSignedEntry(cert->cert_buffer(), + cert->intermediate_buffers().front().get(), &precert_entry)) { - VerifySCTs(embedded_scts, precert_entry, + VerifySCTs(hostname, embedded_scts, precert_entry, ct::SignedCertificateTimestamp::SCT_EMBEDDED, cert, output_scts); } } std::string sct_list_from_ocsp; - if (!stapled_ocsp_response.empty() && - !cert->GetIntermediateCertificates().empty()) { + if (!stapled_ocsp_response.empty() && !cert->intermediate_buffers().empty()) { ct::ExtractSCTListFromOCSPResponse( - cert->GetIntermediateCertificates().front(), cert->serial_number(), + cert->intermediate_buffers().front().get(), cert->serial_number(), stapled_ocsp_response, &sct_list_from_ocsp); } @@ -126,12 +128,12 @@ void MultiLogCTVerifier::Verify( net_log_callback); ct::SignedEntryData x509_entry; - if (ct::GetX509SignedEntry(cert->os_cert_handle(), &x509_entry)) { - VerifySCTs(sct_list_from_ocsp, x509_entry, + if (ct::GetX509SignedEntry(cert->cert_buffer(), &x509_entry)) { + VerifySCTs(hostname, sct_list_from_ocsp, x509_entry, ct::SignedCertificateTimestamp::SCT_FROM_OCSP_RESPONSE, cert, output_scts); - VerifySCTs(sct_list_from_tls_extension, x509_entry, + VerifySCTs(hostname, sct_list_from_tls_extension, x509_entry, ct::SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION, cert, output_scts); } @@ -146,6 +148,7 @@ void MultiLogCTVerifier::Verify( } void MultiLogCTVerifier::VerifySCTs( + base::StringPiece hostname, base::StringPiece encoded_sct_list, const ct::SignedEntryData& expected_entry, ct::SignedCertificateTimestamp::Origin origin, @@ -171,11 +174,12 @@ void MultiLogCTVerifier::VerifySCTs( } decoded_sct->origin = origin; - VerifySingleSCT(decoded_sct, expected_entry, cert, output_scts); + VerifySingleSCT(hostname, decoded_sct, expected_entry, cert, output_scts); } } bool MultiLogCTVerifier::VerifySingleSCT( + base::StringPiece hostname, scoped_refptr<ct::SignedCertificateTimestamp> sct, const ct::SignedEntryData& expected_entry, X509Certificate* cert, @@ -205,7 +209,7 @@ bool MultiLogCTVerifier::VerifySingleSCT( AddSCTAndLogStatus(sct, ct::SCT_STATUS_OK, output_scts); if (observer_) - observer_->OnSCTVerified(cert, sct.get()); + observer_->OnSCTVerified(hostname, cert, sct.get()); return true; } diff --git a/chromium/net/cert/multi_log_ct_verifier.h b/chromium/net/cert/multi_log_ct_verifier.h index 3a69b5e22a3..af389d6f4cc 100644 --- a/chromium/net/cert/multi_log_ct_verifier.h +++ b/chromium/net/cert/multi_log_ct_verifier.h @@ -35,26 +35,30 @@ class NET_EXPORT MultiLogCTVerifier : public CTVerifier { const std::vector<scoped_refptr<const CTLogVerifier>>& log_verifiers); // CTVerifier implementation: - void Verify(X509Certificate* cert, + void Verify(base::StringPiece hostname, + X509Certificate* cert, base::StringPiece stapled_ocsp_response, base::StringPiece sct_list_from_tls_extension, SignedCertificateTimestampAndStatusList* output_scts, const NetLogWithSource& net_log) override; void SetObserver(Observer* observer) override; + Observer* GetObserver() const override; private: // Verify a list of SCTs from |encoded_sct_list| over |expected_entry|, // placing the verification results in |output_scts|. The SCTs in the list // come from |origin| (as will be indicated in the origin field of each SCT). - void VerifySCTs(base::StringPiece encoded_sct_list, + void VerifySCTs(base::StringPiece hostname, + base::StringPiece encoded_sct_list, const ct::SignedEntryData& expected_entry, ct::SignedCertificateTimestamp::Origin origin, X509Certificate* cert, SignedCertificateTimestampAndStatusList* output_scts); // Verifies a single, parsed SCT against all logs. - bool VerifySingleSCT(scoped_refptr<ct::SignedCertificateTimestamp> sct, + bool VerifySingleSCT(base::StringPiece hostname, + scoped_refptr<ct::SignedCertificateTimestamp> sct, const ct::SignedEntryData& expected_entry, X509Certificate* cert, SignedCertificateTimestampAndStatusList* output_scts); diff --git a/chromium/net/cert/multi_log_ct_verifier_unittest.cc b/chromium/net/cert/multi_log_ct_verifier_unittest.cc index fa4a894e653..e12a567d314 100644 --- a/chromium/net/cert/multi_log_ct_verifier_unittest.cc +++ b/chromium/net/cert/multi_log_ct_verifier_unittest.cc @@ -38,14 +38,16 @@ namespace net { namespace { +const char kHostname[] = "example.com"; const char kLogDescription[] = "somelog"; const char kSCTCountHistogram[] = "Net.CertificateTransparency.SCTsPerConnection"; class MockSCTObserver : public CTVerifier::Observer { public: - MOCK_METHOD2(OnSCTVerified, - void(X509Certificate* cert, + MOCK_METHOD3(OnSCTVerified, + void(base::StringPiece hostname, + X509Certificate* cert, const ct::SignedCertificateTimestamp* sct)); }; @@ -111,12 +113,12 @@ class MultiLogCTVerifierTest : public ::testing::Test { return true; } - // Returns true is |chain| is a certificate with embedded SCTs that can be + // Returns true if |chain| is a certificate with embedded SCTs that can be // successfully extracted. bool VerifySinglePrecertificateChain(scoped_refptr<X509Certificate> chain) { SignedCertificateTimestampAndStatusList scts; - verifier_->Verify(chain.get(), base::StringPiece(), base::StringPiece(), - &scts, NetLogWithSource()); + verifier_->Verify(kHostname, chain.get(), base::StringPiece(), + base::StringPiece(), &scts, NetLogWithSource()); return !scts.empty(); } @@ -128,8 +130,8 @@ class MultiLogCTVerifierTest : public ::testing::Test { TestNetLog test_net_log; NetLogWithSource net_log = NetLogWithSource::Make( &test_net_log, NetLogSourceType::SSL_CONNECT_JOB); - verifier_->Verify(chain.get(), base::StringPiece(), base::StringPiece(), - &scts, net_log); + verifier_->Verify(kHostname, chain.get(), base::StringPiece(), + base::StringPiece(), &scts, net_log); return ct::CheckForSingleVerifiedSCTInResult(scts, kLogDescription) && ct::CheckForSCTOrigin( scts, ct::SignedCertificateTimestamp::SCT_EMBEDDED) && @@ -207,8 +209,8 @@ TEST_F(MultiLogCTVerifierTest, VerifiesSCTOverX509Cert) { std::string sct_list = ct::GetSCTListForTesting(); SignedCertificateTimestampAndStatusList scts; - verifier_->Verify(chain_.get(), base::StringPiece(), sct_list, &scts, - NetLogWithSource()); + verifier_->Verify(kHostname, chain_.get(), base::StringPiece(), sct_list, + &scts, NetLogWithSource()); ASSERT_TRUE(ct::CheckForSingleVerifiedSCTInResult(scts, kLogDescription)); ASSERT_TRUE(ct::CheckForSCTOrigin( scts, ct::SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION)); @@ -218,8 +220,8 @@ TEST_F(MultiLogCTVerifierTest, IdentifiesSCTFromUnknownLog) { std::string sct_list = ct::GetSCTListWithInvalidSCT(); SignedCertificateTimestampAndStatusList scts; - verifier_->Verify(chain_.get(), base::StringPiece(), sct_list, &scts, - NetLogWithSource()); + verifier_->Verify(kHostname, chain_.get(), base::StringPiece(), sct_list, + &scts, NetLogWithSource()); EXPECT_EQ(1U, scts.size()); EXPECT_EQ("", scts[0].sct->log_description); EXPECT_EQ(ct::SCT_STATUS_LOG_UNKNOWN, scts[0].status); @@ -241,8 +243,8 @@ TEST_F(MultiLogCTVerifierTest, CountsInvalidSCTsInStatusHistogram) { int num_invalid_scts = GetValueFromHistogram( "Net.CertificateTransparency.SCTStatus", ct::SCT_STATUS_LOG_UNKNOWN); - verifier_->Verify(chain_.get(), base::StringPiece(), sct_list, &scts, - NetLogWithSource()); + verifier_->Verify(kHostname, chain_.get(), base::StringPiece(), sct_list, + &scts, NetLogWithSource()); ASSERT_EQ(num_valid_scts, NumValidSCTsInStatusHistogram()); ASSERT_EQ(num_invalid_scts + 1, @@ -273,7 +275,8 @@ TEST_F(MultiLogCTVerifierTest, NotifiesOfValidSCT) { MockSCTObserver observer; verifier_->SetObserver(&observer); - EXPECT_CALL(observer, OnSCTVerified(embedded_sct_chain_.get(), _)); + EXPECT_CALL(observer, OnSCTVerified(base::StringPiece(kHostname), + embedded_sct_chain_.get(), _)); ASSERT_TRUE(VerifySinglePrecertificateChain(embedded_sct_chain_)); } @@ -281,11 +284,15 @@ TEST_F(MultiLogCTVerifierTest, StopsNotifyingCorrectly) { MockSCTObserver observer; verifier_->SetObserver(&observer); - EXPECT_CALL(observer, OnSCTVerified(embedded_sct_chain_.get(), _)).Times(1); + EXPECT_CALL(observer, OnSCTVerified(base::StringPiece(kHostname), + embedded_sct_chain_.get(), _)) + .Times(1); ASSERT_TRUE(VerifySinglePrecertificateChain(embedded_sct_chain_)); Mock::VerifyAndClearExpectations(&observer); - EXPECT_CALL(observer, OnSCTVerified(embedded_sct_chain_.get(), _)).Times(0); + EXPECT_CALL(observer, OnSCTVerified(base::StringPiece(kHostname), + embedded_sct_chain_.get(), _)) + .Times(0); verifier_->SetObserver(nullptr); ASSERT_TRUE(VerifySinglePrecertificateChain(embedded_sct_chain_)); } diff --git a/chromium/net/cert/nss_cert_database_unittest.cc b/chromium/net/cert/nss_cert_database_unittest.cc index d1753aefb3b..7781ea4fd5f 100644 --- a/chromium/net/cert/nss_cert_database_unittest.cc +++ b/chromium/net/cert/nss_cert_database_unittest.cc @@ -117,9 +117,8 @@ class CertDatabaseNSSTest : public testing::Test { std::sort( result.begin(), result.end(), [](const ScopedCERTCertificate& lhs, const ScopedCERTCertificate& rhs) { - return SHA256HashValueLessThan()( - x509_util::CalculateFingerprint256(lhs.get()), - x509_util::CalculateFingerprint256(rhs.get())); + return x509_util::CalculateFingerprint256(lhs.get()) < + x509_util::CalculateFingerprint256(rhs.get()); }); return result; } @@ -383,7 +382,7 @@ TEST_F(CertDatabaseNSSTest, ImportCA_NotCACert) { ASSERT_EQ(1U, failed.size()); // Note: this compares pointers directly. It's okay in this case because // ImportCACerts returns the same pointers that were passed in. In the - // general case IsSameOSCert should be used. + // general case x509_util::CryptoBufferEqual should be used. EXPECT_EQ(certs[0], failed[0].certificate); EXPECT_THAT(failed[0].net_error, IsError(ERR_IMPORT_CA_CERT_NOT_CA)); diff --git a/chromium/net/cert/nss_profile_filter_chromeos_unittest.cc b/chromium/net/cert/nss_profile_filter_chromeos_unittest.cc index 33019166744..4c2cdef83d6 100644 --- a/chromium/net/cert/nss_profile_filter_chromeos_unittest.cc +++ b/chromium/net/cert/nss_profile_filter_chromeos_unittest.cc @@ -55,9 +55,8 @@ ScopedCERTCertificateList ListCertsInSlot(PK11SlotInfo* slot) { std::sort( result.begin(), result.end(), [](const ScopedCERTCertificate& lhs, const ScopedCERTCertificate& rhs) { - return SHA256HashValueLessThan()( - x509_util::CalculateFingerprint256(lhs.get()), - x509_util::CalculateFingerprint256(rhs.get())); + return x509_util::CalculateFingerprint256(lhs.get()) < + x509_util::CalculateFingerprint256(rhs.get()); }); return result; } diff --git a/chromium/net/cert/symantec_certs.cc b/chromium/net/cert/symantec_certs.cc index 3a1d3886a84..fdaafdf338b 100644 --- a/chromium/net/cert/symantec_certs.cc +++ b/chromium/net/cert/symantec_certs.cc @@ -193,9 +193,15 @@ const SHA256HashValue kSymantecExceptions[] = { {{0x72, 0x89, 0xc0, 0x6d, 0xed, 0xd1, 0x6b, 0x71, 0xa7, 0xdc, 0xca, 0x66, 0x57, 0x85, 0x72, 0xe2, 0xe1, 0x09, 0xb1, 0x1d, 0x70, 0xad, 0x04, 0xc2, 0x60, 0x1b, 0x67, 0x43, 0xbc, 0x66, 0xd0, 0x7b}}, + {{0x8b, 0xb5, 0x93, 0xa9, 0x3b, 0xe1, 0xd0, 0xe8, 0xa8, 0x22, 0xbb, + 0x88, 0x7c, 0x54, 0x78, 0x90, 0xc3, 0xe7, 0x06, 0xaa, 0xd2, 0xda, + 0xb7, 0x62, 0x54, 0xf9, 0x7f, 0xb3, 0x6b, 0x82, 0xfc, 0x26}}, {{0xb5, 0xcf, 0x82, 0xd4, 0x7e, 0xf9, 0x82, 0x3f, 0x9a, 0xa7, 0x8f, 0x12, 0x31, 0x86, 0xc5, 0x2e, 0x88, 0x79, 0xea, 0x84, 0xb0, 0xf8, 0x22, 0xc9, 0x1d, 0x83, 0xe0, 0x42, 0x79, 0xb7, 0x8f, 0xd5}}, + {{0xb9, 0x4c, 0x19, 0x83, 0x00, 0xce, 0xc5, 0xc0, 0x57, 0xad, 0x07, + 0x27, 0xb7, 0x0b, 0xbe, 0x91, 0x81, 0x69, 0x92, 0x25, 0x64, 0x39, + 0xa7, 0xb3, 0x2f, 0x45, 0x98, 0x11, 0x9d, 0xda, 0x9c, 0x97}}, {{0xc0, 0x55, 0x4b, 0xde, 0x87, 0xa0, 0x75, 0xec, 0x13, 0xa6, 0x1f, 0x27, 0x59, 0x83, 0xae, 0x02, 0x39, 0x57, 0x29, 0x4b, 0x45, 0x4c, 0xaf, 0x0a, 0x97, 0x24, 0xe3, 0xb2, 0x1b, 0x79, 0x35, 0xbc}}, @@ -212,11 +218,24 @@ const SHA256HashValue kSymantecExceptions[] = { const size_t kSymantecExceptionsLength = arraysize(kSymantecExceptions); +const SHA256HashValue kSymantecManagedCAs[] = { + {{0x7c, 0xac, 0x9a, 0x0f, 0xf3, 0x15, 0x38, 0x77, 0x50, 0xba, 0x8b, + 0xaf, 0xdb, 0x1c, 0x2b, 0xc2, 0x9b, 0x3f, 0x0b, 0xba, 0x16, 0x36, + 0x2c, 0xa9, 0x3a, 0x90, 0xf8, 0x4d, 0xa2, 0xdf, 0x5f, 0x3e}}, + {{0xac, 0x50, 0xb5, 0xfb, 0x73, 0x8a, 0xed, 0x6c, 0xb7, 0x81, 0xcc, + 0x35, 0xfb, 0xff, 0xf7, 0x78, 0x6f, 0x77, 0x10, 0x9a, 0xda, 0x7c, + 0x08, 0x86, 0x7c, 0x04, 0xa5, 0x73, 0xfd, 0x5c, 0xf9, 0xee}}, +}; + +const size_t kSymantecManagedCAsLength = arraysize(kSymantecManagedCAs); + bool IsLegacySymantecCert(const HashValueVector& public_key_hashes) { return IsAnySHA256HashInSortedArray(public_key_hashes, kSymantecRoots, kSymantecRootsLength) && - !IsAnySHA256HashInSortedArray(public_key_hashes, kSymantecExceptions, - kSymantecExceptionsLength); + !(IsAnySHA256HashInSortedArray(public_key_hashes, kSymantecExceptions, + kSymantecExceptionsLength) || + IsAnySHA256HashInSortedArray(public_key_hashes, kSymantecManagedCAs, + kSymantecManagedCAsLength)); } } // namespace net diff --git a/chromium/net/cert/symantec_certs.h b/chromium/net/cert/symantec_certs.h index 88e4532aeb1..cf4ad4a8555 100644 --- a/chromium/net/cert/symantec_certs.h +++ b/chromium/net/cert/symantec_certs.h @@ -17,12 +17,17 @@ namespace net { // https://security.googleblog.com/2017/09/chromes-plan-to-distrust-symantec.html // for details about why. // -// Independently operated sub-CAs are exempt from these policies, and are -// listed in |kSymantecExceptions|. -extern const SHA256HashValue kSymantecRoots[]; -extern const size_t kSymantecRootsLength; -extern const SHA256HashValue kSymantecExceptions[]; -extern const size_t kSymantecExceptionsLength; +// Pre-existing, independently operated sub-CAs are exempt from these +// policies, and are listed in |kSymantecExceptions|. +// +// The Managed Partner CAs are required to disclose via Certificate +// Transparency, and are listed in |kSymantecManagedCAs|. +NET_EXPORT_PRIVATE extern const SHA256HashValue kSymantecRoots[]; +NET_EXPORT_PRIVATE extern const size_t kSymantecRootsLength; +NET_EXPORT_PRIVATE extern const SHA256HashValue kSymantecExceptions[]; +NET_EXPORT_PRIVATE extern const size_t kSymantecExceptionsLength; +NET_EXPORT_PRIVATE extern const SHA256HashValue kSymantecManagedCAs[]; +NET_EXPORT_PRIVATE extern const size_t kSymantecManagedCAsLength; // Returns true if |public_key_hashes| contains a certificate issued from // Symantec's "legacy" PKI. This constraint excludes certificates that were diff --git a/chromium/net/cert/symantec_certs_unittest.cc b/chromium/net/cert/symantec_certs_unittest.cc index dcb94ab4037..6a1fff6cb31 100644 --- a/chromium/net/cert/symantec_certs_unittest.cc +++ b/chromium/net/cert/symantec_certs_unittest.cc @@ -4,6 +4,9 @@ #include "net/cert/symantec_certs.h" +#include <algorithm> + +#include "net/base/hash_value.h" #include "testing/gtest/include/gtest/gtest.h" namespace net { @@ -38,4 +41,13 @@ TEST(SymantecCertsTest, IsLegacySymantecCert) { EXPECT_FALSE(IsLegacySymantecCert(hashes)); } +TEST(SymantecCertsTest, AreSortedArrays) { + ASSERT_TRUE( + std::is_sorted(kSymantecRoots, kSymantecRoots + kSymantecRootsLength)); + ASSERT_TRUE(std::is_sorted(kSymantecExceptions, + kSymantecExceptions + kSymantecExceptionsLength)); + ASSERT_TRUE(std::is_sorted(kSymantecManagedCAs, + kSymantecManagedCAs + kSymantecManagedCAsLength)); +} + } // namespace net diff --git a/chromium/net/cert/test_root_certs_android.cc b/chromium/net/cert/test_root_certs_android.cc index 44cd1f9d674..6160fa379c6 100644 --- a/chromium/net/cert/test_root_certs_android.cc +++ b/chromium/net/cert/test_root_certs_android.cc @@ -8,16 +8,14 @@ #include "base/logging.h" #include "net/android/network_library.h" #include "net/cert/x509_certificate.h" +#include "third_party/boringssl/src/include/openssl/pool.h" namespace net { bool TestRootCerts::Add(X509Certificate* certificate) { - std::string cert_bytes; - if (!X509Certificate::GetDEREncoded(certificate->os_cert_handle(), - &cert_bytes)) - return false; android::AddTestRootCertificate( - reinterpret_cast<const uint8_t*>(cert_bytes.data()), cert_bytes.size()); + CRYPTO_BUFFER_data(certificate->cert_buffer()), + CRYPTO_BUFFER_len(certificate->cert_buffer())); empty_ = false; return true; } diff --git a/chromium/net/cert/test_root_certs_fuchsia.cc b/chromium/net/cert/test_root_certs_fuchsia.cc index b0bd830f309..cd909be2198 100644 --- a/chromium/net/cert/test_root_certs_fuchsia.cc +++ b/chromium/net/cert/test_root_certs_fuchsia.cc @@ -9,6 +9,7 @@ #include "net/cert/internal/cert_errors.h" #include "net/cert/internal/parsed_certificate.h" #include "net/cert/x509_certificate.h" +#include "net/cert/x509_util.h" #include "third_party/boringssl/src/include/openssl/pool.h" namespace net { @@ -16,8 +17,7 @@ namespace net { bool TestRootCerts::Add(X509Certificate* certificate) { CertErrors errors; auto parsed = ParsedCertificate::Create( - bssl::UniquePtr<CRYPTO_BUFFER>( - X509Certificate::DupOSCertHandle(certificate->os_cert_handle())), + x509_util::DupCryptoBuffer(certificate->cert_buffer()), ParseCertificateOptions(), &errors); if (!parsed) { LOG(ERROR) << "Failed to parse DER certificate: " << errors.ToDebugString(); diff --git a/chromium/net/cert/test_root_certs_mac.cc b/chromium/net/cert/test_root_certs_mac.cc index 876395fc976..9e0206a3c71 100644 --- a/chromium/net/cert/test_root_certs_mac.cc +++ b/chromium/net/cert/test_root_certs_mac.cc @@ -33,12 +33,8 @@ bool TestRootCerts::Add(X509Certificate* certificate) { // Add the certificate to the parallel |test_trust_store_|. CertErrors errors; - std::string cert_bytes; - if (!X509Certificate::GetDEREncoded(certificate->os_cert_handle(), - &cert_bytes)) - return false; scoped_refptr<ParsedCertificate> parsed = ParsedCertificate::Create( - x509_util::CreateCryptoBuffer(cert_bytes), + x509_util::DupCryptoBuffer(certificate->cert_buffer()), x509_util::DefaultParseCertificateOptions(), &errors); if (!parsed) return false; diff --git a/chromium/net/cert/test_root_certs_win.cc b/chromium/net/cert/test_root_certs_win.cc index 3c900ca346d..8bf74cdabd8 100644 --- a/chromium/net/cert/test_root_certs_win.cc +++ b/chromium/net/cert/test_root_certs_win.cc @@ -11,6 +11,7 @@ #include "base/numerics/safe_conversions.h" #include "base/win/win_util.h" #include "net/cert/x509_certificate.h" +#include "third_party/boringssl/src/include/openssl/pool.h" namespace net { @@ -143,12 +144,12 @@ bool TestRootCerts::Add(X509Certificate* certificate) { // happen. g_capi_injector.Get(); - std::string der_cert; - X509Certificate::GetDEREncoded(certificate->os_cert_handle(), &der_cert); BOOL ok = CertAddEncodedCertificateToStore( temporary_roots_, X509_ASN_ENCODING, - reinterpret_cast<const BYTE*>(der_cert.data()), - base::checked_cast<DWORD>(der_cert.size()), CERT_STORE_ADD_NEW, NULL); + reinterpret_cast<const BYTE*>( + CRYPTO_BUFFER_data(certificate->cert_buffer())), + base::checked_cast<DWORD>(CRYPTO_BUFFER_len(certificate->cert_buffer())), + CERT_STORE_ADD_NEW, NULL); if (!ok) { // If the certificate is already added, return successfully. return GetLastError() == static_cast<DWORD>(CRYPT_E_EXISTS); diff --git a/chromium/net/cert/x509_certificate.cc b/chromium/net/cert/x509_certificate.cc index 370d4abbe40..ffc90d02cee 100644 --- a/chromium/net/cert/x509_certificate.cc +++ b/chromium/net/cert/x509_certificate.cc @@ -145,10 +145,10 @@ bool GetNormalizedCertIssuer(CRYPTO_BUFFER* cert, // Parses certificates from a PKCS#7 SignedData structure, appending them to // |handles|. -void CreateOSCertHandlesFromPKCS7Bytes( +void CreateCertBuffersFromPKCS7Bytes( const char* data, size_t length, - X509Certificate::OSCertHandles* handles) { + std::vector<bssl::UniquePtr<CRYPTO_BUFFER>>* handles) { crypto::EnsureOpenSSLInit(); crypto::OpenSSLErrStackTracer err_cleaner(FROM_HERE); @@ -159,7 +159,8 @@ void CreateOSCertHandlesFromPKCS7Bytes( if (PKCS7_get_raw_certificates(certs, &der_data, x509_util::GetBufferPool())) { for (size_t i = 0; i < sk_CRYPTO_BUFFER_num(certs); ++i) { - handles->push_back(sk_CRYPTO_BUFFER_value(certs, i)); + handles->push_back( + bssl::UniquePtr<CRYPTO_BUFFER>(sk_CRYPTO_BUFFER_value(certs, i))); } } // |handles| took ownership of the individual buffers, so only free the list @@ -170,26 +171,26 @@ void CreateOSCertHandlesFromPKCS7Bytes( } // namespace // static -scoped_refptr<X509Certificate> X509Certificate::CreateFromHandle( - OSCertHandle cert_handle, - const OSCertHandles& intermediates) { - DCHECK(cert_handle); +scoped_refptr<X509Certificate> X509Certificate::CreateFromBuffer( + bssl::UniquePtr<CRYPTO_BUFFER> cert_buffer, + std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates) { + DCHECK(cert_buffer); scoped_refptr<X509Certificate> cert( - new X509Certificate(cert_handle, intermediates)); - if (!cert->os_cert_handle()) + new X509Certificate(std::move(cert_buffer), std::move(intermediates))); + if (!cert->cert_buffer()) return nullptr; // Initialize() failed. return cert; } // static -scoped_refptr<X509Certificate> X509Certificate::CreateFromHandleUnsafeOptions( - OSCertHandle cert_handle, - const OSCertHandles& intermediates, +scoped_refptr<X509Certificate> X509Certificate::CreateFromBufferUnsafeOptions( + bssl::UniquePtr<CRYPTO_BUFFER> cert_buffer, + std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates, UnsafeCreateOptions options) { - DCHECK(cert_handle); - scoped_refptr<X509Certificate> cert( - new X509Certificate(cert_handle, intermediates, options)); - if (!cert->os_cert_handle()) + DCHECK(cert_buffer); + scoped_refptr<X509Certificate> cert(new X509Certificate( + std::move(cert_buffer), std::move(intermediates), options)); + if (!cert->cert_buffer()) return nullptr; // Initialize() failed. return cert; } @@ -197,36 +198,39 @@ scoped_refptr<X509Certificate> X509Certificate::CreateFromHandleUnsafeOptions( // static scoped_refptr<X509Certificate> X509Certificate::CreateFromDERCertChain( const std::vector<base::StringPiece>& der_certs) { + return CreateFromDERCertChainUnsafeOptions(der_certs, {}); +} + +// static +scoped_refptr<X509Certificate> +X509Certificate::CreateFromDERCertChainUnsafeOptions( + const std::vector<base::StringPiece>& der_certs, + UnsafeCreateOptions options) { TRACE_EVENT0("io", "X509Certificate::CreateFromDERCertChain"); if (der_certs.empty()) - return NULL; + return nullptr; - X509Certificate::OSCertHandles intermediate_ca_certs; + std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediate_ca_certs; + intermediate_ca_certs.reserve(der_certs.size() - 1); for (size_t i = 1; i < der_certs.size(); i++) { - OSCertHandle handle = CreateOSCertHandleFromBytes( + bssl::UniquePtr<CRYPTO_BUFFER> handle = CreateCertBufferFromBytes( const_cast<char*>(der_certs[i].data()), der_certs[i].size()); if (!handle) break; - intermediate_ca_certs.push_back(handle); + intermediate_ca_certs.push_back(std::move(handle)); } - OSCertHandle handle = NULL; // Return NULL if we failed to parse any of the certs. - if (der_certs.size() - 1 == intermediate_ca_certs.size()) { - handle = CreateOSCertHandleFromBytes( - const_cast<char*>(der_certs[0].data()), der_certs[0].size()); - } - - scoped_refptr<X509Certificate> cert = nullptr; - if (handle) { - cert = CreateFromHandle(handle, intermediate_ca_certs); - FreeOSCertHandle(handle); - } + if (der_certs.size() - 1 != intermediate_ca_certs.size()) + return nullptr; - for (size_t i = 0; i < intermediate_ca_certs.size(); i++) - FreeOSCertHandle(intermediate_ca_certs[i]); + bssl::UniquePtr<CRYPTO_BUFFER> handle = CreateCertBufferFromBytes( + const_cast<char*>(der_certs[0].data()), der_certs[0].size()); + if (!handle) + return nullptr; - return cert; + return CreateFromBufferUnsafeOptions( + std::move(handle), std::move(intermediate_ca_certs), options); } // static @@ -241,19 +245,26 @@ scoped_refptr<X509Certificate> X509Certificate::CreateFromBytesUnsafeOptions( const char* data, size_t length, UnsafeCreateOptions options) { - OSCertHandle cert_handle = CreateOSCertHandleFromBytes(data, length); - if (!cert_handle) + bssl::UniquePtr<CRYPTO_BUFFER> cert_buffer = + CreateCertBufferFromBytes(data, length); + if (!cert_buffer) return NULL; scoped_refptr<X509Certificate> cert = - CreateFromHandleUnsafeOptions(cert_handle, {}, options); - FreeOSCertHandle(cert_handle); + CreateFromBufferUnsafeOptions(std::move(cert_buffer), {}, options); return cert; } // static scoped_refptr<X509Certificate> X509Certificate::CreateFromPickle( base::PickleIterator* pickle_iter) { + return CreateFromPickleUnsafeOptions(pickle_iter, {}); +} + +// static +scoped_refptr<X509Certificate> X509Certificate::CreateFromPickleUnsafeOptions( + base::PickleIterator* pickle_iter, + UnsafeCreateOptions options) { int chain_length = 0; if (!pickle_iter->ReadLength(&chain_length)) return nullptr; @@ -266,7 +277,7 @@ scoped_refptr<X509Certificate> X509Certificate::CreateFromPickle( return nullptr; cert_chain.push_back(base::StringPiece(data, data_length)); } - return CreateFromDERCertChain(cert_chain); + return CreateFromDERCertChainUnsafeOptions(cert_chain, options); } // static @@ -274,7 +285,7 @@ CertificateList X509Certificate::CreateCertificateListFromBytes( const char* data, size_t length, int format) { - OSCertHandles certificates; + std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> certificates; // Check to see if it is in a PEM-encoded form. This check is performed // first, as both OS X and NSS will both try to convert if they detect @@ -292,14 +303,14 @@ CertificateList X509Certificate::CreateCertificateListFromBytes( while (pem_tokenizer.GetNext()) { std::string decoded(pem_tokenizer.data()); - OSCertHandle handle = NULL; + bssl::UniquePtr<CRYPTO_BUFFER> handle; if (format & FORMAT_PEM_CERT_SEQUENCE) - handle = CreateOSCertHandleFromBytes(decoded.c_str(), decoded.size()); - if (handle != NULL) { + handle = CreateCertBufferFromBytes(decoded.c_str(), decoded.size()); + if (handle) { // Parsed a DER encoded certificate. All PEM blocks that follow must // also be DER encoded certificates wrapped inside of PEM blocks. format = FORMAT_PEM_CERT_SEQUENCE; - certificates.push_back(handle); + certificates.push_back(std::move(handle)); continue; } @@ -310,8 +321,8 @@ CertificateList X509Certificate::CreateCertificateListFromBytes( for (size_t i = 0; certificates.empty() && i < arraysize(kFormatDecodePriority); ++i) { if (format & kFormatDecodePriority[i]) { - certificates = CreateOSCertHandlesFromBytes(decoded.c_str(), - decoded.size(), kFormatDecodePriority[i]); + certificates = CreateCertBuffersFromBytes( + decoded.c_str(), decoded.size(), kFormatDecodePriority[i]); } } } @@ -329,8 +340,8 @@ CertificateList X509Certificate::CreateCertificateListFromBytes( for (size_t i = 0; certificates.empty() && i < arraysize(kFormatDecodePriority); ++i) { if (format & kFormatDecodePriority[i]) - certificates = CreateOSCertHandlesFromBytes(data, length, - kFormatDecodePriority[i]); + certificates = + CreateCertBuffersFromBytes(data, length, kFormatDecodePriority[i]); } CertificateList results; @@ -338,29 +349,28 @@ CertificateList X509Certificate::CreateCertificateListFromBytes( if (certificates.empty()) return results; - for (OSCertHandles::iterator it = certificates.begin(); - it != certificates.end(); ++it) { - scoped_refptr<X509Certificate> cert = - CreateFromHandle(*it, OSCertHandles()); + for (auto& it : certificates) { + scoped_refptr<X509Certificate> cert = CreateFromBuffer(std::move(it), {}); if (cert) results.push_back(std::move(cert)); - FreeOSCertHandle(*it); } return results; } void X509Certificate::Persist(base::Pickle* pickle) { - DCHECK(cert_handle_); + DCHECK(cert_buffer_); // This would be an absolutely insane number of intermediates. if (intermediate_ca_certs_.size() > static_cast<size_t>(INT_MAX) - 1) { NOTREACHED(); return; } pickle->WriteInt(static_cast<int>(intermediate_ca_certs_.size() + 1)); - pickle->WriteString(x509_util::CryptoBufferAsStringPiece(cert_handle_)); - for (auto* intermediate : intermediate_ca_certs_) - pickle->WriteString(x509_util::CryptoBufferAsStringPiece(intermediate)); + pickle->WriteString(x509_util::CryptoBufferAsStringPiece(cert_buffer_.get())); + for (const auto& intermediate : intermediate_ca_certs_) { + pickle->WriteString( + x509_util::CryptoBufferAsStringPiece(intermediate.get())); + } } void X509Certificate::GetDNSNames(std::vector<std::string>* dns_names) const { @@ -380,8 +390,8 @@ bool X509Certificate::GetSubjectAltName( der::Input tbs_certificate_tlv; der::Input signature_algorithm_tlv; der::BitString signature_value; - if (!ParseCertificate(der::Input(CRYPTO_BUFFER_data(cert_handle_), - CRYPTO_BUFFER_len(cert_handle_)), + if (!ParseCertificate(der::Input(CRYPTO_BUFFER_data(cert_buffer_.get()), + CRYPTO_BUFFER_len(cert_buffer_.get())), &tbs_certificate_tlv, &signature_algorithm_tlv, &signature_value, nullptr)) { return false; @@ -432,7 +442,8 @@ bool X509Certificate::HasExpired() const { } bool X509Certificate::Equals(const X509Certificate* other) const { - return IsSameOSCert(cert_handle_, other->cert_handle_); + return x509_util::CryptoBufferEqual(cert_buffer_.get(), + other->cert_buffer_.get()); } bool X509Certificate::IsIssuedByEncoded( @@ -450,13 +461,13 @@ bool X509Certificate::IsIssuedByEncoded( } std::string normalized_cert_issuer; - if (!GetNormalizedCertIssuer(cert_handle_, &normalized_cert_issuer)) + if (!GetNormalizedCertIssuer(cert_buffer_.get(), &normalized_cert_issuer)) return false; if (base::ContainsValue(normalized_issuers, normalized_cert_issuer)) return true; - for (CRYPTO_BUFFER* intermediate : intermediate_ca_certs_) { - if (!GetNormalizedCertIssuer(intermediate, &normalized_cert_issuer)) + for (const auto& intermediate : intermediate_ca_certs_) { + if (!GetNormalizedCertIssuer(intermediate.get(), &normalized_cert_issuer)) return false; if (base::ContainsValue(normalized_issuers, normalized_cert_issuer)) return true; @@ -616,18 +627,7 @@ bool X509Certificate::VerifyNameMatch(const std::string& hostname, } // static -bool X509Certificate::GetDEREncoded(X509Certificate::OSCertHandle cert_handle, - std::string* encoded) { - if (!cert_handle) - return false; - encoded->assign( - reinterpret_cast<const char*>(CRYPTO_BUFFER_data(cert_handle)), - CRYPTO_BUFFER_len(cert_handle)); - return true; -} - -// static -bool X509Certificate::GetPEMEncodedFromDER(const std::string& der_encoded, +bool X509Certificate::GetPEMEncodedFromDER(base::StringPiece der_encoded, std::string* pem_encoded) { if (der_encoded.empty()) return false; @@ -649,23 +649,21 @@ bool X509Certificate::GetPEMEncodedFromDER(const std::string& der_encoded, } // static -bool X509Certificate::GetPEMEncoded(OSCertHandle cert_handle, +bool X509Certificate::GetPEMEncoded(const CRYPTO_BUFFER* cert_buffer, std::string* pem_encoded) { - std::string der_encoded; - if (!GetDEREncoded(cert_handle, &der_encoded)) - return false; - return GetPEMEncodedFromDER(der_encoded, pem_encoded); + return GetPEMEncodedFromDER(x509_util::CryptoBufferAsStringPiece(cert_buffer), + pem_encoded); } bool X509Certificate::GetPEMEncodedChain( std::vector<std::string>* pem_encoded) const { std::vector<std::string> encoded_chain; std::string pem_data; - if (!GetPEMEncoded(os_cert_handle(), &pem_data)) + if (!GetPEMEncoded(cert_buffer(), &pem_data)) return false; encoded_chain.push_back(pem_data); for (size_t i = 0; i < intermediate_ca_certs_.size(); ++i) { - if (!GetPEMEncoded(intermediate_ca_certs_[i], &pem_data)) + if (!GetPEMEncoded(intermediate_ca_certs_[i].get(), &pem_data)) return false; encoded_chain.push_back(pem_data); } @@ -674,7 +672,7 @@ bool X509Certificate::GetPEMEncodedChain( } // static -void X509Certificate::GetPublicKeyInfo(OSCertHandle cert_handle, +void X509Certificate::GetPublicKeyInfo(const CRYPTO_BUFFER* cert_buffer, size_t* size_bits, PublicKeyType* type) { *type = kPublicKeyTypeUnknown; @@ -683,8 +681,8 @@ void X509Certificate::GetPublicKeyInfo(OSCertHandle cert_handle, base::StringPiece spki; if (!asn1::ExtractSPKIFromDERCert( base::StringPiece( - reinterpret_cast<const char*>(CRYPTO_BUFFER_data(cert_handle)), - CRYPTO_BUFFER_len(cert_handle)), + reinterpret_cast<const char*>(CRYPTO_BUFFER_data(cert_buffer)), + CRYPTO_BUFFER_len(cert_buffer)), &spki)) { return; } @@ -715,18 +713,7 @@ void X509Certificate::GetPublicKeyInfo(OSCertHandle cert_handle, } // static -bool X509Certificate::IsSameOSCert(X509Certificate::OSCertHandle a, - X509Certificate::OSCertHandle b) { - DCHECK(a && b); - if (a == b) - return true; - return CRYPTO_BUFFER_len(a) == CRYPTO_BUFFER_len(b) && - memcmp(CRYPTO_BUFFER_data(a), CRYPTO_BUFFER_data(b), - CRYPTO_BUFFER_len(a)) == 0; -} - -// static -X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes( +bssl::UniquePtr<CRYPTO_BUFFER> X509Certificate::CreateCertBufferFromBytes( const char* data, size_t length) { der::Input tbs_certificate_tlv; @@ -742,26 +729,27 @@ X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes( return nullptr; } - return CRYPTO_BUFFER_new(reinterpret_cast<const uint8_t*>(data), length, - x509_util::GetBufferPool()); + return x509_util::CreateCryptoBuffer(reinterpret_cast<const uint8_t*>(data), + length); } // static -X509Certificate::OSCertHandles X509Certificate::CreateOSCertHandlesFromBytes( - const char* data, - size_t length, - Format format) { - OSCertHandles results; +std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> +X509Certificate::CreateCertBuffersFromBytes(const char* data, + size_t length, + Format format) { + std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> results; switch (format) { case FORMAT_SINGLE_CERTIFICATE: { - OSCertHandle handle = CreateOSCertHandleFromBytes(data, length); + bssl::UniquePtr<CRYPTO_BUFFER> handle = + CreateCertBufferFromBytes(data, length); if (handle) - results.push_back(handle); + results.push_back(std::move(handle)); break; } case FORMAT_PKCS7: { - CreateOSCertHandlesFromPKCS7Bytes(data, length, &results); + CreateCertBuffersFromPKCS7Bytes(data, length, &results); break; } default: { @@ -774,19 +762,8 @@ X509Certificate::OSCertHandles X509Certificate::CreateOSCertHandlesFromBytes( } // static -X509Certificate::OSCertHandle X509Certificate::DupOSCertHandle( - OSCertHandle cert_handle) { - CRYPTO_BUFFER_up_ref(cert_handle); - return cert_handle; -} - -// static -void X509Certificate::FreeOSCertHandle(OSCertHandle cert_handle) { - CRYPTO_BUFFER_free(cert_handle); -} - -// static -SHA256HashValue X509Certificate::CalculateFingerprint256(OSCertHandle cert) { +SHA256HashValue X509Certificate::CalculateFingerprint256( + const CRYPTO_BUFFER* cert) { SHA256HashValue sha256; SHA256(CRYPTO_BUFFER_data(cert), CRYPTO_BUFFER_len(cert), sha256.data); @@ -799,11 +776,11 @@ SHA256HashValue X509Certificate::CalculateChainFingerprint256() const { SHA256_CTX sha256_ctx; SHA256_Init(&sha256_ctx); - SHA256_Update(&sha256_ctx, CRYPTO_BUFFER_data(cert_handle_), - CRYPTO_BUFFER_len(cert_handle_)); - for (CRYPTO_BUFFER* cert : intermediate_ca_certs_) { - SHA256_Update(&sha256_ctx, CRYPTO_BUFFER_data(cert), - CRYPTO_BUFFER_len(cert)); + SHA256_Update(&sha256_ctx, CRYPTO_BUFFER_data(cert_buffer_.get()), + CRYPTO_BUFFER_len(cert_buffer_.get())); + for (const auto& cert : intermediate_ca_certs_) { + SHA256_Update(&sha256_ctx, CRYPTO_BUFFER_data(cert.get()), + CRYPTO_BUFFER_len(cert.get())); } SHA256_Final(sha256.data, &sha256_ctx); @@ -811,12 +788,12 @@ SHA256HashValue X509Certificate::CalculateChainFingerprint256() const { } // static -bool X509Certificate::IsSelfSigned(OSCertHandle cert_handle) { +bool X509Certificate::IsSelfSigned(const CRYPTO_BUFFER* cert_buffer) { der::Input tbs_certificate_tlv; der::Input signature_algorithm_tlv; der::BitString signature_value; - if (!ParseCertificate(der::Input(CRYPTO_BUFFER_data(cert_handle), - CRYPTO_BUFFER_len(cert_handle)), + if (!ParseCertificate(der::Input(CRYPTO_BUFFER_data(cert_buffer), + CRYPTO_BUFFER_len(cert_buffer)), &tbs_certificate_tlv, &signature_algorithm_tlv, &signature_value, nullptr)) { return false; @@ -856,41 +833,33 @@ bool X509Certificate::IsSelfSigned(OSCertHandle cert_handle) { signature_value, tbs.spki_tlv); } -X509Certificate::X509Certificate(OSCertHandle cert_handle, - const OSCertHandles& intermediates) - : X509Certificate(cert_handle, intermediates, {}) {} +X509Certificate::X509Certificate( + bssl::UniquePtr<CRYPTO_BUFFER> cert_buffer, + std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates) + : X509Certificate(std::move(cert_buffer), std::move(intermediates), {}) {} -X509Certificate::X509Certificate(OSCertHandle cert_handle, - const OSCertHandles& intermediates, - UnsafeCreateOptions options) - : cert_handle_(DupOSCertHandle(cert_handle)) { - for (size_t i = 0; i < intermediates.size(); ++i) { - // Duplicate the incoming certificate, as the caller retains ownership - // of |intermediates|. - intermediate_ca_certs_.push_back(DupOSCertHandle(intermediates[i])); - } +X509Certificate::X509Certificate( + bssl::UniquePtr<CRYPTO_BUFFER> cert_buffer, + std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates, + UnsafeCreateOptions options) + : cert_buffer_(std::move(cert_buffer)), + intermediate_ca_certs_(std::move(intermediates)) { // Platform-specific initialization. - if (!Initialize(options) && cert_handle_) { - // Signal initialization failure by clearing cert_handle_. - FreeOSCertHandle(cert_handle_); - cert_handle_ = nullptr; + if (!Initialize(options) && cert_buffer_) { + // Signal initialization failure by clearing cert_buffer_. + cert_buffer_.reset(); } } -X509Certificate::~X509Certificate() { - if (cert_handle_) - FreeOSCertHandle(cert_handle_); - for (size_t i = 0; i < intermediate_ca_certs_.size(); ++i) - FreeOSCertHandle(intermediate_ca_certs_[i]); -} +X509Certificate::~X509Certificate() = default; bool X509Certificate::Initialize(UnsafeCreateOptions options) { der::Input tbs_certificate_tlv; der::Input signature_algorithm_tlv; der::BitString signature_value; - if (!ParseCertificate(der::Input(CRYPTO_BUFFER_data(cert_handle_), - CRYPTO_BUFFER_len(cert_handle_)), + if (!ParseCertificate(der::Input(CRYPTO_BUFFER_data(cert_buffer_.get()), + CRYPTO_BUFFER_len(cert_buffer_.get())), &tbs_certificate_tlv, &signature_algorithm_tlv, &signature_value, nullptr)) { return false; diff --git a/chromium/net/cert/x509_certificate.h b/chromium/net/cert/x509_certificate.h index 70cc20c122a..9d3af4866e6 100644 --- a/chromium/net/cert/x509_certificate.h +++ b/chromium/net/cert/x509_certificate.h @@ -38,15 +38,6 @@ typedef std::vector<scoped_refptr<X509Certificate> > CertificateList; class NET_EXPORT X509Certificate : public base::RefCountedThreadSafe<X509Certificate> { public: - // An OSCertHandle is a handle to a certificate object in the underlying - // crypto library. We assume that OSCertHandle is a pointer type on all - // platforms and that NULL represents an invalid OSCertHandle. - // TODO(mattm): Remove OSCertHandle type and clean up the interfaces once all - // platforms use the CRYPTO_BUFFER version. - typedef CRYPTO_BUFFER* OSCertHandle; - - typedef std::vector<OSCertHandle> OSCertHandles; - enum PublicKeyType { kPublicKeyTypeUnknown, kPublicKeyTypeRSA, @@ -78,15 +69,15 @@ class NET_EXPORT X509Certificate FORMAT_PKCS7, }; - // Create an X509Certificate from a handle to the certificate object in the - // underlying crypto library. Returns NULL on failure to parse or extract - // data from the the certificate. Note that this does not guarantee the - // certificate is fully parsed and validated, only that the members of this - // class, such as subject, issuer, expiry times, and serial number, could be - // successfully initialized from the certificate. - static scoped_refptr<X509Certificate> CreateFromHandle( - OSCertHandle cert_handle, - const OSCertHandles& intermediates); + // Create an X509Certificate from a CRYPTO_BUFFER containing the DER-encoded + // representation. Returns NULL on failure to parse or extract data from the + // the certificate. Note that this does not guarantee the certificate is + // fully parsed and validated, only that the members of this class, such as + // subject, issuer, expiry times, and serial number, could be successfully + // initialized from the certificate. + static scoped_refptr<X509Certificate> CreateFromBuffer( + bssl::UniquePtr<CRYPTO_BUFFER> cert_buffer, + std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates); // Options for configuring certificate parsing. // Do not use without consulting //net owners. @@ -95,9 +86,9 @@ class NET_EXPORT X509Certificate }; // Create an X509Certificate with non-standard parsing options. // Do not use without consulting //net owners. - static scoped_refptr<X509Certificate> CreateFromHandleUnsafeOptions( - OSCertHandle cert_handle, - const OSCertHandles& intermediates, + static scoped_refptr<X509Certificate> CreateFromBufferUnsafeOptions( + bssl::UniquePtr<CRYPTO_BUFFER> cert_buffer, + std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates, UnsafeCreateOptions options); // Create an X509Certificate from a chain of DER encoded certificates. The @@ -107,6 +98,13 @@ class NET_EXPORT X509Certificate static scoped_refptr<X509Certificate> CreateFromDERCertChain( const std::vector<base::StringPiece>& der_certs); + // Create an X509Certificate from a chain of DER encoded certificates with + // non-standard parsing options. + // Do not use without consulting //net owners. + static scoped_refptr<X509Certificate> CreateFromDERCertChainUnsafeOptions( + const std::vector<base::StringPiece>& der_certs, + UnsafeCreateOptions options); + // Create an X509Certificate from the DER-encoded representation. // Returns NULL on failure. static scoped_refptr<X509Certificate> CreateFromBytes(const char* data, @@ -126,6 +124,13 @@ class NET_EXPORT X509Certificate static scoped_refptr<X509Certificate> CreateFromPickle( base::PickleIterator* pickle_iter); + // Create an X509Certificate from the representation stored in the given + // pickle with non-standard parsing options. + // Do not use without consulting //net owners. + static scoped_refptr<X509Certificate> CreateFromPickleUnsafeOptions( + base::PickleIterator* pickle_iter, + UnsafeCreateOptions options); + // Parses all of the certificates possible from |data|. |format| is a // bit-wise OR of Format, indicating the possible formats the // certificates may have been serialized as. If an error occurs, an empty @@ -187,14 +192,6 @@ class NET_EXPORT X509Certificate // Does not consider any associated intermediates. bool Equals(const X509Certificate* other) const; - // Returns the associated intermediate certificates that were specified - // during creation of this object, if any. - // Ownership follows the "get" rule: it is the caller's responsibility to - // retain the elements of the result. - const OSCertHandles& GetIntermediateCertificates() const { - return intermediate_ca_certs_; - } - // Do any of the given issuer names appear in this cert's chain of trust? // |valid_issuers| is a list of DER-encoded X.509 DistinguishedNames. bool IsIssuedByEncoded(const std::vector<std::string>& valid_issuers); @@ -208,20 +205,15 @@ class NET_EXPORT X509Certificate bool VerifyNameMatch(const std::string& hostname, bool allow_common_name_fallback) const; - // Obtains the DER encoded certificate data for |cert_handle|. On success, - // returns true and writes the DER encoded certificate to |*der_encoded|. - static bool GetDEREncoded(OSCertHandle cert_handle, - std::string* der_encoded); - // Returns the PEM encoded data from a DER encoded certificate. If the return // value is true, then the PEM encoded certificate is written to // |pem_encoded|. - static bool GetPEMEncodedFromDER(const std::string& der_encoded, + static bool GetPEMEncodedFromDER(base::StringPiece der_encoded, std::string* pem_encoded); - // Returns the PEM encoded data from an OSCertHandle. If the return value is + // Returns the PEM encoded data from a CRYPTO_BUFFER. If the return value is // true, then the PEM encoded certificate is written to |pem_encoded|. - static bool GetPEMEncoded(OSCertHandle cert_handle, + static bool GetPEMEncoded(const CRYPTO_BUFFER* cert_buffer, std::string* pem_encoded); // Encodes the entire certificate chain (this certificate and any @@ -234,40 +226,42 @@ class NET_EXPORT X509Certificate // Sets |*size_bits| to be the length of the public key in bits, and sets // |*type| to one of the |PublicKeyType| values. In case of // |kPublicKeyTypeUnknown|, |*size_bits| will be set to 0. - static void GetPublicKeyInfo(OSCertHandle cert_handle, + static void GetPublicKeyInfo(const CRYPTO_BUFFER* cert_buffer, size_t* size_bits, PublicKeyType* type); - // Returns the OSCertHandle of this object. Because of caching, this may - // differ from the OSCertHandle originally supplied during initialization. - // Note: On Windows, CryptoAPI may return unexpected results if this handle - // is used across multiple threads. For more details, see - // CreateOSCertChainForCert(). - OSCertHandle os_cert_handle() const { return cert_handle_; } + // Returns the CRYPTO_BUFFER holding this certificate's DER encoded data. The + // data is not guaranteed to be valid DER or to encode a valid Certificate + // object. + CRYPTO_BUFFER* cert_buffer() const { return cert_buffer_.get(); } - // Returns true if two OSCertHandles refer to identical certificates. - static bool IsSameOSCert(OSCertHandle a, OSCertHandle b); + // Returns the associated intermediate certificates that were specified + // during creation of this object, if any. The intermediates are not + // guaranteed to be valid DER or to encode valid Certificate objects. + // Ownership follows the "get" rule: it is the caller's responsibility to + // retain the elements of the result. + const std::vector<bssl::UniquePtr<CRYPTO_BUFFER>>& intermediate_buffers() + const { + return intermediate_ca_certs_; + } - // Creates an OS certificate handle from the DER-encoded representation. + // Creates a CRYPTO_BUFFER from the DER-encoded representation. Unlike + // creating a CRYPTO_BUFFER directly, this function does some minimal + // checking to reject obviously invalid inputs. // Returns NULL on failure. - static OSCertHandle CreateOSCertHandleFromBytes(const char* data, - size_t length); - - // Creates all possible OS certificate handles from |data| encoded in a - // specific |format|. Returns an empty collection on failure. - static OSCertHandles CreateOSCertHandlesFromBytes(const char* data, - size_t length, - Format format); - - // Duplicates (or adds a reference to) an OS certificate handle. - static OSCertHandle DupOSCertHandle(OSCertHandle cert_handle); + static bssl::UniquePtr<CRYPTO_BUFFER> CreateCertBufferFromBytes( + const char* data, + size_t length); - // Frees (or releases a reference to) an OS certificate handle. - static void FreeOSCertHandle(OSCertHandle cert_handle); + // Creates all possible CRYPTO_BUFFERs from |data| encoded in a specific + // |format|. Returns an empty collection on failure. + static std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> + CreateCertBuffersFromBytes(const char* data, size_t length, Format format); // Calculates the SHA-256 fingerprint of the certificate. Returns an empty // (all zero) fingerprint on failure. - static SHA256HashValue CalculateFingerprint256(OSCertHandle cert_handle); + static SHA256HashValue CalculateFingerprint256( + const CRYPTO_BUFFER* cert_buffer); // Calculates the SHA-256 fingerprint for the complete chain, including the // leaf certificate and all intermediate CA certificates. Returns an empty @@ -275,7 +269,7 @@ class NET_EXPORT X509Certificate SHA256HashValue CalculateChainFingerprint256() const; // Returns true if the certificate is self-signed. - static bool IsSelfSigned(OSCertHandle cert_handle); + static bool IsSelfSigned(const CRYPTO_BUFFER* cert_buffer); private: friend class base::RefCountedThreadSafe<X509Certificate>; @@ -284,12 +278,12 @@ class NET_EXPORT X509Certificate FRIEND_TEST_ALL_PREFIXES(X509CertificateNameVerifyTest, VerifyHostname); FRIEND_TEST_ALL_PREFIXES(X509CertificateTest, SerialNumbers); - // Construct an X509Certificate from a handle to the certificate object - // in the underlying crypto library. - X509Certificate(OSCertHandle cert_handle, - const OSCertHandles& intermediates); - X509Certificate(OSCertHandle cert_handle, - const OSCertHandles& intermediates, + // Construct an X509Certificate from a CRYPTO_BUFFER containing the + // DER-encoded representation. + X509Certificate(bssl::UniquePtr<CRYPTO_BUFFER> cert_buffer, + std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates); + X509Certificate(bssl::UniquePtr<CRYPTO_BUFFER> cert_buffer, + std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates, UnsafeCreateOptions options); ~X509Certificate(); @@ -330,12 +324,12 @@ class NET_EXPORT X509Certificate // The serial number of this certificate, DER encoded. std::string serial_number_; - // A handle to the certificate object in the underlying crypto library. - OSCertHandle cert_handle_; + // A handle to the DER encoded certificate data. + bssl::UniquePtr<CRYPTO_BUFFER> cert_buffer_; // Untrusted intermediate certificates associated with this certificate // that may be needed for chain building. - OSCertHandles intermediate_ca_certs_; + std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediate_ca_certs_; DISALLOW_COPY_AND_ASSIGN(X509Certificate); }; diff --git a/chromium/net/cert/x509_certificate_unittest.cc b/chromium/net/cert/x509_certificate_unittest.cc index a9cee29077d..76ba8500fdf 100644 --- a/chromium/net/cert/x509_certificate_unittest.cc +++ b/chromium/net/cert/x509_certificate_unittest.cc @@ -103,7 +103,7 @@ void CheckGoogleCert(const scoped_refptr<X509Certificate>& google_cert, EXPECT_EQ(valid_to, valid_expiry.ToDoubleT()); EXPECT_EQ(expected_fingerprint, X509Certificate::CalculateFingerprint256( - google_cert->os_cert_handle())); + google_cert->cert_buffer())); std::vector<std::string> dns_names; google_cert->GetDNSNames(&dns_names); @@ -284,13 +284,14 @@ TEST(X509CertificateTest, InvalidPrintableStringIsUtf8) { x509_util::CreateCryptoBuffer(cert_der); ASSERT_TRUE(cert_handle); - EXPECT_FALSE(X509Certificate::CreateFromHandle(cert_handle.get(), {})); + EXPECT_FALSE(X509Certificate::CreateFromBuffer( + x509_util::DupCryptoBuffer(cert_handle.get()), {})); X509Certificate::UnsafeCreateOptions options; options.printable_string_is_utf8 = true; scoped_refptr<X509Certificate> cert = - X509Certificate::CreateFromHandleUnsafeOptions(cert_handle.get(), {}, - options); + X509Certificate::CreateFromBufferUnsafeOptions( + x509_util::DupCryptoBuffer(cert_handle.get()), {}, options); const CertPrincipal& subject = cert->subject(); EXPECT_EQ("Foo@#_ Clïênt Cërt", subject.common_name); @@ -456,7 +457,7 @@ TEST(X509CertificateTest, SHA256FingerprintsCorrectly) { 0x7f, 0x77, 0x49, 0x38, 0x42, 0x81, 0x26, 0x7f, 0xed, 0x38}}; EXPECT_EQ(google_sha256_fingerprint, X509Certificate::CalculateFingerprint256( - google_cert->os_cert_handle())); + google_cert->cert_buffer())); } TEST(X509CertificateTest, CAFingerprints) { @@ -474,25 +475,30 @@ TEST(X509CertificateTest, CAFingerprints) { ImportCertFromFile(certs_dir, "verisign_intermediate_ca_2016.pem"); ASSERT_NE(static_cast<X509Certificate*>(NULL), intermediate_cert2.get()); - X509Certificate::OSCertHandles intermediates; - intermediates.push_back(intermediate_cert1->os_cert_handle()); + std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates; + intermediates.push_back( + x509_util::DupCryptoBuffer(intermediate_cert1->cert_buffer())); scoped_refptr<X509Certificate> cert_chain1 = - X509Certificate::CreateFromHandle(server_cert->os_cert_handle(), - intermediates); + X509Certificate::CreateFromBuffer( + x509_util::DupCryptoBuffer(server_cert->cert_buffer()), + std::move(intermediates)); ASSERT_TRUE(cert_chain1); intermediates.clear(); - intermediates.push_back(intermediate_cert2->os_cert_handle()); + intermediates.push_back( + x509_util::DupCryptoBuffer(intermediate_cert2->cert_buffer())); scoped_refptr<X509Certificate> cert_chain2 = - X509Certificate::CreateFromHandle(server_cert->os_cert_handle(), - intermediates); + X509Certificate::CreateFromBuffer( + x509_util::DupCryptoBuffer(server_cert->cert_buffer()), + std::move(intermediates)); ASSERT_TRUE(cert_chain2); // No intermediate CA certicates. intermediates.clear(); scoped_refptr<X509Certificate> cert_chain3 = - X509Certificate::CreateFromHandle(server_cert->os_cert_handle(), - intermediates); + X509Certificate::CreateFromBuffer( + x509_util::DupCryptoBuffer(server_cert->cert_buffer()), + std::move(intermediates)); ASSERT_TRUE(cert_chain3); SHA256HashValue cert_chain1_chain_fingerprint_256 = { @@ -576,12 +582,9 @@ TEST(X509CertificateTest, ExtractSPKIFromDERCert) { ImportCertFromFile(certs_dir, "nist.der"); ASSERT_NE(static_cast<X509Certificate*>(NULL), cert.get()); - std::string derBytes; - EXPECT_TRUE(X509Certificate::GetDEREncoded(cert->os_cert_handle(), - &derBytes)); - base::StringPiece spkiBytes; - EXPECT_TRUE(asn1::ExtractSPKIFromDERCert(derBytes, &spkiBytes)); + EXPECT_TRUE(asn1::ExtractSPKIFromDERCert( + x509_util::CryptoBufferAsStringPiece(cert->cert_buffer()), &spkiBytes)); uint8_t hash[base::kSHA1Length]; base::SHA1HashBytes(reinterpret_cast<const uint8_t*>(spkiBytes.data()), @@ -596,11 +599,8 @@ TEST(X509CertificateTest, HasTLSFeatureExtension) { ImportCertFromFile(certs_dir, "tls_feature_extension.pem"); ASSERT_NE(static_cast<X509Certificate*>(NULL), cert.get()); - std::string derBytes; - EXPECT_TRUE( - X509Certificate::GetDEREncoded(cert->os_cert_handle(), &derBytes)); - - EXPECT_TRUE(asn1::HasTLSFeatureExtension(derBytes)); + EXPECT_TRUE(asn1::HasTLSFeatureExtension( + x509_util::CryptoBufferAsStringPiece(cert->cert_buffer()))); } TEST(X509CertificateTest, DoesNotHaveTLSFeatureExtension) { @@ -609,83 +609,79 @@ TEST(X509CertificateTest, DoesNotHaveTLSFeatureExtension) { ImportCertFromFile(certs_dir, "ok_cert.pem"); ASSERT_NE(static_cast<X509Certificate*>(NULL), cert.get()); - std::string derBytes; - EXPECT_TRUE( - X509Certificate::GetDEREncoded(cert->os_cert_handle(), &derBytes)); - - EXPECT_FALSE(asn1::HasTLSFeatureExtension(derBytes)); + EXPECT_FALSE(asn1::HasTLSFeatureExtension( + x509_util::CryptoBufferAsStringPiece(cert->cert_buffer()))); } -// Tests OSCertHandle deduping via X509Certificate::CreateFromHandle. We -// call X509Certificate::CreateFromHandle several times and observe whether -// it returns a cached or new OSCertHandle. +// Tests CRYPTO_BUFFER deduping via X509Certificate::CreateFromBuffer. We +// call X509Certificate::CreateFromBuffer several times and observe whether +// it returns a cached or new CRYPTO_BUFFER. TEST(X509CertificateTest, Cache) { - X509Certificate::OSCertHandle google_cert_handle; - X509Certificate::OSCertHandle thawte_cert_handle; + bssl::UniquePtr<CRYPTO_BUFFER> google_cert_handle; + bssl::UniquePtr<CRYPTO_BUFFER> thawte_cert_handle; // Add a single certificate to the certificate cache. - google_cert_handle = X509Certificate::CreateOSCertHandleFromBytes( + google_cert_handle = X509Certificate::CreateCertBufferFromBytes( reinterpret_cast<const char*>(google_der), sizeof(google_der)); - scoped_refptr<X509Certificate> cert1(X509Certificate::CreateFromHandle( - google_cert_handle, X509Certificate::OSCertHandles())); - X509Certificate::FreeOSCertHandle(google_cert_handle); + ASSERT_TRUE(google_cert_handle); + scoped_refptr<X509Certificate> cert1( + X509Certificate::CreateFromBuffer(std::move(google_cert_handle), {})); ASSERT_TRUE(cert1); // Add the same certificate, but as a new handle. - google_cert_handle = X509Certificate::CreateOSCertHandleFromBytes( + google_cert_handle = X509Certificate::CreateCertBufferFromBytes( reinterpret_cast<const char*>(google_der), sizeof(google_der)); - scoped_refptr<X509Certificate> cert2(X509Certificate::CreateFromHandle( - google_cert_handle, X509Certificate::OSCertHandles())); - X509Certificate::FreeOSCertHandle(google_cert_handle); + ASSERT_TRUE(google_cert_handle); + scoped_refptr<X509Certificate> cert2( + X509Certificate::CreateFromBuffer(std::move(google_cert_handle), {})); ASSERT_TRUE(cert2); // A new X509Certificate should be returned. EXPECT_NE(cert1.get(), cert2.get()); // But both instances should share the underlying OS certificate handle. - EXPECT_EQ(cert1->os_cert_handle(), cert2->os_cert_handle()); - EXPECT_EQ(0u, cert1->GetIntermediateCertificates().size()); - EXPECT_EQ(0u, cert2->GetIntermediateCertificates().size()); + EXPECT_EQ(cert1->cert_buffer(), cert2->cert_buffer()); + EXPECT_EQ(0u, cert1->intermediate_buffers().size()); + EXPECT_EQ(0u, cert2->intermediate_buffers().size()); // Add the same certificate, but this time with an intermediate. This // should result in the intermediate being cached. Note that this is not // a legitimate chain, but is suitable for testing. - google_cert_handle = X509Certificate::CreateOSCertHandleFromBytes( + google_cert_handle = X509Certificate::CreateCertBufferFromBytes( reinterpret_cast<const char*>(google_der), sizeof(google_der)); - thawte_cert_handle = X509Certificate::CreateOSCertHandleFromBytes( + thawte_cert_handle = X509Certificate::CreateCertBufferFromBytes( reinterpret_cast<const char*>(thawte_der), sizeof(thawte_der)); - X509Certificate::OSCertHandles intermediates; - intermediates.push_back(thawte_cert_handle); - scoped_refptr<X509Certificate> cert3(X509Certificate::CreateFromHandle( - google_cert_handle, intermediates)); - X509Certificate::FreeOSCertHandle(google_cert_handle); - X509Certificate::FreeOSCertHandle(thawte_cert_handle); + ASSERT_TRUE(google_cert_handle); + ASSERT_TRUE(thawte_cert_handle); + std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates; + intermediates.push_back(std::move(thawte_cert_handle)); + scoped_refptr<X509Certificate> cert3(X509Certificate::CreateFromBuffer( + std::move(google_cert_handle), std::move(intermediates))); ASSERT_TRUE(cert3); // Test that the new certificate, even with intermediates, results in the // same underlying handle being used. - EXPECT_EQ(cert1->os_cert_handle(), cert3->os_cert_handle()); + EXPECT_EQ(cert1->cert_buffer(), cert3->cert_buffer()); // Though they use the same OS handle, the intermediates should be different. - EXPECT_NE(cert1->GetIntermediateCertificates().size(), - cert3->GetIntermediateCertificates().size()); + EXPECT_NE(cert1->intermediate_buffers().size(), + cert3->intermediate_buffers().size()); } TEST(X509CertificateTest, Pickle) { - X509Certificate::OSCertHandle google_cert_handle = - X509Certificate::CreateOSCertHandleFromBytes( + bssl::UniquePtr<CRYPTO_BUFFER> google_cert_handle = + X509Certificate::CreateCertBufferFromBytes( reinterpret_cast<const char*>(google_der), sizeof(google_der)); - X509Certificate::OSCertHandle thawte_cert_handle = - X509Certificate::CreateOSCertHandleFromBytes( + ASSERT_TRUE(google_cert_handle); + bssl::UniquePtr<CRYPTO_BUFFER> thawte_cert_handle = + X509Certificate::CreateCertBufferFromBytes( reinterpret_cast<const char*>(thawte_der), sizeof(thawte_der)); + ASSERT_TRUE(thawte_cert_handle); - X509Certificate::OSCertHandles intermediates; - intermediates.push_back(thawte_cert_handle); - scoped_refptr<X509Certificate> cert = X509Certificate::CreateFromHandle( - google_cert_handle, intermediates); + std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates; + intermediates.push_back(std::move(thawte_cert_handle)); + scoped_refptr<X509Certificate> cert = X509Certificate::CreateFromBuffer( + std::move(google_cert_handle), std::move(intermediates)); ASSERT_TRUE(cert); - X509Certificate::FreeOSCertHandle(google_cert_handle); - X509Certificate::FreeOSCertHandle(thawte_cert_handle); - base::Pickle pickle; cert->Persist(&pickle); @@ -693,16 +689,14 @@ TEST(X509CertificateTest, Pickle) { scoped_refptr<X509Certificate> cert_from_pickle = X509Certificate::CreateFromPickle(&iter); ASSERT_TRUE(cert_from_pickle); - EXPECT_TRUE(X509Certificate::IsSameOSCert( - cert->os_cert_handle(), cert_from_pickle->os_cert_handle())); - const X509Certificate::OSCertHandles& cert_intermediates = - cert->GetIntermediateCertificates(); - const X509Certificate::OSCertHandles& pickle_intermediates = - cert_from_pickle->GetIntermediateCertificates(); + EXPECT_TRUE(x509_util::CryptoBufferEqual(cert->cert_buffer(), + cert_from_pickle->cert_buffer())); + const auto& cert_intermediates = cert->intermediate_buffers(); + const auto& pickle_intermediates = cert_from_pickle->intermediate_buffers(); ASSERT_EQ(cert_intermediates.size(), pickle_intermediates.size()); for (size_t i = 0; i < cert_intermediates.size(); ++i) { - EXPECT_TRUE(X509Certificate::IsSameOSCert(cert_intermediates[i], - pickle_intermediates[i])); + EXPECT_TRUE(x509_util::CryptoBufferEqual(cert_intermediates[i].get(), + pickle_intermediates[i].get())); } } @@ -717,35 +711,34 @@ TEST(X509CertificateTest, IntermediateCertificates) { reinterpret_cast<const char*>(thawte_der), sizeof(thawte_der))); ASSERT_TRUE(thawte_cert); - X509Certificate::OSCertHandle google_handle; + bssl::UniquePtr<CRYPTO_BUFFER> google_handle; // Create object with no intermediates: - google_handle = X509Certificate::CreateOSCertHandleFromBytes( + google_handle = X509Certificate::CreateCertBufferFromBytes( reinterpret_cast<const char*>(google_der), sizeof(google_der)); - X509Certificate::OSCertHandles intermediates1; scoped_refptr<X509Certificate> cert1; - cert1 = X509Certificate::CreateFromHandle(google_handle, intermediates1); + cert1 = X509Certificate::CreateFromBuffer( + x509_util::DupCryptoBuffer(google_handle.get()), {}); ASSERT_TRUE(cert1); - EXPECT_EQ(0u, cert1->GetIntermediateCertificates().size()); + EXPECT_EQ(0u, cert1->intermediate_buffers().size()); // Create object with 2 intermediates: - X509Certificate::OSCertHandles intermediates2; - intermediates2.push_back(webkit_cert->os_cert_handle()); - intermediates2.push_back(thawte_cert->os_cert_handle()); + std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates2; + intermediates2.push_back( + x509_util::DupCryptoBuffer(webkit_cert->cert_buffer())); + intermediates2.push_back( + x509_util::DupCryptoBuffer(thawte_cert->cert_buffer())); scoped_refptr<X509Certificate> cert2; - cert2 = X509Certificate::CreateFromHandle(google_handle, intermediates2); + cert2 = X509Certificate::CreateFromBuffer(std::move(google_handle), + std::move(intermediates2)); ASSERT_TRUE(cert2); // Verify it has all the intermediates: - const X509Certificate::OSCertHandles& cert2_intermediates = - cert2->GetIntermediateCertificates(); + const auto& cert2_intermediates = cert2->intermediate_buffers(); ASSERT_EQ(2u, cert2_intermediates.size()); - EXPECT_TRUE(X509Certificate::IsSameOSCert(cert2_intermediates[0], - webkit_cert->os_cert_handle())); - EXPECT_TRUE(X509Certificate::IsSameOSCert(cert2_intermediates[1], - thawte_cert->os_cert_handle())); - - // Cleanup - X509Certificate::FreeOSCertHandle(google_handle); + EXPECT_TRUE(x509_util::CryptoBufferEqual(cert2_intermediates[0].get(), + webkit_cert->cert_buffer())); + EXPECT_TRUE(x509_util::CryptoBufferEqual(cert2_intermediates[1].get(), + thawte_cert->cert_buffer())); } TEST(X509CertificateTest, IsIssuedByEncoded) { @@ -796,22 +789,22 @@ TEST(X509CertificateTest, IsSelfSigned) { scoped_refptr<X509Certificate> cert( ImportCertFromFile(certs_dir, "mit.davidben.der")); ASSERT_NE(static_cast<X509Certificate*>(NULL), cert.get()); - EXPECT_FALSE(X509Certificate::IsSelfSigned(cert->os_cert_handle())); + EXPECT_FALSE(X509Certificate::IsSelfSigned(cert->cert_buffer())); scoped_refptr<X509Certificate> self_signed( ImportCertFromFile(certs_dir, "aia-root.pem")); ASSERT_NE(static_cast<X509Certificate*>(NULL), self_signed.get()); - EXPECT_TRUE(X509Certificate::IsSelfSigned(self_signed->os_cert_handle())); + EXPECT_TRUE(X509Certificate::IsSelfSigned(self_signed->cert_buffer())); scoped_refptr<X509Certificate> bad_name( ImportCertFromFile(certs_dir, "self-signed-invalid-name.pem")); ASSERT_NE(static_cast<X509Certificate*>(NULL), bad_name.get()); - EXPECT_FALSE(X509Certificate::IsSelfSigned(bad_name->os_cert_handle())); + EXPECT_FALSE(X509Certificate::IsSelfSigned(bad_name->cert_buffer())); scoped_refptr<X509Certificate> bad_sig( ImportCertFromFile(certs_dir, "self-signed-invalid-sig.pem")); ASSERT_NE(static_cast<X509Certificate*>(NULL), bad_sig.get()); - EXPECT_FALSE(X509Certificate::IsSelfSigned(bad_sig->os_cert_handle())); + EXPECT_FALSE(X509Certificate::IsSelfSigned(bad_sig->cert_buffer())); } TEST(X509CertificateTest, IsIssuedByEncodedWithIntermediates) { @@ -841,11 +834,12 @@ TEST(X509CertificateTest, IsIssuedByEncodedWithIntermediates) { std::string policy_root_dn(reinterpret_cast<const char*>(kPolicyRootDN), sizeof(kPolicyRootDN)); - X509Certificate::OSCertHandles intermediates; - intermediates.push_back(policy_chain[1]->os_cert_handle()); - scoped_refptr<X509Certificate> cert_chain = - X509Certificate::CreateFromHandle(policy_chain[0]->os_cert_handle(), - intermediates); + std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates; + intermediates.push_back( + x509_util::DupCryptoBuffer(policy_chain[1]->cert_buffer())); + scoped_refptr<X509Certificate> cert_chain = X509Certificate::CreateFromBuffer( + x509_util::DupCryptoBuffer(policy_chain[0]->cert_buffer()), + std::move(intermediates)); ASSERT_TRUE(cert_chain); std::vector<std::string> issuers; @@ -878,11 +872,6 @@ TEST(X509CertificateTest, IsIssuedByEncodedWithIntermediates) { EXPECT_FALSE(cert_chain->IsIssuedByEncoded(issuers)); } -// Tests that FreeOSCertHandle ignores NULL on each OS. -TEST(X509CertificateTest, FreeNullHandle) { - X509Certificate::FreeOSCertHandle(NULL); -} - const struct CertificateFormatTestData { const char* file_name; X509Certificate::Format format; @@ -1005,7 +994,7 @@ TEST_P(X509CertificateParseTest, CanParseFormat) { // comparing fingerprints. EXPECT_EQ( *test_data_.chain_fingerprints[i], - X509Certificate::CalculateFingerprint256(certs[i]->os_cert_handle())); + X509Certificate::CalculateFingerprint256(certs[i]->cert_buffer())); } } @@ -1281,7 +1270,7 @@ TEST_P(X509CertificatePublicKeyInfoTest, GetPublicKeyInfo) { X509Certificate::PublicKeyType actual_type = X509Certificate::kPublicKeyTypeUnknown; - X509Certificate::GetPublicKeyInfo(cert->os_cert_handle(), &actual_bits, + X509Certificate::GetPublicKeyInfo(cert->cert_buffer(), &actual_bits, &actual_type); EXPECT_EQ(data.expected_bits, actual_bits); diff --git a/chromium/net/cert/x509_util.cc b/chromium/net/cert/x509_util.cc index 9f39287f6a6..b0558744c57 100644 --- a/chromium/net/cert/x509_util.cc +++ b/chromium/net/cert/x509_util.cc @@ -4,6 +4,7 @@ #include "net/cert/x509_util.h" +#include <string.h> #include <memory> #include "base/lazy_instance.h" @@ -113,33 +114,6 @@ bool AddTime(CBB* cbb, base::Time time) { der::EncodeGeneralizedTime(generalized_time, out) && CBB_flush(cbb); } -bool GetCommonName(const der::Input& tlv, std::string* common_name) { - RDNSequence rdn_sequence; - if (!ParseName(tlv, &rdn_sequence)) - return false; - - for (const auto& rdn : rdn_sequence) { - for (const auto& atv : rdn) { - if (atv.type == TypeCommonNameOid()) { - return atv.ValueAsString(common_name); - } - } - } - return true; -} - -bool DecodeTime(const der::GeneralizedTime& generalized_time, - base::Time* time) { - base::Time::Exploded exploded = {0}; - exploded.year = generalized_time.year; - exploded.month = generalized_time.month; - exploded.day_of_month = generalized_time.day; - exploded.hour = generalized_time.hours; - exploded.minute = generalized_time.minutes; - exploded.second = generalized_time.seconds; - return base::Time::FromUTCExploded(exploded, time); -} - class BufferPoolSingleton { public: BufferPoolSingleton() : pool_(CRYPTO_BUFFER_POOL_new()) {} @@ -159,15 +133,13 @@ bool GetTLSServerEndPointChannelBinding(const X509Certificate& certificate, std::string* token) { static const char kChannelBindingPrefix[] = "tls-server-end-point:"; - std::string der_encoded_certificate; - if (!X509Certificate::GetDEREncoded(certificate.os_cert_handle(), - &der_encoded_certificate)) - return false; + base::StringPiece der_encoded_certificate = + x509_util::CryptoBufferAsStringPiece(certificate.cert_buffer()); der::Input tbs_certificate_tlv; der::Input signature_algorithm_tlv; der::BitString signature_value; - if (!ParseCertificate(der::Input(&der_encoded_certificate), + if (!ParseCertificate(der::Input(der_encoded_certificate), &tbs_certificate_tlv, &signature_algorithm_tlv, &signature_value, nullptr)) return false; @@ -321,61 +293,6 @@ bool CreateSelfSignedCert(crypto::RSAPrivateKey* key, return true; } -bool ParseCertificateSandboxed(const base::StringPiece& certificate, - std::string* subject, - std::string* issuer, - base::Time* not_before, - base::Time* not_after, - std::vector<std::string>* dns_names, - std::vector<std::string>* ip_addresses) { - der::Input cert_data(certificate); - der::Input tbs_cert, signature_alg; - der::BitString signature_value; - if (!ParseCertificate(cert_data, &tbs_cert, &signature_alg, &signature_value, - nullptr)) - return false; - - ParsedTbsCertificate parsed_tbs_cert; - if (!ParseTbsCertificate(tbs_cert, DefaultParseCertificateOptions(), - &parsed_tbs_cert, nullptr)) - return false; - - if (!GetCommonName(parsed_tbs_cert.subject_tlv, subject)) - return false; - - if (!GetCommonName(parsed_tbs_cert.issuer_tlv, issuer)) - return false; - - if (!DecodeTime(parsed_tbs_cert.validity_not_before, not_before)) - return false; - - if (!DecodeTime(parsed_tbs_cert.validity_not_after, not_after)) - return false; - - if (!parsed_tbs_cert.has_extensions) - return true; - - std::map<der::Input, ParsedExtension> extensions; - if (!ParseExtensions(parsed_tbs_cert.extensions_tlv, &extensions)) - return false; - - CertErrors unused_errors; - std::vector<std::string> san; - auto iter = extensions.find(SubjectAltNameOid()); - if (iter != extensions.end()) { - std::unique_ptr<GeneralNames> subject_alt_names = - GeneralNames::Create(iter->second.value, &unused_errors); - if (subject_alt_names) { - for (const auto& dns_name : subject_alt_names->dns_names) - dns_names->push_back(dns_name.as_string()); - for (const auto& ip : subject_alt_names->ip_addresses) - ip_addresses->push_back(ip.ToString()); - } - } - - return true; -} - CRYPTO_BUFFER_POOL* GetBufferPool() { return g_buffer_pool_singleton.Get().pool(); } @@ -393,6 +310,20 @@ bssl::UniquePtr<CRYPTO_BUFFER> CreateCryptoBuffer( data.size(), GetBufferPool())); } +bssl::UniquePtr<CRYPTO_BUFFER> DupCryptoBuffer(CRYPTO_BUFFER* buffer) { + CRYPTO_BUFFER_up_ref(buffer); + return bssl::UniquePtr<CRYPTO_BUFFER>(buffer); +} + +bool CryptoBufferEqual(const CRYPTO_BUFFER* a, const CRYPTO_BUFFER* b) { + DCHECK(a && b); + if (a == b) + return true; + return CRYPTO_BUFFER_len(a) == CRYPTO_BUFFER_len(b) && + memcmp(CRYPTO_BUFFER_data(a), CRYPTO_BUFFER_data(b), + CRYPTO_BUFFER_len(a)) == 0; +} + base::StringPiece CryptoBufferAsStringPiece(const CRYPTO_BUFFER* buffer) { return base::StringPiece( reinterpret_cast<const char*>(CRYPTO_BUFFER_data(buffer)), @@ -406,11 +337,14 @@ scoped_refptr<X509Certificate> CreateX509CertificateFromBuffers( return nullptr; } - std::vector<CRYPTO_BUFFER*> intermediate_chain; - for (size_t i = 1; i < sk_CRYPTO_BUFFER_num(buffers); ++i) - intermediate_chain.push_back(sk_CRYPTO_BUFFER_value(buffers, i)); - return X509Certificate::CreateFromHandle(sk_CRYPTO_BUFFER_value(buffers, 0), - intermediate_chain); + std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediate_chain; + for (size_t i = 1; i < sk_CRYPTO_BUFFER_num(buffers); ++i) { + intermediate_chain.push_back( + DupCryptoBuffer(sk_CRYPTO_BUFFER_value(buffers, i))); + } + return X509Certificate::CreateFromBuffer( + DupCryptoBuffer(sk_CRYPTO_BUFFER_value(buffers, 0)), + std::move(intermediate_chain)); } ParseCertificateOptions DefaultParseCertificateOptions() { diff --git a/chromium/net/cert/x509_util.h b/chromium/net/cert/x509_util.h index c75059ad5d2..6f0b8b215b0 100644 --- a/chromium/net/cert/x509_util.h +++ b/chromium/net/cert/x509_util.h @@ -74,17 +74,6 @@ NET_EXPORT bool CreateSelfSignedCert(crypto::RSAPrivateKey* key, base::Time not_valid_after, std::string* der_cert); -// Provides a method to parse a DER-encoded X509 certificate without calling any -// OS primitives. This is useful in sandboxed processes. -NET_EXPORT bool ParseCertificateSandboxed( - const base::StringPiece& certificate, - std::string* subject, - std::string* issuer, - base::Time* not_before, - base::Time* not_after, - std::vector<std::string>* dns_names, - std::vector<std::string>* ip_addresses); - // Returns a CRYPTO_BUFFER_POOL for deduplicating certificates. NET_EXPORT CRYPTO_BUFFER_POOL* GetBufferPool(); @@ -102,6 +91,15 @@ NET_EXPORT bssl::UniquePtr<CRYPTO_BUFFER> CreateCryptoBuffer( NET_EXPORT bssl::UniquePtr<CRYPTO_BUFFER> CreateCryptoBuffer( const char* invalid_data); +// Increments the reference count of |buffer| and returns a UniquePtr owning +// that reference. +NET_EXPORT bssl::UniquePtr<CRYPTO_BUFFER> DupCryptoBuffer( + CRYPTO_BUFFER* buffer); + +// Compares two CRYPTO_BUFFERs and returns true if they have the same contents. +NET_EXPORT bool CryptoBufferEqual(const CRYPTO_BUFFER* a, + const CRYPTO_BUFFER* b); + // Returns a StringPiece pointing to the data in |buffer|. NET_EXPORT base::StringPiece CryptoBufferAsStringPiece( const CRYPTO_BUFFER* buffer); diff --git a/chromium/net/cert/x509_util_android.cc b/chromium/net/cert/x509_util_android.cc index 8da297b03c7..8ee18742066 100644 --- a/chromium/net/cert/x509_util_android.cc +++ b/chromium/net/cert/x509_util_android.cc @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "base/android/build_info.h" -#include "base/metrics/histogram_macros.h" #include "jni/X509Util_jni.h" #include "net/cert/cert_database.h" @@ -16,16 +14,4 @@ void JNI_X509Util_NotifyKeyChainChanged(JNIEnv* env, CertDatabase::GetInstance()->OnAndroidKeyChainChanged(); } -void JNI_X509Util_RecordCertVerifyCapabilitiesHistogram( - JNIEnv* env, - const JavaParamRef<jclass>& clazz, - jboolean found_system_trust_roots) { - // Only record the histogram for 4.2 and up. Before 4.2, the platform doesn't - // return the certificate chain anyway. - if (base::android::BuildInfo::GetInstance()->sdk_int() >= 17) { - UMA_HISTOGRAM_BOOLEAN("Net.FoundSystemTrustRootsAndroid", - found_system_trust_roots); - } -} - } // namespace net diff --git a/chromium/net/cert/x509_util_ios.cc b/chromium/net/cert/x509_util_ios.cc index 26c4354d166..0ae1e779f28 100644 --- a/chromium/net/cert/x509_util_ios.cc +++ b/chromium/net/cert/x509_util_ios.cc @@ -26,9 +26,8 @@ base::ScopedCFTypeRef<SecCertificateRef> CreateSecCertificateFromBytes( base::ScopedCFTypeRef<SecCertificateRef> CreateSecCertificateFromX509Certificate(const X509Certificate* cert) { - return CreateSecCertificateFromBytes( - CRYPTO_BUFFER_data(cert->os_cert_handle()), - CRYPTO_BUFFER_len(cert->os_cert_handle())); + return CreateSecCertificateFromBytes(CRYPTO_BUFFER_data(cert->cert_buffer()), + CRYPTO_BUFFER_len(cert->cert_buffer())); } scoped_refptr<X509Certificate> CreateX509CertificateFromSecCertificate( @@ -40,13 +39,12 @@ scoped_refptr<X509Certificate> CreateX509CertificateFromSecCertificate( if (!der_data) return nullptr; bssl::UniquePtr<CRYPTO_BUFFER> cert_handle( - X509Certificate::CreateOSCertHandleFromBytes( + X509Certificate::CreateCertBufferFromBytes( reinterpret_cast<const char*>(CFDataGetBytePtr(der_data)), CFDataGetLength(der_data))); if (!cert_handle) return nullptr; std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates; - X509Certificate::OSCertHandles intermediates_raw; for (const SecCertificateRef& sec_intermediate : sec_chain) { if (!sec_intermediate) return nullptr; @@ -54,16 +52,15 @@ scoped_refptr<X509Certificate> CreateX509CertificateFromSecCertificate( if (!der_data) return nullptr; bssl::UniquePtr<CRYPTO_BUFFER> intermediate_cert_handle( - X509Certificate::CreateOSCertHandleFromBytes( + X509Certificate::CreateCertBufferFromBytes( reinterpret_cast<const char*>(CFDataGetBytePtr(der_data)), CFDataGetLength(der_data))); if (!intermediate_cert_handle) return nullptr; - intermediates_raw.push_back(intermediate_cert_handle.get()); intermediates.push_back(std::move(intermediate_cert_handle)); } - scoped_refptr<X509Certificate> result( - X509Certificate::CreateFromHandle(cert_handle.get(), intermediates_raw)); + scoped_refptr<X509Certificate> result(X509Certificate::CreateFromBuffer( + std::move(cert_handle), std::move(intermediates))); return result; } diff --git a/chromium/net/cert/x509_util_ios_and_mac.cc b/chromium/net/cert/x509_util_ios_and_mac.cc index 0659e43871d..8e41cd87cd0 100644 --- a/chromium/net/cert/x509_util_ios_and_mac.cc +++ b/chromium/net/cert/x509_util_ios_and_mac.cc @@ -32,16 +32,15 @@ CreateSecCertificateArrayForX509Certificate( return base::ScopedCFTypeRef<CFMutableArrayRef>(); std::string bytes; base::ScopedCFTypeRef<SecCertificateRef> sec_cert( - CreateSecCertificateFromBytes(CRYPTO_BUFFER_data(cert->os_cert_handle()), - CRYPTO_BUFFER_len(cert->os_cert_handle()))); + CreateSecCertificateFromBytes(CRYPTO_BUFFER_data(cert->cert_buffer()), + CRYPTO_BUFFER_len(cert->cert_buffer()))); if (!sec_cert) return base::ScopedCFTypeRef<CFMutableArrayRef>(); CFArrayAppendValue(cert_list, sec_cert); - for (X509Certificate::OSCertHandle intermediate : - cert->GetIntermediateCertificates()) { + for (const auto& intermediate : cert->intermediate_buffers()) { base::ScopedCFTypeRef<SecCertificateRef> sec_cert( - CreateSecCertificateFromBytes(CRYPTO_BUFFER_data(intermediate), - CRYPTO_BUFFER_len(intermediate))); + CreateSecCertificateFromBytes(CRYPTO_BUFFER_data(intermediate.get()), + CRYPTO_BUFFER_len(intermediate.get()))); if (!sec_cert) { if (invalid_intermediate_behavior == InvalidIntermediateBehavior::kFail) return base::ScopedCFTypeRef<CFMutableArrayRef>(); diff --git a/chromium/net/cert/x509_util_ios_and_mac_unittest.cc b/chromium/net/cert/x509_util_ios_and_mac_unittest.cc index 5b2eae18c34..d2e6883b1c6 100644 --- a/chromium/net/cert/x509_util_ios_and_mac_unittest.cc +++ b/chromium/net/cert/x509_util_ios_and_mac_unittest.cc @@ -39,17 +39,6 @@ std::string BytesForSecCert(const void* sec_cert) { reinterpret_cast<SecCertificateRef>(const_cast<void*>(sec_cert))); } -std::string BytesForX509CertHandle(X509Certificate::OSCertHandle handle) { - std::string result; - if (!X509Certificate::GetDEREncoded(handle, &result)) - ADD_FAILURE(); - return result; -} - -std::string BytesForX509Cert(X509Certificate* cert) { - return BytesForX509CertHandle(cert->os_cert_handle()); -} - } // namespace TEST(X509UtilTest, CreateSecCertificateArrayForX509Certificate) { @@ -57,7 +46,7 @@ TEST(X509UtilTest, CreateSecCertificateArrayForX509Certificate) { GetTestCertsDirectory(), "multi-root-chain1.pem", X509Certificate::FORMAT_PEM_CERT_SEQUENCE); ASSERT_TRUE(cert); - EXPECT_EQ(3U, cert->GetIntermediateCertificates().size()); + EXPECT_EQ(3U, cert->intermediate_buffers().size()); base::ScopedCFTypeRef<CFMutableArrayRef> sec_certs( CreateSecCertificateArrayForX509Certificate(cert.get())); @@ -66,13 +55,16 @@ TEST(X509UtilTest, CreateSecCertificateArrayForX509Certificate) { for (int i = 0; i < 4; ++i) ASSERT_TRUE(CFArrayGetValueAtIndex(sec_certs.get(), i)); - EXPECT_EQ(BytesForX509Cert(cert.get()), + EXPECT_EQ(x509_util::CryptoBufferAsStringPiece(cert->cert_buffer()), BytesForSecCert(CFArrayGetValueAtIndex(sec_certs.get(), 0))); - EXPECT_EQ(BytesForX509CertHandle(cert->GetIntermediateCertificates()[0]), + EXPECT_EQ(x509_util::CryptoBufferAsStringPiece( + cert->intermediate_buffers()[0].get()), BytesForSecCert(CFArrayGetValueAtIndex(sec_certs.get(), 1))); - EXPECT_EQ(BytesForX509CertHandle(cert->GetIntermediateCertificates()[1]), + EXPECT_EQ(x509_util::CryptoBufferAsStringPiece( + cert->intermediate_buffers()[1].get()), BytesForSecCert(CFArrayGetValueAtIndex(sec_certs.get(), 2))); - EXPECT_EQ(BytesForX509CertHandle(cert->GetIntermediateCertificates()[2]), + EXPECT_EQ(x509_util::CryptoBufferAsStringPiece( + cert->intermediate_buffers()[2].get()), BytesForSecCert(CFArrayGetValueAtIndex(sec_certs.get(), 3))); } @@ -89,12 +81,15 @@ TEST(X509UtilTest, CreateSecCertificateArrayForX509CertificateErrors) { ImportCertFromFile(GetTestCertsDirectory(), "root_ca_cert.pem")); ASSERT_TRUE(ok_cert); + std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates; + intermediates.push_back(std::move(bad_cert)); + intermediates.push_back(x509_util::DupCryptoBuffer(ok_cert2->cert_buffer())); scoped_refptr<X509Certificate> cert_with_intermediates( - X509Certificate::CreateFromHandle( - ok_cert->os_cert_handle(), - {bad_cert.get(), ok_cert2->os_cert_handle()})); + X509Certificate::CreateFromBuffer( + x509_util::DupCryptoBuffer(ok_cert->cert_buffer()), + std::move(intermediates))); ASSERT_TRUE(cert_with_intermediates); - EXPECT_EQ(2U, cert_with_intermediates->GetIntermediateCertificates().size()); + EXPECT_EQ(2U, cert_with_intermediates->intermediate_buffers().size()); // Normal CreateSecCertificateArrayForX509Certificate fails with invalid // certs in chain. @@ -111,9 +106,9 @@ TEST(X509UtilTest, CreateSecCertificateArrayForX509CertificateErrors) { for (int i = 0; i < 2; ++i) ASSERT_TRUE(CFArrayGetValueAtIndex(sec_certs.get(), i)); - EXPECT_EQ(BytesForX509Cert(ok_cert.get()), + EXPECT_EQ(x509_util::CryptoBufferAsStringPiece(ok_cert->cert_buffer()), BytesForSecCert(CFArrayGetValueAtIndex(sec_certs.get(), 0))); - EXPECT_EQ(BytesForX509Cert(ok_cert2.get()), + EXPECT_EQ(x509_util::CryptoBufferAsStringPiece(ok_cert2->cert_buffer()), BytesForSecCert(CFArrayGetValueAtIndex(sec_certs.get(), 1))); } @@ -124,10 +119,14 @@ TEST(X509UtilTest, X509Certificate::FORMAT_PEM_CERT_SEQUENCE); ASSERT_EQ(4u, certs.size()); - std::string bytes_cert0 = BytesForX509CertHandle(certs[0]->os_cert_handle()); - std::string bytes_cert1 = BytesForX509CertHandle(certs[1]->os_cert_handle()); - std::string bytes_cert2 = BytesForX509CertHandle(certs[2]->os_cert_handle()); - std::string bytes_cert3 = BytesForX509CertHandle(certs[3]->os_cert_handle()); + std::string bytes_cert0( + x509_util::CryptoBufferAsStringPiece(certs[0]->cert_buffer())); + std::string bytes_cert1( + x509_util::CryptoBufferAsStringPiece(certs[1]->cert_buffer())); + std::string bytes_cert2( + x509_util::CryptoBufferAsStringPiece(certs[2]->cert_buffer())); + std::string bytes_cert3( + x509_util::CryptoBufferAsStringPiece(certs[3]->cert_buffer())); base::ScopedCFTypeRef<SecCertificateRef> sec_cert0( CreateSecCertificateFromBytes( @@ -156,37 +155,34 @@ TEST(X509UtilTest, scoped_refptr<X509Certificate> x509_cert_no_intermediates = CreateX509CertificateFromSecCertificate(sec_cert0.get(), {}); ASSERT_TRUE(x509_cert_no_intermediates); - EXPECT_EQ(0U, - x509_cert_no_intermediates->GetIntermediateCertificates().size()); - EXPECT_EQ(bytes_cert0, BytesForX509CertHandle( - x509_cert_no_intermediates->os_cert_handle())); + EXPECT_EQ(0U, x509_cert_no_intermediates->intermediate_buffers().size()); + EXPECT_EQ(bytes_cert0, x509_util::CryptoBufferAsStringPiece( + x509_cert_no_intermediates->cert_buffer())); scoped_refptr<X509Certificate> x509_cert_one_intermediate = CreateX509CertificateFromSecCertificate(sec_cert0.get(), {sec_cert1.get()}); ASSERT_TRUE(x509_cert_one_intermediate); - EXPECT_EQ(bytes_cert0, BytesForX509CertHandle( - x509_cert_one_intermediate->os_cert_handle())); - ASSERT_EQ(1U, - x509_cert_one_intermediate->GetIntermediateCertificates().size()); + EXPECT_EQ(bytes_cert0, x509_util::CryptoBufferAsStringPiece( + x509_cert_one_intermediate->cert_buffer())); + ASSERT_EQ(1U, x509_cert_one_intermediate->intermediate_buffers().size()); EXPECT_EQ(bytes_cert1, - BytesForX509CertHandle( - x509_cert_one_intermediate->GetIntermediateCertificates()[0])); + x509_util::CryptoBufferAsStringPiece( + x509_cert_one_intermediate->intermediate_buffers()[0].get())); scoped_refptr<X509Certificate> x509_cert_two_intermediates = CreateX509CertificateFromSecCertificate( sec_cert0.get(), {sec_cert1.get(), sec_cert2.get()}); ASSERT_TRUE(x509_cert_two_intermediates); - EXPECT_EQ(bytes_cert0, BytesForX509CertHandle( - x509_cert_two_intermediates->os_cert_handle())); - ASSERT_EQ(2U, - x509_cert_two_intermediates->GetIntermediateCertificates().size()); + EXPECT_EQ(bytes_cert0, x509_util::CryptoBufferAsStringPiece( + x509_cert_two_intermediates->cert_buffer())); + ASSERT_EQ(2U, x509_cert_two_intermediates->intermediate_buffers().size()); EXPECT_EQ(bytes_cert1, - BytesForX509CertHandle( - x509_cert_two_intermediates->GetIntermediateCertificates()[0])); + x509_util::CryptoBufferAsStringPiece( + x509_cert_two_intermediates->intermediate_buffers()[0].get())); EXPECT_EQ(bytes_cert2, - BytesForX509CertHandle( - x509_cert_two_intermediates->GetIntermediateCertificates()[1])); + x509_util::CryptoBufferAsStringPiece( + x509_cert_two_intermediates->intermediate_buffers()[1].get())); } } // namespace x509_util diff --git a/chromium/net/cert/x509_util_mac.cc b/chromium/net/cert/x509_util_mac.cc index 51c5a19d2d8..5285c4bcd4a 100644 --- a/chromium/net/cert/x509_util_mac.cc +++ b/chromium/net/cert/x509_util_mac.cc @@ -80,9 +80,8 @@ base::ScopedCFTypeRef<SecCertificateRef> CreateSecCertificateFromBytes( base::ScopedCFTypeRef<SecCertificateRef> CreateSecCertificateFromX509Certificate(const X509Certificate* cert) { - return CreateSecCertificateFromBytes( - CRYPTO_BUFFER_data(cert->os_cert_handle()), - CRYPTO_BUFFER_len(cert->os_cert_handle())); + return CreateSecCertificateFromBytes(CRYPTO_BUFFER_data(cert->cert_buffer()), + CRYPTO_BUFFER_len(cert->cert_buffer())); } scoped_refptr<X509Certificate> CreateX509CertificateFromSecCertificate( @@ -99,28 +98,26 @@ scoped_refptr<X509Certificate> CreateX509CertificateFromSecCertificate( if (!sec_cert || SecCertificateGetData(sec_cert, &der_data) != noErr) return nullptr; bssl::UniquePtr<CRYPTO_BUFFER> cert_handle( - X509Certificate::CreateOSCertHandleFromBytes( + X509Certificate::CreateCertBufferFromBytes( reinterpret_cast<const char*>(der_data.Data), der_data.Length)); if (!cert_handle) return nullptr; std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates; - X509Certificate::OSCertHandles intermediates_raw; for (const SecCertificateRef& sec_intermediate : sec_chain) { if (!sec_intermediate || SecCertificateGetData(sec_intermediate, &der_data) != noErr) { return nullptr; } bssl::UniquePtr<CRYPTO_BUFFER> intermediate_cert_handle( - X509Certificate::CreateOSCertHandleFromBytes( + X509Certificate::CreateCertBufferFromBytes( reinterpret_cast<const char*>(der_data.Data), der_data.Length)); if (!intermediate_cert_handle) return nullptr; - intermediates_raw.push_back(intermediate_cert_handle.get()); intermediates.push_back(std::move(intermediate_cert_handle)); } scoped_refptr<X509Certificate> result( - X509Certificate::CreateFromHandleUnsafeOptions( - cert_handle.get(), intermediates_raw, options)); + X509Certificate::CreateFromBufferUnsafeOptions( + std::move(cert_handle), std::move(intermediates), options)); return result; } diff --git a/chromium/net/cert/x509_util_nss.cc b/chromium/net/cert/x509_util_nss.cc index 33f39d2a461..9ba26e3b967 100644 --- a/chromium/net/cert/x509_util_nss.cc +++ b/chromium/net/cert/x509_util_nss.cc @@ -142,8 +142,8 @@ bool IsSameCertificate(CERTCertificate* a, CERTCertificate* b) { } bool IsSameCertificate(CERTCertificate* a, const X509Certificate* b) { - return a->derCert.len == CRYPTO_BUFFER_len(b->os_cert_handle()) && - memcmp(a->derCert.data, CRYPTO_BUFFER_data(b->os_cert_handle()), + return a->derCert.len == CRYPTO_BUFFER_len(b->cert_buffer()) && + memcmp(a->derCert.data, CRYPTO_BUFFER_data(b->cert_buffer()), a->derCert.len) == 0; } bool IsSameCertificate(const X509Certificate* a, CERTCertificate* b) { @@ -170,9 +170,8 @@ ScopedCERTCertificate CreateCERTCertificateFromBytes(const uint8_t* data, ScopedCERTCertificate CreateCERTCertificateFromX509Certificate( const X509Certificate* cert) { - return CreateCERTCertificateFromBytes( - CRYPTO_BUFFER_data(cert->os_cert_handle()), - CRYPTO_BUFFER_len(cert->os_cert_handle())); + return CreateCERTCertificateFromBytes(CRYPTO_BUFFER_data(cert->cert_buffer()), + CRYPTO_BUFFER_len(cert->cert_buffer())); } ScopedCERTCertificateList CreateCERTCertificateListFromX509Certificate( @@ -185,16 +184,16 @@ ScopedCERTCertificateList CreateCERTCertificateListFromX509Certificate( const X509Certificate* cert, InvalidIntermediateBehavior invalid_intermediate_behavior) { ScopedCERTCertificateList nss_chain; - nss_chain.reserve(1 + cert->GetIntermediateCertificates().size()); + nss_chain.reserve(1 + cert->intermediate_buffers().size()); ScopedCERTCertificate nss_cert = CreateCERTCertificateFromX509Certificate(cert); if (!nss_cert) return {}; nss_chain.push_back(std::move(nss_cert)); - for (net::X509Certificate::OSCertHandle intermediate : - cert->GetIntermediateCertificates()) { - ScopedCERTCertificate nss_intermediate = CreateCERTCertificateFromBytes( - CRYPTO_BUFFER_data(intermediate), CRYPTO_BUFFER_len(intermediate)); + for (const auto& intermediate : cert->intermediate_buffers()) { + ScopedCERTCertificate nss_intermediate = + CreateCERTCertificateFromBytes(CRYPTO_BUFFER_data(intermediate.get()), + CRYPTO_BUFFER_len(intermediate.get())); if (!nss_intermediate) { if (invalid_intermediate_behavior == InvalidIntermediateBehavior::kFail) return {}; @@ -249,7 +248,7 @@ scoped_refptr<X509Certificate> CreateX509CertificateFromCERTCertificate( if (!nss_cert || !nss_cert->derCert.len) return nullptr; bssl::UniquePtr<CRYPTO_BUFFER> cert_handle( - X509Certificate::CreateOSCertHandleFromBytes( + X509Certificate::CreateCertBufferFromBytes( reinterpret_cast<const char*>(nss_cert->derCert.data), nss_cert->derCert.len)); if (!cert_handle) @@ -257,23 +256,20 @@ scoped_refptr<X509Certificate> CreateX509CertificateFromCERTCertificate( std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates; intermediates.reserve(nss_chain.size()); - X509Certificate::OSCertHandles intermediates_raw; - intermediates_raw.reserve(nss_chain.size()); for (const CERTCertificate* nss_intermediate : nss_chain) { if (!nss_intermediate || !nss_intermediate->derCert.len) return nullptr; bssl::UniquePtr<CRYPTO_BUFFER> intermediate_cert_handle( - X509Certificate::CreateOSCertHandleFromBytes( + X509Certificate::CreateCertBufferFromBytes( reinterpret_cast<const char*>(nss_intermediate->derCert.data), nss_intermediate->derCert.len)); if (!intermediate_cert_handle) return nullptr; - intermediates_raw.push_back(intermediate_cert_handle.get()); intermediates.push_back(std::move(intermediate_cert_handle)); } scoped_refptr<X509Certificate> result( - X509Certificate::CreateFromHandleUnsafeOptions( - cert_handle.get(), intermediates_raw, options)); + X509Certificate::CreateFromBufferUnsafeOptions( + std::move(cert_handle), std::move(intermediates), options)); return result; } diff --git a/chromium/net/cert/x509_util_nss_unittest.cc b/chromium/net/cert/x509_util_nss_unittest.cc index d9b9a70072b..fb671259a38 100644 --- a/chromium/net/cert/x509_util_nss_unittest.cc +++ b/chromium/net/cert/x509_util_nss_unittest.cc @@ -25,17 +25,6 @@ std::string BytesForNSSCert(CERTCertificate* cert) { return der_encoded; } -std::string BytesForX509CertHandle(X509Certificate::OSCertHandle handle) { - std::string result; - if (!X509Certificate::GetDEREncoded(handle, &result)) - ADD_FAILURE(); - return result; -} - -std::string BytesForX509Cert(X509Certificate* cert) { - return BytesForX509CertHandle(cert->os_cert_handle()); -} - } // namespace TEST(X509UtilNSSTest, IsSameCertificate) { @@ -121,7 +110,7 @@ TEST(X509UtilNSSTest, CreateCERTCertificateListFromX509Certificate) { GetTestCertsDirectory(), "multi-root-chain1.pem", X509Certificate::FORMAT_PEM_CERT_SEQUENCE); ASSERT_TRUE(x509_cert); - EXPECT_EQ(3U, x509_cert->GetIntermediateCertificates().size()); + EXPECT_EQ(3U, x509_cert->intermediate_buffers().size()); ScopedCERTCertificateList nss_certs = x509_util::CreateCERTCertificateListFromX509Certificate(x509_cert.get()); @@ -129,13 +118,16 @@ TEST(X509UtilNSSTest, CreateCERTCertificateListFromX509Certificate) { for (int i = 0; i < 4; ++i) ASSERT_TRUE(nss_certs[i]); - EXPECT_EQ(BytesForX509Cert(x509_cert.get()), + EXPECT_EQ(x509_util::CryptoBufferAsStringPiece(x509_cert->cert_buffer()), BytesForNSSCert(nss_certs[0].get())); - EXPECT_EQ(BytesForX509CertHandle(x509_cert->GetIntermediateCertificates()[0]), + EXPECT_EQ(x509_util::CryptoBufferAsStringPiece( + x509_cert->intermediate_buffers()[0].get()), BytesForNSSCert(nss_certs[1].get())); - EXPECT_EQ(BytesForX509CertHandle(x509_cert->GetIntermediateCertificates()[1]), + EXPECT_EQ(x509_util::CryptoBufferAsStringPiece( + x509_cert->intermediate_buffers()[1].get()), BytesForNSSCert(nss_certs[2].get())); - EXPECT_EQ(BytesForX509CertHandle(x509_cert->GetIntermediateCertificates()[2]), + EXPECT_EQ(x509_util::CryptoBufferAsStringPiece( + x509_cert->intermediate_buffers()[2].get()), BytesForNSSCert(nss_certs[3].get())); } @@ -152,12 +144,15 @@ TEST(X509UtilTest, CreateCERTCertificateListFromX509CertificateErrors) { ImportCertFromFile(GetTestCertsDirectory(), "root_ca_cert.pem")); ASSERT_TRUE(ok_cert); + std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates; + intermediates.push_back(std::move(bad_cert)); + intermediates.push_back(x509_util::DupCryptoBuffer(ok_cert2->cert_buffer())); scoped_refptr<X509Certificate> cert_with_intermediates( - X509Certificate::CreateFromHandle( - ok_cert->os_cert_handle(), - {bad_cert.get(), ok_cert2->os_cert_handle()})); + X509Certificate::CreateFromBuffer( + x509_util::DupCryptoBuffer(ok_cert->cert_buffer()), + std::move(intermediates))); ASSERT_TRUE(cert_with_intermediates); - EXPECT_EQ(2U, cert_with_intermediates->GetIntermediateCertificates().size()); + EXPECT_EQ(2U, cert_with_intermediates->intermediate_buffers().size()); // Normal CreateCERTCertificateListFromX509Certificate fails with invalid // certs in chain. @@ -175,9 +170,9 @@ TEST(X509UtilTest, CreateCERTCertificateListFromX509CertificateErrors) { for (const auto& nss_cert : nss_certs) ASSERT_TRUE(nss_cert.get()); - EXPECT_EQ(BytesForX509Cert(ok_cert.get()), + EXPECT_EQ(x509_util::CryptoBufferAsStringPiece(ok_cert->cert_buffer()), BytesForNSSCert(nss_certs[0].get())); - EXPECT_EQ(BytesForX509Cert(ok_cert2.get()), + EXPECT_EQ(x509_util::CryptoBufferAsStringPiece(ok_cert2->cert_buffer()), BytesForNSSCert(nss_certs[1].get())); } @@ -254,8 +249,9 @@ TEST(X509UtilNSSTest, CreateX509CertificateFromCERTCertificate_NoChain) { ASSERT_TRUE(nss_cert); scoped_refptr<X509Certificate> x509_cert = x509_util::CreateX509CertificateFromCERTCertificate(nss_cert.get()); - EXPECT_EQ(BytesForNSSCert(nss_cert.get()), BytesForX509Cert(x509_cert.get())); - EXPECT_TRUE(x509_cert->GetIntermediateCertificates().empty()); + EXPECT_EQ(BytesForNSSCert(nss_cert.get()), + x509_util::CryptoBufferAsStringPiece(x509_cert->cert_buffer())); + EXPECT_TRUE(x509_cert->intermediate_buffers().empty()); } TEST(X509UtilNSSTest, CreateX509CertificateFromCERTCertificate_EmptyChain) { @@ -265,8 +261,9 @@ TEST(X509UtilNSSTest, CreateX509CertificateFromCERTCertificate_EmptyChain) { scoped_refptr<X509Certificate> x509_cert = x509_util::CreateX509CertificateFromCERTCertificate( nss_cert.get(), std::vector<CERTCertificate*>()); - EXPECT_EQ(BytesForNSSCert(nss_cert.get()), BytesForX509Cert(x509_cert.get())); - EXPECT_TRUE(x509_cert->GetIntermediateCertificates().empty()); + EXPECT_EQ(BytesForNSSCert(nss_cert.get()), + x509_util::CryptoBufferAsStringPiece(x509_cert->cert_buffer())); + EXPECT_TRUE(x509_cert->intermediate_buffers().empty()); } TEST(X509UtilNSSTest, CreateX509CertificateFromCERTCertificate_WithChain) { @@ -283,9 +280,11 @@ TEST(X509UtilNSSTest, CreateX509CertificateFromCERTCertificate_WithChain) { scoped_refptr<X509Certificate> x509_cert = x509_util::CreateX509CertificateFromCERTCertificate(nss_cert.get(), chain); - EXPECT_EQ(BytesForNSSCert(nss_cert.get()), BytesForX509Cert(x509_cert.get())); - ASSERT_EQ(1U, x509_cert->GetIntermediateCertificates().size()); - EXPECT_EQ(BytesForX509CertHandle(x509_cert->GetIntermediateCertificates()[0]), + EXPECT_EQ(BytesForNSSCert(nss_cert.get()), + x509_util::CryptoBufferAsStringPiece(x509_cert->cert_buffer())); + ASSERT_EQ(1U, x509_cert->intermediate_buffers().size()); + EXPECT_EQ(x509_util::CryptoBufferAsStringPiece( + x509_cert->intermediate_buffers()[0].get()), BytesForNSSCert(nss_cert2.get())); } @@ -305,9 +304,9 @@ TEST(X509UtilNSSTest, CreateX509CertificateListFromCERTCertificates) { ASSERT_EQ(2U, x509_certs.size()); EXPECT_EQ(BytesForNSSCert(nss_certs[0].get()), - BytesForX509Cert(x509_certs[0].get())); + x509_util::CryptoBufferAsStringPiece(x509_certs[0]->cert_buffer())); EXPECT_EQ(BytesForNSSCert(nss_certs[1].get()), - BytesForX509Cert(x509_certs[1].get())); + x509_util::CryptoBufferAsStringPiece(x509_certs[1]->cert_buffer())); } TEST(X509UtilNSSTest, CreateX509CertificateListFromCERTCertificates_EmptyList) { diff --git a/chromium/net/cert/x509_util_win.cc b/chromium/net/cert/x509_util_win.cc index 09d94576cb5..9def51f963a 100644 --- a/chromium/net/cert/x509_util_win.cc +++ b/chromium/net/cert/x509_util_win.cc @@ -35,29 +35,27 @@ scoped_refptr<X509Certificate> CreateX509CertificateFromCertContexts( if (!os_cert || !os_cert->pbCertEncoded || !os_cert->cbCertEncoded) return nullptr; bssl::UniquePtr<CRYPTO_BUFFER> cert_handle( - X509Certificate::CreateOSCertHandleFromBytes( + X509Certificate::CreateCertBufferFromBytes( reinterpret_cast<const char*>(os_cert->pbCertEncoded), os_cert->cbCertEncoded)); if (!cert_handle) return nullptr; std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates; - X509Certificate::OSCertHandles intermediates_raw; for (PCCERT_CONTEXT os_intermediate : os_chain) { if (!os_intermediate || !os_intermediate->pbCertEncoded || !os_intermediate->cbCertEncoded) return nullptr; bssl::UniquePtr<CRYPTO_BUFFER> intermediate_cert_handle( - X509Certificate::CreateOSCertHandleFromBytes( + X509Certificate::CreateCertBufferFromBytes( reinterpret_cast<const char*>(os_intermediate->pbCertEncoded), os_intermediate->cbCertEncoded)); if (!intermediate_cert_handle) return nullptr; - intermediates_raw.push_back(intermediate_cert_handle.get()); intermediates.push_back(std::move(intermediate_cert_handle)); } scoped_refptr<X509Certificate> result( - X509Certificate::CreateFromHandleUnsafeOptions( - cert_handle.get(), intermediates_raw, options)); + X509Certificate::CreateFromBufferUnsafeOptions( + std::move(cert_handle), std::move(intermediates), options)); return result; } @@ -80,19 +78,17 @@ ScopedPCCERT_CONTEXT CreateCertContextWithChain( PCCERT_CONTEXT primary_cert = nullptr; BOOL ok = CertAddEncodedCertificateToStore( - store.get(), X509_ASN_ENCODING, - CRYPTO_BUFFER_data(cert->os_cert_handle()), - base::checked_cast<DWORD>(CRYPTO_BUFFER_len(cert->os_cert_handle())), + store.get(), X509_ASN_ENCODING, CRYPTO_BUFFER_data(cert->cert_buffer()), + base::checked_cast<DWORD>(CRYPTO_BUFFER_len(cert->cert_buffer())), CERT_STORE_ADD_ALWAYS, &primary_cert); if (!ok || !primary_cert) return nullptr; ScopedPCCERT_CONTEXT scoped_primary_cert(primary_cert); - for (X509Certificate::OSCertHandle intermediate : - cert->GetIntermediateCertificates()) { + for (const auto& intermediate : cert->intermediate_buffers()) { ok = CertAddEncodedCertificateToStore( - store.get(), X509_ASN_ENCODING, CRYPTO_BUFFER_data(intermediate), - base::checked_cast<DWORD>(CRYPTO_BUFFER_len(intermediate)), + store.get(), X509_ASN_ENCODING, CRYPTO_BUFFER_data(intermediate.get()), + base::checked_cast<DWORD>(CRYPTO_BUFFER_len(intermediate.get())), CERT_STORE_ADD_ALWAYS, NULL); if (!ok) { if (invalid_intermediate_behavior == InvalidIntermediateBehavior::kFail) diff --git a/chromium/net/cookies/cookie_monster_unittest.cc b/chromium/net/cookies/cookie_monster_unittest.cc index da851febcf5..5d45b3014b2 100644 --- a/chromium/net/cookies/cookie_monster_unittest.cc +++ b/chromium/net/cookies/cookie_monster_unittest.cc @@ -1988,7 +1988,6 @@ TEST_F(CookieMonsterTest, BackingStoreCommunication) { base::Time current(base::Time::Now()); scoped_refptr<MockSimplePersistentCookieStore> store( new MockSimplePersistentCookieStore); - base::Time new_access_time; base::Time expires(base::Time::Now() + base::TimeDelta::FromSeconds(100)); const CookiesInputInfo input_info[] = { diff --git a/chromium/net/data/gencerts/__init__.py b/chromium/net/data/gencerts/__init__.py new file mode 100755 index 00000000000..a7e82b57760 --- /dev/null +++ b/chromium/net/data/gencerts/__init__.py @@ -0,0 +1,525 @@ +#!/usr/bin/python +# Copyright (c) 2015 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. + +"""Set of helpers to generate signed X.509v3 certificates. + +This works by shelling out calls to the 'openssl req' and 'openssl ca' +commands, and passing the appropriate command line flags and configuration file +(.cnf). +""" + +import base64 +import os +import shutil +import subprocess +import sys + +import openssl_conf + +# Enum for the "type" of certificate that is to be created. This is used to +# select sane defaults for the .cnf file and command line flags, but they can +# all be overridden. +TYPE_CA = 2 +TYPE_END_ENTITY = 3 + +# March 1st, 2015 12:00 UTC +MARCH_1_2015_UTC = '150301120000Z' + +# March 2nd, 2015 12:00 UTC +MARCH_2_2015_UTC = '150302120000Z' + +# January 1st, 2015 12:00 UTC +JANUARY_1_2015_UTC = '150101120000Z' + +# September 1st, 2015 12:00 UTC +SEPTEMBER_1_2015_UTC = '150901120000Z' + +# January 1st, 2016 12:00 UTC +JANUARY_1_2016_UTC = '160101120000Z' + +# January 1st, 2021 12:00 UTC +JANUARY_1_2021_UTC = '210101120000Z' + +# The default time tests should use when verifying. +DEFAULT_TIME = MARCH_2_2015_UTC + +KEY_PURPOSE_ANY = 'anyExtendedKeyUsage' +KEY_PURPOSE_SERVER_AUTH = 'serverAuth' +KEY_PURPOSE_CLIENT_AUTH = 'clientAuth' + +DEFAULT_KEY_PURPOSE = KEY_PURPOSE_SERVER_AUTH + +# Counters used to generate unique (but readable) path names. +g_cur_path_id = {} + +# Output paths used: +# - g_tmp_dir: where any temporary files (cert req, signing db etc) are +# saved to. + +# See init() for how these are assigned. +g_tmp_dir = None + +# The default validity range of generated certificates. Can be modified with +# set_default_validity_range(). +g_default_start_date = JANUARY_1_2015_UTC +g_default_end_date = JANUARY_1_2016_UTC + + +def set_default_validity_range(start_date, end_date): + """Sets the validity range that will be used for certificates created with + Certificate""" + global g_default_start_date + global g_default_end_date + g_default_start_date = start_date + g_default_end_date = end_date + + +def get_unique_path_id(name): + """Returns a base filename that contains 'name', but is unique to the output + directory""" + # Use case-insensitive matching for counting duplicates, since some + # filesystems are case insensitive, but case preserving. + lowercase_name = name.lower() + path_id = g_cur_path_id.get(lowercase_name, 0) + g_cur_path_id[lowercase_name] = path_id + 1 + + # Use a short and clean name for the first use of this name. + if path_id == 0: + return name + + # Otherwise append the count to make it unique. + return '%s_%d' % (name, path_id) + + +def get_path_in_tmp_dir(name, suffix): + return os.path.join(g_tmp_dir, '%s%s' % (name, suffix)) + + +class Key(object): + """Describes a public + private key pair. It is a dumb wrapper around an + on-disk key.""" + + def __init__(self, path): + self.path = path + + + def get_path(self): + """Returns the path to a file that contains the key contents.""" + return self.path + + +def get_or_generate_key(generation_arguments, path): + """Helper function to either retrieve a key from an existing file |path|, or + generate a new one using the command line |generation_arguments|.""" + + generation_arguments_str = ' '.join(generation_arguments) + + # If the file doesn't already exist, generate a new key using the generation + # parameters. + if not os.path.isfile(path): + key_contents = subprocess.check_output(generation_arguments) + + # Prepend the generation parameters to the key file. + write_string_to_file(generation_arguments_str + '\n' + key_contents, + path) + else: + # If the path already exists, confirm that it is for the expected key type. + first_line = read_file_to_string(path).splitlines()[0] + if first_line != generation_arguments_str: + sys.stderr.write(('\nERROR: The existing key file:\n %s\nis not ' + 'compatible with the requested parameters:\n "%s" vs "%s".\n' + 'Delete the file if you want to re-generate it with the new ' + 'parameters, otherwise pick a new filename\n') % ( + path, first_line, generation_arguments_str)) + sys.exit(1) + + return Key(path) + + +def get_or_generate_rsa_key(size_bits, path): + """Retrieves an existing key from a file if the path exists. Otherwise + generates an RSA key with the specified bit size and saves it to the path.""" + return get_or_generate_key(['openssl', 'genrsa', str(size_bits)], path) + + +def get_or_generate_ec_key(named_curve, path): + """Retrieves an existing key from a file if the path exists. Otherwise + generates an EC key with the specified named curve and saves it to the + path.""" + return get_or_generate_key(['openssl', 'ecparam', '-name', named_curve, + '-genkey'], path) + + +def create_key_path(base_name): + """Generates a name that contains |base_name| in it, and is relative to the + "keys/" directory. If create_key_path(xxx) is called more than once during + the script run, a suffix will be added.""" + + # Save keys to CWD/keys/*.key + keys_dir = 'keys' + + # Create the keys directory if it doesn't exist + if not os.path.exists(keys_dir): + os.makedirs(keys_dir) + + return get_unique_path_id(os.path.join(keys_dir, base_name)) + '.key' + + +class Certificate(object): + """Helper for building an X.509 certificate.""" + + def __init__(self, name, cert_type, issuer): + # The name will be used for the subject's CN, and also as a component of + # the temporary filenames to help with debugging. + self.name = name + self.path_id = get_unique_path_id(name) + + # Allow the caller to override the key later. If no key was set will + # auto-generate one. + self.key = None + + # The issuer is also a Certificate object. Passing |None| means it is a + # self-signed certificate. + self.issuer = issuer + if issuer is None: + self.issuer = self + + # The config contains all the OpenSSL options that will be passed via a + # .cnf file. Set up defaults. + self.config = openssl_conf.Config() + self.init_config() + + # Some settings need to be passed as flags rather than in the .cnf file. + # Technically these can be set though a .cnf, however doing so makes it + # sticky to the issuing certificate, rather than selecting it per + # subordinate certificate. + self.validity_flags = [] + self.md_flags = [] + + # By default OpenSSL will use the current time for the start time. Instead + # default to using a fixed timestamp for more predictable results each time + # the certificates are re-generated. + self.set_validity_range(g_default_start_date, g_default_end_date) + + # Use SHA-256 when THIS certificate is signed (setting it in the + # configuration would instead set the hash to use when signing other + # certificates with this one). + self.set_signature_hash('sha256') + + # Set appropriate key usages and basic constraints. For flexibility in + # testing (since want to generate some flawed certificates) these are set + # on a per-certificate basis rather than automatically when signing. + if cert_type == TYPE_END_ENTITY: + self.get_extensions().set_property('keyUsage', + 'critical,digitalSignature,keyEncipherment') + self.get_extensions().set_property('extendedKeyUsage', + 'serverAuth,clientAuth') + else: + self.get_extensions().set_property('keyUsage', + 'critical,keyCertSign,cRLSign') + self.get_extensions().set_property('basicConstraints', 'critical,CA:true') + + # Tracks whether the PEM file for this certificate has been written (since + # generation is done lazily). + self.finalized = False + + # Initialize any files that will be needed if this certificate is used to + # sign other certificates. Starts off serial numbers at 1, and will + # increment them for each signed certificate. + if not os.path.exists(self.get_serial_path()): + write_string_to_file('01\n', self.get_serial_path()) + if not os.path.exists(self.get_database_path()): + write_string_to_file('', self.get_database_path()) + + + def set_validity_range(self, start_date, end_date): + """Sets the Validity notBefore and notAfter properties for the + certificate""" + self.validity_flags = ['-startdate', start_date, '-enddate', end_date] + + + def set_signature_hash(self, md): + """Sets the hash function that will be used when signing this certificate. + Can be sha1, sha256, sha512, md5, etc.""" + self.md_flags = ['-md', md] + + + def get_extensions(self): + return self.config.get_section('req_ext') + + + def get_path(self, suffix): + """Forms a path to an output file for this certificate, containing the + indicated suffix. The certificate's name will be used as its basis.""" + return os.path.join(g_tmp_dir, '%s%s' % (self.path_id, suffix)) + + + def get_name_path(self, suffix): + """Forms a path to an output file for this CA, containing the indicated + suffix. If multiple certificates have the same name, they will use the same + path.""" + return get_path_in_tmp_dir(self.name, suffix) + + + def set_key(self, key): + assert self.finalized is False + self.set_key_internal(key) + + + def set_key_internal(self, key): + self.key = key + + # Associate the private key with the certificate. + section = self.config.get_section('root_ca') + section.set_property('private_key', self.key.get_path()) + + + def get_key(self): + if self.key is None: + self.set_key_internal( + get_or_generate_rsa_key(2048, create_key_path(self.name))) + return self.key + + + def get_cert_path(self): + return self.get_path('.pem') + + + def get_serial_path(self): + return self.get_name_path('.serial') + + + def get_csr_path(self): + return self.get_path('.csr') + + + def get_database_path(self): + return self.get_name_path('.db') + + + def get_config_path(self): + return self.get_path('.cnf') + + + def get_cert_pem(self): + # Finish generating a .pem file for the certificate. + self.finalize() + + # Read the certificate data. + return read_file_to_string(self.get_cert_path()) + + + def finalize(self): + """Finishes the certificate creation process. This generates any needed + key, creates and signs the CSR. On completion the resulting PEM file can be + found at self.get_cert_path()""" + + if self.finalized: + return # Already finalized, no work needed. + + self.finalized = True + + # Ensure that the issuer has been "finalized", since its outputs need to be + # accessible. Note that self.issuer could be the same as self. + self.issuer.finalize() + + # Ensure the certificate has a key (gets lazily created by this call if + # missing). + self.get_key() + + # Serialize the config to a file. + self.config.write_to_file(self.get_config_path()) + + # Create a CSR. + subprocess.check_call( + ['openssl', 'req', '-new', + '-key', self.key.get_path(), + '-out', self.get_csr_path(), + '-config', self.get_config_path()]) + + cmd = ['openssl', 'ca', '-batch', '-in', + self.get_csr_path(), '-out', self.get_cert_path(), '-config', + self.issuer.get_config_path()] + + if self.issuer == self: + cmd.append('-selfsign') + + # Add in any extra flags. + cmd.extend(self.validity_flags) + cmd.extend(self.md_flags) + + # Run the 'openssl ca' command. + subprocess.check_call(cmd) + + + def init_config(self): + """Initializes default properties in the certificate .cnf file that are + generic enough to work for all certificates (but can be overridden later). + """ + + # -------------------------------------- + # 'req' section + # -------------------------------------- + + section = self.config.get_section('req') + + section.set_property('encrypt_key', 'no') + section.set_property('utf8', 'yes') + section.set_property('string_mask', 'utf8only') + section.set_property('prompt', 'no') + section.set_property('distinguished_name', 'req_dn') + section.set_property('req_extensions', 'req_ext') + + # -------------------------------------- + # 'req_dn' section + # -------------------------------------- + + # This section describes the certificate subject's distinguished name. + + section = self.config.get_section('req_dn') + section.set_property('commonName', '"%s"' % (self.name)) + + # -------------------------------------- + # 'req_ext' section + # -------------------------------------- + + # This section describes the certificate's extensions. + + section = self.config.get_section('req_ext') + section.set_property('subjectKeyIdentifier', 'hash') + + # -------------------------------------- + # SECTIONS FOR CAs + # -------------------------------------- + + # The following sections are used by the 'openssl ca' and relate to the + # signing operation. They are not needed for end-entity certificate + # configurations, but only if this certifiate will be used to sign other + # certificates. + + # -------------------------------------- + # 'ca' section + # -------------------------------------- + + section = self.config.get_section('ca') + section.set_property('default_ca', 'root_ca') + + section = self.config.get_section('root_ca') + section.set_property('certificate', self.get_cert_path()) + section.set_property('new_certs_dir', g_tmp_dir) + section.set_property('serial', self.get_serial_path()) + section.set_property('database', self.get_database_path()) + section.set_property('unique_subject', 'no') + + # These will get overridden via command line flags. + section.set_property('default_days', '365') + section.set_property('default_md', 'sha256') + + section.set_property('policy', 'policy_anything') + section.set_property('email_in_dn', 'no') + section.set_property('preserve', 'yes') + section.set_property('name_opt', 'multiline,-esc_msb,utf8') + section.set_property('cert_opt', 'ca_default') + section.set_property('copy_extensions', 'copy') + section.set_property('x509_extensions', 'signing_ca_ext') + section.set_property('default_crl_days', '30') + section.set_property('crl_extensions', 'crl_ext') + + section = self.config.get_section('policy_anything') + section.set_property('domainComponent', 'optional') + section.set_property('countryName', 'optional') + section.set_property('stateOrProvinceName', 'optional') + section.set_property('localityName', 'optional') + section.set_property('organizationName', 'optional') + section.set_property('organizationalUnitName', 'optional') + section.set_property('commonName', 'optional') + section.set_property('emailAddress', 'optional') + + section = self.config.get_section('signing_ca_ext') + section.set_property('subjectKeyIdentifier', 'hash') + section.set_property('authorityKeyIdentifier', 'keyid:always') + section.set_property('authorityInfoAccess', '@issuer_info') + section.set_property('crlDistributionPoints', '@crl_info') + + section = self.config.get_section('issuer_info') + section.set_property('caIssuers;URI.0', + 'http://url-for-aia/%s.cer' % (self.name)) + + section = self.config.get_section('crl_info') + section.set_property('URI.0', 'http://url-for-crl/%s.crl' % (self.name)) + + section = self.config.get_section('crl_ext') + section.set_property('authorityKeyIdentifier', 'keyid:always') + section.set_property('authorityInfoAccess', '@issuer_info') + + +def text_data_to_pem(block_header, text_data): + return '%s\n-----BEGIN %s-----\n%s\n-----END %s-----\n' % (text_data, + block_header, base64.b64encode(text_data), block_header) + + +def write_chain(description, chain, out_pem): + """Writes the chain to a .pem file as a series of CERTIFICATE blocks""" + + # Prepend the script name that generated the file to the description. + test_data = '[Created by: %s]\n\n%s\n' % (sys.argv[0], description) + + # Write the certificate chain to the output file. + for cert in chain: + test_data += '\n' + cert.get_cert_pem() + + write_string_to_file(test_data, out_pem) + + +def write_string_to_file(data, path): + with open(path, 'w') as f: + f.write(data) + + +def read_file_to_string(path): + with open(path, 'r') as f: + return f.read() + + +def init(invoking_script_path): + """Creates an output directory to contain all the temporary files that may be + created, as well as determining the path for the final output. These paths + are all based off of the name of the calling script. + """ + + global g_tmp_dir + + # The scripts assume to be run from within their containing directory (paths + # to things like "keys/" are written relative). + expected_cwd = os.path.realpath(os.path.dirname(invoking_script_path)) + actual_cwd = os.path.realpath(os.getcwd()) + if actual_cwd != expected_cwd: + sys.stderr.write( + ('Your current working directory must be that containing the python ' + 'scripts:\n%s\nas the script may reference paths relative to this\n') + % (expected_cwd)) + sys.exit(1) + + # Use an output directory with the same name as the invoking script. + g_tmp_dir = 'out' + + # Ensure the output directory exists and is empty. + sys.stdout.write('Creating output directory: %s\n' % (g_tmp_dir)) + shutil.rmtree(g_tmp_dir, True) + os.makedirs(g_tmp_dir) + + +def create_self_signed_root_certificate(name): + return Certificate(name, TYPE_CA, None) + + +def create_intermediate_certificate(name, issuer): + return Certificate(name, TYPE_CA, issuer) + + +def create_end_entity_certificate(name, issuer): + return Certificate(name, TYPE_END_ENTITY, issuer) + +init(sys.argv[0]) diff --git a/chromium/net/data/gencerts/openssl_conf.py b/chromium/net/data/gencerts/openssl_conf.py new file mode 100755 index 00000000000..fe1838d6638 --- /dev/null +++ b/chromium/net/data/gencerts/openssl_conf.py @@ -0,0 +1,136 @@ +#!/usr/bin/python +# Copyright (c) 2015 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 file contains helpers for representing, manipulating, and writing +OpenSSL configuration files [1] + +Configuration files are simply a collection of name=value "properties", which +are grouped into "sections". + +[1] https://www.openssl.org/docs/manmaster/apps/config.html +""" + +class Property(object): + """Represents a key/value pair in OpenSSL .cnf files. + + Names and values are not quoted in any way, so callers need to pass the text + exactly as it should be written to the file (leading and trailing whitespace + doesn't matter). + + For instance: + baseConstraints = critical, CA:false + + Could be represented by a Property where: + name = 'baseConstraints' + value = 'critical, CA:false' + """ + def __init__(self, name, value): + self.name = name + self.value = value + + + def write_to(self, out): + """Outputs this property to .cnf file.""" + out.write('%s = %s\n' % (self.name, self.value)) + + +class Section(object): + """Represents a section in OpenSSL. For instance: + [CA_root] + preserve = true + + Could be represented by a Section where: + name = 'CA_root' + properties = [Property('preserve', 'true')] + """ + def __init__(self, name): + self.name = name + self.properties = [] + + + def ensure_property_name_not_duplicated(self, name): + """Raises an exception of there is more than 1 property named |name|.""" + count = 0 + for prop in self.properties: + if prop.name == name: + count += 1 + if count > 1: + raise Exception('Duplicate property: %s' % (name)) + + + def set_property(self, name, value): + """Replaces, adds, or removes a Property from the Section: + + - If |value| is None, then this is equivalent to calling + remove_property(name) + - If there is an existing property matching |name| then its value is + replaced with |value| + - If there are no properties matching |name| then a new one is added at + the end of the section + + It is expected that there is AT MOST 1 property with the given name. If + that is not the case then this function will raise an error.""" + + if value is None: + self.remove_property(name) + return + + self.ensure_property_name_not_duplicated(name) + + for prop in self.properties: + if prop.name == name: + prop.value = value + return + + self.add_property(name, value) + + + def add_property(self, name, value): + """Adds a property (allows duplicates)""" + self.properties.append(Property(name, value)) + + + def remove_property(self, name): + """Removes the property with the indicated name, if it exists. + + It is expected that there is AT MOST 1 property with the given name. If + that is not the case then this function will raise an error.""" + self.ensure_property_name_not_duplicated(name) + + for i in range(len(self.properties)): + if self.properties[i].name == name: + self.properties.pop(i) + return + + + def write_to(self, out): + """Outputs the section in the format used by .cnf files""" + out.write('[%s]\n' % (self.name)) + for prop in self.properties: + prop.write_to(out) + out.write('\n') + + +class Config(object): + """Represents a .cnf (configuration) file in OpenSSL""" + def __init__(self): + self.sections = [] + + + def get_section(self, name): + """Gets or creates a section with the given name.""" + for section in self.sections: + if section.name == name: + return section + new_section = Section(name) + self.sections.append(new_section) + return new_section + + + def write_to_file(self, path): + """Outputs the Config to a .cnf files.""" + with open(path, 'w') as out: + for section in self.sections: + section.write_to(out) diff --git a/chromium/net/data/ssl/certificates/README b/chromium/net/data/ssl/certificates/README index e70316247ec..3c0f4ac7cc6 100644 --- a/chromium/net/data/ssl/certificates/README +++ b/chromium/net/data/ssl/certificates/README @@ -114,11 +114,16 @@ unit tests. NSS certificate nickname for a user certificate. This certificate's Subject field doesn't have a common name. -- quic_intermediate.crt -- quic_test_ecc.example.com.crt -- quic_test.example.com.crt -- quic_root.crt - These certificates are used by the ProofVerifier's unit tests of QUIC. +===== From net/data/ssl/scripts/generate-quic-chain.sh +- quic-chain.pem +- quic-leaf-cert.key +- quic-leaf-cert.key.pkcs8.pem +- quic-root.pem + These certificates are used by integration tests that use QUIC. + +- quic-leaf-cert.key.sct + This isn't generated and just contains a simple text file (the contents + don't actually matter, just the presence of the file). ===== From net/data/ssl/scripts/generate-test-certs.sh - expired_cert.pem @@ -180,11 +185,11 @@ unit tests. - pre_june_2016.pem - post_june_2016.pem +- dec_2017.pem Certs to test that policies related to enforcing CT on Symantec are - properly gated on the issuance date. These files also contain legacy - Symantec roots to simulate a chain for testing the upcoming Symantec - distrust events; see https://g.co/chrome/symantecpkicerts. (Note, - however, that the leaf and root do not actually form a chain.) + properly gated on the issuance date. See + https://g.co/chrome/symantecpkicerts. (Note, however, that the leaf and + root do not actually form a chain.) - tls_feature_extension.pem A certificate that contains the TLS Feature Extension. diff --git a/chromium/net/data/ssl/certificates/common_name_only.pem b/chromium/net/data/ssl/certificates/common_name_only.pem new file mode 100644 index 00000000000..5f7811a0a46 --- /dev/null +++ b/chromium/net/data/ssl/certificates/common_name_only.pem @@ -0,0 +1,109 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCp1J9FuvCmfgoP +pUn3w+iVRBwBOCXlZyzRcfRsiOfEGNnY8gEDNoyccKFHnj5rtJ/kQc9IgcZC2nob +qUSdHBEhUjKZbDZXOTXlBmpVY3qw0edMgwS9SSmaM5axPXEqJn7KShyzEC+3qux1 +T+gH8DBgwiP2qjM1A6nqf0/QDDms15sKhZJm9Z/MBpbpO/4zPjYSdsADv9sc7uyU +xRnNp3PQWu/hZjgg9w0tZWOzBaKHTHJLV+wH8frRqwLdHoB+gSIUfmNnGHKe59ia +rWjGU4l5b4kOVS8e5dSfdvNLbUM8z8dMvRq68fJnCJLkqnV7cehYmi+c6iGvDbkV +y7vVzfWnAgMBAAECggEALyW5+c/GE1KWVHWcrU4T+axo4eXGj4MvLA4ovyDaxtPn +VpUItu2j56JVA97okVoZsXKbqxNsCQ9CKv+47qzmDIwXRASIqXpWffhj+MSfQQtk +3Rbab/optIdx5E6cZgk91cbxZLyvopuu/XprfhiuNY5wEYB6qtMTjug9LhLWyCa3 +N2tTlIi8qMa79HPYcJ3l7en8jXrx+/856hCGGXXNP6H3HP4Kf171tZryDuekJhwt +pm6chDeFMkvJVa8GflKUxC5aVqhb84apCArvuaP/IXlDf0mEcyToyTjQaHitWtYo +BqueC3wMU5e5TvfQ3CKutWP3L9fQzU/mzpbEAuMMcQKBgQDUU47C0xwaIhfTyY2V +j9xDoEyJiRiaw0wUg2WtlNyIfUCOJSFxHeXqCmu1TurBxoNprlWZCf+myBR7hKXV +XbjRSluo7EFe6qF5ZxfVkTgaggSUmqd65kCDGyWQTZQ4tw+qal6T3TekJOwoAPa0 +ifKfPmzW/uleFwsXRJb5ydNA3QKBgQDMw13gt6s9xSAjvmZwdHdwb7712K4RrcoL +vrdOI6HEVDYsu2+zJxEtp0koE1Dk5LBUP4VAaDw1ABcx+Qon29mFy/orc8uH0PEu +SES6kZxr70eKJ67jvgs370m8zM+IJsC4RJ1wu09Q0vsdJ2TZLG5jlQD1no08Ta37 +Wv27zenGUwKBgH7ukPsBj9xDo3D2HlFaFnjLPNZAAliLBlGBF+kEhC6Iim4v3mUs +VYVrw2Y5jnhXf7pPAVcjNhVzqWMKMsVyaQmdZVyAGLhwliXorsP7M8oNDkX0iskb +G1gFg5hX+JNLRO9A9dd5uUjE1fU4VkQp78SpYhHJhKO+LOA1HfioYkV1AoGALHAt +3Iof2M0CN5+nvboY/cbSq6o1xNJxqfDe+U9UWTZpd3XKPRg6ay0F/HOMt9BF0FLk +yWCVyG7XmdnRcWsOHzJwfaOoxTX8Ua4PdGoLh4UrgnkwRG7HIoGFADt2wraeVp9V +h9Su1vyi0OXuxg8VefkpdyTMxAybuJQ7wtliZc8CgYEAouBfKjc3xn/jrf++kgie +taZ+ormKZs2mfTfcEMeQv7Bd7sEUWCoRevdorTlHaw1DKBqFq56Y1v3ppH83C6DH +5v1+43M6zq7qWGSgf5nbQ1ZBMUR0FMcBujc9JFX52Zc7ScvE1hwMT3lBJut/ln5W +h1oQd50MoCr4WE39Em4/H3o= +-----END PRIVATE KEY----- +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 24 (0x18) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, ST=California, L=Mountain View, O=Test CA, CN=Test Root CA + Validity + Not Before: Dec 20 00:00:00 2017 GMT + Not After : Dec 20 00:00:00 2020 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 + Public-Key: (2048 bit) + Modulus: + 00:a9:d4:9f:45:ba:f0:a6:7e:0a:0f:a5:49:f7:c3: + e8:95:44:1c:01:38:25:e5:67:2c:d1:71:f4:6c:88: + e7:c4:18:d9:d8:f2:01:03:36:8c:9c:70:a1:47:9e: + 3e:6b:b4:9f:e4:41:cf:48:81:c6:42:da:7a:1b:a9: + 44:9d:1c:11:21:52:32:99:6c:36:57:39:35:e5:06: + 6a:55:63:7a:b0:d1:e7:4c:83:04:bd:49:29:9a:33: + 96:b1:3d:71:2a:26:7e:ca:4a:1c:b3:10:2f:b7:aa: + ec:75:4f:e8:07:f0:30:60:c2:23:f6:aa:33:35:03: + a9:ea:7f:4f:d0:0c:39:ac:d7:9b:0a:85:92:66:f5: + 9f:cc:06:96:e9:3b:fe:33:3e:36:12:76:c0:03:bf: + db:1c:ee:ec:94:c5:19:cd:a7:73:d0:5a:ef:e1:66: + 38:20:f7:0d:2d:65:63:b3:05:a2:87:4c:72:4b:57: + ec:07:f1:fa:d1:ab:02:dd:1e:80:7e:81:22:14:7e: + 63:67:18:72:9e:e7:d8:9a:ad:68:c6:53:89:79:6f: + 89:0e:55:2f:1e:e5:d4:9f:76:f3:4b:6d:43:3c:cf: + c7:4c:bd:1a:ba:f1:f2:67:08:92:e4:aa:75:7b:71: + e8:58:9a:2f:9c:ea:21:af:0d:b9:15:cb:bb:d5:cd: + f5:a7 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:FALSE + X509v3 Subject Key Identifier: + 41:E5:87:59:14:3F:3E:99:24:67:DF:F8:B7:59:F6:81:3D:9C:F7:14 + 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 + Signature Algorithm: sha256WithRSAEncryption + 39:41:78:9d:38:e1:d2:7e:92:34:7a:da:32:6c:2d:51:d6:a4: + c1:d9:84:5f:24:2e:8f:ce:a8:60:29:ba:01:01:4b:a3:e0:fe: + 56:9c:5a:0b:8b:9f:b1:b6:55:89:0e:40:8f:09:0c:10:f1:dc: + 9a:3d:85:7c:ef:83:f9:0e:42:81:89:ac:a4:11:b9:e9:fd:db: + 58:54:63:51:66:5c:0e:0e:42:68:58:d9:0e:aa:54:70:6d:e7: + 51:e5:8b:fd:d0:da:dd:7b:b9:97:55:42:42:e7:39:b4:4b:4b: + c4:89:90:d1:6e:4b:0a:fd:cc:a8:a3:a7:70:ed:d6:e8:c4:09: + 80:d7:b0:09:ae:db:d2:4b:4f:0a:ec:73:28:bf:6f:cb:61:bd: + ab:5f:9a:2d:81:5e:e0:be:8c:32:d1:24:ea:a3:83:04:b8:81: + 97:e2:26:91:a2:fa:da:18:fa:54:58:46:d9:38:9b:66:b0:80: + 1d:a3:55:5b:86:7d:77:ca:0c:ba:e1:e6:c5:8c:e3:08:73:0f: + 73:b7:8b:42:75:6b:62:6e:bf:73:2d:4c:11:07:b4:b7:a0:72: + 0d:23:08:4b:65:8e:fd:1d:61:15:e6:d0:a5:ad:31:0b:d4:35: + 3a:f7:aa:e7:50:38:a2:dc:b0:24:52:9d:86:fc:ce:1a:d8:29: + 4b:de:82:af +-----BEGIN CERTIFICATE----- +MIIDrTCCApWgAwIBAgIBGDANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJVUzET +MBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEQMA4G +A1UECgwHVGVzdCBDQTEVMBMGA1UEAwwMVGVzdCBSb290IENBMB4XDTE3MTIyMDAw +MDAwMFoXDTIwMTIyMDAwMDAwMFowYDELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNh +bGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxEDAOBgNVBAoMB1Rlc3Qg +Q0ExEjAQBgNVBAMMCTEyNy4wLjAuMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBAKnUn0W68KZ+Cg+lSffD6JVEHAE4JeVnLNFx9GyI58QY2djyAQM2jJxw +oUeePmu0n+RBz0iBxkLaehupRJ0cESFSMplsNlc5NeUGalVjerDR50yDBL1JKZoz +lrE9cSomfspKHLMQL7eq7HVP6AfwMGDCI/aqMzUDqep/T9AMOazXmwqFkmb1n8wG +luk7/jM+NhJ2wAO/2xzu7JTFGc2nc9Ba7+FmOCD3DS1lY7MFoodMcktX7Afx+tGr +At0egH6BIhR+Y2cYcp7n2JqtaMZTiXlviQ5VLx7l1J9280ttQzzPx0y9Grrx8mcI +kuSqdXtx6FiaL5zqIa8NuRXLu9XN9acCAwEAAaNvMG0wDAYDVR0TAQH/BAIwADAd +BgNVHQ4EFgQUQeWHWRQ/PpkkZ9/4t1n2gT2c9xQwHwYDVR0jBBgwFoAUmyYLipip +ux25HxzjGkAz7Y4XiKswHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMA0G +CSqGSIb3DQEBCwUAA4IBAQA5QXidOOHSfpI0etoybC1R1qTB2YRfJC6PzqhgKboB +AUuj4P5WnFoLi5+xtlWJDkCPCQwQ8dyaPYV874P5DkKBiaykEbnp/dtYVGNRZlwO +DkJoWNkOqlRwbedR5Yv90Nrde7mXVUJC5zm0S0vEiZDRbksK/cyoo6dw7dboxAmA +17AJrtvSS08K7HMov2/LYb2rX5otgV7gvowy0STqo4MEuIGX4iaRovraGPpUWEbZ +OJtmsIAdo1Vbhn13ygy64ebFjOMIcw9zt4tCdWtibr9zLUwRB7S3oHINIwhLZY79 +HWEV5tClrTEL1DU696rnUDii3LAkUp2G/M4a2ClL3oKv +-----END CERTIFICATE----- diff --git a/chromium/net/data/ssl/certificates/crlset_by_leaf_subject_no_spki.raw b/chromium/net/data/ssl/certificates/crlset_by_leaf_subject_no_spki.raw Binary files differnew file mode 100644 index 00000000000..3a22aa7dd4c --- /dev/null +++ b/chromium/net/data/ssl/certificates/crlset_by_leaf_subject_no_spki.raw diff --git a/chromium/net/data/ssl/certificates/crlset_by_root_subject.raw b/chromium/net/data/ssl/certificates/crlset_by_root_subject.raw Binary files differnew file mode 100644 index 00000000000..95404126d17 --- /dev/null +++ b/chromium/net/data/ssl/certificates/crlset_by_root_subject.raw diff --git a/chromium/net/data/ssl/certificates/crlset_by_root_subject_no_spki.raw b/chromium/net/data/ssl/certificates/crlset_by_root_subject_no_spki.raw Binary files differnew file mode 100644 index 00000000000..d556a83ada6 --- /dev/null +++ b/chromium/net/data/ssl/certificates/crlset_by_root_subject_no_spki.raw diff --git a/chromium/net/data/ssl/certificates/dec_2017.pem b/chromium/net/data/ssl/certificates/dec_2017.pem new file mode 100644 index 00000000000..e0dff799390 --- /dev/null +++ b/chromium/net/data/ssl/certificates/dec_2017.pem @@ -0,0 +1,84 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 25 (0x19) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, ST=California, L=Mountain View, O=Test CA, CN=Test Root CA + Validity + Not Before: Dec 20 00:00:00 2017 GMT + Not After : Dec 20 00:00:00 2020 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 + Public-Key: (2048 bit) + Modulus: + 00:d0:c1:27:76:2d:56:e6:b9:e3:23:b9:b6:c3:0e: + f4:8c:cb:73:85:0e:45:ed:b8:ea:e6:21:b6:60:56: + 1d:b7:24:72:b9:51:72:68:07:22:9f:8f:fd:47:c7: + da:9b:7b:5c:ad:e8:f5:6a:72:4d:8b:e4:55:fc:c6: + 41:d8:53:5e:0a:ba:35:4e:bc:98:21:d0:c2:ae:f7: + ff:ec:8f:26:eb:a1:71:74:11:b7:21:fd:38:04:5a: + e5:42:3d:02:28:05:3a:8d:2d:9b:5e:7b:39:35:e4: + fe:59:a8:98:39:c7:6c:d1:9e:1a:d7:c3:11:78:cb: + 44:72:e4:a0:89:83:e2:f8:de:c9:46:3a:c5:71:7f: + af:ee:e5:ba:1f:fa:97:19:f0:d0:5c:32:81:d3:7d: + 80:99:70:49:2a:ba:c8:40:b0:32:51:ec:16:3b:4d: + 61:05:e2:dc:b9:24:f0:a6:6b:ad:cd:53:1d:cd:9a: + ba:bb:df:96:f1:ac:e6:5e:03:cb:98:07:da:21:6e: + 8c:ac:56:37:39:15:d4:ab:b0:43:d1:64:7a:05:59: + f8:f8:bd:4e:31:c7:8c:d6:23:e8:3d:99:ea:75:78: + 25:8d:1a:83:32:39:ec:ec:69:ef:76:cc:b6:cf:06: + 0e:1d:ca:ac:8c:b7:10:a7:d2:ec:18:86:7c:6f:20: + 9c:bf + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:FALSE + X509v3 Subject Key Identifier: + 4F:62:A1:56:D4:81:D5:18:65:C6:E0:DC:91:72:07:32:58:0C:79:EE + 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 + a5:16:f1:6f:8d:ab:b2:d7:c1:f6:98:98:d4:2d:8d:0f:85:09: + 65:73:f4:72:40:66:8b:28:f3:e4:d8:b8:8e:21:2b:9f:27:f2: + ab:0f:b6:e7:94:9a:1c:b1:58:9a:71:5e:79:d4:1b:9b:11:f3: + 52:ee:a2:00:85:75:d5:a0:6e:af:11:39:cd:72:f8:a8:57:09: + 09:4f:df:e7:42:26:63:08:a2:fb:19:ff:ab:97:e4:f1:01:7c: + df:e5:87:58:e7:90:e6:61:c0:f8:35:89:5f:4b:f2:f0:ae:cb: + 1a:69:3b:1f:0b:ac:38:18:28:5a:ca:92:75:fa:ee:56:69:dd: + dc:e8:c4:db:8f:84:20:d2:50:ee:34:32:e6:2f:90:aa:12:3d: + db:56:a3:38:0f:80:b7:f5:32:b6:12:b8:30:1c:14:84:83:4e: + 7b:42:49:16:ef:1e:b0:3a:f5:03:30:72:86:1f:0d:77:1a:7b: + 44:8b:60:e4:34:49:d8:b0:af:8d:a6:f1:08:70:b3:69:54:5f: + e0:2f:6d:42:2f:ff:68:07:fd:cf:c1:f7:fa:e7:5f:fe:1f:93: + ba:02:01:29:69:37:97:6a:16:03:7f:2d:0c:b2:2a:d8:43:13: + ed:cf:1b:2d:1f:b0:f3:b6:e1:98:cb:92:d3:26:5e:f4:a7:a3: + 90:de:6a:ab +-----BEGIN CERTIFICATE----- +MIIDvzCCAqegAwIBAgIBGTANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJVUzET +MBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEQMA4G +A1UECgwHVGVzdCBDQTEVMBMGA1UEAwwMVGVzdCBSb290IENBMB4XDTE3MTIyMDAw +MDAwMFoXDTIwMTIyMDAwMDAwMFowYDELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNh +bGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxEDAOBgNVBAoMB1Rlc3Qg +Q0ExEjAQBgNVBAMMCTEyNy4wLjAuMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBANDBJ3YtVua54yO5tsMO9IzLc4UORe246uYhtmBWHbckcrlRcmgHIp+P +/UfH2pt7XK3o9WpyTYvkVfzGQdhTXgq6NU68mCHQwq73/+yPJuuhcXQRtyH9OARa +5UI9AigFOo0tm157OTXk/lmomDnHbNGeGtfDEXjLRHLkoImD4vjeyUY6xXF/r+7l +uh/6lxnw0FwygdN9gJlwSSq6yECwMlHsFjtNYQXi3Lkk8KZrrc1THc2aurvflvGs +5l4Dy5gH2iFujKxWNzkV1KuwQ9FkegVZ+Pi9TjHHjNYj6D2Z6nV4JY0agzI57Oxp +73bMts8GDh3KrIy3EKfS7BiGfG8gnL8CAwEAAaOBgDB+MAwGA1UdEwEB/wQCMAAw +HQYDVR0OBBYEFE9ioVbUgdUYZcbg3JFyBzJYDHnuMB8GA1UdIwQYMBaAFJsmC4qY +qbsduR8c4xpAM+2OF4irMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAP +BgNVHREECDAGhwR/AAABMA0GCSqGSIb3DQEBCwUAA4IBAQClFvFvjauy18H2mJjU +LY0PhQllc/RyQGaLKPPk2LiOISufJ/KrD7bnlJocsViacV551BubEfNS7qIAhXXV +oG6vETnNcvioVwkJT9/nQiZjCKL7Gf+rl+TxAXzf5YdY55DmYcD4NYlfS/Lwrssa +aTsfC6w4GChaypJ1+u5Wad3c6MTbj4Qg0lDuNDLmL5CqEj3bVqM4D4C39TK2Ergw +HBSEg057QkkW7x6wOvUDMHKGHw13GntEi2DkNEnYsK+NpvEIcLNpVF/gL21CL/9o +B/3Pwff651/+H5O6AgEpaTeXahYDfy0MsirYQxPtzxstH7DztuGYy5LTJl70p6OQ +3mqr +-----END CERTIFICATE----- diff --git a/chromium/net/data/ssl/certificates/quic-chain.pem b/chromium/net/data/ssl/certificates/quic-chain.pem new file mode 100644 index 00000000000..ab0893b282f --- /dev/null +++ b/chromium/net/data/ssl/certificates/quic-chain.pem @@ -0,0 +1,147 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 1 (0x1) + Signature Algorithm: sha256WithRSAEncryption + Issuer: CN=Test Intermediate CA + Validity + Not Before: Dec 18 23:44:03 2017 GMT + Not After : Dec 16 23:44:03 2027 GMT + Subject: CN=test.example.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + 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 Basic Constraints: critical + CA:FALSE + X509v3 Extended Key Usage: + TLS Web Server Authentication, TLS Web Client Authentication + X509v3 Subject Alternative Name: + DNS:test.example.com + Signature Algorithm: sha256WithRSAEncryption + bd:55:54:e5:ac:2b:e6:6f:c9:45:b7:77:97:af:37:e6:6b:60: + cb:51:0f:b0:2c:40:71:39:73:7a:0b:6f:37:a5:cc:40:4f:d1: + 43:3d:8e:1d:37:ba:ff:2d:7b:80:21:fd:ec:e4:7c:20:6a:ce: + 6e:28:9b:c1:4e:9e:1e:17:1f:cb:04:61:c1:d0:72:0c:31:f6: + ee:2b:a9:9c:29:6b:45:bd:97:57:a6:25:f3:f0:6b:08:3f:4e: + 00:33:cf:47:3b:50:4a:15:a7:a0:c8:e0:8b:86:7b:48:3e:39: + 15:00:0a:aa:79:3c:8d:fd:d7:4a:68:2f:05:2b:60:2a:d1:7e: + 1c:bc:06:e9:b7:51:35:71:d7:6b:f4:b8:f3:17:d7:f1:d4:8d: + f8:0e:4a:11:34:4d:d9:19:70:33:0a:66:e6:4c:11:93:90:5c: + 5d:a1:f3:8a:1c:ce:0c:12:5e:a9:6b:e1:1f:eb:b3:65:b8:bc: + 1a:48:af:cc:af:fc:db:3e:0b:32:47:8d:fc:ed:b3:50:9a:65: + b8:19:eb:db:18:21:5f:e4:1d:c5:87:57:9b:5a:8a:59:16:84: + 8d:27:3e:f9:7a:c0:fa:e7:84:90:da:1a:03:98:b5:c6:a9:52: + ed:df:0e:7a:02:c7:e6:82:d2:06:cb:97:75:90:89:d6:d1:cf: + 43:74:09:f7 +-----BEGIN CERTIFICATE----- +MIIDATCCAemgAwIBAgIBATANBgkqhkiG9w0BAQsFADAfMR0wGwYDVQQDDBRUZXN0 +IEludGVybWVkaWF0ZSBDQTAeFw0xNzEyMTgyMzQ0MDNaFw0yNzEyMTYyMzQ0MDNa +MBsxGTAXBgNVBAMMEHRlc3QuZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUA +A4IBDwAwggEKAoIBAQCyVm9+1LS2TuMVjorpRgYVY0xtOjJnxxSkF/y3BJj7tRGu +kxwgcxXNs7zuYYKOy7h4ym3mV3PzRW4ewyddr15SbRJHRHI9fYrBR1AZSiGkCLTM +LpyiKs4bh4KuOiOw3dI+ZP7OpjU0kwf4iG7IvrILX5yWDnkcoyvJI1qKHx4X4qnU +PEkiKUP6Y1U8cmJK0XJarnWoFGfrWIjOEQy/CWfyu8iAPkrwNa3S3EOjL9rGOxxu +dnAxc8wzW0823POPn6YHbWHgZm8sdr2Fo4vQis7EvJfg7eEp36Fiua3YDxr4rkT+ +piiVxMzftfdtRq7vm69zUB2f8Meg7zdLE3OWJJUPAgMBAAGjTDBKMAwGA1UdEwEB +/wQCMAAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBsGA1UdEQQUMBKC +EHRlc3QuZXhhbXBsZS5jb20wDQYJKoZIhvcNAQELBQADggEBAL1VVOWsK+ZvyUW3 +d5evN+ZrYMtRD7AsQHE5c3oLbzelzEBP0UM9jh03uv8te4Ah/ezkfCBqzm4om8FO +nh4XH8sEYcHQcgwx9u4rqZwpa0W9l1emJfPwawg/TgAzz0c7UEoVp6DI4IuGe0g+ +ORUACqp5PI3910poLwUrYCrRfhy8Bum3UTVx12v0uPMX1/HUjfgOShE0TdkZcDMK +ZuZMEZOQXF2h84oczgwSXqlr4R/rs2W4vBpIr8yv/Ns+CzJHjfzts1CaZbgZ69sY +IV/kHcWHV5tailkWhI0nPvl6wPrnhJDaGgOYtcapUu3fDnoCx+aC0gbLl3WQidbR +z0N0Cfc= +-----END CERTIFICATE----- +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 1 (0x1) + Signature Algorithm: sha256WithRSAEncryption + Issuer: CN=Test Root CA + Validity + Not Before: Dec 18 23:44:03 2017 GMT + Not After : Dec 16 23:44:03 2027 GMT + Subject: CN=Test Intermediate CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:e4:cd:89:4c:65:4f:4d:68:bd:2a:7a:4f:0b:10: + 3f:02:d6:2a:5b:5b:76:c8:97:59:67:19:6e:95:45: + c3:38:a4:c7:29:f5:f7:95:52:97:a3:01:19:b2:b3: + ec:09:97:08:4f:f1:db:43:67:50:59:ac:ca:9a:05: + 56:fc:73:42:f3:90:e1:e5:3e:03:75:35:33:d2:df: + aa:3d:f8:ca:16:5e:7e:ef:01:9c:2a:30:eb:c7:cc: + 06:04:90:14:c0:54:f5:96:22:26:30:39:73:c5:c0: + 9d:0d:b0:9f:b0:e5:cf:f6:b1:0c:10:ab:f0:c9:54: + a6:30:d5:b4:fd:a7:23:7f:1e:57:7b:72:d7:af:0d: + a2:3e:4d:b2:c5:51:70:2a:06:2f:66:21:ca:7f:7d: + 6b:60:24:5e:ed:5f:74:ee:4b:b1:f1:ec:54:a0:fb: + 89:05:69:94:78:9b:a4:85:8c:ea:e6:b5:d6:fd:c5: + 6d:98:28:e4:1d:81:1b:26:3b:21:c2:e4:df:bd:a1: + 0d:51:35:40:43:a0:a4:00:66:fa:97:46:d6:9d:95: + ca:da:62:f8:c7:60:6c:e4:89:c2:d0:74:30:fe:2a: + db:54:95:5b:68:5f:ca:bd:e9:af:27:13:fc:c4:6f: + e6:5d:05:92:cc:bc:e4:76:8a:2e:34:0b:5e:39:11: + 75:57 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + Signature Algorithm: sha256WithRSAEncryption + 60:4e:38:f3:7b:00:46:75:8f:d0:4e:08:76:2d:ed:9f:bf:cc: + 50:1b:bf:e4:6d:76:50:fe:fa:7d:46:90:1c:75:f1:3f:47:19: + eb:02:38:cb:3e:56:0f:8f:09:ae:a8:42:d0:e6:5a:31:54:24: + b2:fe:4b:a2:e4:44:14:64:44:d8:50:12:62:4a:06:60:29:22: + 95:bb:c8:7e:dd:d4:7d:a6:dd:3c:0d:fb:71:67:6f:9b:49:05: + 09:7c:5c:63:2b:df:71:aa:ae:92:28:98:73:c2:60:b6:54:10: + f6:f5:54:d6:93:0a:22:56:0a:fd:45:8a:a4:d7:a7:21:df:f5: + 53:07:1c:3b:63:c1:7c:4e:f0:3d:5c:c4:c9:cc:55:ae:ec:fb: + 2e:4f:b0:f9:5b:1d:c3:46:ba:38:f6:ff:8d:b3:3b:d0:7d:15: + 3f:fd:6a:bd:a1:59:18:ff:57:fc:d6:c0:3d:7e:75:61:ff:13: + 09:81:5f:38:82:22:78:78:97:5e:e6:7c:fb:16:a8:92:40:97: + eb:7c:a5:37:da:ca:5f:28:69:e4:63:b7:07:61:ad:e8:5a:e8: + 06:55:c0:34:7c:30:66:1e:9a:7e:ed:cb:c8:14:c1:e3:b3:ac: + 8d:89:9c:6b:b1:ea:eb:71:94:c0:1d:63:b7:d9:82:74:13:0c: + ee:8a:ca:dc +-----BEGIN CERTIFICATE----- +MIIC1DCCAbygAwIBAgIBATANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxUZXN0 +IFJvb3QgQ0EwHhcNMTcxMjE4MjM0NDAzWhcNMjcxMjE2MjM0NDAzWjAfMR0wGwYD +VQQDDBRUZXN0IEludGVybWVkaWF0ZSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAOTNiUxlT01ovSp6TwsQPwLWKltbdsiXWWcZbpVFwzikxyn195VS +l6MBGbKz7AmXCE/x20NnUFmsypoFVvxzQvOQ4eU+A3U1M9Lfqj34yhZefu8BnCow +68fMBgSQFMBU9ZYiJjA5c8XAnQ2wn7Dlz/axDBCr8MlUpjDVtP2nI38eV3ty168N +oj5NssVRcCoGL2Yhyn99a2AkXu1fdO5LsfHsVKD7iQVplHibpIWM6ua11v3FbZgo +5B2BGyY7IcLk372hDVE1QEOgpABm+pdG1p2Vytpi+MdgbOSJwtB0MP4q21SVW2hf +yr3prycT/MRv5l0Fksy85HaKLjQLXjkRdVcCAwEAAaMjMCEwDwYDVR0TAQH/BAUw +AwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQADggEBAGBOOPN7AEZ1 +j9BOCHYt7Z+/zFAbv+RtdlD++n1GkBx18T9HGesCOMs+Vg+PCa6oQtDmWjFUJLL+ +S6LkRBRkRNhQEmJKBmApIpW7yH7d1H2m3TwN+3Fnb5tJBQl8XGMr33GqrpIomHPC +YLZUEPb1VNaTCiJWCv1FiqTXpyHf9VMHHDtjwXxO8D1cxMnMVa7s+y5PsPlbHcNG +ujj2/42zO9B9FT/9ar2hWRj/V/zWwD1+dWH/EwmBXziCInh4l17mfPsWqJJAl+t8 +pTfayl8oaeRjtwdhreha6AZVwDR8MGYemn7ty8gUweOzrI2JnGux6utxlMAdY7fZ +gnQTDO6Kytw= +-----END CERTIFICATE----- diff --git a/chromium/net/data/ssl/certificates/quic-leaf-cert.key b/chromium/net/data/ssl/certificates/quic-leaf-cert.key Binary files differnew file mode 100644 index 00000000000..e509d72513b --- /dev/null +++ b/chromium/net/data/ssl/certificates/quic-leaf-cert.key diff --git a/chromium/net/data/ssl/certificates/quic-leaf-cert.key.pkcs8.pem b/chromium/net/data/ssl/certificates/quic-leaf-cert.key.pkcs8.pem new file mode 100644 index 00000000000..00983fc3aae --- /dev/null +++ b/chromium/net/data/ssl/certificates/quic-leaf-cert.key.pkcs8.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCyVm9+1LS2TuMV +jorpRgYVY0xtOjJnxxSkF/y3BJj7tRGukxwgcxXNs7zuYYKOy7h4ym3mV3PzRW4e +wyddr15SbRJHRHI9fYrBR1AZSiGkCLTMLpyiKs4bh4KuOiOw3dI+ZP7OpjU0kwf4 +iG7IvrILX5yWDnkcoyvJI1qKHx4X4qnUPEkiKUP6Y1U8cmJK0XJarnWoFGfrWIjO +EQy/CWfyu8iAPkrwNa3S3EOjL9rGOxxudnAxc8wzW0823POPn6YHbWHgZm8sdr2F +o4vQis7EvJfg7eEp36Fiua3YDxr4rkT+piiVxMzftfdtRq7vm69zUB2f8Meg7zdL +E3OWJJUPAgMBAAECggEAWhFzcB/nQOfoonuCRrxZ2DV1ZPjueiE+mH2Q4bINvZo+ +WufrXawiB+jN86sFsC7NdRvvk1T5t5SKQDkZyaQHRCPYBmxYMhwUlvb4Sj15bgoD +ndewvepWe+rdoja0zd/KDj8dvaqN1oankOr+4J4G992LDPI0UrVKKOSVFosOvMqh +zAJy19KGzfSzBU40xnWk4MEq7ZPksdeMFN5Dv+C4lFCmd/ddTFQ7EcqeSRqv2JCC +fAH9wF6GFUXfYqU7h3CTt686kxhbgle4U5rzr126ByZjysAKv5OnNOEDlNi8D5og +SX/vjuek8eL3Ypmho1Wch+f3w315gs8KWQjx0lcv+QKBgQDlvCRPat/qu0v/hsE7 +iopkV5I3AghzfNXzaHFrwgkXFXu+pArTk3r22aY3strAXfiYp7Blz10+LUrZyvB6 +0wa//Mk3nZ67BcViy1HykJJd6hHXYXxqih8Ig0JQJrD12iEwo3RUZ/G+L4EVOcG/ +kS/C8sUbp3j6mqxJe18xgvCF0wKBgQDGugDL8xfzuqTT3XPhCTmUL1nAO3Xv0vRb +Vuzx0bFeGvAPHWFAb2FtEkXc4pDCPb+73q9ByBwukVB0nPpiaPzlJHGMocBANxh6 +tvO/XMcfmQmhQ+2yXgXEb7/RamULdjn7dlE+0l8kvCI37LYB/lPq2cdA1vnugxkB +55fls4GCVQKBgQC35snyQQ2KK/CEVmzsqtRpyqgjHJ+DQ1VJijvxFNyN/AaY71wz +TgXLASPLxoLSJudP3Dya40oy8bLPcWLcD32BxmuU97oO4GnH0haBZDWmtC8gCMu9 +xV9eQyScYLybsceL1ezTfHnJ0uE0Co4MOb7QAeLDZmazxYlRMU9cpQLBPQKBgQCT +yYwCIHy1kx41OUGOH3AklbonTZD9k2KJ8vEvPQSsuVfBxdWnN626kZZHGG8TJRzL +uGWZhBoBP6wXrQ4/1VgNiLaxITF6D/8yc5B9xZ+IDiWtOnkw5t9fIMQEFx2iEoA4 +U9tD3utGxGqmMHGCtgLuaprVy4n/KJuWYQcDmiU8KQKBgQClNWD+p5caD82Z4QB5 +Y/lTbjmmF4nLHlwfLpWI+nJ76kvFMnLYgJY8oZgBwBZsEkQG8so/nejBFsYvIDeR +5W7cQVJ+ED8GCF9O4H77U0R8rpuL4z61ni4rXHc9+rABaHBHJ1aF8h3SlceHVdow +FBU427jUeVKBN9UnFo4wrogjMA== +-----END PRIVATE KEY----- diff --git a/chromium/net/data/ssl/certificates/quic_test.example.com.key.sct b/chromium/net/data/ssl/certificates/quic-leaf-cert.key.sct Binary files differindex 0d19282b535..0d19282b535 100644 --- a/chromium/net/data/ssl/certificates/quic_test.example.com.key.sct +++ b/chromium/net/data/ssl/certificates/quic-leaf-cert.key.sct diff --git a/chromium/net/data/ssl/certificates/quic-root.pem b/chromium/net/data/ssl/certificates/quic-root.pem new file mode 100644 index 00000000000..f25cd2eeed3 --- /dev/null +++ b/chromium/net/data/ssl/certificates/quic-root.pem @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC1DCCAbygAwIBAgIJANU1FI5oBbmLMA0GCSqGSIb3DQEBCwUAMBcxFTATBgNV +BAMMDFRlc3QgUm9vdCBDQTAeFw0xNzEyMTgyMzQ0MDNaFw0yNzEyMTYyMzQ0MDNa +MBcxFTATBgNVBAMMDFRlc3QgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBALqSSRbDX0cmxTOeBh4qqMtw8BA7J8l6CYZqeUgigR67xAvJGEqx +WhYDBjodWIYucrwqkRuju1ufRXVNAD8rqs47db5NPDHH+FqN33RkSa9XIdOGdnHX +NfCQ13Vpq9tnvZ3zCzvSWXDVYz6GcCBJ51tjWNZtX8O8N179HcVef3LhBGweAJJv ++FkOLiClZ1y2A5hfdmuYmIYy2Iwc7we/R6jm+Ns0pVA8NrLicEHzrxJLMlMD5+zd +WjkY6Bv9OdPipmEr1/EP3957bZ7uIUZWEq79SnQ90sKkMVS+q7Ckz7PdMBJI+fZc +HsjucLXL0tysbcF+CtYqHsbrazye0yERUFECAwEAAaMjMCEwDwYDVR0TAQH/BAUw +AwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQADggEBAJZRG2cJGaGF +Tl8H6+SltT9dlZ//Z7ZNsWEfv8xehGrRHsV2kxXvuVf1K4EpP3FAEvDJgOvP1MkA +rmcpI9SsY4cr0Zy/s+Ez8SwespXkSKvtCXCmq9/kpadFPDWwR1NAXVzSEuhXJxDR +bA+boLCu6rMFbkoRi/aFYzro+9m8RsXlyYGVGspov411lu56huoJ3ooGTIfQM8or +N6ZNWkb+RTUUj29o3qr3kiQv73mB6h47/3IkYC5mITl+vK3OtwIRwjLzXZuS40/W +RlI+SRYG4/yTzgV1DB4JlVJl4qMsF3z1zY1P7WeCU4YqZoIam/Ig/ZzxfOFTczk8 +vw1/E4YbkfE= +-----END CERTIFICATE----- diff --git a/chromium/net/data/ssl/certificates/quic_chain.crt b/chromium/net/data/ssl/certificates/quic_chain.crt deleted file mode 100644 index 57a8f342837..00000000000 --- a/chromium/net/data/ssl/certificates/quic_chain.crt +++ /dev/null @@ -1,226 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: 3 (0x3) - Signature Algorithm: sha1WithRSAEncryption - Issuer: O=Acme Co, CN=Intermediate CA - Validity - Not Before: Jan 1 10:00:00 2013 GMT - Not After : Dec 31 10:00:00 2023 GMT - Subject: O=Acme Co, CN=Leaf certificate - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (2048 bit) - Modulus: - 00:d5:ca:19:79:8e:a9:ab:46:f0:4e:b7:58:6d:b3: - a3:9a:68:10:52:af:f0:00:94:ae:34:bd:b4:50:1f: - a3:26:a4:9e:1c:90:37:5b:3d:e8:d7:3b:bc:93:fb: - 00:fb:c7:49:54:9b:f1:d0:9a:f2:51:84:7b:59:8b: - bd:66:f3:ae:92:5a:b9:63:8c:64:a7:d0:9e:e3:0c: - 50:d2:cf:93:9d:e9:4a:11:57:93:c1:de:af:7b:5a: - 44:1d:0a:8c:22:a6:1d:c6:ad:e9:8f:16:8d:4e:91: - f1:d3:f1:f3:82:fe:f6:55:dc:72:f1:11:07:75:ec: - bb:e9:3a:35:87:43:81:5e:dc:43:4a:b7:7c:a1:1a: - d5:d2:c1:40:39:69:7d:89:ad:64:1b:31:34:a8:ea: - 9e:5e:26:fc:71:d2:c6:6b:e5:c2:73:30:3f:59:a7: - 35:8d:a9:a5:e9:3d:43:41:bd:54:f2:2a:e1:15:0c: - 35:30:6b:8b:f2:77:ca:5c:07:8f:58:f4:54:77:5e: - af:ce:b1:c1:2b:a7:bb:c0:e9:7d:ef:1a:d7:03:ee: - 8f:67:ad:c6:e6:1d:a9:e7:91:3f:41:e7:d6:86:20: - 8c:53:b3:d8:79:09:e2:4b:15:5a:d8:92:3b:62:4f: - 68:e4:cb:d0:a4:4e:b6:7d:3e:5f:b0:24:ea:62:61: - cf:7b - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Key Usage: critical - Digital Signature, Key Encipherment - X509v3 Extended Key Usage: - TLS Web Server Authentication - X509v3 Basic Constraints: critical - CA:FALSE - X509v3 Subject Alternative Name: - DNS:test.example.com - Signature Algorithm: sha1WithRSAEncryption - 58:c3:dc:e3:4d:ec:76:c6:62:99:ba:ba:6d:da:e4:2f:ec:00: - f8:fb:2a:e3:f6:a4:bc:37:c9:53:0f:73:2e:a6:79:8f:6b:ef: - 87:16:56:7b:9e:6d:ac:1a:ec:8b:49:71:7d:f2:11:11:a4:0d: - 5e:6e:be:93:6b:fe:cb:44:1b:4e:99:2a:d2:eb:d8:91:80:d7: - c8:87:fd:c8:fa:cf:c2:68:06:07:2d:60:ae:56:c4:3c:49:4d: - e3:05:3f:1b:15:a8:a9:ea:85:d8:af:d3:f5:be:b5:71:28:23: - 8d:04:f1:c6:e1:fb:0c:1b:ac:5a:2d:e0:7f:fb:4e:79:47:29: - b3:9c:27:09:7d:3c:84:0b:59:0a:03:c5:86:a9:aa:90:49:89: - 0b:bc:8e:0e:2e:b1:67:ed:99:be:37:ee:75:7f:a9:fa:62:95: - 44:02:1c:99:26:fa:a7:17:61:d2:ec:e1:ca:42:2b:69:97:8f: - 71:dc:1b:41:7b:91:a8:d6:b2:82:05:ef:d0:0b:3c:46:a3:9d: - 7c:06:81:da:de:b6:54:ad:97:bd:c2:03:02:ff:1b:64:17:25: - 4a:4c:9b:85:c1:bb:6f:26:3a:b5:ba:9b:2d:17:b9:bd:36:b1: - 43:48:29:f7:da:88:8d:ce:f0:ac:7f:03:a7:93:e1:e9:c1:58: - 15:b3:30:22 ------BEGIN CERTIFICATE----- -MIIDIjCCAgygAwIBAgIBAzALBgkqhkiG9w0BAQUwLDEQMA4GA1UEChMHQWNtZSBD -bzEYMBYGA1UEAxMPSW50ZXJtZWRpYXRlIENBMB4XDTEzMDEwMTEwMDAwMFoXDTIz -MTIzMTEwMDAwMFowLTEQMA4GA1UEChMHQWNtZSBDbzEZMBcGA1UEAxMQTGVhZiBj -ZXJ0aWZpY2F0ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANXKGXmO -qatG8E63WG2zo5poEFKv8ACUrjS9tFAfoyaknhyQN1s96Nc7vJP7APvHSVSb8dCa -8lGEe1mLvWbzrpJauWOMZKfQnuMMUNLPk53pShFXk8Her3taRB0KjCKmHcat6Y8W -jU6R8dPx84L+9lXccvERB3Xsu+k6NYdDgV7cQ0q3fKEa1dLBQDlpfYmtZBsxNKjq -nl4m/HHSxmvlwnMwP1mnNY2ppek9Q0G9VPIq4RUMNTBri/J3ylwHj1j0VHder86x -wSunu8Dpfe8a1wPuj2etxuYdqeeRP0Hn1oYgjFOz2HkJ4ksVWtiSO2JPaOTL0KRO -tn0+X7Ak6mJhz3sCAwEAAaNSMFAwDgYDVR0PAQH/BAQDAgCgMBMGA1UdJQQMMAoG -CCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwGwYDVR0RBBQwEoIQdGVzdC5leGFtcGxl -LmNvbTALBgkqhkiG9w0BAQUDggEBAFjD3ONN7HbGYpm6um3a5C/sAPj7KuP2pLw3 -yVMPcy6meY9r74cWVnuebawa7ItJcX3yERGkDV5uvpNr/stEG06ZKtLr2JGA18iH -/cj6z8JoBgctYK5WxDxJTeMFPxsVqKnqhdiv0/W+tXEoI40E8cbh+wwbrFot4H/7 -TnlHKbOcJwl9PIQLWQoDxYapqpBJiQu8jg4usWftmb437nV/qfpilUQCHJkm+qcX -YdLs4cpCK2mXj3HcG0F7kajWsoIF79ALPEajnXwGgdretlStl73CAwL/G2QXJUpM -m4XBu28mOrW6my0Xub02sUNIKffaiI3O8Kx/A6eT4enBWBWzMCI= ------END CERTIFICATE----- -Certificate: - Data: - Version: 3 (0x2) - Serial Number: 2 (0x2) - Signature Algorithm: sha1WithRSAEncryption - Issuer: O=Acme Co, CN=Root CA - Validity - Not Before: Jan 1 10:00:00 2013 GMT - Not After : Dec 31 10:00:00 2023 GMT - Subject: O=Acme Co, CN=Intermediate CA - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (2048 bit) - Modulus: - 00:cd:35:50:e7:0a:68:80:e5:2b:f0:01:2b:93:11: - 0c:50:f7:23:e1:d8:d2:ed:48:9a:ea:3b:64:9f:82: - fa:e4:ad:23:96:a8:a1:9b:31:d1:d6:4a:b2:79:f1: - c1:80:03:18:41:54:a5:30:3a:82:bd:57:10:9c:fd: - 5d:34:fd:19:d3:21:1b:cb:06:e7:66:40:e1:27:89: - 98:82:2d:d7:2e:0d:5c:05:9a:74:0d:45:de:32:5e: - 78:4e:81:b4:c8:60:97:f0:8b:2a:8c:e0:57:f6:b9: - db:5a:53:64:1d:27:e0:93:47:d9:93:ee:ac:f6:7b: - e7:d2:97:b1:a6:85:37:75:ff:aa:f7:8f:ae:92:4e: - 30:0b:56:54:fd:32:f9:9d:3c:d8:2e:95:f5:64:17: - ff:26:d2:65:e2:b1:78:6c:83:5d:67:a4:d8:ae:89: - 6b:6e:b3:4b:35:a5:b1:03:3c:20:97:79:ed:0b:f8: - de:25:a1:3a:50:70:40:ae:9e:04:75:a2:6a:2f:15: - 84:5b:08:c3:e0:55:4e:47:db:bc:79:25:b0:2e:58: - 0d:bc:aa:a6:f2:ee:cd:e6:b8:02:8c:5b:00:b3:3d: - 44:d0:a6:bf:b3:e7:2e:9d:46:70:de:45:d1:bd:79: - bd:c0:f2:47:0b:71:28:60:91:c2:98:73:15:2d:b4: - b1:f3 - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Key Usage: critical - Certificate Sign - X509v3 Extended Key Usage: - TLS Web Server Authentication - X509v3 Basic Constraints: critical - CA:TRUE - Signature Algorithm: sha1WithRSAEncryption - b5:66:2c:a1:f8:76:8a:3b:6c:06:2d:d5:1e:4b:25:5c:b8:6d: - ee:0e:7e:09:a4:43:58:65:93:e9:da:6c:42:2e:5d:74:3f:79: - 61:4d:e5:72:45:d7:2d:fd:73:8e:e2:98:fe:8e:4a:e4:11:6e: - 94:5c:d9:84:c9:cb:a1:1c:fa:95:d9:15:c1:87:72:98:2e:63: - df:67:4d:04:1f:da:d7:29:66:ec:20:ea:b6:5d:71:dd:bc:5a: - 16:55:87:8f:51:9f:40:05:00:3b:21:ee:74:bc:3b:11:9a:10: - ba:b4:e8:5e:6e:90:c3:22:ca:da:92:f8:fb:8e:73:fd:69:91: - 13:48:11:01:58:ae:f4:b2:8c:38:56:f0:a5:3b:2a:64:5c:25: - 9a:bb:fd:94:27:34:af:b4:21:4c:08:23:3c:fb:3f:08:6f:07: - b8:05:9d:85:1d:73:0e:f0:83:f4:3c:9b:cc:aa:fd:3d:fa:82: - a4:dd:01:10:9d:10:2c:c4:47:64:ca:b4:b5:6e:be:59:d1:d2: - a1:6a:b5:d3:08:23:49:fc:4f:d4:f3:a5:63:b5:e1:34:19:9d: - 8c:33:0f:8e:47:01:9a:eb:2a:eb:cb:f4:1a:0c:ee:8e:68:d3: - c1:8e:fd:4b:93:ff:40:8c:3a:11:2b:62:a3:c1:a7:13:bd:26: - 37:c5:85:c5 ------BEGIN CERTIFICATE----- -MIIC/zCCAemgAwIBAgIBAjALBgkqhkiG9w0BAQUwJDEQMA4GA1UEChMHQWNtZSBD -bzEQMA4GA1UEAxMHUm9vdCBDQTAeFw0xMzAxMDExMDAwMDBaFw0yMzEyMzExMDAw -MDBaMCwxEDAOBgNVBAoTB0FjbWUgQ28xGDAWBgNVBAMTD0ludGVybWVkaWF0ZSBD -QTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM01UOcKaIDlK/ABK5MR -DFD3I+HY0u1Imuo7ZJ+C+uStI5aooZsx0dZKsnnxwYADGEFUpTA6gr1XEJz9XTT9 -GdMhG8sG52ZA4SeJmIIt1y4NXAWadA1F3jJeeE6BtMhgl/CLKozgV/a521pTZB0n -4JNH2ZPurPZ759KXsaaFN3X/qvePrpJOMAtWVP0y+Z082C6V9WQX/ybSZeKxeGyD -XWek2K6Ja26zSzWlsQM8IJd57Qv43iWhOlBwQK6eBHWiai8VhFsIw+BVTkfbvHkl -sC5YDbyqpvLuzea4AoxbALM9RNCmv7PnLp1GcN5F0b15vcDyRwtxKGCRwphzFS20 -sfMCAwEAAaM4MDYwDgYDVR0PAQH/BAQDAgAEMBMGA1UdJQQMMAoGCCsGAQUFBwMB -MA8GA1UdEwEB/wQFMAMBAf8wCwYJKoZIhvcNAQEFA4IBAQC1Ziyh+HaKO2wGLdUe -SyVcuG3uDn4JpENYZZPp2mxCLl10P3lhTeVyRdct/XOO4pj+jkrkEW6UXNmEycuh -HPqV2RXBh3KYLmPfZ00EH9rXKWbsIOq2XXHdvFoWVYePUZ9ABQA7Ie50vDsRmhC6 -tOhebpDDIsrakvj7jnP9aZETSBEBWK70sow4VvClOypkXCWau/2UJzSvtCFMCCM8 -+z8Ibwe4BZ2FHXMO8IP0PJvMqv09+oKk3QEQnRAsxEdkyrS1br5Z0dKharXTCCNJ -/E/U86VjteE0GZ2MMw+ORwGa6yrry/QaDO6OaNPBjv1Lk/9AjDoRK2KjwacTvSY3 -xYXF ------END CERTIFICATE----- -Certificate: - Data: - Version: 3 (0x2) - Serial Number: 1 (0x1) - Signature Algorithm: sha1WithRSAEncryption - Issuer: O=Acme Co, CN=Root CA - Validity - Not Before: Jan 1 10:00:00 2013 GMT - Not After : Dec 31 10:00:00 2023 GMT - Subject: O=Acme Co, CN=Root CA - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (2048 bit) - Modulus: - 00:e4:2b:91:c7:7d:ab:32:b7:38:e1:38:ae:c8:b9: - 0b:15:1c:64:76:47:84:5d:cb:e7:e7:0c:30:77:84: - 6a:8e:75:95:42:b2:78:c8:88:10:ac:98:47:97:38: - d1:3a:7f:86:0d:20:f1:1d:70:84:a2:9d:ed:1a:28: - af:5e:43:dd:31:a3:bb:b8:5c:c4:83:79:b8:83:9a: - e7:a9:63:04:59:93:b6:26:67:2d:dd:e6:2d:bb:e4: - 13:eb:d5:17:0b:de:63:46:76:6f:10:05:40:b0:16: - fc:ea:f4:97:1c:d6:dc:fe:37:72:d5:40:df:e3:b4: - d5:ac:cf:c9:ae:7c:21:49:01:1e:7e:d4:c1:e1:2a: - 11:01:b4:70:3a:31:3d:9a:33:b7:7f:20:f2:8b:e7: - 54:8e:06:f2:4b:5f:f0:e2:b9:8f:64:1f:50:bd:b3: - a5:ac:69:44:42:6c:12:e9:11:9d:74:b4:49:77:e3: - 0f:8b:9c:94:53:17:0c:23:ba:61:fa:70:3d:93:8d: - ad:5f:dd:4f:32:84:5b:07:50:e4:58:c7:00:45:82: - 1f:21:14:4c:bf:43:92:76:fb:24:09:33:df:58:8d: - be:87:ee:b5:54:e4:d3:32:f6:b1:2d:69:74:86:ad: - 1f:57:7e:9b:05:11:74:b5:c4:68:ac:9a:80:74:7a: - 34:89 - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Key Usage: critical - Certificate Sign - X509v3 Extended Key Usage: - TLS Web Server Authentication - X509v3 Basic Constraints: critical - CA:TRUE - Signature Algorithm: sha1WithRSAEncryption - 96:cd:db:46:6e:5b:de:fa:f1:d3:1c:e0:fe:47:67:2a:59:d5: - f8:c4:0b:25:14:0b:06:8d:82:67:f4:a9:36:e8:53:bc:eb:40: - 51:05:8a:42:09:e7:48:a3:7c:42:6d:c1:37:06:49:cf:58:87: - d0:0e:c7:9e:4b:0e:34:72:f8:65:65:b2:c4:68:ca:a3:14:e9: - 11:5c:da:78:4e:74:80:43:dc:b8:b6:ce:a8:0c:a2:8f:52:59: - 89:e0:5a:01:e5:e9:b8:4b:31:91:25:bf:7d:e1:7c:86:e9:36: - c1:5b:10:e5:2c:cc:6f:99:c4:66:79:30:41:1f:0b:f9:4b:ea: - 1e:8a:45:73:3c:79:21:20:c8:80:c4:f4:e9:4f:85:69:7c:2e: - 61:80:3a:4f:5b:92:be:97:12:75:9e:43:09:01:b6:b3:a1:c1: - 5f:2d:86:be:d1:6c:55:ee:27:f8:bf:3a:bc:fb:b2:42:8a:6f: - 51:a0:d3:46:54:f6:1e:73:42:2a:95:5e:eb:bc:40:6b:71:bf: - 90:94:62:f4:90:17:82:e5:1e:33:db:f4:50:11:e5:55:10:09: - 6a:11:a9:1e:d4:07:60:58:f7:16:b1:bd:8b:29:f6:3d:61:ad: - 73:da:ae:e3:e4:6e:59:46:7f:c0:fb:fa:be:6d:7c:31:94:86: - 2e:b3:29:7b ------BEGIN CERTIFICATE----- -MIIC9zCCAeGgAwIBAgIBATALBgkqhkiG9w0BAQUwJDEQMA4GA1UEChMHQWNtZSBD -bzEQMA4GA1UEAxMHUm9vdCBDQTAeFw0xMzAxMDExMDAwMDBaFw0yMzEyMzExMDAw -MDBaMCQxEDAOBgNVBAoTB0FjbWUgQ28xEDAOBgNVBAMTB1Jvb3QgQ0EwggEiMA0G -CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkK5HHfasytzjhOK7IuQsVHGR2R4Rd -y+fnDDB3hGqOdZVCsnjIiBCsmEeXONE6f4YNIPEdcISine0aKK9eQ90xo7u4XMSD -ebiDmuepYwRZk7YmZy3d5i275BPr1RcL3mNGdm8QBUCwFvzq9Jcc1tz+N3LVQN/j -tNWsz8mufCFJAR5+1MHhKhEBtHA6MT2aM7d/IPKL51SOBvJLX/DiuY9kH1C9s6Ws -aURCbBLpEZ10tEl34w+LnJRTFwwjumH6cD2Tja1f3U8yhFsHUORYxwBFgh8hFEy/ -Q5J2+yQJM99Yjb6H7rVU5NMy9rEtaXSGrR9XfpsFEXS1xGismoB0ejSJAgMBAAGj -ODA2MA4GA1UdDwEB/wQEAwIABDATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHRMB -Af8EBTADAQH/MAsGCSqGSIb3DQEBBQOCAQEAls3bRm5b3vrx0xzg/kdnKlnV+MQL -JRQLBo2CZ/SpNuhTvOtAUQWKQgnnSKN8Qm3BNwZJz1iH0A7HnksONHL4ZWWyxGjK -oxTpEVzaeE50gEPcuLbOqAyij1JZieBaAeXpuEsxkSW/feF8huk2wVsQ5SzMb5nE -ZnkwQR8L+UvqHopFczx5ISDIgMT06U+FaXwuYYA6T1uSvpcSdZ5DCQG2s6HBXy2G -vtFsVe4n+L86vPuyQopvUaDTRlT2HnNCKpVe67xAa3G/kJRi9JAXguUeM9v0UBHl -VRAJahGpHtQHYFj3FrG9iyn2PWGtc9qu4+RuWUZ/wPv6vm18MZSGLrMpew== ------END CERTIFICATE----- diff --git a/chromium/net/data/ssl/certificates/quic_intermediate.crt b/chromium/net/data/ssl/certificates/quic_intermediate.crt deleted file mode 100644 index 29e3a66fd37..00000000000 --- a/chromium/net/data/ssl/certificates/quic_intermediate.crt +++ /dev/null @@ -1,75 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: 2 (0x2) - Signature Algorithm: sha1WithRSAEncryption - Issuer: O=Acme Co, CN=Root CA - Validity - Not Before: Jan 1 10:00:00 2013 GMT - Not After : Dec 31 10:00:00 2023 GMT - Subject: O=Acme Co, CN=Intermediate CA - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (2048 bit) - Modulus: - 00:cd:35:50:e7:0a:68:80:e5:2b:f0:01:2b:93:11: - 0c:50:f7:23:e1:d8:d2:ed:48:9a:ea:3b:64:9f:82: - fa:e4:ad:23:96:a8:a1:9b:31:d1:d6:4a:b2:79:f1: - c1:80:03:18:41:54:a5:30:3a:82:bd:57:10:9c:fd: - 5d:34:fd:19:d3:21:1b:cb:06:e7:66:40:e1:27:89: - 98:82:2d:d7:2e:0d:5c:05:9a:74:0d:45:de:32:5e: - 78:4e:81:b4:c8:60:97:f0:8b:2a:8c:e0:57:f6:b9: - db:5a:53:64:1d:27:e0:93:47:d9:93:ee:ac:f6:7b: - e7:d2:97:b1:a6:85:37:75:ff:aa:f7:8f:ae:92:4e: - 30:0b:56:54:fd:32:f9:9d:3c:d8:2e:95:f5:64:17: - ff:26:d2:65:e2:b1:78:6c:83:5d:67:a4:d8:ae:89: - 6b:6e:b3:4b:35:a5:b1:03:3c:20:97:79:ed:0b:f8: - de:25:a1:3a:50:70:40:ae:9e:04:75:a2:6a:2f:15: - 84:5b:08:c3:e0:55:4e:47:db:bc:79:25:b0:2e:58: - 0d:bc:aa:a6:f2:ee:cd:e6:b8:02:8c:5b:00:b3:3d: - 44:d0:a6:bf:b3:e7:2e:9d:46:70:de:45:d1:bd:79: - bd:c0:f2:47:0b:71:28:60:91:c2:98:73:15:2d:b4: - b1:f3 - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Key Usage: critical - Certificate Sign - X509v3 Extended Key Usage: - TLS Web Server Authentication - X509v3 Basic Constraints: critical - CA:TRUE - Signature Algorithm: sha1WithRSAEncryption - b5:66:2c:a1:f8:76:8a:3b:6c:06:2d:d5:1e:4b:25:5c:b8:6d: - ee:0e:7e:09:a4:43:58:65:93:e9:da:6c:42:2e:5d:74:3f:79: - 61:4d:e5:72:45:d7:2d:fd:73:8e:e2:98:fe:8e:4a:e4:11:6e: - 94:5c:d9:84:c9:cb:a1:1c:fa:95:d9:15:c1:87:72:98:2e:63: - df:67:4d:04:1f:da:d7:29:66:ec:20:ea:b6:5d:71:dd:bc:5a: - 16:55:87:8f:51:9f:40:05:00:3b:21:ee:74:bc:3b:11:9a:10: - ba:b4:e8:5e:6e:90:c3:22:ca:da:92:f8:fb:8e:73:fd:69:91: - 13:48:11:01:58:ae:f4:b2:8c:38:56:f0:a5:3b:2a:64:5c:25: - 9a:bb:fd:94:27:34:af:b4:21:4c:08:23:3c:fb:3f:08:6f:07: - b8:05:9d:85:1d:73:0e:f0:83:f4:3c:9b:cc:aa:fd:3d:fa:82: - a4:dd:01:10:9d:10:2c:c4:47:64:ca:b4:b5:6e:be:59:d1:d2: - a1:6a:b5:d3:08:23:49:fc:4f:d4:f3:a5:63:b5:e1:34:19:9d: - 8c:33:0f:8e:47:01:9a:eb:2a:eb:cb:f4:1a:0c:ee:8e:68:d3: - c1:8e:fd:4b:93:ff:40:8c:3a:11:2b:62:a3:c1:a7:13:bd:26: - 37:c5:85:c5 ------BEGIN CERTIFICATE----- -MIIC/zCCAemgAwIBAgIBAjALBgkqhkiG9w0BAQUwJDEQMA4GA1UEChMHQWNtZSBD -bzEQMA4GA1UEAxMHUm9vdCBDQTAeFw0xMzAxMDExMDAwMDBaFw0yMzEyMzExMDAw -MDBaMCwxEDAOBgNVBAoTB0FjbWUgQ28xGDAWBgNVBAMTD0ludGVybWVkaWF0ZSBD -QTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM01UOcKaIDlK/ABK5MR -DFD3I+HY0u1Imuo7ZJ+C+uStI5aooZsx0dZKsnnxwYADGEFUpTA6gr1XEJz9XTT9 -GdMhG8sG52ZA4SeJmIIt1y4NXAWadA1F3jJeeE6BtMhgl/CLKozgV/a521pTZB0n -4JNH2ZPurPZ759KXsaaFN3X/qvePrpJOMAtWVP0y+Z082C6V9WQX/ybSZeKxeGyD -XWek2K6Ja26zSzWlsQM8IJd57Qv43iWhOlBwQK6eBHWiai8VhFsIw+BVTkfbvHkl -sC5YDbyqpvLuzea4AoxbALM9RNCmv7PnLp1GcN5F0b15vcDyRwtxKGCRwphzFS20 -sfMCAwEAAaM4MDYwDgYDVR0PAQH/BAQDAgAEMBMGA1UdJQQMMAoGCCsGAQUFBwMB -MA8GA1UdEwEB/wQFMAMBAf8wCwYJKoZIhvcNAQEFA4IBAQC1Ziyh+HaKO2wGLdUe -SyVcuG3uDn4JpENYZZPp2mxCLl10P3lhTeVyRdct/XOO4pj+jkrkEW6UXNmEycuh -HPqV2RXBh3KYLmPfZ00EH9rXKWbsIOq2XXHdvFoWVYePUZ9ABQA7Ie50vDsRmhC6 -tOhebpDDIsrakvj7jnP9aZETSBEBWK70sow4VvClOypkXCWau/2UJzSvtCFMCCM8 -+z8Ibwe4BZ2FHXMO8IP0PJvMqv09+oKk3QEQnRAsxEdkyrS1br5Z0dKharXTCCNJ -/E/U86VjteE0GZ2MMw+ORwGa6yrry/QaDO6OaNPBjv1Lk/9AjDoRK2KjwacTvSY3 -xYXF ------END CERTIFICATE----- diff --git a/chromium/net/data/ssl/certificates/quic_intermediate.key b/chromium/net/data/ssl/certificates/quic_intermediate.key deleted file mode 100644 index a8d1b8cfaa9..00000000000 --- a/chromium/net/data/ssl/certificates/quic_intermediate.key +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEpAIBAAKCAQEAzTVQ5wpogOUr8AErkxEMUPcj4djS7Uia6jtkn4L65K0jlqih -mzHR1kqyefHBgAMYQVSlMDqCvVcQnP1dNP0Z0yEbywbnZkDhJ4mYgi3XLg1cBZp0 -DUXeMl54ToG0yGCX8IsqjOBX9rnbWlNkHSfgk0fZk+6s9nvn0pexpoU3df+q94+u -kk4wC1ZU/TL5nTzYLpX1ZBf/JtJl4rF4bINdZ6TYrolrbrNLNaWxAzwgl3ntC/je -JaE6UHBArp4EdaJqLxWEWwjD4FVOR9u8eSWwLlgNvKqm8u7N5rgCjFsAsz1E0Ka/ -s+cunUZw3kXRvXm9wPJHC3EoYJHCmHMVLbSx8wIDAQABAoIBAQCSQevVoA93vt8g -AlWCTmZO1raWY6mCQXtYcth28C3OCrEQ0kPMjyeV6ktmqq5VhN8mwSOzSiCgvosy -uUpTWAmt9y0N+W+364oOWf1+2xlA03jA7aLFSwThNX/dxIiLQH1KjoXXPpazXShA -KqtyNFfV4SHsU/KnAwzphgCyRMSQrk/5YZfdfkbnhKhXGtdBmja+4wB7khOcv5Vb -+S2FAxftWdyTo3AOSwSED5Evq8gML4RWl46bZ5r2Gu6W+eBxDyRT+iftNLOMO6PL -7ivn3mbZSBUxOZPvKNh6sxrUsSnxUrcZ5d819yiRolKywY5lM+BrqP9CFMfEKFP9 -R9zooJdhAoGBAOLXZviVGzOgLB418GKkw5NReeiKNPPX+w7vX+VYTiw60yRf87iS -RhgqTXQDYKExgOO/giEJ0M3VJ6RU8MqqeHtDoKPjzZmGXs/zB0WSPIYa1A4QjQHO -UNE1OvTwxHQCKZg0u46AZMnZWHpt005iVQ4LG8uHpUYdYxLn0LfPTvWpAoGBAOeW -Cecnv/1GU5ft4Y8LDlFzwFzgRjRBMuX8erQz6lJUlnWLq/ZwSbag0qK+9iVfrvUT -F9zNpfgFFsyMI8OPeJsEJkvQEZA4XDEZyvZCstjxWvI81T1bnc1/JU+YeaFcqSDq -X7+ARNquoH9ntbXRRW4ACafQdY3KNqeBCpKBlfQ7AoGAVK/cNoPcMuribajvhLRE -e7RYUfN/D2YbyZiecY4FKUgQ2ayk3cxmNNFeNyino6ZKmzw9Bb6XYLDqatR3TQJV -lpdJ2sXKVT2wGex+U3/j7qEHd/S/3+O5klFQIG/et/yysKtHNk1C04S8HoDv+XyG -ioalKtgKYOHJwh4fcvAHZ3kCgYAen25rzIvMl/IR0vjSi2m3R5EWNunRmxV55+rp -zTuc62aB4Jg6nBqDNbzknE+8HWzrJz0ui1r48uNS5O0NvPj7to7B05+e7HT0YS6/ -ZY50tWWLRpQD6wtw0vFCFy1uMuyCV7uVfQadzB2Y+0PB6Qw/QW4FbME+oJCdkaiu -OshzZQKBgQCXKYjh2fwBozDn7u8OQZ6sJt74EOZqAMfv7NQ2xbD5Jg5ABnOcFrXu -FWvE9KoiJYmDD26lFIbmQ9KlAsQjKrOiRit50IALrlfATRYpEGnlO8M+c209+5wx -FVncGUcoKbzLIrIJz7Cfd3MLbB8wSO8RBpeTa0IU5XhkTnk130Ue7A== ------END RSA PRIVATE KEY----- diff --git a/chromium/net/data/ssl/certificates/quic_root.crt b/chromium/net/data/ssl/certificates/quic_root.crt deleted file mode 100644 index 730bfcd6816..00000000000 --- a/chromium/net/data/ssl/certificates/quic_root.crt +++ /dev/null @@ -1,74 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: 1 (0x1) - Signature Algorithm: sha1WithRSAEncryption - Issuer: O=Acme Co, CN=Root CA - Validity - Not Before: Jan 1 10:00:00 2013 GMT - Not After : Dec 31 10:00:00 2023 GMT - Subject: O=Acme Co, CN=Root CA - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (2048 bit) - Modulus: - 00:e4:2b:91:c7:7d:ab:32:b7:38:e1:38:ae:c8:b9: - 0b:15:1c:64:76:47:84:5d:cb:e7:e7:0c:30:77:84: - 6a:8e:75:95:42:b2:78:c8:88:10:ac:98:47:97:38: - d1:3a:7f:86:0d:20:f1:1d:70:84:a2:9d:ed:1a:28: - af:5e:43:dd:31:a3:bb:b8:5c:c4:83:79:b8:83:9a: - e7:a9:63:04:59:93:b6:26:67:2d:dd:e6:2d:bb:e4: - 13:eb:d5:17:0b:de:63:46:76:6f:10:05:40:b0:16: - fc:ea:f4:97:1c:d6:dc:fe:37:72:d5:40:df:e3:b4: - d5:ac:cf:c9:ae:7c:21:49:01:1e:7e:d4:c1:e1:2a: - 11:01:b4:70:3a:31:3d:9a:33:b7:7f:20:f2:8b:e7: - 54:8e:06:f2:4b:5f:f0:e2:b9:8f:64:1f:50:bd:b3: - a5:ac:69:44:42:6c:12:e9:11:9d:74:b4:49:77:e3: - 0f:8b:9c:94:53:17:0c:23:ba:61:fa:70:3d:93:8d: - ad:5f:dd:4f:32:84:5b:07:50:e4:58:c7:00:45:82: - 1f:21:14:4c:bf:43:92:76:fb:24:09:33:df:58:8d: - be:87:ee:b5:54:e4:d3:32:f6:b1:2d:69:74:86:ad: - 1f:57:7e:9b:05:11:74:b5:c4:68:ac:9a:80:74:7a: - 34:89 - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Key Usage: critical - Certificate Sign - X509v3 Extended Key Usage: - TLS Web Server Authentication - X509v3 Basic Constraints: critical - CA:TRUE - Signature Algorithm: sha1WithRSAEncryption - 96:cd:db:46:6e:5b:de:fa:f1:d3:1c:e0:fe:47:67:2a:59:d5: - f8:c4:0b:25:14:0b:06:8d:82:67:f4:a9:36:e8:53:bc:eb:40: - 51:05:8a:42:09:e7:48:a3:7c:42:6d:c1:37:06:49:cf:58:87: - d0:0e:c7:9e:4b:0e:34:72:f8:65:65:b2:c4:68:ca:a3:14:e9: - 11:5c:da:78:4e:74:80:43:dc:b8:b6:ce:a8:0c:a2:8f:52:59: - 89:e0:5a:01:e5:e9:b8:4b:31:91:25:bf:7d:e1:7c:86:e9:36: - c1:5b:10:e5:2c:cc:6f:99:c4:66:79:30:41:1f:0b:f9:4b:ea: - 1e:8a:45:73:3c:79:21:20:c8:80:c4:f4:e9:4f:85:69:7c:2e: - 61:80:3a:4f:5b:92:be:97:12:75:9e:43:09:01:b6:b3:a1:c1: - 5f:2d:86:be:d1:6c:55:ee:27:f8:bf:3a:bc:fb:b2:42:8a:6f: - 51:a0:d3:46:54:f6:1e:73:42:2a:95:5e:eb:bc:40:6b:71:bf: - 90:94:62:f4:90:17:82:e5:1e:33:db:f4:50:11:e5:55:10:09: - 6a:11:a9:1e:d4:07:60:58:f7:16:b1:bd:8b:29:f6:3d:61:ad: - 73:da:ae:e3:e4:6e:59:46:7f:c0:fb:fa:be:6d:7c:31:94:86: - 2e:b3:29:7b ------BEGIN CERTIFICATE----- -MIIC9zCCAeGgAwIBAgIBATALBgkqhkiG9w0BAQUwJDEQMA4GA1UEChMHQWNtZSBD -bzEQMA4GA1UEAxMHUm9vdCBDQTAeFw0xMzAxMDExMDAwMDBaFw0yMzEyMzExMDAw -MDBaMCQxEDAOBgNVBAoTB0FjbWUgQ28xEDAOBgNVBAMTB1Jvb3QgQ0EwggEiMA0G -CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkK5HHfasytzjhOK7IuQsVHGR2R4Rd -y+fnDDB3hGqOdZVCsnjIiBCsmEeXONE6f4YNIPEdcISine0aKK9eQ90xo7u4XMSD -ebiDmuepYwRZk7YmZy3d5i275BPr1RcL3mNGdm8QBUCwFvzq9Jcc1tz+N3LVQN/j -tNWsz8mufCFJAR5+1MHhKhEBtHA6MT2aM7d/IPKL51SOBvJLX/DiuY9kH1C9s6Ws -aURCbBLpEZ10tEl34w+LnJRTFwwjumH6cD2Tja1f3U8yhFsHUORYxwBFgh8hFEy/ -Q5J2+yQJM99Yjb6H7rVU5NMy9rEtaXSGrR9XfpsFEXS1xGismoB0ejSJAgMBAAGj -ODA2MA4GA1UdDwEB/wQEAwIABDATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHRMB -Af8EBTADAQH/MAsGCSqGSIb3DQEBBQOCAQEAls3bRm5b3vrx0xzg/kdnKlnV+MQL -JRQLBo2CZ/SpNuhTvOtAUQWKQgnnSKN8Qm3BNwZJz1iH0A7HnksONHL4ZWWyxGjK -oxTpEVzaeE50gEPcuLbOqAyij1JZieBaAeXpuEsxkSW/feF8huk2wVsQ5SzMb5nE -ZnkwQR8L+UvqHopFczx5ISDIgMT06U+FaXwuYYA6T1uSvpcSdZ5DCQG2s6HBXy2G -vtFsVe4n+L86vPuyQopvUaDTRlT2HnNCKpVe67xAa3G/kJRi9JAXguUeM9v0UBHl -VRAJahGpHtQHYFj3FrG9iyn2PWGtc9qu4+RuWUZ/wPv6vm18MZSGLrMpew== ------END CERTIFICATE----- diff --git a/chromium/net/data/ssl/certificates/quic_root.key b/chromium/net/data/ssl/certificates/quic_root.key deleted file mode 100644 index 9791d1fdb48..00000000000 --- a/chromium/net/data/ssl/certificates/quic_root.key +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEowIBAAKCAQEA5CuRx32rMrc44TiuyLkLFRxkdkeEXcvn5wwwd4RqjnWVQrJ4 -yIgQrJhHlzjROn+GDSDxHXCEop3tGiivXkPdMaO7uFzEg3m4g5rnqWMEWZO2Jmct -3eYtu+QT69UXC95jRnZvEAVAsBb86vSXHNbc/jdy1UDf47TVrM/JrnwhSQEeftTB -4SoRAbRwOjE9mjO3fyDyi+dUjgbyS1/w4rmPZB9QvbOlrGlEQmwS6RGddLRJd+MP -i5yUUxcMI7ph+nA9k42tX91PMoRbB1DkWMcARYIfIRRMv0OSdvskCTPfWI2+h+61 -VOTTMvaxLWl0hq0fV36bBRF0tcRorJqAdHo0iQIDAQABAoIBAC9L/Mb+fMthgY/m -IQ0IloyEuyptfrm2t9aEB1PvBeuL4inWNwVSdypf0o89PtnCb3YvOuvgVA4lcG24 -u0luBd7xUstPp4idZasaJCVPmio7XUmun6pcuWQ2Tg7XuBREwA1uJW2LuTIHQdwu -YVigDWVA9zPPY9metaBB3kul/XxVM7+fXheCHzXTzJEaAw+7Gexe8QYuq4ftcocD -f7O/j/ts3IrKa1Xrl5RFC/tCNwpZ3yrp/Scdit32wbvCQwcdZ6/dDu6BWY4GJm8q -z7kaDZkXQa50EzT9g+DPTLC3qA2USh8M+NfqVjdHYkAqj64StCjvXHboTbDdZXoz -HvsONNUCgYEA/THRfqRpRPHW9ONSyRma6+XtzrCepVn/ceguO9bfD0e2+l1/6uXQ -hctuwelRD89Z6Ir5kW2I8fRT0mPhCcuv5TW1hOiwK6WKasYxRu3ox+bZiAoRsEBd -Xm4bvr814E/QO5DsDd5KMdEPb6ulStI1y94atCjX50r+vZWMGG82dK8CgYEA5rLF -FPBt+049Wq8bIXXVbInwPD0hHeIrhfTqsDeuLwYsmf7o29dU7sjDFS5x1cCfVsqO -UpXM5J4C3lhDC9ZTX0vVgT/TROq7etRZeBHVN+CJS0jgeMjUqWQTZYPMzE0Bu8/P -+9mqSZzkwipesG4JpdSkt/1IOIoDrbK8mYpDqEcCgYEA5wfGOOCcjaR+mAW1THpo -ukebrrXKjOaKB83sIf32m2K8u8cFKbl5hBwUfCwBI4P4bhAhmWlxRBXFRnyMovuR -DHztnNEVrz3mB3fBDw+XEJC8fT1y1nhkuf2Oo4amCn/JahDa0+y5lqtEgokE0jjt -jZCknS+Hki0ENMl4g/M2pVECgYB8oF6vbSM8+4tRjf8OGGXveKT7JdraFfCFMUYH -ZE0IwkEeAAMzoCQVywb4TlrYqnJppIs2Og6yAlpyWyP9JQ9tD76LUDuFo3kcZdLf -dmLFCNuifAAnv/aCe7muwYDFbWReXWlyGKhRlBxQeCsnDIrRtwo1CvMU+Bn8n+4a -1AKwyQKBgGpBZwN28VjqYkM5fO6RDNBvgQ1ApfSh/Kfwg0MrO8uhmvlWDuWCoei4 -v08pchPRO75ktIv4r9bR7ylTpB9JhCe2kNABWma4mnlUg4+nmiWMTZo6Pyabstkt -yzGIGZYdMDzOBjph7JxQZhGijz3uVc9CiFg+2AElbpCYDRHn5N3s ------END RSA PRIVATE KEY----- diff --git a/chromium/net/data/ssl/certificates/quic_test.example.com.crt b/chromium/net/data/ssl/certificates/quic_test.example.com.crt deleted file mode 100644 index b8123386fa9..00000000000 --- a/chromium/net/data/ssl/certificates/quic_test.example.com.crt +++ /dev/null @@ -1,77 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: 3 (0x3) - Signature Algorithm: sha1WithRSAEncryption - Issuer: O=Acme Co, CN=Intermediate CA - Validity - Not Before: Jan 1 10:00:00 2013 GMT - Not After : Dec 31 10:00:00 2023 GMT - Subject: O=Acme Co, CN=Leaf certificate - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (2048 bit) - Modulus: - 00:d5:ca:19:79:8e:a9:ab:46:f0:4e:b7:58:6d:b3: - a3:9a:68:10:52:af:f0:00:94:ae:34:bd:b4:50:1f: - a3:26:a4:9e:1c:90:37:5b:3d:e8:d7:3b:bc:93:fb: - 00:fb:c7:49:54:9b:f1:d0:9a:f2:51:84:7b:59:8b: - bd:66:f3:ae:92:5a:b9:63:8c:64:a7:d0:9e:e3:0c: - 50:d2:cf:93:9d:e9:4a:11:57:93:c1:de:af:7b:5a: - 44:1d:0a:8c:22:a6:1d:c6:ad:e9:8f:16:8d:4e:91: - f1:d3:f1:f3:82:fe:f6:55:dc:72:f1:11:07:75:ec: - bb:e9:3a:35:87:43:81:5e:dc:43:4a:b7:7c:a1:1a: - d5:d2:c1:40:39:69:7d:89:ad:64:1b:31:34:a8:ea: - 9e:5e:26:fc:71:d2:c6:6b:e5:c2:73:30:3f:59:a7: - 35:8d:a9:a5:e9:3d:43:41:bd:54:f2:2a:e1:15:0c: - 35:30:6b:8b:f2:77:ca:5c:07:8f:58:f4:54:77:5e: - af:ce:b1:c1:2b:a7:bb:c0:e9:7d:ef:1a:d7:03:ee: - 8f:67:ad:c6:e6:1d:a9:e7:91:3f:41:e7:d6:86:20: - 8c:53:b3:d8:79:09:e2:4b:15:5a:d8:92:3b:62:4f: - 68:e4:cb:d0:a4:4e:b6:7d:3e:5f:b0:24:ea:62:61: - cf:7b - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Key Usage: critical - Digital Signature, Key Encipherment - X509v3 Extended Key Usage: - TLS Web Server Authentication - X509v3 Basic Constraints: critical - CA:FALSE - X509v3 Subject Alternative Name: - DNS:test.example.com - Signature Algorithm: sha1WithRSAEncryption - 58:c3:dc:e3:4d:ec:76:c6:62:99:ba:ba:6d:da:e4:2f:ec:00: - f8:fb:2a:e3:f6:a4:bc:37:c9:53:0f:73:2e:a6:79:8f:6b:ef: - 87:16:56:7b:9e:6d:ac:1a:ec:8b:49:71:7d:f2:11:11:a4:0d: - 5e:6e:be:93:6b:fe:cb:44:1b:4e:99:2a:d2:eb:d8:91:80:d7: - c8:87:fd:c8:fa:cf:c2:68:06:07:2d:60:ae:56:c4:3c:49:4d: - e3:05:3f:1b:15:a8:a9:ea:85:d8:af:d3:f5:be:b5:71:28:23: - 8d:04:f1:c6:e1:fb:0c:1b:ac:5a:2d:e0:7f:fb:4e:79:47:29: - b3:9c:27:09:7d:3c:84:0b:59:0a:03:c5:86:a9:aa:90:49:89: - 0b:bc:8e:0e:2e:b1:67:ed:99:be:37:ee:75:7f:a9:fa:62:95: - 44:02:1c:99:26:fa:a7:17:61:d2:ec:e1:ca:42:2b:69:97:8f: - 71:dc:1b:41:7b:91:a8:d6:b2:82:05:ef:d0:0b:3c:46:a3:9d: - 7c:06:81:da:de:b6:54:ad:97:bd:c2:03:02:ff:1b:64:17:25: - 4a:4c:9b:85:c1:bb:6f:26:3a:b5:ba:9b:2d:17:b9:bd:36:b1: - 43:48:29:f7:da:88:8d:ce:f0:ac:7f:03:a7:93:e1:e9:c1:58: - 15:b3:30:22 ------BEGIN CERTIFICATE----- -MIIDIjCCAgygAwIBAgIBAzALBgkqhkiG9w0BAQUwLDEQMA4GA1UEChMHQWNtZSBD -bzEYMBYGA1UEAxMPSW50ZXJtZWRpYXRlIENBMB4XDTEzMDEwMTEwMDAwMFoXDTIz -MTIzMTEwMDAwMFowLTEQMA4GA1UEChMHQWNtZSBDbzEZMBcGA1UEAxMQTGVhZiBj -ZXJ0aWZpY2F0ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANXKGXmO -qatG8E63WG2zo5poEFKv8ACUrjS9tFAfoyaknhyQN1s96Nc7vJP7APvHSVSb8dCa -8lGEe1mLvWbzrpJauWOMZKfQnuMMUNLPk53pShFXk8Her3taRB0KjCKmHcat6Y8W -jU6R8dPx84L+9lXccvERB3Xsu+k6NYdDgV7cQ0q3fKEa1dLBQDlpfYmtZBsxNKjq -nl4m/HHSxmvlwnMwP1mnNY2ppek9Q0G9VPIq4RUMNTBri/J3ylwHj1j0VHder86x -wSunu8Dpfe8a1wPuj2etxuYdqeeRP0Hn1oYgjFOz2HkJ4ksVWtiSO2JPaOTL0KRO -tn0+X7Ak6mJhz3sCAwEAAaNSMFAwDgYDVR0PAQH/BAQDAgCgMBMGA1UdJQQMMAoG -CCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwGwYDVR0RBBQwEoIQdGVzdC5leGFtcGxl -LmNvbTALBgkqhkiG9w0BAQUDggEBAFjD3ONN7HbGYpm6um3a5C/sAPj7KuP2pLw3 -yVMPcy6meY9r74cWVnuebawa7ItJcX3yERGkDV5uvpNr/stEG06ZKtLr2JGA18iH -/cj6z8JoBgctYK5WxDxJTeMFPxsVqKnqhdiv0/W+tXEoI40E8cbh+wwbrFot4H/7 -TnlHKbOcJwl9PIQLWQoDxYapqpBJiQu8jg4usWftmb437nV/qfpilUQCHJkm+qcX -YdLs4cpCK2mXj3HcG0F7kajWsoIF79ALPEajnXwGgdretlStl73CAwL/G2QXJUpM -m4XBu28mOrW6my0Xub02sUNIKffaiI3O8Kx/A6eT4enBWBWzMCI= ------END CERTIFICATE----- diff --git a/chromium/net/data/ssl/certificates/quic_test.example.com.key b/chromium/net/data/ssl/certificates/quic_test.example.com.key deleted file mode 100644 index 9449ec673d7..00000000000 --- a/chromium/net/data/ssl/certificates/quic_test.example.com.key +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEpAIBAAKCAQEA1coZeY6pq0bwTrdYbbOjmmgQUq/wAJSuNL20UB+jJqSeHJA3 -Wz3o1zu8k/sA+8dJVJvx0JryUYR7WYu9ZvOuklq5Y4xkp9Ce4wxQ0s+TnelKEVeT -wd6ve1pEHQqMIqYdxq3pjxaNTpHx0/Hzgv72Vdxy8REHdey76To1h0OBXtxDSrd8 -oRrV0sFAOWl9ia1kGzE0qOqeXib8cdLGa+XCczA/Wac1jaml6T1DQb1U8irhFQw1 -MGuL8nfKXAePWPRUd16vzrHBK6e7wOl97xrXA+6PZ63G5h2p55E/QefWhiCMU7PY -eQniSxVa2JI7Yk9o5MvQpE62fT5fsCTqYmHPewIDAQABAoIBABIwh8pX4Qe5mWiZ -IOT0i87vW7QtU/Y4sDm8ikLm7jKzfuBfRNZ2hgEKDBlrGcJSSmLwgbqF9GgLJZOQ -2CSSRyAcp/lYUJgWn+4hdh75mk2tM6gWE3RDRhrwqyrtYs7v40isM1sBSDSPJkwq -IdXba4oSn5TzJfdalQJa+YLws2kmnKL2cHvHJudazeV3JScfqOkjjYT1HZVFiech -KQOJo1d3guvyLzzqDJq/BkUvaAQepJu8oXGhq0lApXPit5aRRft4Fw+ewAbU9t7r -KzRp7YusZ1EQ2A5vn1F9o/JGRERL42BqwjRqfhHnK084Y4GhbpMrMkV0ae5i7xhK -npKHXIECgYEA5tW5imZhPtBWSSA1w+MTIoqXPrK3eirmgmHSeYtMbfcUwuSiQOXk -pqEJ9PoVmvNOuQPdbR4kfLuPUJecT+qEMPJAN3aWZYmSUi/6O1fml6DDvf0dx/LW -4mZ9Mu3DGGmK+zxplwv4IkkOWIu6hPsioyoMd+QxhIk2o7eBViev7IkCgYEA7Rip -T8k/5PFxs99OasNlu3fJxRbEeJEiZaW21gcK36LosNITgEQs3r2Q6us0hsfUCvEr -+QAjNOk6zsUlTbJYymshStBPh3OTf2zYwg8SXfuAoFDYTNk2uML2alvBRkIKYSVV -J2Lv2GoYxE1oTIgBDj3Jv4+xPZPx0AYmYsa6AuMCgYAd8wbirQva8X7wd+xh4Plf -lumuqdNiV2SW8Ag12tvsvI0GCFIA55L2B5jaHwRkmULSgGzfNnT3dgJPK4yNVdkW -3Kd2Sr2SqPnCDhWCU5JIhARBhzCw+5Hjx/ZggDa62R6+IAV3IodsM1xYIrDthgPl -dZQujf3au07KiQmP2xBZOQKBgQDACJ5xwgXfT/ORBYgFDxgh2+bvm/4rzRl4DN1m -wrN66P7g4HXtCMry6cUrkK+tjsJeznGYLxVU8Kax/Jm3MYGbCWQgrVIM2n6X0bhK -jVyKBH9s2a4nqDMbOMXO5VxIpIq1nkA3M3oh5eUDcdLNUcbRGxiB8EdVIbPUknaa -wGy+kwKBgQDE90KVnTzZQ6D20pAAvYaFCGkWUvKzf/C7NZcGH+UcWok3BCrkNiGK -YTEbEs6h26Q8S7Vm7FiRnfVQEW4HPFuQ8wpnYrYFJbfRbGsG8agxju25Kg+EBJGU -uu83oQ8zNiK/LMtNEGcQotXSVxAUdg1AoS5p1UX9cgmM9MZhkkbJIw== ------END RSA PRIVATE KEY----- diff --git a/chromium/net/data/ssl/certificates/quic_test.example.com.key.pkcs8 b/chromium/net/data/ssl/certificates/quic_test.example.com.key.pkcs8 Binary files differdeleted file mode 100644 index 5f341e52106..00000000000 --- a/chromium/net/data/ssl/certificates/quic_test.example.com.key.pkcs8 +++ /dev/null diff --git a/chromium/net/data/ssl/certificates/quic_test.example.com.key.pkcs8.pem b/chromium/net/data/ssl/certificates/quic_test.example.com.key.pkcs8.pem deleted file mode 100644 index e52b455f53f..00000000000 --- a/chromium/net/data/ssl/certificates/quic_test.example.com.key.pkcs8.pem +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDVyhl5jqmrRvBO -t1hts6OaaBBSr/AAlK40vbRQH6MmpJ4ckDdbPejXO7yT+wD7x0lUm/HQmvJRhHtZ -i71m866SWrljjGSn0J7jDFDSz5Od6UoRV5PB3q97WkQdCowiph3GremPFo1OkfHT -8fOC/vZV3HLxEQd17LvpOjWHQ4Fe3ENKt3yhGtXSwUA5aX2JrWQbMTSo6p5eJvxx -0sZr5cJzMD9ZpzWNqaXpPUNBvVTyKuEVDDUwa4vyd8pcB49Y9FR3Xq/OscErp7vA -6X3vGtcD7o9nrcbmHannkT9B59aGIIxTs9h5CeJLFVrYkjtiT2jky9CkTrZ9Pl+w -JOpiYc97AgMBAAECggEAEjCHylfhB7mZaJkg5PSLzu9btC1T9jiwObyKQubuMrN+ -4F9E1naGAQoMGWsZwlJKYvCBuoX0aAslk5DYJJJHIByn+VhQmBaf7iF2HvmaTa0z -qBYTdENGGvCrKu1izu/jSKwzWwFINI8mTCoh1dtrihKflPMl91qVAlr5gvCzaSac -ovZwe8cm51rN5XclJx+o6SONhPUdlUWJ5yEpA4mjV3eC6/IvPOoMmr8GRS9oBB6k -m7yhcaGrSUClc+K3lpFF+3gXD57ABtT23usrNGnti6xnURDYDm+fUX2j8kZEREvj -YGrCNGp+EecrTzhjgaFukysyRXRp7mLvGEqekodcgQKBgQDm1bmKZmE+0FZJIDXD -4xMiipc+srd6KuaCYdJ5i0xt9xTC5KJA5eSmoQn0+hWa8065A91tHiR8u49Ql5xP -6oQw8kA3dpZliZJSL/o7V+aXoMO9/R3H8tbiZn0y7cMYaYr7PGmXC/giSQ5Yi7qE -+yKjKgx35DGEiTajt4FWJ6/siQKBgQDtGKlPyT/k8XGz305qw2W7d8nFFsR4kSJl -pbbWBwrfouiw0hOARCzevZDq6zSGx9QK8Sv5ACM06TrOxSVNsljKayFK0E+Hc5N/ -bNjCDxJd+4CgUNhM2Ta4wvZqW8FGQgphJVUnYu/YahjETWhMiAEOPcm/j7E9k/HQ -BiZixroC4wKBgB3zBuKtC9rxfvB37GHg+V+W6a6p02JXZJbwCDXa2+y8jQYIUgDn -kvYHmNofBGSZQtKAbN82dPd2Ak8rjI1V2Rbcp3ZKvZKo+cIOFYJTkkiEBEGHMLD7 -kePH9mCANrrZHr4gBXcih2wzXFgisO2GA+V1lC6N/dq7TsqJCY/bEFk5AoGBAMAI -nnHCBd9P85EFiAUPGCHb5u+b/ivNGXgM3WbCs3ro/uDgde0IyvLpxSuQr62Owl7O -cZgvFVTwprH8mbcxgZsJZCCtUgzafpfRuEqNXIoEf2zZrieoMxs4xc7lXEikirWe -QDczeiHl5QNx0s1RxtEbGIHwR1Uhs9SSdprAbL6TAoGBAMT3QpWdPNlDoPbSkAC9 -hoUIaRZS8rN/8Ls1lwYf5RxaiTcEKuQ2IYphMRsSzqHbpDxLtWbsWJGd9VARbgc8 -W5DzCmditgUlt9FsawbxqDGO7bkqD4QEkZS67zehDzM2Ir8sy00QZxCi1dJXEBR2 -DUChLmnVRf1yCYz0xmGSRskj ------END PRIVATE KEY----- diff --git a/chromium/net/data/ssl/certificates/quic_test_ecc.example.com.crt b/chromium/net/data/ssl/certificates/quic_test_ecc.example.com.crt deleted file mode 100644 index ff8a18def0a..00000000000 --- a/chromium/net/data/ssl/certificates/quic_test_ecc.example.com.crt +++ /dev/null @@ -1,60 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: 4 (0x4) - Signature Algorithm: sha1WithRSAEncryption - Issuer: O=Acme Co, CN=Intermediate CA - Validity - Not Before: Jan 1 10:00:00 2013 GMT - Not After : Dec 31 10:00:00 2023 GMT - Subject: O=Acme Co, CN=ECDSA Leaf certificate - Subject Public Key Info: - Public Key Algorithm: id-ecPublicKey - Public-Key: (256 bit) - pub: - 04:05:26:22:0e:77:27:83:00:d0:6b:c0:86:af:f4: - f9:99:a8:28:a2:ed:5c:c7:5a:dc:29:72:79:4b:ef: - e8:85:aa:3a:9b:84:3d:e3:21:b3:6b:0a:79:52:89: - ce:bf:f1:a5:42:8b:ad:5e:34:66:5c:e5:e3:6d:aa: - d0:8f:b3:ff:d8 - ASN1 OID: prime256v1 - X509v3 extensions: - X509v3 Key Usage: critical - Digital Signature - X509v3 Extended Key Usage: - TLS Web Server Authentication - X509v3 Basic Constraints: critical - CA:FALSE - X509v3 Subject Alternative Name: - DNS:test.example.com - Signature Algorithm: sha1WithRSAEncryption - 40:cb:4b:4f:63:13:8a:4e:b9:76:f6:01:82:f1:29:6d:64:d5: - ab:87:2f:5f:4f:e9:97:f7:0d:1c:95:f1:c1:7e:9e:26:c1:f8: - b5:6c:5c:7d:7a:54:95:96:0c:ad:72:27:e5:47:2d:13:11:0e: - 56:d7:37:0e:9b:ea:1e:93:dc:78:e4:12:3b:bd:d5:21:44:92: - cb:bf:f1:36:f5:67:3a:85:92:78:da:1b:c6:01:04:4e:6d:a7: - 1b:0e:3b:96:59:a2:da:96:db:8e:97:be:dc:f0:7e:54:3b:12: - 3a:e9:44:a0:56:e4:a5:9f:f4:58:7a:22:b9:85:be:b7:ad:51: - 05:95:70:ba:d0:69:11:f1:2d:47:32:98:bf:e8:1c:9d:f9:19: - 29:f8:17:72:30:bb:3d:4a:d7:f5:cc:50:55:14:a9:6b:37:e7: - 08:f2:b6:87:4d:d8:3d:fb:eb:0d:45:3b:bc:3c:c1:92:2d:69: - 17:39:4b:b4:ff:04:21:ec:cc:74:ff:37:b4:6d:6f:b1:5d:89: - 9c:32:ee:99:60:52:87:15:8f:b7:50:ba:2d:f5:fd:11:f1:f8: - 38:94:b6:db:7f:cb:fa:2f:d1:41:26:cc:fa:ec:4d:49:ed:d8: - a8:8a:13:e7:14:32:6a:c6:6a:66:c9:5b:81:92:ca:cf:b4:7c: - c8:91:cc:a8 ------BEGIN CERTIFICATE----- -MIICXTCCAUegAwIBAgIBBDALBgkqhkiG9w0BAQUwLDEQMA4GA1UEChMHQWNtZSBD -bzEYMBYGA1UEAxMPSW50ZXJtZWRpYXRlIENBMB4XDTEzMDEwMTEwMDAwMFoXDTIz -MTIzMTEwMDAwMFowMzEQMA4GA1UEChMHQWNtZSBDbzEfMB0GA1UEAxMWRUNEU0Eg -TGVhZiBjZXJ0aWZpY2F0ZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAUmIg53 -J4MA0GvAhq/0+ZmoKKLtXMda3ClyeUvv6IWqOpuEPeMhs2sKeVKJzr/xpUKLrV40 -Zlzl422q0I+z/9ijUjBQMA4GA1UdDwEB/wQEAwIAgDATBgNVHSUEDDAKBggrBgEF -BQcDATAMBgNVHRMBAf8EAjAAMBsGA1UdEQQUMBKCEHRlc3QuZXhhbXBsZS5jb20w -CwYJKoZIhvcNAQEFA4IBAQBAy0tPYxOKTrl29gGC8SltZNWrhy9fT+mX9w0clfHB -fp4mwfi1bFx9elSVlgytciflRy0TEQ5W1zcOm+oek9x45BI7vdUhRJLLv/E29Wc6 -hZJ42hvGAQRObacbDjuWWaLaltuOl77c8H5UOxI66USgVuSln/RYeiK5hb63rVEF -lXC60GkR8S1HMpi/6Byd+Rkp+BdyMLs9Stf1zFBVFKlrN+cI8raHTdg9++sNRTu8 -PMGSLWkXOUu0/wQh7Mx0/ze0bW+xXYmcMu6ZYFKHFY+3ULot9f0R8fg4lLbbf8v6 -L9FBJsz67E1J7dioihPnFDJqxmpmyVuBksrPtHzIkcyo ------END CERTIFICATE----- diff --git a/chromium/net/data/ssl/certificates/quic_test_ecc.example.com.key b/chromium/net/data/ssl/certificates/quic_test_ecc.example.com.key deleted file mode 100644 index 0e2f2763b2b..00000000000 --- a/chromium/net/data/ssl/certificates/quic_test_ecc.example.com.key +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN EC PRIVATE KEY----- -MHcCAQEEIPqnEQNfDLijySw1wwD3RNPQvgPyAPvaZarw327ZM2lwoAoGCCqGSM49 -AwEHoUQDQgAEBSYiDncngwDQa8CGr/T5magoou1cx1rcKXJ5S+/ohao6m4Q94yGz -awp5UonOv/GlQoutXjRmXOXjbarQj7P/2A== ------END EC PRIVATE KEY----- diff --git a/chromium/net/data/ssl/certificates/quic_test_ecc.example.com.sct b/chromium/net/data/ssl/certificates/quic_test_ecc.example.com.sct Binary files differdeleted file mode 100644 index 37582658969..00000000000 --- a/chromium/net/data/ssl/certificates/quic_test_ecc.example.com.sct +++ /dev/null diff --git a/chromium/net/data/ssl/certificates/sha1_leaf.pem b/chromium/net/data/ssl/certificates/sha1_leaf.pem new file mode 100644 index 00000000000..598b48d8821 --- /dev/null +++ b/chromium/net/data/ssl/certificates/sha1_leaf.pem @@ -0,0 +1,112 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCt5Mpt4Jw+UG9v +qfdbenxHoJJ8YcG9PZssBRhmA4GIwNGoYqG5D50gMxppUybpdZtQus+FF/lS8v2R +0+my4D3cgLo+eIebg2oqhz/x5QLQlWsGvcjcn6bTg0INuK9vn9HNqeMQkDotxK9X +zvcbKazzxzV1K81PGgocpjhj10qdOZoboDu+eTN8bFe13uRNFG13l1nQmU0B6R6n +BreDtxggA/C9H0x9YjRVyDamxwXe5c1yrye2HZXdxJneEEm+CMUSjKXlpK1it/+U +1mafGMtrSdl++aspmO3lZ61TUNdSqdSUBGL8azw7AzewvRj48KN8V4EPG7WUvu4a +CrZpy3O1AgMBAAECggEAcz5ibcliouWZxK4m0YhuXuXqzuXWiP0QHm9OCSWfrirj +h62+MjBH2LQld9H0wtn/UdRMfY8y3CdPp1qC0dpNBRqG06n7bTP9oyu5VC2K3QN5 +R6F1QcnIvPqLRx6znc2UNLG3Wx3KgNSNxCrUlzradUD7i6i4ywid1PjP/FMNDv6q +k07xSxc0VpWwkUC0j3uau0qewfnjP3+Toe7au4vHhy+Opyudsu4WETlbhkZq2mlD +bgUS8/06FOjlf/2tfnElysL2NPvj0sFpm1yUckxZVjiepJ8QfqU46zsxUTqKrtca +b6kYiJmB30wSxwnsweBhJ6w7UOOV6kmB6scc5OD2IQKBgQDgZESH7yLkqBdY1qFE +AfWvyMfIe/buB8UNLcicGuSPkjdtCzsXoDgzXxt37RSLFMsPTDBM51KPAzJkWaeM +Jksbivw/+bEFTyY/AaYreiRHrpIXvLM/mNJFZ514ImZ+mY8YU7nuTZRMn7Ysfs9c +kHc7r3ET65KOcnXtPVGk6h2rHQKBgQDGY4dc0vWHktGLLqmgIJZHVcojj4NLuX67 +KCj1/DhNFpJhq24MKucxmaOlXXXPgEGTA/JwWnolo1fcT2Vv4LrlgL75SYVHOF71 +2PTIrlM3w6lOJNyzyD3Sjh2wZ87u993P2z6Z/qDWOMTdfD/jvyoU/k1uq6rTxJzy +SktzfqRveQKBgBwI6vcAzZ870Q7sYeGZTRTVRQCrXEKI/fmTisjWI1A8uGgLSyq8 +fckNTOVC3Zoy0tvqbO5uyEXN5HHdMa206xVZ3AIyNAexx9l/Xz93VykNinskvFBp +y3uYYngr9BpFHTew3j4Du0+HdL9CaK3r7rmqRbpzaDAb5NfrHVQ5W9ORAoGASfSq +bnkaHKsnwFnp1A6x1u/tRepnCKCi1MQ42NJobpxef1h30sNfokbjEW9QzsTCLTsI +csfXxxYoV7GlX9qH8axYBPhaXd1u0PlK71DFJwGiqMXnHIImQcrG2I8qPj1ai/Tw +VlnsvU82XFbIPm9yEZdnaD1Ill8yHsSBchGg3QkCgYEAxZcgtHjspR9TTzuyl8qm +gciF8YDwYIIHqOPnVKoC6+EQJf/BJnTU5naf56sa4aMg9eqqNA5eG0aohM1uZJAJ +TaxkXZ8wTCwFoIh6O05+SD4bHDWvr7Sur1z0HeasYH2OPf/H/N0Xuq10rphCr7dx +HYbEecCcSPrbEtOR7++xRvA= +-----END PRIVATE KEY----- +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 23 (0x17) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, ST=California, L=Mountain View, O=Test CA, CN=Test Root CA + Validity + Not Before: Dec 20 00:00:00 2017 GMT + Not After : Dec 20 00:00:00 2020 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 + Public-Key: (2048 bit) + Modulus: + 00:ad:e4:ca:6d:e0:9c:3e:50:6f:6f:a9:f7:5b:7a: + 7c:47:a0:92:7c:61:c1:bd:3d:9b:2c:05:18:66:03: + 81:88:c0:d1:a8:62:a1:b9:0f:9d:20:33:1a:69:53: + 26:e9:75:9b:50:ba:cf:85:17:f9:52:f2:fd:91:d3: + e9:b2:e0:3d:dc:80:ba:3e:78:87:9b:83:6a:2a:87: + 3f:f1:e5:02:d0:95:6b:06:bd:c8:dc:9f:a6:d3:83: + 42:0d:b8:af:6f:9f:d1:cd:a9:e3:10:90:3a:2d:c4: + af:57:ce:f7:1b:29:ac:f3:c7:35:75:2b:cd:4f:1a: + 0a:1c:a6:38:63:d7:4a:9d:39:9a:1b:a0:3b:be:79: + 33:7c:6c:57:b5:de:e4:4d:14:6d:77:97:59:d0:99: + 4d:01:e9:1e:a7:06:b7:83:b7:18:20:03:f0:bd:1f: + 4c:7d:62:34:55:c8:36:a6:c7:05:de:e5:cd:72:af: + 27:b6:1d:95:dd:c4:99:de:10:49:be:08:c5:12:8c: + a5:e5:a4:ad:62:b7:ff:94:d6:66:9f:18:cb:6b:49: + d9:7e:f9:ab:29:98:ed:e5:67:ad:53:50:d7:52:a9: + d4:94:04:62:fc:6b:3c:3b:03:37:b0:bd:18:f8:f0: + a3:7c:57:81:0f:1b:b5:94:be:ee:1a:0a:b6:69:cb: + 73:b5 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:FALSE + X509v3 Subject Key Identifier: + 18:9A:76:1E:86:4C:EF:67:5D:20:7F:24:4C:DC:3F:AE:B5:B5:5C:A1 + 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: sha1WithRSAEncryption + a0:b6:c2:65:a0:9b:25:b7:c9:81:9a:dc:63:aa:ae:6e:f3:8a: + 62:92:66:6e:ad:3d:a7:fd:26:d4:ea:7b:7c:00:80:2b:73:db: + 36:86:fe:b1:b5:8a:05:40:d3:3c:6f:1d:11:1b:b2:a0:0d:f6: + 26:aa:ac:63:62:61:c0:7e:b0:7d:da:73:2c:14:71:41:fd:93: + f5:76:cd:21:13:42:df:e5:b0:26:e8:d0:ec:a2:e4:26:b8:ba: + e8:bd:49:f9:38:7f:92:1c:a2:7e:8f:b3:d3:e6:0a:51:60:88: + c4:ab:08:65:14:53:fd:c3:70:8a:6f:49:99:d7:09:38:00:20: + b5:3d:3c:f1:7c:2c:ab:67:4d:df:1d:c2:1e:24:d3:31:60:71: + be:b3:85:7e:a7:1e:ce:41:1f:21:58:63:83:3c:e5:91:4a:18: + 4d:6c:97:13:d5:df:34:c7:22:0a:92:3a:fb:03:3a:b8:62:2b: + 7e:be:03:fb:39:74:03:1d:f3:c7:55:28:e7:ed:cd:28:75:2b: + 75:c5:38:b7:fd:da:98:60:61:0a:aa:eb:17:1a:26:e1:74:7e: + 84:e8:76:bf:15:18:e3:b2:4e:25:41:cb:2b:19:c9:63:6f:aa: + 8a:58:c7:01:2a:cd:fc:04:ea:63:7f:b3:ed:5d:96:a2:b0:26: + 63:8d:0d:3f +-----BEGIN CERTIFICATE----- +MIIDvzCCAqegAwIBAgIBFzANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzET +MBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEQMA4G +A1UECgwHVGVzdCBDQTEVMBMGA1UEAwwMVGVzdCBSb290IENBMB4XDTE3MTIyMDAw +MDAwMFoXDTIwMTIyMDAwMDAwMFowYDELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNh +bGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxEDAOBgNVBAoMB1Rlc3Qg +Q0ExEjAQBgNVBAMMCTEyNy4wLjAuMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBAK3kym3gnD5Qb2+p91t6fEegknxhwb09mywFGGYDgYjA0ahiobkPnSAz +GmlTJul1m1C6z4UX+VLy/ZHT6bLgPdyAuj54h5uDaiqHP/HlAtCVawa9yNyfptOD +Qg24r2+f0c2p4xCQOi3Er1fO9xsprPPHNXUrzU8aChymOGPXSp05mhugO755M3xs +V7Xe5E0UbXeXWdCZTQHpHqcGt4O3GCAD8L0fTH1iNFXINqbHBd7lzXKvJ7Ydld3E +md4QSb4IxRKMpeWkrWK3/5TWZp8Yy2tJ2X75qymY7eVnrVNQ11Kp1JQEYvxrPDsD +N7C9GPjwo3xXgQ8btZS+7hoKtmnLc7UCAwEAAaOBgDB+MAwGA1UdEwEB/wQCMAAw +HQYDVR0OBBYEFBiadh6GTO9nXSB/JEzcP661tVyhMB8GA1UdIwQYMBaAFJsmC4qY +qbsduR8c4xpAM+2OF4irMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAP +BgNVHREECDAGhwR/AAABMA0GCSqGSIb3DQEBBQUAA4IBAQCgtsJloJslt8mBmtxj +qq5u84pikmZurT2n/SbU6nt8AIArc9s2hv6xtYoFQNM8bx0RG7KgDfYmqqxjYmHA +frB92nMsFHFB/ZP1ds0hE0Lf5bAm6NDsouQmuLrovUn5OH+SHKJ+j7PT5gpRYIjE +qwhlFFP9w3CKb0mZ1wk4ACC1PTzxfCyrZ03fHcIeJNMxYHG+s4V+px7OQR8hWGOD +POWRShhNbJcT1d80xyIKkjr7Azq4Yit+vgP7OXQDHfPHVSjn7c0odSt1xTi3/dqY +YGEKqusXGibhdH6E6Ha/FRjjsk4lQcsrGcljb6qKWMcBKs38BOpjf7PtXZaisCZj +jQ0/ +-----END CERTIFICATE----- diff --git a/chromium/net/data/ssl/scripts/crlsetutil.py b/chromium/net/data/ssl/scripts/crlsetutil.py index 2fcad54c5a9..c96d818f7f2 100755 --- a/chromium/net/data/ssl/scripts/crlsetutil.py +++ b/chromium/net/data/ssl/scripts/crlsetutil.py @@ -162,6 +162,39 @@ def pem_cert_file_to_spki_hash(pem_filename): return der_cert_to_spki_hash(_pem_cert_to_binary(pem_filename)) +def der_cert_to_subject_hash(der_bytes): + """Returns SHA256(subject) of a DER-encoded certificate + + Args: + der_bytes: A DER-encoded certificate (RFC 5280) + + Returns: + The SHA-256 hash of the certificate's subject. + """ + iterator = ASN1Iterator(der_bytes) + iterator.step_into() # enter certificate structure + iterator.step_into() # enter TBSCertificate + iterator.step_over() # over version + iterator.step_over() # over serial + iterator.step_over() # over signature algorithm + iterator.step_over() # over issuer name + iterator.step_over() # over validity + return hashlib.sha256(iterator.contents()).digest() + + +def pem_cert_file_to_subject_hash(pem_filename): + """Gets the SHA-256 hash of the subject of a cert in a file + + Args: + pem_filename: A file containing a PEM-encoded certificate. + + Returns: + The SHA-256 hash of the subject of the first certificate in the file, as a + byte sequence + """ + return der_cert_to_subject_hash(_pem_cert_to_binary(pem_filename)) + + def main(): parser = optparse.OptionParser(description=sys.modules[__name__].__doc__) parser.add_option('-o', '--output', @@ -179,6 +212,13 @@ def main(): pem_cert_file_to_spki_hash(pem_file): serials for pem_file, serials in config.get('BlockedByHash', {}).iteritems() } + limited_subjects = { + pem_cert_file_to_subject_hash(pem_file).encode('base64').strip(): [ + pem_cert_file_to_spki_hash(filename).encode('base64').strip() + for filename in allowed_pems + ] + for pem_file, allowed_pems in config.get('LimitedSubjects', {}).iteritems() + } header_json = { 'Version': 0, 'ContentType': 'CRLSet', @@ -186,6 +226,7 @@ def main(): 'DeltaFrom': 0, 'NumParents': len(parents), 'BlockedSPKIs': blocked_spkis, + 'LimitedSubjects': limited_subjects, } header = json.dumps(header_json) outfile.write(struct.pack('<H', len(header))) diff --git a/chromium/net/data/ssl/scripts/ee.cnf b/chromium/net/data/ssl/scripts/ee.cnf index 3d42df1b65b..d5811b914d7 100644 --- a/chromium/net/data/ssl/scripts/ee.cnf +++ b/chromium/net/data/ssl/scripts/ee.cnf @@ -17,6 +17,9 @@ L = Mountain View O = Test CA CN = 127.0.0.1 +[req_no_san] +basicConstraints = critical, CA:false + [req_duplicate_cn_1] O = Foo CN = Duplicate diff --git a/chromium/net/data/ssl/scripts/generate-quic-chain.sh b/chromium/net/data/ssl/scripts/generate-quic-chain.sh new file mode 100755 index 00000000000..707ecda67a5 --- /dev/null +++ b/chromium/net/data/ssl/scripts/generate-quic-chain.sh @@ -0,0 +1,97 @@ +#!/bin/sh + +# Copyright 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. + +# This script generates a test chain of (end-entity, intermediate, root) +# certificates used to run a test QUIC server. + +try() { + "$@" || (e=$?; echo "$@" > /dev/stderr; exit $e) +} + +try rm -rf out +try mkdir out + +# Create the serial number files. +try /bin/sh -c "echo 01 > out/quic-test-root-serial" +try /bin/sh -c "echo 01 > out/quic-test-intermediate-serial" + +# Create the signers' DB files. +touch out/quic-test-root-index.txt +touch out/quic-test-intermediate-index.txt + +# Generate the keys +try openssl genrsa -out out/quic-test-root.key 2048 +try openssl genrsa -out out/quic-test-intermediate.key 2048 +try openssl genrsa -out out/quic-test-cert.key 2048 + +# Generate the root certificate +CA_COMMON_NAME="Test Root CA" \ + CA_DIR=out \ + CA_NAME=test-root \ + try openssl req \ + -new \ + -key out/quic-test-root.key \ + -out out/quic-test-root.csr \ + -config quic-test.cnf + +CA_COMMON_NAME="Test Root CA" \ + CA_DIR=out \ + CA_NAME=quic-test-root \ + try openssl x509 \ + -req -days 3650 \ + -in out/quic-test-root.csr \ + -out out/quic-test-root.pem \ + -signkey out/quic-test-root.key \ + -extfile quic-test.cnf \ + -extensions ca_cert \ + -text + +# Generate the intermediate +CA_COMMON_NAME="Test Intermediate CA" \ + CA_DIR=out \ + CA_NAME=quic-test-root \ + try openssl req \ + -new \ + -key out/quic-test-intermediate.key \ + -out out/quic-test-intermediate.csr \ + -config quic-test.cnf + +CA_COMMON_NAME="Test Intermediate CA" \ + CA_DIR=out \ + CA_NAME=quic-test-root \ + try openssl ca \ + -batch \ + -in out/quic-test-intermediate.csr \ + -out out/quic-test-intermediate.pem \ + -config quic-test.cnf \ + -extensions ca_cert + +# Generate the leaf +CA_COMMON_NAME="test.example.com" \ +CA_DIR=out \ +CA_NAME=quic-test-intermediate \ +try openssl req \ + -new \ + -key out/quic-test-cert.key \ + -out out/quic-test-cert.csr \ + -config quic-test.cnf + +CA_COMMON_NAME="Test Intermediate CA" \ + HOST_NAME="test.example.com" \ + CA_DIR=out \ + CA_NAME=quic-test-intermediate \ + try openssl ca \ + -batch \ + -in out/quic-test-cert.csr \ + -out out/quic-test-cert.pem \ + -config quic-test.cnf \ + -extensions user_cert + +# Copy to the file names that are actually checked in. +try openssl pkcs8 -topk8 -inform pem -outform der -in out/quic-test-cert.key -out ../certificates/quic-leaf-cert.key -nocrypt +try cat out/quic-test-cert.pem out/quic-test-intermediate.pem > ../certificates/quic-chain.pem +try cp out/quic-test-root.pem ../certificates/quic-root.pem +try openssl pkcs8 -nocrypt -inform der -outform pem -in ../certificates/quic-leaf-cert.key -out ../certificates/quic-leaf-cert.key.pkcs8.pem diff --git a/chromium/net/data/ssl/scripts/generate-test-certs.sh b/chromium/net/data/ssl/scripts/generate-test-certs.sh index ca8a3ca7ea6..622897b7b89 100755 --- a/chromium/net/data/ssl/scripts/generate-test-certs.sh +++ b/chromium/net/data/ssl/scripts/generate-test-certs.sh @@ -423,6 +423,61 @@ openssl req -x509 -newkey rsa:2048 \ -extensions req_extensions_with_tls_feature \ -nodes -config ee.cnf +# SHA-1 certificate issued by locally trusted CA +openssl req \ + -config ../scripts/ee.cnf \ + -newkey rsa:2048 \ + -text \ + -keyout out/sha1_leaf.key \ + -out out/sha1_leaf.req +CA_NAME="req_ca_dn" \ + openssl ca \ + -batch \ + -extensions user_cert \ + -startdate 171220000000Z \ + -enddate 201220000000Z \ + -in out/sha1_leaf.req \ + -out out/sha1_leaf.pem \ + -config ca.cnf \ + -md sha1 +/bin/sh -c "cat out/sha1_leaf.key out/sha1_leaf.pem \ + > ../certificates/sha1_leaf.pem" + +# Certificate with only a common name (no SAN) issued by a locally trusted CA +openssl req \ + -config ../scripts/ee.cnf \ + -reqexts req_no_san \ + -newkey rsa:2048 \ + -text \ + -keyout out/common_name_only.key \ + -out out/common_name_only.req +CA_NAME="req_ca_dn" \ + openssl ca \ + -batch \ + -extensions user_cert \ + -startdate 171220000000Z \ + -enddate 201220000000Z \ + -in out/common_name_only.req \ + -out out/common_name_only.pem \ + -config ca.cnf +/bin/sh -c "cat out/common_name_only.key out/common_name_only.pem \ + > ../certificates/common_name_only.pem" + +# Issued after 1 Dec 2017 (Symantec Legacy Distrust Date) +openssl req \ + -config ../scripts/ee.cnf \ + -newkey rsa:2048 \ + -text \ + -out out/dec_2017.req +CA_NAME="req_ca_dn" \ + openssl ca \ + -batch \ + -extensions user_cert \ + -startdate 171220000000Z \ + -enddate 201220000000Z \ + -in out/dec_2017.req \ + -out ../certificates/dec_2017.pem \ + -config ca.cnf # Regenerate CRLSets ## Block a leaf cert directly by SPKI @@ -454,3 +509,35 @@ python crlsetutil.py -o ../certificates/crlset_by_intermediate_serial.raw \ } } CRLSETBYINTERMEDIATESERIAL + +## Block a subject with a single-entry allowlist of SPKI hashes. +python crlsetutil.py -o ../certificates/crlset_by_root_subject.raw \ +<<CRLSETBYROOTSUBJECT +{ + "LimitedSubjects": { + "../certificates/root_ca_cert.pem": [ + "../certificates/root_ca_cert.pem" + ] + } +} +CRLSETBYROOTSUBJECT + +## Block a subject with an empty allowlist of SPKI hashes. +python crlsetutil.py -o ../certificates/crlset_by_root_subject_no_spki.raw \ +<<CRLSETBYROOTSUBJECTNOSPKI +{ + "LimitedSubjects": { + "../certificates/root_ca_cert.pem": [] + } +} +CRLSETBYROOTSUBJECTNOSPKI + +## Block a subject with an empty allowlist of SPKI hashes. +python crlsetutil.py -o ../certificates/crlset_by_leaf_subject_no_spki.raw \ +<<CRLSETBYLEAFSUBJECTNOSPKI +{ + "LimitedSubjects": { + "../certificates/ok_cert.pem": [] + } +} +CRLSETBYLEAFSUBJECTNOSPKI diff --git a/chromium/net/data/ssl/scripts/quic-test.cnf.txt b/chromium/net/data/ssl/scripts/quic-test.cnf.txt new file mode 100644 index 00000000000..c8daaf30d0a --- /dev/null +++ b/chromium/net/data/ssl/scripts/quic-test.cnf.txt @@ -0,0 +1,54 @@ +CA_DIR=out +CA_NAME=quic-test-root +HOST_NAME=test.example.com + +[ca] +default_ca = CA_root +preserve = yes + +[CA_root] +dir = ${ENV::CA_DIR} +key_size = 2048 +algo = sha256 +database = $dir/${ENV::CA_NAME}-index.txt +new_certs_dir = $dir +serial = $dir/${ENV::CA_NAME}-serial +certificate = $dir/${ENV::CA_NAME}.pem +private_key = $dir/${ENV::CA_NAME}.key +RANDFILE = $dir/.rand +default_days = 3650 +default_crl_days = 30 +default_md = sha256 +policy = policy_anything +unique_subject = no +copy_extensions = copy + +[user_cert] +basicConstraints = critical, CA:false +extendedKeyUsage = serverAuth, clientAuth +subjectAltName = DNS:${ENV::HOST_NAME} + +[ca_cert] +basicConstraints = critical, CA:true +keyUsage = critical, keyCertSign, cRLSign + +[policy_anything] +# Default signing policy +countryName = optional +stateOrProvinceName = optional +localityName = optional +organizationName = optional +organizationalUnitName = optional +commonName = optional +emailAddress = optional + +[req] +default_bits = 2048 +default_md = sha256 +string_mask = utf8only +prompt = no +encrypt_key = no +distinguished_name = req_env_dn + +[req_env_dn] +CN = ${ENV::CA_COMMON_NAME} diff --git a/chromium/net/data/ssl/symantec/README.md b/chromium/net/data/ssl/symantec/README.md index f4926bbefc9..4d8219d121e 100644 --- a/chromium/net/data/ssl/symantec/README.md +++ b/chromium/net/data/ssl/symantec/README.md @@ -1,15 +1,17 @@ # Symantec Certificates This directory contains the set of known active and legacy root certificates -operated by Symantec Corporation. In order for certificates issued from -roots to be trusted, it is required that the certificates be logged using -Certificate Transparency. +that were operated by Symantec Corporation. In order for certificates issued +from these roots to be trusted, it is required that they comply with the +policies outlined at <https://security.googleblog.com/2017/09/chromes-plan-to-distrust-symantec.html>. -For details about why, see <https://security.googleblog.com/2015/10/sustaining-digital-certificate-security.html> +The exceptions to this are: + * Pre-existing independently operated sub-CAs, whose keys were and are not + controled by Symantec and which maintain current and appropriate audits. + * The set of Managed CAs in accordance with the above policies. -The exception to this is sub-CAs which have been disclosed as independently -operated, whose keys are not in control of Symantec, and which are -maintaining a current and appropriate audit. +In addition to the above, no changes exist from the Certificate Transparency +requirement outlined at <https://security.googleblog.com/2015/10/sustaining-digital-certificate-security.html> ## Roots @@ -34,6 +36,14 @@ The following command can be used to match certificates and their key hashes: * [ac2b922ecfd5e01711772fea8ed372de9d1e2245fce3f57a9cdbec77296a424b.pem](excluded/ac2b922ecfd5e01711772fea8ed372de9d1e2245fce3f57a9cdbec77296a424b.pem) * [a4fe7c7f15155f3f0aef7aaa83cf6e06deb97ca3f909df920ac1490882d488ed.pem](excluded/a4fe7c7f15155f3f0aef7aaa83cf6e06deb97ca3f909df920ac1490882d488ed.pem) +### DigiCert + +[WebTrust Audit](https://cert.webtrust.org/ViewSeal?id=2228) +[Certification Practices Statement](https://www.digicert.com/CPS) + + * [8bb593a93be1d0e8a822bb887c547890c3e706aad2dab76254f97fb36b82fc26.pem](excluded/8bb593a93be1d0e8a822bb887c547890c3e706aad2dab76254f97fb36b82fc26.pem) + * [b94c198300cec5c057ad0727b70bbe91816992256439a7b32f4598119dda9c97.pem](excluded/b94c198300cec5c057ad0727b70bbe91816992256439a7b32f4598119dda9c97.pem) + ### Google [WebTrust Audit](https://cert.webtrust.org/ViewSeal?id=1941) @@ -41,3 +51,9 @@ The following command can be used to match certificates and their key hashes: * [c3f697a92a293d86f9a3ee7ccb970e20e0050b8728cc83ed1b996ce9005d4c36.pem](excluded/c3f697a92a293d86f9a3ee7ccb970e20e0050b8728cc83ed1b996ce9005d4c36.pem) +## Excluded Managed CAs + +### DigiCert + + * [7cac9a0ff315387750ba8bafdb1c2bc29b3f0bba16362ca93a90f84da2df5f3e.pem](managed/7cac9a0ff315387750ba8bafdb1c2bc29b3f0bba16362ca93a90f84da2df5f3e.pem) + * [ac50b5fb738aed6cb781cc35fbfff7786f77109ada7c08867c04a573fd5cf9ee.pem](managed/ac50b5fb738aed6cb781cc35fbfff7786f77109ada7c08867c04a573fd5cf9ee.pem) diff --git a/chromium/net/data/ssl/symantec/excluded/8bb593a93be1d0e8a822bb887c547890c3e706aad2dab76254f97fb36b82fc26.pem b/chromium/net/data/ssl/symantec/excluded/8bb593a93be1d0e8a822bb887c547890c3e706aad2dab76254f97fb36b82fc26.pem new file mode 100644 index 00000000000..f6d561eb172 --- /dev/null +++ b/chromium/net/data/ssl/symantec/excluded/8bb593a93be1d0e8a822bb887c547890c3e706aad2dab76254f97fb36b82fc26.pem @@ -0,0 +1,103 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 63:18:0d:38:fb:80:97:78:a9:d0:35:a3:16:18:f8:40 + Signature Algorithm: sha256WithRSAEncryption + 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 6 00:00:00 2017 GMT + Not After : Nov 5 23:59:59 2022 GMT + Subject: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Global Root G2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:bb:37:cd:34:dc:7b:6b:c9:b2:68:90:ad:4a:75: + ff:46:ba:21:0a:08:8d:f5:19:54:c9:fb:88:db:f3: + ae:f2:3a:89:91:3c:7a:e6:ab:06:1a:6b:cf:ac:2d: + e8:5e:09:24:44:ba:62:9a:7e:d6:a3:a8:7e:e0:54: + 75:20:05:ac:50:b7:9c:63:1a:6c:30:dc:da:1f:19: + b1:d7:1e:de:fd:d7:e0:cb:94:83:37:ae:ec:1f:43: + 4e:dd:7b:2c:d2:bd:2e:a5:2f:e4:a9:b8:ad:3a:d4: + 99:a4:b6:25:e9:9b:6b:00:60:92:60:ff:4f:21:49: + 18:f7:67:90:ab:61:06:9c:8f:f2:ba:e9:b4:e9:92: + 32:6b:b5:f3:57:e8:5d:1b:cd:8c:1d:ab:95:04:95: + 49:f3:35:2d:96:e3:49:6d:dd:77:e3:fb:49:4b:b4: + ac:55:07:a9:8f:95:b3:b4:23:bb:4c:6d:45:f0:f6: + a9:b2:95:30:b4:fd:4c:55:8c:27:4a:57:14:7c:82: + 9d:cd:73:92:d3:16:4a:06:0c:8c:50:d1:8f:1e:09: + be:17:a1:e6:21:ca:fd:83:e5:10:bc:83:a5:0a:c4: + 67:28:f6:73:14:14:3d:46:76:c3:87:14:89:21:34: + 4d:af:0f:45:0c:a6:49:a1:ba:bb:9c:c5:b1:33:83: + 29:85 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + 4E:22:54:20:18:95:E6:E3:6E:E6:0F:FA:FA:B9:12:ED:06:17:8F:39 + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: https://d.symcb.com/cps + User Notice: + Explicit Text: https://d.symcb.com/rpa + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://s.symcb.com/pca3-g5.crl + + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + Authority Information Access: + OCSP - URI:http://s.symcd.com + + X509v3 Authority Key Identifier: + keyid:7F:D3:65:A7:C2:DD:EC:BB:F0:30:09:F3:43:39:FA:02:AF:33:31:33 + + Signature Algorithm: sha256WithRSAEncryption + 50:dd:d3:56:29:25:01:8a:9e:a7:e5:7d:4d:b9:af:1b:8c:a2: + d2:27:35:e5:9d:eb:1c:6a:f3:c4:08:ca:45:06:52:08:28:7d: + a6:73:a9:8b:d9:7a:ff:c2:44:88:04:3a:ec:a8:03:b7:b0:17: + 26:a0:93:7e:9f:c5:77:d0:ee:49:7a:5a:ed:10:01:58:4b:24: + 43:5d:fb:bb:f1:99:47:9f:a9:2f:57:9f:e3:3d:41:44:08:43: + 3f:85:d3:74:c7:c5:9d:2e:91:a3:24:ca:9f:b3:41:06:e6:a1: + e3:f9:46:b1:a6:e7:16:0f:8e:39:c1:e6:b8:ce:52:bb:85:44: + 7e:30:0f:1f:ab:46:1d:d4:71:0a:8f:87:3c:4d:c8:1a:40:81: + cc:6b:82:87:af:8e:3c:71:0e:bd:7b:70:8f:10:24:61:44:d8: + 3e:44:02:93:d8:8e:d2:95:a5:73:2e:f6:81:ff:cc:b2:9b:6a: + 0c:08:4b:28:aa:24:53:f1:d6:d7:83:7e:5a:28:46:26:9b:39: + f7:3b:f9:a7:07:b6:c6:51:df:c4:52:b9:08:7f:b1:55:6a:68: + 18:65:dd:5f:4b:34:1e:83:57:07:a9:fd:23:6b:a7:87:a6:fa: + b6:6d:39:7e:71:61:47:6a:af:fc:e0:a9:47:7b:94:61:d0:2b: + 26:a5:9c:e7 +-----BEGIN CERTIFICATE----- +MIIE3zCCA8egAwIBAgIQYxgNOPuAl3ip0DWjFhj4QDANBgkqhkiG9w0BAQsFADCB +yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL +ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp +U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW +ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5IC0gRzUwHhcNMTcxMTA2MDAwMDAwWhcNMjIxMTA1MjM1OTU5WjBhMQsw +CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu +ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMjCC +ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALs3zTTce2vJsmiQrUp1/0a6 +IQoIjfUZVMn7iNvzrvI6iZE8euarBhprz6wt6F4JJES6Ypp+1qOofuBUdSAFrFC3 +nGMabDDc2h8Zsdce3v3X4MuUgzeu7B9DTt17LNK9LqUv5Km4rTrUmaS2JembawBg +kmD/TyFJGPdnkKthBpyP8rrptOmSMmu181foXRvNjB2rlQSVSfM1LZbjSW3dd+P7 +SUu0rFUHqY+Vs7Qju0xtRfD2qbKVMLT9TFWMJ0pXFHyCnc1zktMWSgYMjFDRjx4J +vheh5iHK/YPlELyDpQrEZyj2cxQUPUZ2w4cUiSE0Ta8PRQymSaG6u5zFsTODKYUC +AwEAAaOCAScwggEjMB0GA1UdDgQWBBROIlQgGJXm427mD/r6uRLtBhePOTAPBgNV +HRMBAf8EBTADAQH/MF8GA1UdIARYMFYwVAYEVR0gADBMMCMGCCsGAQUFBwIBFhdo +dHRwczovL2Quc3ltY2IuY29tL2NwczAlBggrBgEFBQcCAjAZDBdodHRwczovL2Qu +c3ltY2IuY29tL3JwYTAvBgNVHR8EKDAmMCSgIqAghh5odHRwOi8vcy5zeW1jYi5j +b20vcGNhMy1nNS5jcmwwDgYDVR0PAQH/BAQDAgGGMC4GCCsGAQUFBwEBBCIwIDAe +BggrBgEFBQcwAYYSaHR0cDovL3Muc3ltY2QuY29tMB8GA1UdIwQYMBaAFH/TZafC +3ey78DAJ80M5+gKvMzEzMA0GCSqGSIb3DQEBCwUAA4IBAQBQ3dNWKSUBip6n5X1N +ua8bjKLSJzXlnescavPECMpFBlIIKH2mc6mL2Xr/wkSIBDrsqAO3sBcmoJN+n8V3 +0O5JelrtEAFYSyRDXfu78ZlHn6kvV5/jPUFECEM/hdN0x8WdLpGjJMqfs0EG5qHj ++UaxpucWD445wea4zlK7hUR+MA8fq0Yd1HEKj4c8TcgaQIHMa4KHr448cQ69e3CP +ECRhRNg+RAKT2I7SlaVzLvaB/8yym2oMCEsoqiRT8dbXg35aKEYmmzn3O/mnB7bG +Ud/EUrkIf7FVamgYZd1fSzQeg1cHqf0ja6eHpvq2bTl+cWFHaq/84KlHe5Rh0Csm +pZzn +-----END CERTIFICATE----- diff --git a/chromium/net/data/ssl/symantec/excluded/b94c198300cec5c057ad0727b70bbe91816992256439a7b32f4598119dda9c97.pem b/chromium/net/data/ssl/symantec/excluded/b94c198300cec5c057ad0727b70bbe91816992256439a7b32f4598119dda9c97.pem new file mode 100644 index 00000000000..73543a32ea0 --- /dev/null +++ b/chromium/net/data/ssl/symantec/excluded/b94c198300cec5c057ad0727b70bbe91816992256439a7b32f4598119dda9c97.pem @@ -0,0 +1,76 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 3d:cd:5f:22:5e:a4:c9:6d:4b:90:94:a0:2d:2b:56:c6 + 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 6 00:00:00 2017 GMT + Not After : Nov 5 23:59:59 2022 GMT + Subject: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Global Root G3 + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (384 bit) + pub: + 04:dd:a7:d9:bb:8a:b8:0b:fb:0b:7f:21:d2:f0:be: + be:73:f3:33:5d:1a:bc:34:ea:de:c6:9b:bc:d0:95: + f6:f0:cc:d0:0b:ba:61:5b:51:46:7e:9e:2d:9f:ee: + 8e:63:0c:17:ec:07:70:f5:cf:84:2e:40:83:9c:e8: + 3f:41:6d:3b:ad:d3:a4:14:59:36:78:9d:03:43:ee: + 10:13:6c:72:de:ae:88:a7:a1:6b:b5:43:ce:67:dc: + 23:ff:03:1c:a3:e2:3e + ASN1 OID: secp384r1 + X509v3 extensions: + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + B3:DB:48:A4:F9:A1:C5:D8:AE:36:41:CC:11:63:69:62:29:BC:4B:C6 + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: https://d.symcb.com/cps + User Notice: + Explicit Text: https://d.symcb.com/rpa + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://s.symcb.com/pca3-g4.crl + + Authority Information Access: + OCSP - URI:http://s.symcd.com + + X509v3 Authority Key Identifier: + keyid: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:31:00:f7:91:70:39:bc:f0:9b:8f:73:b1:c1:bf:cb: + 62:a2:06:ef:04:f3:eb:bf:ee:4a:cf:a9:fb:02:21:17:c1:af: + 77:bc:cc:34:ff:2d:79:54:b3:8e:57:46:fb:9e:9d:f8:05:02: + 30:26:bf:8d:dd:63:bd:65:80:46:cd:4f:12:82:21:79:e4:cf: + 71:09:3b:fd:ac:90:3f:34:3d:ba:0c:0c:d9:5f:80:88:88:c9: + 92:af:93:24:4e:44:c9:1c:ed:40:24:15:23 +-----BEGIN CERTIFICATE----- +MIIDkDCCAxagAwIBAgIQPc1fIl6kyW1LkJSgLStWxjAKBggqhkjOPQQDAzCByjEL +MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW +ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2ln +biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp +U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y +aXR5IC0gRzQwHhcNMTcxMTA2MDAwMDAwWhcNMjIxMTA1MjM1OTU5WjBhMQswCQYD +VQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGln +aWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzB2MBAG +ByqGSM49AgEGBSuBBAAiA2IABN2n2buKuAv7C38h0vC+vnPzM10avDTq3sabvNCV +9vDM0Au6YVtRRn6eLZ/ujmMMF+wHcPXPhC5Ag5zoP0FtO63TpBRZNnidA0PuEBNs +ct6uiKeha7VDzmfcI/8DHKPiPqOCAScwggEjMA4GA1UdDwEB/wQEAwIBhjAdBgNV +HQ4EFgQUs9tIpPmhxdiuNkHMEWNpYim8S8YwDwYDVR0TAQH/BAUwAwEB/zBfBgNV +HSAEWDBWMFQGBFUdIAAwTDAjBggrBgEFBQcCARYXaHR0cHM6Ly9kLnN5bWNiLmNv +bS9jcHMwJQYIKwYBBQUHAgIwGQwXaHR0cHM6Ly9kLnN5bWNiLmNvbS9ycGEwLwYD +VR0fBCgwJjAkoCKgIIYeaHR0cDovL3Muc3ltY2IuY29tL3BjYTMtZzQuY3JsMC4G +CCsGAQUFBwEBBCIwIDAeBggrBgEFBQcwAYYSaHR0cDovL3Muc3ltY2QuY29tMB8G +A1UdIwQYMBaAFLMWkf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMDA2gAMGUC +MQD3kXA5vPCbj3Oxwb/LYqIG7wTz67/uSs+p+wIhF8Gvd7zMNP8teVSzjldG+56d ++AUCMCa/jd1jvWWARs1PEoIheeTPcQk7/ayQPzQ9ugwM2V+AiIjJkq+TJE5EyRzt +QCQVIw== +-----END CERTIFICATE----- diff --git a/chromium/net/data/ssl/symantec/managed/7cac9a0ff315387750ba8bafdb1c2bc29b3f0bba16362ca93a90f84da2df5f3e.pem b/chromium/net/data/ssl/symantec/managed/7cac9a0ff315387750ba8bafdb1c2bc29b3f0bba16362ca93a90f84da2df5f3e.pem new file mode 100644 index 00000000000..b1efd7972ca --- /dev/null +++ b/chromium/net/data/ssl/symantec/managed/7cac9a0ff315387750ba8bafdb1c2bc29b3f0bba16362ca93a90f84da2df5f3e.pem @@ -0,0 +1,73 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 79:c6:70:41:b4:62:32:04:39:4d:d0:42:fb:6e:96:80 + 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 6 00:00:00 2017 GMT + Not After : Nov 5 23:59:59 2022 GMT + Subject: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Transition ECC Root + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:5a:ff:46:dc:c9:ae:bd:2c:e7:1c:56:97:e4:fa: + eb:d5:c6:ff:75:53:23:5e:c6:b0:7d:ac:ac:57:3a: + 9f:94:50:07:0d:f1:f3:4d:51:0d:7d:fd:88:41:82: + 3f:1c:7f:fb:c3:1e:fa:f6:eb:d4:37:ff:fe:18:9d: + 01:83:2a:80:3a + ASN1 OID: prime256v1 + X509v3 extensions: + X509v3 Subject Key Identifier: + CF:37:24:66:74:19:7E:7F:A3:64:E4:BD:99:36:34:8B:7D:FB:42:BE + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: https://d.symcb.com/cps + User Notice: + Explicit Text: https://d.symcb.com/rpa + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://s.symcb.com/pca3-g4.crl + + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + Authority Information Access: + OCSP - URI:http://s.symcd.com + + X509v3 Authority Key Identifier: + keyid: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:64:02:30:58:17:b0:44:e7:e3:c4:09:ba:de:bd:db:84:d9: + ca:b1:71:fb:68:5d:56:7a:68:d8:3a:ce:e3:a0:af:02:5e:80: + 7b:60:f0:97:de:0d:13:26:35:50:fe:ba:84:bd:d9:1b:02:30: + 08:2c:18:cf:8f:72:e1:b5:dc:2a:91:76:09:00:bf:80:3a:f0: + 79:4b:29:7f:89:c2:db:b6:4d:26:c6:6d:94:14:a6:40:78:9a: + ac:ab:af:96:52:63:f9:51:31:52:f6:f8 +-----BEGIN CERTIFICATE----- +MIIDdzCCAv6gAwIBAgIQecZwQbRiMgQ5TdBC+26WgDAKBggqhkjOPQQDAzCByjEL +MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW +ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2ln +biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp +U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y +aXR5IC0gRzQwHhcNMTcxMTA2MDAwMDAwWhcNMjIxMTA1MjM1OTU5WjBmMQswCQYD +VQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGln +aWNlcnQuY29tMSUwIwYDVQQDExxEaWdpQ2VydCBUcmFuc2l0aW9uIEVDQyBSb290 +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEWv9G3MmuvSznHFaX5Prr1cb/dVMj +XsawfaysVzqflFAHDfHzTVENff2IQYI/HH/7wx769uvUN//+GJ0BgyqAOqOCAScw +ggEjMB0GA1UdDgQWBBTPNyRmdBl+f6Nk5L2ZNjSLfftCvjAPBgNVHRMBAf8EBTAD +AQH/MF8GA1UdIARYMFYwVAYEVR0gADBMMCMGCCsGAQUFBwIBFhdodHRwczovL2Qu +c3ltY2IuY29tL2NwczAlBggrBgEFBQcCAjAZDBdodHRwczovL2Quc3ltY2IuY29t +L3JwYTAvBgNVHR8EKDAmMCSgIqAghh5odHRwOi8vcy5zeW1jYi5jb20vcGNhMy1n +NC5jcmwwDgYDVR0PAQH/BAQDAgGGMC4GCCsGAQUFBwEBBCIwIDAeBggrBgEFBQcw +AYYSaHR0cDovL3Muc3ltY2QuY29tMB8GA1UdIwQYMBaAFLMWkf3upm7ktS5Jj4d4 +gYDs5bG1MAoGCCqGSM49BAMDA2cAMGQCMFgXsETn48QJut6924TZyrFx+2hdVnpo +2DrO46CvAl6Ae2Dwl94NEyY1UP66hL3ZGwIwCCwYz49y4bXcKpF2CQC/gDrweUsp +f4nC27ZNJsZtlBSmQHiarKuvllJj+VExUvb4 +-----END CERTIFICATE----- diff --git a/chromium/net/data/ssl/symantec/managed/ac50b5fb738aed6cb781cc35fbfff7786f77109ada7c08867c04a573fd5cf9ee.pem b/chromium/net/data/ssl/symantec/managed/ac50b5fb738aed6cb781cc35fbfff7786f77109ada7c08867c04a573fd5cf9ee.pem new file mode 100644 index 00000000000..8f9d5c77e7b --- /dev/null +++ b/chromium/net/data/ssl/symantec/managed/ac50b5fb738aed6cb781cc35fbfff7786f77109ada7c08867c04a573fd5cf9ee.pem @@ -0,0 +1,103 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 78:ae:a4:31:c1:5c:eb:75:7b:0d:8a:61:0a:74:8e:67 + Signature Algorithm: sha256WithRSAEncryption + 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 6 00:00:00 2017 GMT + Not After : Nov 5 23:59:59 2022 GMT + Subject: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Transition RSA Root + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:b0:3e:d8:46:63:32:df:49:1f:61:6d:ae:df:c9: + 7f:2b:b1:63:a1:a7:e6:46:35:34:0e:d4:a5:3d:12: + af:04:6a:d5:f8:ba:a7:65:93:ec:66:c5:ca:eb:68: + 01:24:69:1f:af:b0:a3:59:af:3c:5b:39:44:29:60: + 6e:8b:41:98:49:21:d8:18:13:d3:41:55:fe:aa:22: + 7e:a7:51:4a:a6:d0:23:5f:73:84:a2:9c:b4:cb:17: + d0:65:24:87:e9:80:cb:b7:3c:a1:10:f5:97:b5:0d: + 9d:ec:f7:ba:5b:a3:0b:65:eb:12:75:a9:46:74:0d: + 80:d7:08:13:93:21:57:c6:38:3d:a8:4b:3b:0b:6f: + 18:e5:b3:4c:f7:c2:cd:18:f9:58:2d:03:33:1b:fc: + 16:dd:90:4e:c2:1f:37:9c:d6:7b:61:96:f1:c5:26: + 87:52:e3:e2:a4:f8:15:e5:4c:22:e9:09:2b:95:d1: + 93:f9:3a:39:76:74:2a:0b:80:be:be:0e:d3:10:0b: + e2:e1:48:a6:24:05:69:3d:17:fd:c7:37:21:b2:b0: + e3:77:47:39:87:01:e0:4e:db:23:e8:f9:39:9f:36: + 46:66:23:1e:c7:22:51:44:3f:33:c5:f5:76:a9:f8: + 06:b0:79:cc:ee:41:dc:71:8e:0d:50:8e:b0:3c:48: + ab:f5 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + 90:47:8A:1B:84:D3:A0:DF:A4:24:D6:19:B4:17:F5:21:A3:B2:9B:A8 + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: https://d.symcb.com/cps + User Notice: + Explicit Text: https://d.symcb.com/rpa + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://s.symcb.com/pca3-g5.crl + + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + Authority Information Access: + OCSP - URI:http://s.symcd.com + + X509v3 Authority Key Identifier: + keyid:7F:D3:65:A7:C2:DD:EC:BB:F0:30:09:F3:43:39:FA:02:AF:33:31:33 + + Signature Algorithm: sha256WithRSAEncryption + 89:c4:a9:58:d9:16:5d:80:c5:9d:b0:ec:c5:56:48:5a:51:29: + 5a:01:89:94:56:cd:cd:2a:b9:b0:16:b7:4b:ea:17:69:f0:7c: + 4c:28:fe:73:85:4f:3c:f9:85:83:99:11:43:f7:5a:e0:a2:f8: + 43:8c:9a:2c:e3:83:f8:05:50:99:dc:f0:e7:ef:36:3b:36:48: + ff:5d:a3:18:d0:cb:c1:41:68:18:f1:f6:8f:0c:97:1c:4c:2a: + 69:17:dc:3f:24:20:5a:e4:26:61:c8:fe:e5:92:10:bf:4d:9e: + ec:f2:6e:ca:67:1e:46:b8:e3:f8:b0:69:e7:51:cf:26:cf:05: + 91:cf:1d:b7:c6:3a:89:41:78:2b:6e:eb:13:7a:4b:9d:da:88: + 0e:bd:53:08:8d:38:4d:17:5c:65:c9:42:d3:9b:35:36:e2:7e: + 60:df:e6:c3:24:e3:d0:fc:8b:36:1e:5a:38:bc:d4:c7:8c:3b: + 07:35:64:22:46:de:66:8a:34:5b:50:c5:42:95:68:dd:0c:84: + be:2c:e4:e4:2e:42:00:60:f9:1e:d7:0d:3d:40:a6:f0:3b:5d: + 9b:17:07:b7:f2:30:47:e4:8b:06:d7:a2:06:37:2b:3c:a2:a9: + 82:e8:0d:a3:e3:1b:4c:e5:91:43:fe:3d:78:b9:03:8a:e0:d6: + c1:05:a8:2c +-----BEGIN CERTIFICATE----- +MIIE5DCCA8ygAwIBAgIQeK6kMcFc63V7DYphCnSOZzANBgkqhkiG9w0BAQsFADCB +yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL +ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp +U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW +ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5IC0gRzUwHhcNMTcxMTA2MDAwMDAwWhcNMjIxMTA1MjM1OTU5WjBmMQsw +CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu +ZGlnaWNlcnQuY29tMSUwIwYDVQQDExxEaWdpQ2VydCBUcmFuc2l0aW9uIFJTQSBS +b290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsD7YRmMy30kfYW2u +38l/K7FjoafmRjU0DtSlPRKvBGrV+LqnZZPsZsXK62gBJGkfr7CjWa88WzlEKWBu +i0GYSSHYGBPTQVX+qiJ+p1FKptAjX3OEopy0yxfQZSSH6YDLtzyhEPWXtQ2d7Pe6 +W6MLZesSdalGdA2A1wgTkyFXxjg9qEs7C28Y5bNM98LNGPlYLQMzG/wW3ZBOwh83 +nNZ7YZbxxSaHUuPipPgV5Uwi6QkrldGT+To5dnQqC4C+vg7TEAvi4UimJAVpPRf9 +xzchsrDjd0c5hwHgTtsj6Pk5nzZGZiMexyJRRD8zxfV2qfgGsHnM7kHccY4NUI6w +PEir9QIDAQABo4IBJzCCASMwHQYDVR0OBBYEFJBHihuE06DfpCTWGbQX9SGjspuo +MA8GA1UdEwEB/wQFMAMBAf8wXwYDVR0gBFgwVjBUBgRVHSAAMEwwIwYIKwYBBQUH +AgEWF2h0dHBzOi8vZC5zeW1jYi5jb20vY3BzMCUGCCsGAQUFBwICMBkMF2h0dHBz +Oi8vZC5zeW1jYi5jb20vcnBhMC8GA1UdHwQoMCYwJKAioCCGHmh0dHA6Ly9zLnN5 +bWNiLmNvbS9wY2EzLWc1LmNybDAOBgNVHQ8BAf8EBAMCAYYwLgYIKwYBBQUHAQEE +IjAgMB4GCCsGAQUFBzABhhJodHRwOi8vcy5zeW1jZC5jb20wHwYDVR0jBBgwFoAU +f9Nlp8Ld7LvwMAnzQzn6Aq8zMTMwDQYJKoZIhvcNAQELBQADggEBAInEqVjZFl2A +xZ2w7MVWSFpRKVoBiZRWzc0qubAWt0vqF2nwfEwo/nOFTzz5hYOZEUP3WuCi+EOM +mizjg/gFUJnc8OfvNjs2SP9doxjQy8FBaBjx9o8MlxxMKmkX3D8kIFrkJmHI/uWS +EL9NnuzybspnHka44/iwaedRzybPBZHPHbfGOolBeCtu6xN6S53aiA69UwiNOE0X +XGXJQtObNTbifmDf5sMk49D8izYeWji81MeMOwc1ZCJG3maKNFtQxUKVaN0MhL4s +5OQuQgBg+R7XDT1ApvA7XZsXB7fyMEfkiwbXogY3KzyiqYLoDaPjG0zlkUP+PXi5 +A4rg1sEFqCw= +-----END CERTIFICATE----- diff --git a/chromium/net/der/parser.cc b/chromium/net/der/parser.cc index be1c484af44..4a43c2f275b 100644 --- a/chromium/net/der/parser.cc +++ b/chromium/net/der/parser.cc @@ -11,34 +11,6 @@ namespace net { namespace der { -namespace { - -bool TagFromCBS(unsigned tag_value, Tag* out) { - unsigned tag_number = tag_value & CBS_ASN1_TAG_NUMBER_MASK; - if (tag_number >= 31) { - // Tag can only represent small tag numbers. - return false; - } - *out = static_cast<Tag>(tag_number); - if (tag_value & CBS_ASN1_CONSTRUCTED) { - *out |= kTagConstructed; - } - switch (tag_value & CBS_ASN1_CLASS_MASK) { - case CBS_ASN1_APPLICATION: - *out |= kTagApplication; - break; - case CBS_ASN1_CONTEXT_SPECIFIC: - *out |= kTagContextSpecific; - break; - case CBS_ASN1_PRIVATE: - *out |= kTagPrivate; - break; - } - return true; -} - -} // namespace - Parser::Parser() : advance_len_(0) { CBS_init(&cbs_, nullptr, 0); } @@ -53,10 +25,11 @@ bool Parser::PeekTagAndValue(Tag* tag, Input* out) { size_t header_len; unsigned tag_value; if (!CBS_get_any_asn1_element(&peeker, &tmp_out, &tag_value, &header_len) || - !CBS_skip(&tmp_out, header_len) || !TagFromCBS(tag_value, tag)) { + !CBS_skip(&tmp_out, header_len)) { return false; } advance_len_ = CBS_len(&tmp_out) + header_len; + *tag = tag_value; *out = Input(CBS_data(&tmp_out), CBS_len(&tmp_out)); return true; } diff --git a/chromium/net/der/parser_unittest.cc b/chromium/net/der/parser_unittest.cc index d3f86fcb0a7..781bd34f3b2 100644 --- a/chromium/net/der/parser_unittest.cc +++ b/chromium/net/der/parser_unittest.cc @@ -13,12 +13,12 @@ namespace der { namespace test { TEST(ParserTest, ConsumesAllBytesOfTLV) { - const uint8_t der[] = {0x04, 0x00}; + const uint8_t der[] = {0x04 /* OCTET STRING */, 0x00}; Parser parser((Input(der))); Tag tag; Input value; ASSERT_TRUE(parser.ReadTagAndValue(&tag, &value)); - ASSERT_EQ(0x04, tag); + ASSERT_EQ(kOctetString, tag); ASSERT_FALSE(parser.HasMore()); } @@ -66,39 +66,40 @@ TEST(ParserTest, FailsIfLengthOverlapsAnotherTLV) { } TEST(ParserTest, CanSkipOptionalTagAtEndOfInput) { - const uint8_t der[] = {0x02, 0x01, 0x01}; + const uint8_t der[] = {0x02 /* INTEGER */, 0x01, 0x01}; Parser parser((Input(der))); Tag tag; Input value; ASSERT_TRUE(parser.ReadTagAndValue(&tag, &value)); bool present; - ASSERT_TRUE(parser.ReadOptionalTag(0x02, &value, &present)); + ASSERT_TRUE(parser.ReadOptionalTag(kInteger, &value, &present)); ASSERT_FALSE(present); ASSERT_FALSE(parser.HasMore()); } TEST(ParserTest, SkipOptionalTagDoesntConsumePresentNonMatchingTLVs) { - const uint8_t der[] = {0x02, 0x01, 0x01}; + const uint8_t der[] = {0x02 /* INTEGER */, 0x01, 0x01}; Parser parser((Input(der))); bool present; - ASSERT_TRUE(parser.SkipOptionalTag(0x04, &present)); + ASSERT_TRUE(parser.SkipOptionalTag(kOctetString, &present)); ASSERT_FALSE(present); - ASSERT_TRUE(parser.SkipOptionalTag(0x02, &present)); + ASSERT_TRUE(parser.SkipOptionalTag(kInteger, &present)); ASSERT_TRUE(present); ASSERT_FALSE(parser.HasMore()); } -TEST(ParserTest, TagNumbersAboveThirtyUnsupported) { +TEST(ParserTest, TagNumbersAboveThirtySupported) { // Context-specific class, tag number 31, length 0. const uint8_t der[] = {0x9f, 0x1f, 0x00}; Parser parser((Input(der))); Tag tag; Input value; - ASSERT_FALSE(parser.ReadTagAndValue(&tag, &value)); - ASSERT_TRUE(parser.HasMore()); + ASSERT_TRUE(parser.ReadTagAndValue(&tag, &value)); + EXPECT_EQ(kTagContextSpecific | 31u, tag); + ASSERT_FALSE(parser.HasMore()); } TEST(ParserTest, ParseTags) { diff --git a/chromium/net/der/tag.cc b/chromium/net/der/tag.cc index bdd5a6bfc9a..a2b00747e3e 100644 --- a/chromium/net/der/tag.cc +++ b/chromium/net/der/tag.cc @@ -10,10 +10,9 @@ namespace net { namespace der { -Tag ContextSpecificConstructed(uint8_t class_number) { - DCHECK_EQ(class_number, class_number & kTagNumberMask); - return (class_number & kTagNumberMask) | kTagConstructed | - kTagContextSpecific; +Tag ContextSpecificConstructed(uint8_t tag_number) { + DCHECK_EQ(tag_number, tag_number & kTagNumberMask); + return (tag_number & kTagNumberMask) | kTagConstructed | kTagContextSpecific; } Tag ContextSpecificPrimitive(uint8_t base) { diff --git a/chromium/net/der/tag.h b/chromium/net/der/tag.h index a168df66686..82d3b257e78 100644 --- a/chromium/net/der/tag.h +++ b/chromium/net/der/tag.h @@ -8,63 +8,66 @@ #include <stdint.h> #include "net/base/net_export.h" +#include "third_party/boringssl/src/include/openssl/bytestring.h" namespace net { namespace der { -// This Tag type represents the identifier for an ASN.1 tag as encoded with DER. -// It follows the same bit-for-bit representation (including the class, tag -// number, and primitive/constructed bit) as DER. Constants are provided for -// universal class types, and functions are provided for building context -// specific tags. Tags can also be built from the provided constants and -// bitmasks. -using Tag = uint8_t; +// This Tag type represents the identifier for an ASN.1 tag as encoded with +// DER. It matches the BoringSSL CBS and CBB in-memory representation for a +// tag. +// +// Callers must not assume it matches the DER representation for small tag +// numbers. Instead, constants are provided for universal class types, and +// functions are provided for building context specific tags. Tags can also be +// built from the provided constants and bitmasks. +using Tag = unsigned; // Universal class primitive types -const Tag kBool = 0x01; -const Tag kInteger = 0x02; -const Tag kBitString = 0x03; -const Tag kOctetString = 0x04; -const Tag kNull = 0x05; -const Tag kOid = 0x06; -const Tag kEnumerated = 0x0A; -const Tag kUtf8String = 0x0C; -const Tag kPrintableString = 0x13; -const Tag kTeletexString = 0x14; -const Tag kIA5String = 0x16; -const Tag kUtcTime = 0x17; -const Tag kGeneralizedTime = 0x18; -const Tag kUniversalString = 0x1C; -const Tag kBmpString = 0x1E; +const Tag kBool = CBS_ASN1_BOOLEAN; +const Tag kInteger = CBS_ASN1_INTEGER; +const Tag kBitString = CBS_ASN1_BITSTRING; +const Tag kOctetString = CBS_ASN1_OCTETSTRING; +const Tag kNull = CBS_ASN1_NULL; +const Tag kOid = CBS_ASN1_OBJECT; +const Tag kEnumerated = CBS_ASN1_ENUMERATED; +const Tag kUtf8String = CBS_ASN1_UTF8STRING; +const Tag kPrintableString = CBS_ASN1_PRINTABLESTRING; +const Tag kTeletexString = CBS_ASN1_T61STRING; +const Tag kIA5String = CBS_ASN1_IA5STRING; +const Tag kUtcTime = CBS_ASN1_UTCTIME; +const Tag kGeneralizedTime = CBS_ASN1_GENERALIZEDTIME; +const Tag kUniversalString = CBS_ASN1_UNIVERSALSTRING; +const Tag kBmpString = CBS_ASN1_BMPSTRING; // Universal class constructed types -const Tag kSequence = 0x30; -const Tag kSet = 0x31; +const Tag kSequence = CBS_ASN1_SEQUENCE; +const Tag kSet = CBS_ASN1_SET; // Primitive/constructed bits -const uint8_t kTagPrimitive = 0x00; -const uint8_t kTagConstructed = 0x20; +const unsigned kTagPrimitive = 0x00; +const unsigned kTagConstructed = CBS_ASN1_CONSTRUCTED; // Tag classes -const uint8_t kTagUniversal = 0x00; -const uint8_t kTagApplication = 0x40; -const uint8_t kTagContextSpecific = 0x80; -const uint8_t kTagPrivate = 0xC0; +const unsigned kTagUniversal = 0x00; +const unsigned kTagApplication = CBS_ASN1_APPLICATION; +const unsigned kTagContextSpecific = CBS_ASN1_CONTEXT_SPECIFIC; +const unsigned kTagPrivate = CBS_ASN1_PRIVATE; // Masks for the 3 components of a tag (class, primitive/constructed, number) -const uint8_t kTagNumberMask = 0x1F; -const uint8_t kTagConstructionMask = 0x20; -const uint8_t kTagClassMask = 0xC0; +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. // // The ASN.1 keyword for this is: -// [class_number] EXPLICIT +// [tag_number] EXPLICIT // // (Note, the EXPLICIT may be omitted if the entire schema is in // EXPLICIT mode, the default) -NET_EXPORT Tag ContextSpecificConstructed(uint8_t class_number); +NET_EXPORT Tag ContextSpecificConstructed(uint8_t tag_number); NET_EXPORT Tag ContextSpecificPrimitive(uint8_t base); diff --git a/chromium/net/disk_cache/OWNERS b/chromium/net/disk_cache/OWNERS index 854e7d8ff3d..7e2c65ec292 100644 --- a/chromium/net/disk_cache/OWNERS +++ b/chromium/net/disk_cache/OWNERS @@ -1,4 +1,4 @@ -morlovich@chromium.org jkarlin@chromium.org +morlovich@chromium.org # COMPONENT: Internals>Network>Cache diff --git a/chromium/net/disk_cache/backend_unittest.cc b/chromium/net/disk_cache/backend_unittest.cc index 80057fc25d5..6bd72f90fdd 100644 --- a/chromium/net/disk_cache/backend_unittest.cc +++ b/chromium/net/disk_cache/backend_unittest.cc @@ -1473,6 +1473,12 @@ void DiskCacheBackendTest::BackendTrimInvalidEntry2() { ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN(); EXPECT_GE(30, cache_->GetEntryCount()); ANNOTATE_IGNORE_READS_AND_WRITES_END(); + + // For extra messiness, the integrity check for the cache can actually cause + // evictions if it's over-capacity, which would race with above. So change the + // size we pass to CheckCacheIntegrity (but don't mess with existing backend's + // state. + size_ = 0; } // We'll be leaking memory from this test. @@ -2168,7 +2174,7 @@ void DiskCacheBackendTest::BackendTransaction(const std::string& name, cache_.reset(); cache_impl_ = NULL; - ASSERT_TRUE(CheckCacheIntegrity(cache_path_, new_eviction_, mask)); + ASSERT_TRUE(CheckCacheIntegrity(cache_path_, new_eviction_, MaxSize(), mask)); success_ = true; } @@ -2427,7 +2433,8 @@ TEST_F(DiskCacheBackendTest, DeleteOld) { ASSERT_THAT(cb.GetResult(rv), IsOk()); base::ThreadRestrictions::SetIOAllowed(prev); cache_.reset(); - EXPECT_TRUE(CheckCacheIntegrity(cache_path_, new_eviction_, mask_)); + EXPECT_TRUE(CheckCacheIntegrity(cache_path_, new_eviction_, /*max_size = */ 0, + mask_)); } #endif diff --git a/chromium/net/disk_cache/blockfile/file.h b/chromium/net/disk_cache/blockfile/file.h index 0e34fabf3d6..6aa6ba25b3e 100644 --- a/chromium/net/disk_cache/blockfile/file.h +++ b/chromium/net/disk_cache/blockfile/file.h @@ -68,6 +68,8 @@ class NET_EXPORT_PRIVATE File : public base::RefCounted<File> { size_t GetLength(); // Blocks until |num_pending_io| IO operations complete. + // TODO(fdoray): Rename to WaitForPendingIOForTesting() since this should only + // be called in tests. static void WaitForPendingIO(int* num_pending_io); // Drops current pending operations without waiting for them to complete. diff --git a/chromium/net/disk_cache/blockfile/file_posix.cc b/chromium/net/disk_cache/blockfile/file_posix.cc index 69058f1f28c..e1d0b3639e6 100644 --- a/chromium/net/disk_cache/blockfile/file_posix.cc +++ b/chromium/net/disk_cache/blockfile/file_posix.cc @@ -9,36 +9,14 @@ #include <utility> #include "base/bind.h" -#include "base/lazy_instance.h" #include "base/location.h" #include "base/logging.h" #include "base/run_loop.h" -#include "base/task_runner_util.h" -#include "base/threading/sequenced_worker_pool.h" +#include "base/task_scheduler/post_task.h" +#include "base/task_scheduler/task_scheduler.h" #include "net/base/net_errors.h" #include "net/disk_cache/disk_cache.h" -namespace { - -// The maximum number of threads for this pool. -const int kMaxThreads = 5; - -class FileWorkerPool : public base::SequencedWorkerPool { - public: - FileWorkerPool() - : base::SequencedWorkerPool(kMaxThreads, - "CachePool", - base::TaskPriority::USER_BLOCKING) {} - - protected: - ~FileWorkerPool() override = default; -}; - -base::LazyInstance<FileWorkerPool>::Leaky s_worker_pool = - LAZY_INSTANCE_INITIALIZER; - -} // namespace - namespace disk_cache { File::File(base::File file) @@ -95,11 +73,11 @@ bool File::Read(void* buffer, size_t buffer_len, size_t offset, return false; } - base::PostTaskAndReplyWithResult( - s_worker_pool.Pointer(), FROM_HERE, - base::Bind(&File::DoRead, base::Unretained(this), buffer, buffer_len, - offset), - base::Bind(&File::OnOperationComplete, this, callback)); + base::PostTaskWithTraitsAndReplyWithResult( + FROM_HERE, {base::TaskPriority::USER_BLOCKING, base::MayBlock()}, + base::BindOnce(&File::DoRead, base::Unretained(this), buffer, buffer_len, + offset), + base::BindOnce(&File::OnOperationComplete, this, callback)); *completed = false; return true; @@ -119,11 +97,15 @@ bool File::Write(const void* buffer, size_t buffer_len, size_t offset, return false; } - base::PostTaskAndReplyWithResult( - s_worker_pool.Pointer(), FROM_HERE, - base::Bind(&File::DoWrite, base::Unretained(this), buffer, buffer_len, - offset), - base::Bind(&File::OnOperationComplete, this, callback)); + // The priority is USER_BLOCKING because the cache waits for the write to + // finish before it reads from the network again. + // TODO(fdoray): Consider removing this from the critical path of network + // requests and changing the priority to BACKGROUND. + base::PostTaskWithTraitsAndReplyWithResult( + FROM_HERE, {base::TaskPriority::USER_BLOCKING, base::MayBlock()}, + base::BindOnce(&File::DoWrite, base::Unretained(this), buffer, buffer_len, + offset), + base::BindOnce(&File::OnOperationComplete, this, callback)); *completed = false; return true; @@ -151,10 +133,11 @@ size_t File::GetLength() { // Static. void File::WaitForPendingIO(int* num_pending_io) { - // We are running unit tests so we should wait for all callbacks. Sadly, the - // worker pool only waits for tasks on the worker pool, not the "Reply" tasks - // so we have to let the current message loop to run. - s_worker_pool.Get().FlushForTesting(); + // We are running unit tests so we should wait for all callbacks. + + // This waits for callbacks running on worker threads. + base::TaskScheduler::GetInstance()->FlushForTesting(); + // This waits for the "Reply" tasks running on the current MessageLoop. base::RunLoop().RunUntilIdle(); } diff --git a/chromium/net/disk_cache/blockfile/file_win.cc b/chromium/net/disk_cache/blockfile/file_win.cc index 219df2a7449..e2ea893a219 100644 --- a/chromium/net/disk_cache/blockfile/file_win.cc +++ b/chromium/net/disk_cache/blockfile/file_win.cc @@ -15,6 +15,7 @@ namespace { +class CompletionHandler; // Structure used for asynchronous operations. struct MyOverlapped { MyOverlapped(disk_cache::File* file, size_t offset, @@ -26,6 +27,7 @@ struct MyOverlapped { base::MessageLoopForIO::IOContext context_; scoped_refptr<disk_cache::File> file_; + scoped_refptr<CompletionHandler> completion_handler_; disk_cache::FileIOCallback* callback_; }; @@ -33,14 +35,43 @@ static_assert(offsetof(MyOverlapped, context_) == 0, "should start with overlapped"); // Helper class to handle the IO completion notifications from the message loop. -class CompletionHandler : public base::MessageLoopForIO::IOHandler { +class CompletionHandler : public base::MessageLoopForIO::IOHandler, + public base::RefCounted<CompletionHandler> { + public: + CompletionHandler() = default; + static CompletionHandler* Get(); + + private: + friend class base::RefCounted<CompletionHandler>; + ~CompletionHandler() override {} + + // implement base::MessageLoopForIO::IOHandler. void OnIOCompleted(base::MessageLoopForIO::IOContext* context, DWORD actual_bytes, DWORD error) override; + + DISALLOW_COPY_AND_ASSIGN(CompletionHandler); +}; + +class CompletionHandlerHolder { + public: + CompletionHandlerHolder() { completion_handler_ = new CompletionHandler; } + + CompletionHandler* completion_handler() { return completion_handler_.get(); } + + private: + scoped_refptr<CompletionHandler> completion_handler_; }; -static base::LazyInstance<CompletionHandler>::DestructorAtExit - g_completion_handler = LAZY_INSTANCE_INITIALIZER; +static base::LazyInstance<CompletionHandlerHolder>::DestructorAtExit + g_completion_handler_holder = LAZY_INSTANCE_INITIALIZER; + +CompletionHandler* CompletionHandler::Get() { + if (auto* holder = g_completion_handler_holder.Pointer()) { + return holder->completion_handler(); + } + return nullptr; +} void CompletionHandler::OnIOCompleted( base::MessageLoopForIO::IOContext* context, @@ -65,6 +96,7 @@ MyOverlapped::MyOverlapped(disk_cache::File* file, size_t offset, context_.overlapped.Offset = static_cast<DWORD>(offset); file_ = file; callback_ = callback; + completion_handler_ = CompletionHandler::Get(); } } // namespace @@ -89,7 +121,7 @@ bool File::Init(const base::FilePath& name) { return false; base::MessageLoopForIO::current()->RegisterIOHandler( - base_file_.GetPlatformFile(), g_completion_handler.Pointer()); + base_file_.GetPlatformFile(), CompletionHandler::Get()); init_ = true; sync_base_file_ = @@ -244,7 +276,7 @@ void File::WaitForPendingIO(int* num_pending_io) { while (*num_pending_io) { // Asynchronous IO operations may be in flight and the completion may end // up calling us back so let's wait for them. - base::MessageLoopForIO::IOHandler* handler = g_completion_handler.Pointer(); + base::MessageLoopForIO::IOHandler* handler = CompletionHandler::Get(); base::MessageLoopForIO::current()->WaitForIOCompletion(100, handler); } } diff --git a/chromium/net/disk_cache/blockfile/mapped_file_win.cc b/chromium/net/disk_cache/blockfile/mapped_file_win.cc index 9a128a36d0e..706ae09221a 100644 --- a/chromium/net/disk_cache/blockfile/mapped_file_win.cc +++ b/chromium/net/disk_cache/blockfile/mapped_file_win.cc @@ -10,6 +10,8 @@ #include "base/logging.h" #include "net/disk_cache/disk_cache.h" +#include <windows.h> + namespace disk_cache { void* MappedFile::Init(const base::FilePath& name, size_t size) { diff --git a/chromium/net/disk_cache/blockfile/rankings.cc b/chromium/net/disk_cache/blockfile/rankings.cc index 68d2c3be92d..41a47a3965b 100644 --- a/chromium/net/disk_cache/blockfile/rankings.cc +++ b/chromium/net/disk_cache/blockfile/rankings.cc @@ -9,6 +9,7 @@ #include <limits> #include "base/macros.h" +#include "build/build_config.h" #include "net/base/net_export.h" #include "net/disk_cache/blockfile/backend_impl.h" #include "net/disk_cache/blockfile/disk_format.h" @@ -17,6 +18,10 @@ #include "net/disk_cache/blockfile/histogram_macros.h" #include "net/disk_cache/blockfile/stress_support.h" +#if defined(OS_WIN) +#include <windows.h> +#endif + // Provide a BackendImpl object to macros from histogram_macros.h. #define CACHE_UMA_BACKEND_IMPL_OBJ backend_ diff --git a/chromium/net/disk_cache/blockfile/sparse_control.cc b/chromium/net/disk_cache/blockfile/sparse_control.cc index 3391533b40c..c18c4d0e683 100644 --- a/chromium/net/disk_cache/blockfile/sparse_control.cc +++ b/chromium/net/disk_cache/blockfile/sparse_control.cc @@ -16,6 +16,7 @@ #include "base/strings/stringprintf.h" #include "base/threading/thread_task_runner_handle.h" #include "base/time/time.h" +#include "net/base/interval.h" #include "net/base/io_buffer.h" #include "net/base/net_errors.h" #include "net/disk_cache/blockfile/backend_impl.h" @@ -768,68 +769,82 @@ int SparseControl::DoGetAvailableRange() { if (!child_) return child_len_; // Move on to the next child. - // Bits on the bitmap should only be set when the corresponding block was - // fully written (it's really being used). If a block is partially used, it - // has to start with valid data, the length of the valid data is saved in - // |header.last_block_len| and the block itself should match - // |header.last_block|. + // Blockfile splits sparse files into multiple child entries, each responsible + // for managing 1MiB of address space. This method is responsible for + // implementing GetAvailableRange within a single child. + // + // Input: + // |child_offset_|, |child_len_|: + // describe range in current child's address space the client requested. + // |offset_| is equivalent to |child_offset_| but in global address space. + // + // For example if this were child [2] and the original call was for + // [0x200005, 0x200007) then |offset_| would be 0x200005, |child_offset_| + // would be 5, and |child_len| would be 2. // - // In other words, (|header.last_block| + |header.last_block_len|) is the - // offset where the last write ended, and data in that block (which is not - // marked as used because it is not full) will only be reused if the next - // write continues at that point. + // Output: + // If nothing found: + // return |child_len_| // - // This code has to find if there is any data between child_offset_ and - // child_offset_ + child_len_. + // If something found: + // |result_| gets the length of the available range. + // |offset_| gets the global address of beginning of the available range. + // |range_found_| get true to signal SparseControl::GetAvailableRange(). + // return 0 to exit loop. + net::Interval<int> to_find(child_offset_, child_offset_ + child_len_); + + // Within each child, valid portions are mostly tracked via the |child_map_| + // bitmap which marks which 1KiB 'blocks' have valid data. Scan the bitmap + // for the first contiguous range of set bits that's relevant to the range + // [child_offset_, child_offset_ + len) + int first_bit = child_offset_ >> 10; int last_bit = (child_offset_ + child_len_ + kBlockSize - 1) >> 10; - int start = child_offset_ >> 10; - int partial_start_bytes = PartialBlockLength(start); - int found = start; + int found = first_bit; int bits_found = child_map_.FindBits(&found, last_bit, true); - bool is_last_block_in_range = start < child_data_.header.last_block && - child_data_.header.last_block < last_bit; + net::Interval<int> bitmap_range(found * kBlockSize, + found * kBlockSize + bits_found * kBlockSize); - int block_offset = child_offset_ & (kBlockSize - 1); - if (!bits_found && partial_start_bytes <= block_offset) { - if (!is_last_block_in_range) - return child_len_; - found = last_bit - 1; // There are some bytes here. + // Bits on the bitmap should only be set when the corresponding block was + // fully written (it's really being used). If a block is partially used, it + // has to start with valid data, the length of the valid data is saved in + // |header.last_block_len| and the block number saved in |header.last_block|. + // This is updated after every write; with |header.last_block| set to -1 + // if no sub-KiB range is being tracked. + net::Interval<int> last_write_range; + if (child_data_.header.last_block >= 0) { + last_write_range = + net::Interval<int>(child_data_.header.last_block * kBlockSize, + child_data_.header.last_block * kBlockSize + + child_data_.header.last_block_len); } - // We are done. Just break the loop and reset result_ to our real result. - range_found_ = true; - - int bytes_found = bits_found << 10; - bytes_found += PartialBlockLength(found + bits_found); - - // found now points to the first bytes. Lets see if we have data before it. - int empty_start = std::max((found << 10) - child_offset_, 0); - if (empty_start >= child_len_) - return child_len_; - - // At this point we have bytes_found stored after (found << 10), and we want - // child_len_ bytes after child_offset_. The first empty_start bytes after - // child_offset_ are invalid. + // Often |last_write_range| is contiguously after |bitmap_range|, but not + // always. See if they can be combined. + if (!last_write_range.Empty() && !bitmap_range.Empty() && + bitmap_range.max() == last_write_range.min()) { + bitmap_range.SetMax(last_write_range.max()); + last_write_range.Clear(); + } - if (start == found) - bytes_found -= block_offset; + // Do any of them have anything relevant? + bitmap_range.IntersectWith(to_find); + last_write_range.IntersectWith(to_find); - // If the user is searching past the end of this child, bits_found is the - // right result; otherwise, we have some empty space at the start of this - // query that we have to subtract from the range that we searched. - result_ = std::min(bytes_found, child_len_ - empty_start); + // Now return the earliest non-empty interval, if any. + net::Interval<int> result_range = bitmap_range; + if (bitmap_range.Empty() || (!last_write_range.Empty() && + last_write_range.min() < bitmap_range.min())) + result_range = last_write_range; - if (partial_start_bytes) { - result_ = std::min(partial_start_bytes - block_offset, child_len_); - empty_start = 0; + if (result_range.Empty()) { + // Nothing found, so we just skip over this child. + return child_len_; } - // Only update offset_ when this query found zeros at the start. - if (empty_start) - offset_ += empty_start; - - // This will actually break the loop. - buf_len_ = 0; + // Package up our results. + range_found_ = true; + offset_ += result_range.min() - child_offset_; + result_ = result_range.max() - result_range.min(); return 0; } diff --git a/chromium/net/disk_cache/disk_cache_perftest.cc b/chromium/net/disk_cache/disk_cache_perftest.cc index d5e9431eb90..8df5c2007f9 100644 --- a/chromium/net/disk_cache/disk_cache_perftest.cc +++ b/chromium/net/disk_cache/disk_cache_perftest.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include <limits> +#include <memory> #include <string> #include "base/barrier_closure.h" @@ -40,6 +41,17 @@ using base::Time; namespace { +const size_t kNumEntries = 10000; +const int kHeadersSize = 2000; + +const int kBodySize = 72 * 1024 - 1; + +// HttpCache likes this chunk size. +const int kChunkSize = 32 * 1024; + +// As of 2017-01-12, this is a typical per-tab limit on HTTP connections. +const int kMaxParallelOperations = 10; + void MaybeSetFdLimit(unsigned int max_descriptors) { #if defined(OS_POSIX) base::SetFdLimit(max_descriptors); @@ -51,6 +63,11 @@ struct TestEntry { int data_len; }; +enum class WhatToRead { + HEADERS_ONLY, + HEADERS_AND_BODY, +}; + class DiskCachePerfTest : public DiskCacheTestWithCache { public: DiskCachePerfTest() @@ -65,26 +82,29 @@ class DiskCachePerfTest : public DiskCacheTestWithCache { MaybeSetFdLimit(saved_fd_limit_); } + const std::vector<TestEntry>& entries() const { return entries_; } + protected: - enum class WhatToRead { - HEADERS_ONLY, - HEADERS_AND_BODY, - }; // Helper methods for constructing tests. - bool TimeWrite(); - bool TimeRead(WhatToRead what_to_read, const char* timer_message); + bool TimeWrites(); + bool TimeReads(WhatToRead what_to_read, const char* timer_message); void ResetAndEvictSystemDiskCache(); + // Callbacks used within tests for intermediate operations. + void WriteCallback(const net::CompletionCallback& final_callback, + scoped_refptr<net::IOBuffer> headers_buffer, + scoped_refptr<net::IOBuffer> body_buffer, + disk_cache::Entry* cache_entry, + int entry_index, + size_t write_offset, + int result); + // Complete perf tests. void CacheBackendPerformance(); const size_t kFdLimitForCacheTests = 8192; - const int kNumEntries = 1000; - const int kHeadersSize = 800; - const int kBodySize = 256 * 1024 - 1; - std::vector<TestEntry> entries_; private: @@ -92,109 +112,291 @@ class DiskCachePerfTest : public DiskCacheTestWithCache { base::test::ScopedTaskEnvironment scoped_task_environment_; }; -// Creates num_entries on the cache, and writes kHeaderSize bytes of metadata -// and up to kBodySize of data to each entry. -bool DiskCachePerfTest::TimeWrite() { - // TODO(gavinp): This test would be significantly more realistic if it didn't - // do single reads and writes. Perhaps entries should be written 64kb at a - // time. As well, not all entries should be created and written essentially - // simultaneously; some number of entries in flight at a time would be a - // likely better testing load. - scoped_refptr<net::IOBuffer> buffer1(new net::IOBuffer(kHeadersSize)); - scoped_refptr<net::IOBuffer> buffer2(new net::IOBuffer(kBodySize)); +class WriteHandler { + public: + WriteHandler(const DiskCachePerfTest* test, + disk_cache::Backend* cache, + net::CompletionCallback final_callback) + : test_(test), cache_(cache), final_callback_(final_callback) { + CacheTestFillBuffer(headers_buffer_->data(), kHeadersSize, false); + CacheTestFillBuffer(body_buffer_->data(), kChunkSize, false); + } - CacheTestFillBuffer(buffer1->data(), kHeadersSize, false); - CacheTestFillBuffer(buffer2->data(), kBodySize, false); + void Run(); - int expected = 0; + protected: + void CreateNextEntry(); - MessageLoopHelper helper; - CallbackTest callback(&helper, true); + void CreateCallback(std::unique_ptr<disk_cache::Entry*> unique_entry_ptr, + int data_len, + int result); + void WriteDataCallback(disk_cache::Entry* entry, + int next_offset, + int data_len, + int expected_result, + int result); - base::PerfTimeLogger timer("Write disk cache entries"); + private: + bool CheckForErrorAndCancel(int result); - for (int i = 0; i < kNumEntries; i++) { - TestEntry entry; - entry.key = GenerateKey(true); - entry.data_len = base::RandInt(0, kBodySize); - entries_.push_back(entry); + const DiskCachePerfTest* test_; + disk_cache::Backend* cache_; + net::CompletionCallback final_callback_; - disk_cache::Entry* cache_entry; - net::TestCompletionCallback cb; - int rv = cache_->CreateEntry(entry.key, &cache_entry, cb.callback()); - if (net::OK != cb.GetResult(rv)) - break; - int ret = cache_entry->WriteData( - 0, 0, buffer1.get(), kHeadersSize, - base::Bind(&CallbackTest::Run, base::Unretained(&callback)), false); - if (net::ERR_IO_PENDING == ret) - expected++; - else if (kHeadersSize != ret) - break; - - ret = cache_entry->WriteData( - 1, 0, buffer2.get(), entry.data_len, - base::Bind(&CallbackTest::Run, base::Unretained(&callback)), false); - if (net::ERR_IO_PENDING == ret) - expected++; - else if (entry.data_len != ret) - break; - cache_entry->Close(); + size_t next_entry_index_ = 0; + size_t pending_operations_count_ = 0; + + int pending_result_ = net::OK; + + scoped_refptr<net::IOBuffer> headers_buffer_ = + new net::IOBuffer(kHeadersSize); + scoped_refptr<net::IOBuffer> body_buffer_ = new net::IOBuffer(kChunkSize); +}; + +void WriteHandler::Run() { + for (int i = 0; i < kMaxParallelOperations; ++i) { + ++pending_operations_count_; + CreateNextEntry(); } +} - helper.WaitUntilCacheIoFinished(expected); - timer.Done(); +void WriteHandler::CreateNextEntry() { + ASSERT_GT(kNumEntries, next_entry_index_); + TestEntry test_entry = test_->entries()[next_entry_index_++]; + disk_cache::Entry** entry_ptr = new disk_cache::Entry*(); + std::unique_ptr<disk_cache::Entry*> unique_entry_ptr(entry_ptr); + net::CompletionCallback callback = + base::Bind(&WriteHandler::CreateCallback, base::Unretained(this), + base::Passed(&unique_entry_ptr), test_entry.data_len); + int result = cache_->CreateEntry(test_entry.key, entry_ptr, callback); + if (result != net::ERR_IO_PENDING) + callback.Run(result); +} - return expected == helper.callbacks_called(); +void WriteHandler::CreateCallback(std::unique_ptr<disk_cache::Entry*> entry_ptr, + int data_len, + int result) { + if (CheckForErrorAndCancel(result)) + return; + + disk_cache::Entry* entry = *entry_ptr; + + net::CompletionCallback callback = + base::Bind(&WriteHandler::WriteDataCallback, base::Unretained(this), + entry, 0, data_len, kHeadersSize); + int new_result = entry->WriteData(0, 0, headers_buffer_.get(), kHeadersSize, + callback, false); + if (new_result != net::ERR_IO_PENDING) + callback.Run(new_result); } -// Reads the data and metadata from each entry listed on |entries|. -bool DiskCachePerfTest::TimeRead(WhatToRead what_to_read, - const char* timer_message) { - scoped_refptr<net::IOBuffer> buffer1(new net::IOBuffer(kHeadersSize)); - scoped_refptr<net::IOBuffer> buffer2(new net::IOBuffer(kBodySize)); +void WriteHandler::WriteDataCallback(disk_cache::Entry* entry, + int next_offset, + int data_len, + int expected_result, + int result) { + if (CheckForErrorAndCancel(result)) { + entry->Close(); + return; + } + DCHECK_LE(next_offset, data_len); + if (next_offset == data_len) { + entry->Close(); + if (next_entry_index_ < kNumEntries) { + CreateNextEntry(); + } else { + --pending_operations_count_; + if (pending_operations_count_ == 0) + final_callback_.Run(net::OK); + } + return; + } - CacheTestFillBuffer(buffer1->data(), kHeadersSize, false); - CacheTestFillBuffer(buffer2->data(), kBodySize, false); + int write_size = std::min(kChunkSize, data_len - next_offset); + net::CompletionCallback callback = + base::Bind(&WriteHandler::WriteDataCallback, base::Unretained(this), + entry, next_offset + write_size, data_len, write_size); + int new_result = entry->WriteData(1, next_offset, body_buffer_.get(), + write_size, callback, true); + if (new_result != net::ERR_IO_PENDING) + callback.Run(new_result); +} + +bool WriteHandler::CheckForErrorAndCancel(int result) { + DCHECK_NE(net::ERR_IO_PENDING, result); + if (result != net::OK && !(result > 0)) + pending_result_ = result; + if (pending_result_ != net::OK) { + --pending_operations_count_; + if (pending_operations_count_ == 0) + final_callback_.Run(pending_result_); + return true; + } + return false; +} - int expected = 0; +class ReadHandler { + public: + ReadHandler(const DiskCachePerfTest* test, + WhatToRead what_to_read, + disk_cache::Backend* cache, + net::CompletionCallback final_callback) + : test_(test), + what_to_read_(what_to_read), + cache_(cache), + final_callback_(final_callback) { + for (int i = 0; i < kMaxParallelOperations; ++i) + read_buffers_[i] = new net::IOBuffer(std::max(kHeadersSize, kChunkSize)); + } - MessageLoopHelper helper; - CallbackTest callback(&helper, true); + void Run(); - base::PerfTimeLogger timer(timer_message); + protected: + void OpenNextEntry(int parallel_operation_index); + + void OpenCallback(int parallel_operation_index, + std::unique_ptr<disk_cache::Entry*> unique_entry_ptr, + int data_len, + int result); + void ReadDataCallback(int parallel_operation_index, + disk_cache::Entry* entry, + int next_offset, + int data_len, + int expected_result, + int result); - for (int i = 0; i < kNumEntries; i++) { - disk_cache::Entry* cache_entry; - net::TestCompletionCallback cb; - int rv = cache_->OpenEntry(entries_[i].key, &cache_entry, cb.callback()); - if (net::OK != cb.GetResult(rv)) - break; - int ret = cache_entry->ReadData( - 0, 0, buffer1.get(), kHeadersSize, - base::Bind(&CallbackTest::Run, base::Unretained(&callback))); - if (net::ERR_IO_PENDING == ret) - expected++; - else if (kHeadersSize != ret) - break; - - if (what_to_read == WhatToRead::HEADERS_AND_BODY) { - ret = cache_entry->ReadData( - 1, 0, buffer2.get(), entries_[i].data_len, - base::Bind(&CallbackTest::Run, base::Unretained(&callback))); - if (net::ERR_IO_PENDING == ret) - expected++; - else if (entries_[i].data_len != ret) - break; + private: + bool CheckForErrorAndCancel(int result); + + const DiskCachePerfTest* test_; + const WhatToRead what_to_read_; + + disk_cache::Backend* cache_; + net::CompletionCallback final_callback_; + + size_t next_entry_index_ = 0; + size_t pending_operations_count_ = 0; + + int pending_result_ = net::OK; + + scoped_refptr<net::IOBuffer> read_buffers_[kMaxParallelOperations]; +}; + +void ReadHandler::Run() { + for (int i = 0; i < kMaxParallelOperations; ++i) { + OpenNextEntry(pending_operations_count_); + ++pending_operations_count_; + } +} + +void ReadHandler::OpenNextEntry(int parallel_operation_index) { + ASSERT_GT(kNumEntries, next_entry_index_); + TestEntry test_entry = test_->entries()[next_entry_index_++]; + disk_cache::Entry** entry_ptr = new disk_cache::Entry*(); + std::unique_ptr<disk_cache::Entry*> unique_entry_ptr(entry_ptr); + net::CompletionCallback callback = + base::Bind(&ReadHandler::OpenCallback, base::Unretained(this), + parallel_operation_index, base::Passed(&unique_entry_ptr), + test_entry.data_len); + int result = cache_->OpenEntry(test_entry.key, entry_ptr, callback); + if (result != net::ERR_IO_PENDING) + callback.Run(result); +} + +void ReadHandler::OpenCallback(int parallel_operation_index, + std::unique_ptr<disk_cache::Entry*> entry_ptr, + int data_len, + int result) { + if (CheckForErrorAndCancel(result)) + return; + + disk_cache::Entry* entry = *entry_ptr; + + EXPECT_EQ(data_len, entry->GetDataSize(1)); + + net::CompletionCallback callback = + base::Bind(&ReadHandler::ReadDataCallback, base::Unretained(this), + parallel_operation_index, entry, 0, data_len, kHeadersSize); + int new_result = + entry->ReadData(0, 0, read_buffers_[parallel_operation_index].get(), + kChunkSize, callback); + if (new_result != net::ERR_IO_PENDING) + callback.Run(new_result); +} + +void ReadHandler::ReadDataCallback(int parallel_operation_index, + disk_cache::Entry* entry, + int next_offset, + int data_len, + int expected_result, + int result) { + if (CheckForErrorAndCancel(result)) { + entry->Close(); + return; + } + DCHECK_LE(next_offset, data_len); + if (what_to_read_ == WhatToRead::HEADERS_ONLY || next_offset == data_len) { + entry->Close(); + if (next_entry_index_ < kNumEntries) { + OpenNextEntry(parallel_operation_index); + } else { + --pending_operations_count_; + if (pending_operations_count_ == 0) + final_callback_.Run(net::OK); } + return; + } + + int expected_read_size = std::min(kChunkSize, data_len - next_offset); + net::CompletionCallback callback = base::Bind( + &ReadHandler::ReadDataCallback, base::Unretained(this), + parallel_operation_index, entry, next_offset + expected_read_size, + data_len, expected_read_size); + int new_result = entry->ReadData( + 1, next_offset, read_buffers_[parallel_operation_index].get(), kChunkSize, + callback); + if (new_result != net::ERR_IO_PENDING) + callback.Run(new_result); +} - cache_entry->Close(); +bool ReadHandler::CheckForErrorAndCancel(int result) { + DCHECK_NE(net::ERR_IO_PENDING, result); + if (result != net::OK && !(result > 0)) + pending_result_ = result; + if (pending_result_ != net::OK) { + --pending_operations_count_; + if (pending_operations_count_ == 0) + final_callback_.Run(pending_result_); + return true; } + return false; +} - helper.WaitUntilCacheIoFinished(expected); - timer.Done(); +bool DiskCachePerfTest::TimeWrites() { + for (size_t i = 0; i < kNumEntries; i++) { + TestEntry entry; + entry.key = GenerateKey(true); + entry.data_len = base::RandInt(0, kBodySize); + entries_.push_back(entry); + } + + net::TestCompletionCallback cb; + + base::PerfTimeLogger timer("Write disk cache entries"); + + WriteHandler write_handler(this, cache_.get(), cb.callback()); + write_handler.Run(); + return cb.WaitForResult() == net::OK; +} + +bool DiskCachePerfTest::TimeReads(WhatToRead what_to_read, + const char* timer_message) { + base::PerfTimeLogger timer(timer_message); - return (expected == helper.callbacks_called()); + net::TestCompletionCallback cb; + ReadHandler read_handler(this, what_to_read, cache_.get(), cb.callback()); + read_handler.Run(); + return cb.WaitForResult() == net::OK; } TEST_F(DiskCachePerfTest, BlockfileHashes) { @@ -233,26 +435,28 @@ void DiskCachePerfTest::ResetAndEvictSystemDiskCache() { } void DiskCachePerfTest::CacheBackendPerformance() { + LOG(ERROR) << "Using cache at:" << cache_path_.MaybeAsASCII(); + SetMaxSize(500 * 1024 * 1024); InitCache(); - EXPECT_TRUE(TimeWrite()); + EXPECT_TRUE(TimeWrites()); disk_cache::SimpleBackendImpl::FlushWorkerPoolForTesting(); base::RunLoop().RunUntilIdle(); ResetAndEvictSystemDiskCache(); - EXPECT_TRUE(TimeRead(WhatToRead::HEADERS_ONLY, - "Read disk cache headers only (cold)")); - EXPECT_TRUE(TimeRead(WhatToRead::HEADERS_ONLY, - "Read disk cache headers only (warm)")); + EXPECT_TRUE(TimeReads(WhatToRead::HEADERS_ONLY, + "Read disk cache headers only (cold)")); + EXPECT_TRUE(TimeReads(WhatToRead::HEADERS_ONLY, + "Read disk cache headers only (warm)")); disk_cache::SimpleBackendImpl::FlushWorkerPoolForTesting(); base::RunLoop().RunUntilIdle(); ResetAndEvictSystemDiskCache(); - EXPECT_TRUE( - TimeRead(WhatToRead::HEADERS_AND_BODY, "Read disk cache entries (cold)")); - EXPECT_TRUE( - TimeRead(WhatToRead::HEADERS_AND_BODY, "Read disk cache entries (warm)")); + EXPECT_TRUE(TimeReads(WhatToRead::HEADERS_AND_BODY, + "Read disk cache entries (cold)")); + EXPECT_TRUE(TimeReads(WhatToRead::HEADERS_AND_BODY, + "Read disk cache entries (warm)")); disk_cache::SimpleBackendImpl::FlushWorkerPoolForTesting(); base::RunLoop().RunUntilIdle(); diff --git a/chromium/net/disk_cache/disk_cache_test_base.cc b/chromium/net/disk_cache/disk_cache_test_base.cc index 727dbb8fa9f..b5483cf2d6a 100644 --- a/chromium/net/disk_cache/disk_cache_test_base.cc +++ b/chromium/net/disk_cache/disk_cache_test_base.cc @@ -117,7 +117,7 @@ void DiskCacheTestWithCache::SimulateCrash() { cache_impl_->ClearRefCountForTest(); cache_.reset(); - EXPECT_TRUE(CheckCacheIntegrity(cache_path_, new_eviction_, mask_)); + EXPECT_TRUE(CheckCacheIntegrity(cache_path_, new_eviction_, size_, mask_)); CreateBackend(disk_cache::kNoRandom); } @@ -287,7 +287,7 @@ void DiskCacheTestWithCache::TearDown() { cache_.reset(); if (!memory_only_ && !simple_cache_mode_ && integrity_) { - EXPECT_TRUE(CheckCacheIntegrity(cache_path_, new_eviction_, mask_)); + EXPECT_TRUE(CheckCacheIntegrity(cache_path_, new_eviction_, size_, mask_)); } scoped_task_env_->RunUntilIdle(); if (simple_cache_mode_ && simple_file_tracker_) diff --git a/chromium/net/disk_cache/disk_cache_test_base.h b/chromium/net/disk_cache/disk_cache_test_base.h index cfa463cbeb1..b70ee389781 100644 --- a/chromium/net/disk_cache/disk_cache_test_base.h +++ b/chromium/net/disk_cache/disk_cache_test_base.h @@ -108,6 +108,9 @@ class DiskCacheTestWithCache : public DiskCacheTest { void SetMaxSize(int size); + // Returns value last given to SetMaxSize (or 0). + int MaxSize() const { return size_; } + // Deletes and re-creates the files on initialization errors. void SetForceCreation() { force_creation_ = true; diff --git a/chromium/net/disk_cache/disk_cache_test_util.cc b/chromium/net/disk_cache/disk_cache_test_util.cc index 69314c5e544..7382adaaa79 100644 --- a/chromium/net/disk_cache/disk_cache_test_util.cc +++ b/chromium/net/disk_cache/disk_cache_test_util.cc @@ -61,9 +61,12 @@ bool DeleteCache(const base::FilePath& path) { bool CheckCacheIntegrity(const base::FilePath& path, bool new_eviction, + int max_size, uint32_t mask) { std::unique_ptr<disk_cache::BackendImpl> cache(new disk_cache::BackendImpl( path, mask, base::ThreadTaskRunnerHandle::Get(), NULL)); + if (max_size) + cache->SetMaxSize(max_size); if (!cache.get()) return false; if (new_eviction) diff --git a/chromium/net/disk_cache/disk_cache_test_util.h b/chromium/net/disk_cache/disk_cache_test_util.h index 2f59a46de7e..02dd6f491c0 100644 --- a/chromium/net/disk_cache/disk_cache_test_util.h +++ b/chromium/net/disk_cache/disk_cache_test_util.h @@ -29,9 +29,11 @@ void CacheTestFillBuffer(char* buffer, size_t len, bool no_nulls); // Generates a random key of up to 200 bytes. std::string GenerateKey(bool same_length); -// Returns true if the cache is not corrupt. +// Returns true if the cache is not corrupt. Assumes blockfile cache. +// |max_size|, if non-zero, will be set as its size. bool CheckCacheIntegrity(const base::FilePath& path, bool new_eviction, + int max_size, uint32_t mask); // ----------------------------------------------------------------------- diff --git a/chromium/net/disk_cache/entry_unittest.cc b/chromium/net/disk_cache/entry_unittest.cc index ae97a761cb6..4363813551a 100644 --- a/chromium/net/disk_cache/entry_unittest.cc +++ b/chromium/net/disk_cache/entry_unittest.cc @@ -1835,6 +1835,91 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyGetAvailableRange) { GetAvailableRange(); } +TEST_F(DiskCacheEntryTest, GetAvailableRangeBlockFileDiscontinuous) { + // crbug.com/791056 --- blockfile problem when there is a sub-KiB write before + // a bunch of full 1KiB blocks, and a GetAvailableRange is issued to which + // both are a potentially relevant. + InitCache(); + + std::string key("the first key"); + disk_cache::Entry* entry; + ASSERT_THAT(CreateEntry(key, &entry), IsOk()); + + scoped_refptr<net::IOBuffer> buf_2k(new net::IOBuffer(2 * 1024)); + CacheTestFillBuffer(buf_2k->data(), 2 * 1024, false); + + const int kSmallSize = 612; // sub-1k + scoped_refptr<net::IOBuffer> buf_small(new net::IOBuffer(kSmallSize)); + CacheTestFillBuffer(buf_small->data(), kSmallSize, false); + + // Sets some bits for blocks representing 1K ranges [1024, 3072), + // which will be relevant for the next GetAvailableRange call. + EXPECT_EQ(2 * 1024, WriteSparseData(entry, /* offset = */ 1024, buf_2k.get(), + /* size = */ 2 * 1024)); + + // Now record a partial write from start of the first kb. + EXPECT_EQ(kSmallSize, WriteSparseData(entry, /* offset = */ 0, + buf_small.get(), kSmallSize)); + + // Try to query a range starting from that block 0. + // The cache tracks: [0, 612) [1024, 3072). + // The request is for: [812, 2059) so response should be [1024, 2059), which + // has lenth = 1035. Previously this return a negative number for rv. + int64_t start = -1; + net::TestCompletionCallback cb; + int rv = entry->GetAvailableRange(812, 1247, &start, cb.callback()); + EXPECT_EQ(1035, cb.GetResult(rv)); + EXPECT_EQ(1024, start); + + // Now query [512, 1536). This matches both [512, 612) and [1024, 1536), + // so this should return [512, 612). + rv = entry->GetAvailableRange(512, 1024, &start, cb.callback()); + EXPECT_EQ(100, cb.GetResult(rv)); + EXPECT_EQ(512, start); + + // Now query next portion, [612, 1636). This now just should produce + // [1024, 1636) + rv = entry->GetAvailableRange(612, 1024, &start, cb.callback()); + EXPECT_EQ(612, cb.GetResult(rv)); + EXPECT_EQ(1024, start); + + // Do a continuous small write, this one at [3072, 3684). + // This means the cache tracks [1024, 3072) via bitmaps and [3072, 3684) + // as the last write. + EXPECT_EQ(kSmallSize, WriteSparseData(entry, /* offset = */ 3072, + buf_small.get(), kSmallSize)); + + // Query [2048, 4096). Should get [2048, 3684) + rv = entry->GetAvailableRange(2048, 2048, &start, cb.callback()); + EXPECT_EQ(1636, cb.GetResult(rv)); + EXPECT_EQ(2048, start); + + // Now write at [4096, 4708). Since only one sub-kb thing is tracked, this + // now tracks [1024, 3072) via bitmaps and [4096, 4708) as the last write. + EXPECT_EQ(kSmallSize, WriteSparseData(entry, /* offset = */ 4096, + buf_small.get(), kSmallSize)); + + // Query [2048, 4096). Should get [2048, 3072) + rv = entry->GetAvailableRange(2048, 2048, &start, cb.callback()); + EXPECT_EQ(1024, cb.GetResult(rv)); + EXPECT_EQ(2048, start); + + // Query 2K more after that: [3072, 5120). Should get [4096, 4708) + rv = entry->GetAvailableRange(3072, 2048, &start, cb.callback()); + EXPECT_EQ(612, cb.GetResult(rv)); + EXPECT_EQ(4096, start); + + // Also double-check that offsets within later children are correctly + // computed. + EXPECT_EQ(kSmallSize, WriteSparseData(entry, /* offset = */ 0x200400, + buf_small.get(), kSmallSize)); + rv = entry->GetAvailableRange(0x100000, 0x200000, &start, cb.callback()); + EXPECT_EQ(kSmallSize, cb.GetResult(rv)); + EXPECT_EQ(0x200400, start); + + entry->Close(); +} + // Tests that non-sequential writes that are not aligned with the minimum sparse // data granularity (1024 bytes) do in fact result in dropped data. TEST_F(DiskCacheEntryTest, SparseWriteDropped) { @@ -2716,6 +2801,92 @@ TEST_F(DiskCacheEntryTest, SimpleCacheErrorThenDoom) { entry->Doom(); // Should not crash. } +TEST_F(DiskCacheEntryTest, SimpleCacheCreateAfterDiskLayerDoom) { + // Code coverage for what happens when a queued create runs after failure + // was noticed at SimpleSynchronousEntry layer. + SetSimpleCacheMode(); + // Disable optimistic ops so we can block on CreateEntry and start + // WriteData off with an empty op queue. + SetCacheType(net::APP_CACHE); + InitCache(); + + const char key[] = "the key"; + const int kSize1 = 10; + scoped_refptr<net::IOBuffer> buffer1(new net::IOBuffer(kSize1)); + CacheTestFillBuffer(buffer1->data(), kSize1, false); + + disk_cache::Entry* entry = nullptr; + ASSERT_EQ(net::OK, CreateEntry(key, &entry)); + ASSERT_TRUE(entry != nullptr); + + // Make an empty _1 file, to cause a stream 2 write to fail. + base::FilePath entry_file1_path = cache_path_.AppendASCII( + disk_cache::simple_util::GetFilenameFromKeyAndFileIndex(key, 1)); + base::File entry_file1(entry_file1_path, + base::File::FLAG_WRITE | base::File::FLAG_CREATE); + ASSERT_TRUE(entry_file1.IsValid()); + + entry->WriteData(2, 0, buffer1.get(), kSize1, net::CompletionCallback(), + /* truncate= */ true); + entry->Close(); + + // At this point we have put WriteData & Close on the queue, and WriteData + // started, but we haven't given the event loop control so the failure + // hasn't been reported and handled here, so the entry is still active + // for the key. Queue up another create for same key, and run through the + // events. + disk_cache::Entry* entry2 = nullptr; + ASSERT_EQ(net::ERR_FAILED, CreateEntry(key, &entry2)); + ASSERT_TRUE(entry2 == nullptr); + + EXPECT_EQ(0, cache_->GetEntryCount()); + + // Should be able to create properly next time, though. + disk_cache::Entry* entry3 = nullptr; + ASSERT_EQ(net::OK, CreateEntry(key, &entry3)); + ASSERT_TRUE(entry3 != nullptr); + entry3->Close(); +} + +TEST_F(DiskCacheEntryTest, SimpleCacheQueuedOpenOnDoomedEntry) { + // This tests the following sequence of ops: + // A = Create(K); + // Close(A); + // B = Open(K); + // Doom(K); + // Close(B); + // + // ... where the execution of the Open sits on the queue all the way till + // Doom. Currently this fails the open. + + SetSimpleCacheMode(); + // Disable optimistic ops so we can block on CreateEntry and start + // WriteData off with an empty op queue. + SetCacheType(net::APP_CACHE); + InitCache(); + + const char key[] = "the key"; + + disk_cache::Entry* entry = nullptr; + ASSERT_EQ(net::OK, CreateEntry(key, &entry)); // event loop! + ASSERT_TRUE(entry != nullptr); + + entry->Close(); + + disk_cache::Entry* entry2 = nullptr; + // Done via cache_ -> no event loop. + net::TestCompletionCallback cb; + ASSERT_EQ(net::ERR_IO_PENDING, + cache_->OpenEntry(key, &entry2, cb.callback())); + + cache_->DoomEntry(key, base::Bind([](int) {})); + // Now event loop. + EXPECT_EQ(net::ERR_FAILED, cb.WaitForResult()); + ASSERT_TRUE(entry2 == nullptr); + + EXPECT_EQ(0, cache_->GetEntryCount()); +} + bool TruncatePath(const base::FilePath& file_path, int64_t length) { base::File file(file_path, base::File::FLAG_WRITE | base::File::FLAG_OPEN); if (!file.IsValid()) @@ -3645,7 +3816,15 @@ TEST_F(DiskCacheEntryTest, SimpleCacheOpenCreateRaceWithNoIndex) { EXPECT_THAT(cb1.GetResult(rv1), IsError(net::ERR_FAILED)); ASSERT_THAT(cb2.GetResult(rv2), IsOk()); + + // Try to get an alias for entry2. Open should succeed, and return the same + // pointer. + disk_cache::Entry* entry3 = nullptr; + ASSERT_EQ(net::OK, OpenEntry("key", &entry3)); + EXPECT_EQ(entry3, entry2); + entry2->Close(); + entry3->Close(); } // Checking one more scenario of overlapped reading of a bad entry. diff --git a/chromium/net/disk_cache/simple/simple_backend_impl.cc b/chromium/net/disk_cache/simple/simple_backend_impl.cc index e08ae98fb4b..52f76002e24 100644 --- a/chromium/net/disk_cache/simple/simple_backend_impl.cc +++ b/chromium/net/disk_cache/simple/simple_backend_impl.cc @@ -20,8 +20,8 @@ #include "base/location.h" #include "base/macros.h" #include "base/metrics/field_trial.h" +#include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" -#include "base/metrics/sparse_histogram.h" #include "base/single_thread_task_runner.h" #include "base/sys_info.h" #include "base/task_runner_util.h" @@ -70,7 +70,7 @@ scoped_refptr<base::SequencedTaskRunner> FallbackToInternalIfNull( bool g_fd_limit_histogram_has_been_populated = false; -void MaybeHistogramFdLimit(net::CacheType cache_type) { +void MaybeHistogramFdLimit() { if (g_fd_limit_histogram_has_been_populated) return; @@ -96,14 +96,13 @@ void MaybeHistogramFdLimit(net::CacheType cache_type) { } #endif - SIMPLE_CACHE_UMA(ENUMERATION, - "FileDescriptorLimitStatus", cache_type, - fd_limit_status, FD_LIMIT_STATUS_MAX); + UMA_HISTOGRAM_ENUMERATION("SimpleCache.FileDescriptorLimitStatus", + fd_limit_status, FD_LIMIT_STATUS_MAX); if (fd_limit_status == FD_LIMIT_STATUS_SUCCEEDED) { - SIMPLE_CACHE_UMA(SPARSE_SLOWLY, - "FileDescriptorLimitSoft", cache_type, soft_fd_limit); - SIMPLE_CACHE_UMA(SPARSE_SLOWLY, - "FileDescriptorLimitHard", cache_type, hard_fd_limit); + base::UmaHistogramSparse("SimpleCache.FileDescriptorLimitSoft", + soft_fd_limit); + base::UmaHistogramSparse("SimpleCache.FileDescriptorLimitHard", + hard_fd_limit); } g_fd_limit_histogram_has_been_populated = true; @@ -246,7 +245,7 @@ SimpleBackendImpl::SimpleBackendImpl( // backends, as default (if first call). if (orig_max_size_ < 0) orig_max_size_ = 0; - MaybeHistogramFdLimit(cache_type_); + MaybeHistogramFdLimit(); } SimpleBackendImpl::~SimpleBackendImpl() { @@ -291,19 +290,25 @@ int SimpleBackendImpl::GetMaxFileSize() const { void SimpleBackendImpl::OnDoomStart(uint64_t entry_hash) { DCHECK_EQ(0u, entries_pending_doom_.count(entry_hash)); entries_pending_doom_.insert( - std::make_pair(entry_hash, std::vector<Closure>())); + std::make_pair(entry_hash, std::vector<PostDoomWaiter>())); } void SimpleBackendImpl::OnDoomComplete(uint64_t entry_hash) { DCHECK_EQ(1u, entries_pending_doom_.count(entry_hash)); - std::unordered_map<uint64_t, std::vector<Closure>>::iterator it = + std::unordered_map<uint64_t, std::vector<PostDoomWaiter>>::iterator it = entries_pending_doom_.find(entry_hash); - std::vector<Closure> to_run_closures; - to_run_closures.swap(it->second); + std::vector<PostDoomWaiter> to_handle_waiters; + to_handle_waiters.swap(it->second); entries_pending_doom_.erase(it); - for (auto& closure : to_run_closures) - closure.Run(); + SIMPLE_CACHE_UMA(COUNTS_1000, "NumOpsBlockedByPendingDoom", cache_type_, + to_handle_waiters.size()); + + for (const PostDoomWaiter& post_doom : to_handle_waiters) { + SIMPLE_CACHE_UMA(TIMES, "QueueLatency.PendingDoom", cache_type_, + (base::TimeTicks::Now() - post_doom.time_queued)); + post_doom.run_post_doom.Run(); + } } void SimpleBackendImpl::DoomEntries(std::vector<uint64_t>* entry_hashes, @@ -381,14 +386,14 @@ int SimpleBackendImpl::OpenEntry(const std::string& key, const CompletionCallback& callback) { const uint64_t entry_hash = simple_util::GetEntryHashKey(key); - std::vector<Closure>* post_doom = nullptr; + std::vector<PostDoomWaiter>* post_doom = nullptr; scoped_refptr<SimpleEntryImpl> simple_entry = CreateOrFindActiveOrDoomedEntry(entry_hash, key, &post_doom); if (!simple_entry) { Callback<int(const net::CompletionCallback&)> operation = base::Bind(&SimpleBackendImpl::OpenEntry, base::Unretained(this), key, entry); - post_doom->push_back( + post_doom->emplace_back( base::Bind(&RunOperationAndCallback, operation, callback)); return net::ERR_IO_PENDING; } @@ -401,7 +406,7 @@ int SimpleBackendImpl::CreateEntry(const std::string& key, DCHECK_LT(0u, key.size()); const uint64_t entry_hash = simple_util::GetEntryHashKey(key); - std::vector<Closure>* post_doom = nullptr; + std::vector<PostDoomWaiter>* post_doom = nullptr; scoped_refptr<SimpleEntryImpl> simple_entry = CreateOrFindActiveOrDoomedEntry(entry_hash, key, &post_doom); @@ -421,13 +426,13 @@ int SimpleBackendImpl::CreateEntry(const std::string& key, std::pair<EntryMap::iterator, bool> insert_result = active_entries_.insert( EntryMap::value_type(entry_hash, simple_entry.get())); - post_doom->push_back(base::Bind( + post_doom->emplace_back(base::Bind( &SimpleEntryImpl::NotifyDoomBeforeCreateComplete, simple_entry)); DCHECK(insert_result.second); } else { Callback<int(const net::CompletionCallback&)> operation = base::Bind( &SimpleBackendImpl::CreateEntry, base::Unretained(this), key, entry); - post_doom->push_back( + post_doom->emplace_back( base::Bind(&RunOperationAndCallback, operation, callback)); return net::ERR_IO_PENDING; } @@ -440,7 +445,7 @@ int SimpleBackendImpl::DoomEntry(const std::string& key, const net::CompletionCallback& callback) { const uint64_t entry_hash = simple_util::GetEntryHashKey(key); - std::vector<Closure>* post_doom = nullptr; + std::vector<PostDoomWaiter>* post_doom = nullptr; scoped_refptr<SimpleEntryImpl> simple_entry = CreateOrFindActiveOrDoomedEntry(entry_hash, key, &post_doom); if (!simple_entry) { @@ -450,7 +455,7 @@ int SimpleBackendImpl::DoomEntry(const std::string& key, // create for our key, in which case we still have work to do. Callback<int(const net::CompletionCallback&)> operation = base::Bind(&SimpleBackendImpl::DoomEntry, base::Unretained(this), key); - post_doom->push_back( + post_doom->emplace_back( base::Bind(&RunOperationAndCallback, operation, callback)); return net::ERR_IO_PENDING; } @@ -603,6 +608,17 @@ void SimpleBackendImpl::SetEntryInMemoryData(const std::string& key, index_->SetEntryInMemoryData(entry_hash, data); } +SimpleBackendImpl::PostDoomWaiter::PostDoomWaiter() {} + +SimpleBackendImpl::PostDoomWaiter::PostDoomWaiter( + const base::Closure& to_run_post_doom) + : time_queued(base::TimeTicks::Now()), run_post_doom(to_run_post_doom) {} + +SimpleBackendImpl::PostDoomWaiter::PostDoomWaiter(const PostDoomWaiter& other) + : time_queued(other.time_queued), run_post_doom(other.run_post_doom) {} + +SimpleBackendImpl::PostDoomWaiter::~PostDoomWaiter() {} + void SimpleBackendImpl::InitializeIndex(const CompletionCallback& callback, const DiskStatResult& result) { if (result.net_error == net::OK) { @@ -682,11 +698,11 @@ scoped_refptr<SimpleEntryImpl> SimpleBackendImpl::CreateOrFindActiveOrDoomedEntry( const uint64_t entry_hash, const std::string& key, - std::vector<Closure>** post_doom) { + std::vector<PostDoomWaiter>** post_doom) { DCHECK_EQ(entry_hash, simple_util::GetEntryHashKey(key)); // If there is a doom pending, we would want to serialize after it. - std::unordered_map<uint64_t, std::vector<Closure>>::iterator doom_it = + std::unordered_map<uint64_t, std::vector<PostDoomWaiter>>::iterator doom_it = entries_pending_doom_.find(entry_hash); if (doom_it != entries_pending_doom_.end()) { *post_doom = &doom_it->second; @@ -720,14 +736,14 @@ SimpleBackendImpl::CreateOrFindActiveOrDoomedEntry( int SimpleBackendImpl::OpenEntryFromHash(uint64_t entry_hash, Entry** entry, const CompletionCallback& callback) { - std::unordered_map<uint64_t, std::vector<Closure>>::iterator it = + std::unordered_map<uint64_t, std::vector<PostDoomWaiter>>::iterator it = entries_pending_doom_.find(entry_hash); if (it != entries_pending_doom_.end()) { Callback<int(const net::CompletionCallback&)> operation = base::Bind(&SimpleBackendImpl::OpenEntryFromHash, base::Unretained(this), entry_hash, entry); - it->second.push_back(base::Bind(&RunOperationAndCallback, - operation, callback)); + it->second.emplace_back( + base::Bind(&RunOperationAndCallback, operation, callback)); return net::ERR_IO_PENDING; } @@ -750,14 +766,14 @@ int SimpleBackendImpl::DoomEntryFromHash(uint64_t entry_hash, Entry** entry = new Entry*(); std::unique_ptr<Entry*> scoped_entry(entry); - std::unordered_map<uint64_t, std::vector<Closure>>::iterator pending_it = - entries_pending_doom_.find(entry_hash); + std::unordered_map<uint64_t, std::vector<PostDoomWaiter>>::iterator + pending_it = entries_pending_doom_.find(entry_hash); if (pending_it != entries_pending_doom_.end()) { Callback<int(const net::CompletionCallback&)> operation = base::Bind(&SimpleBackendImpl::DoomEntryFromHash, base::Unretained(this), entry_hash); - pending_it->second.push_back(base::Bind(&RunOperationAndCallback, - operation, callback)); + pending_it->second.emplace_back( + base::Bind(&RunOperationAndCallback, operation, callback)); return net::ERR_IO_PENDING; } diff --git a/chromium/net/disk_cache/simple/simple_backend_impl.h b/chromium/net/disk_cache/simple/simple_backend_impl.h index 0da30fb6fca..b2ed0169823 100644 --- a/chromium/net/disk_cache/simple/simple_backend_impl.h +++ b/chromium/net/disk_cache/simple/simple_backend_impl.h @@ -150,6 +150,17 @@ class NET_EXPORT_PRIVATE SimpleBackendImpl : public Backend, int net_error; }; + struct PostDoomWaiter { + PostDoomWaiter(); + // Also initializes |time_queued|. + explicit PostDoomWaiter(const base::Closure& to_run_post_doom); + explicit PostDoomWaiter(const PostDoomWaiter& other); + ~PostDoomWaiter(); + + base::TimeTicks time_queued; + base::Closure run_post_doom; + }; + void InitializeIndex(const CompletionCallback& callback, const DiskStatResult& result); @@ -187,7 +198,7 @@ class NET_EXPORT_PRIVATE SimpleBackendImpl : public Backend, scoped_refptr<SimpleEntryImpl> CreateOrFindActiveOrDoomedEntry( uint64_t entry_hash, const std::string& key, - std::vector<base::Closure>** post_doom); + std::vector<PostDoomWaiter>** post_doom); // Given a hash, will try to open the corresponding Entry. If we have an Entry // corresponding to |hash| in the map of active entries, opens it. Otherwise, @@ -245,9 +256,9 @@ class NET_EXPORT_PRIVATE SimpleBackendImpl : public Backend, // The set of all entries which are currently being doomed. To avoid races, // these entries cannot have Doom/Create/Open operations run until the doom - // is complete. The base::Closure map target is used to store deferred - // operations to be run at the completion of the Doom. - std::unordered_map<uint64_t, std::vector<base::Closure>> + // is complete. The base::Closure |PostDoomWaiter::run_post_doom| field is + // used to store deferred operations to be run at the completion of the Doom. + std::unordered_map<uint64_t, std::vector<PostDoomWaiter>> entries_pending_doom_; net::NetLog* const net_log_; diff --git a/chromium/net/disk_cache/simple/simple_entry_impl.cc b/chromium/net/disk_cache/simple/simple_entry_impl.cc index 7123aac04ab..dda8a1e5e2d 100644 --- a/chromium/net/disk_cache/simple/simple_entry_impl.cc +++ b/chromium/net/disk_cache/simple/simple_entry_impl.cc @@ -216,7 +216,7 @@ SimpleEntryImpl::SimpleEntryImpl( "arrays should be the same size"); static_assert(arraysize(data_size_) == arraysize(crc_check_state_), "arrays should be the same size"); - MakeUninitialized(); + ResetEntry(); net_log_.BeginEvent(net::NetLogEventType::SIMPLE_CACHE_ENTRY, CreateNetLogSimpleEntryConstructionCallback(this)); } @@ -628,8 +628,10 @@ void SimpleEntryImpl::PostClientCallback(const CompletionCallback& callback, base::Bind(&InvokeCallbackIfBackendIsAlive, backend_, callback, result)); } -void SimpleEntryImpl::MakeUninitialized() { - state_ = STATE_UNINITIALIZED; +void SimpleEntryImpl::ResetEntry() { + // If we're doomed, we can't really do anything else with the entry, since + // we no longer own the name and are disconnected from the active entry table. + state_ = doomed_ ? STATE_FAILURE : STATE_UNINITIALIZED; std::memset(crc32s_end_offset_, 0, sizeof(crc32s_end_offset_)); std::memset(crc32s_, 0, sizeof(crc32s_)); std::memset(have_written_, 0, sizeof(have_written_)); @@ -1213,12 +1215,11 @@ void SimpleEntryImpl::DoomEntryInternal(const CompletionCallback& callback) { state_ = STATE_IO_PENDING; return; } - PostTaskAndReplyWithResult( - worker_pool_.get(), - FROM_HERE, - base::Bind(&SimpleSynchronousEntry::DoomEntry, path_, entry_hash_), - base::Bind( - &SimpleEntryImpl::DoomOperationComplete, this, callback, state_)); + PostTaskAndReplyWithResult(worker_pool_.get(), FROM_HERE, + base::Bind(&SimpleSynchronousEntry::DoomEntry, + path_, cache_type_, entry_hash_), + base::Bind(&SimpleEntryImpl::DoomOperationComplete, + this, callback, state_)); state_ = STATE_IO_PENDING; } @@ -1236,14 +1237,29 @@ void SimpleEntryImpl::CreationOperationComplete( "EntryCreationResult", cache_type_, in_results->result == net::OK); if (in_results->result != net::OK) { - if (in_results->result != net::ERR_FILE_EXISTS) - MarkAsDoomed(); + if (in_results->result != net::ERR_FILE_EXISTS) { + // Here we keep index up-to-date, but don't remove ourselves from active + // entries since we may have queued operations, and it would be + // problematic to run further Creates, Opens, or Dooms if we are not + // the active entry. We can only do this because OpenEntryInternal + // and CreateEntryInternal have to start from STATE_UNINITIALIZED, so + // nothing else is going on which may be confused. + if (backend_) + backend_->index()->Remove(entry_hash_); + } net_log_.AddEventWithNetErrorCode(end_event_type, net::ERR_FAILED); PostClientCallback(completion_callback, net::ERR_FAILED); - MakeUninitialized(); + ResetEntry(); return; } + + // Make sure to keep the index up-to-date. We likely already did this when + // CreateEntry was called, but it's possible we were sitting on a queue + // after an op that removed us. + if (backend_ && !doomed_) + backend_->index()->Insert(entry_hash_); + // If out_entry is NULL, it means we already called ReturnEntryToCaller from // the optimistic Create case. if (out_entry) @@ -1461,7 +1477,7 @@ void SimpleEntryImpl::CloseOperationComplete() { STATE_UNINITIALIZED == state_); net_log_.AddEvent(net::NetLogEventType::SIMPLE_CACHE_ENTRY_CLOSE_END); AdjustOpenEntryCountBy(cache_type_, -1); - MakeUninitialized(); + ResetEntry(); RunNextOperationIfNeeded(); } diff --git a/chromium/net/disk_cache/simple/simple_entry_impl.h b/chromium/net/disk_cache/simple/simple_entry_impl.h index e2fddd5b74f..1a7027dab61 100644 --- a/chromium/net/disk_cache/simple/simple_entry_impl.h +++ b/chromium/net/disk_cache/simple/simple_entry_impl.h @@ -142,8 +142,8 @@ class NET_EXPORT_PRIVATE SimpleEntryImpl : public Entry, enum State { // The state immediately after construction, but before |synchronous_entry_| - // has been assigned. This is the state at construction, and is the only - // legal state to destruct an entry in. + // has been assigned. This is the state at construction, and is one of the + // two states (along with failure) one can destruct an entry in. STATE_UNINITIALIZED, // This entry is available for regular IO. @@ -175,8 +175,11 @@ class NET_EXPORT_PRIVATE SimpleEntryImpl : public Entry, // not expect). void PostClientCallback(const CompletionCallback& callback, int result); - // Sets entry to STATE_UNINITIALIZED. - void MakeUninitialized(); + // Clears entry state enough to prepare it for re-use. This will generally + // put it back into STATE_UNINITIALIZED, except if the entry is doomed and + // therefore disconnected from ownership of corresponding filename, in which + // case it will be put into STATE_FAILURE. + void ResetEntry(); // Return this entry to a user of the API in |out_entry|. Increments the user // count. diff --git a/chromium/net/disk_cache/simple/simple_histogram_macros.h b/chromium/net/disk_cache/simple/simple_histogram_macros.h index edccfc079ac..fa302c31662 100644 --- a/chromium/net/disk_cache/simple/simple_histogram_macros.h +++ b/chromium/net/disk_cache/simple/simple_histogram_macros.h @@ -6,7 +6,6 @@ #define NET_DISK_CACHE_SIMPLE_SIMPLE_HISTOGRAM_MACROS_H_ #include "base/metrics/histogram_macros.h" -#include "base/metrics/sparse_histogram.h" #include "net/base/cache_type.h" // This file contains macros used to report histograms. The main issue is that diff --git a/chromium/net/disk_cache/simple/simple_synchronous_entry.cc b/chromium/net/disk_cache/simple/simple_synchronous_entry.cc index 74b07f632aa..f2b1e89bbce 100644 --- a/chromium/net/disk_cache/simple/simple_synchronous_entry.cc +++ b/chromium/net/disk_cache/simple/simple_synchronous_entry.cc @@ -292,8 +292,12 @@ void SimpleSynchronousEntry::CreateEntry( // static int SimpleSynchronousEntry::DoomEntry(const FilePath& path, + net::CacheType cache_type, uint64_t entry_hash) { + base::TimeTicks start = base::TimeTicks::Now(); const bool deleted_well = DeleteFilesForEntryHash(path, entry_hash); + SIMPLE_CACHE_UMA(TIMES, "DiskDoomLatency", cache_type, + base::TimeTicks::Now() - start); return deleted_well ? net::OK : net::ERR_FAILED; } @@ -1004,7 +1008,6 @@ bool SimpleSynchronousEntry::OpenFiles(SimpleEntryStat* out_entry_stat) { SimpleFileTracker::FileHandle file = file_tracker_->Acquire(this, SubFileForFileIndex(i)); bool success = file.IsOK() && file->GetInfo(&file_info); - base::Time file_last_modified; if (!success) { DLOG(WARNING) << "Could not get platform file info."; continue; @@ -1461,7 +1464,7 @@ int SimpleSynchronousEntry::GetEOFRecordData(base::File* file, void SimpleSynchronousEntry::Doom() const { DCHECK_EQ(0u, entry_file_key_.doom_generation); - DeleteFilesForEntryHash(path_, entry_file_key_.entry_hash); + DoomEntry(path_, cache_type_, entry_file_key_.entry_hash); } // static diff --git a/chromium/net/disk_cache/simple/simple_synchronous_entry.h b/chromium/net/disk_cache/simple/simple_synchronous_entry.h index 38779a7ef7e..b2bdde1b1c3 100644 --- a/chromium/net/disk_cache/simple/simple_synchronous_entry.h +++ b/chromium/net/disk_cache/simple/simple_synchronous_entry.h @@ -179,7 +179,9 @@ class SimpleSynchronousEntry { // Deletes an entry from the file system without affecting the state of the // corresponding instance, if any (allowing operations to continue to be // executed through that instance). Returns a net error code. - static int DoomEntry(const base::FilePath& path, uint64_t entry_hash); + static int DoomEntry(const base::FilePath& path, + net::CacheType cache_type, + uint64_t entry_hash); // Like |DoomEntry()| above, except that it truncates the entry files rather // than deleting them. Used when dooming entries after the backend has diff --git a/chromium/net/dns/address_sorter_posix_unittest.cc b/chromium/net/dns/address_sorter_posix_unittest.cc index 3871e7ee183..204fc87e64c 100644 --- a/chromium/net/dns/address_sorter_posix_unittest.cc +++ b/chromium/net/dns/address_sorter_posix_unittest.cc @@ -16,6 +16,7 @@ #include "net/socket/socket_performance_watcher.h" #include "net/socket/ssl_client_socket.h" #include "net/socket/stream_socket.h" +#include "net/traffic_annotation/network_traffic_annotation.h" #include "testing/gtest/include/gtest/gtest.h" namespace net { @@ -42,7 +43,10 @@ class TestUDPClientSocket : public DatagramClientSocket { NOTIMPLEMENTED(); return OK; } - int Write(IOBuffer*, int, const CompletionCallback&) override { + int Write(IOBuffer*, + int, + const CompletionCallback&, + const NetworkTrafficAnnotationTag& traffic_annotation) override { NOTIMPLEMENTED(); return OK; } @@ -74,6 +78,7 @@ class TestUDPClientSocket : public DatagramClientSocket { NetworkChangeNotifier::NetworkHandle GetBoundNetwork() const override { return NetworkChangeNotifier::kInvalidNetworkHandle; } + void ApplySocketTag(const SocketTag& tag) override {} int Connect(const IPEndPoint& remote) override { if (connected_) diff --git a/chromium/net/dns/dns_config_service.h b/chromium/net/dns/dns_config_service.h index 603fb4ccc0f..6ccd52f3f72 100644 --- a/chromium/net/dns/dns_config_service.h +++ b/chromium/net/dns/dns_config_service.h @@ -34,7 +34,7 @@ const int64_t kDnsDefaultTimeoutMs = 1000; struct NET_EXPORT_PRIVATE DnsConfig { DnsConfig(); DnsConfig(const DnsConfig& other); - virtual ~DnsConfig(); + ~DnsConfig(); bool Equals(const DnsConfig& d) const; diff --git a/chromium/net/dns/dns_config_service_posix.cc b/chromium/net/dns/dns_config_service_posix.cc index 60d6abe860a..f2e66331e33 100644 --- a/chromium/net/dns/dns_config_service_posix.cc +++ b/chromium/net/dns/dns_config_service_posix.cc @@ -11,7 +11,6 @@ #include "base/files/file.h" #include "base/files/file_path.h" #include "base/files/file_path_watcher.h" -#include "base/files/file_util.h" #include "base/lazy_instance.h" #include "base/location.h" #include "base/macros.h" @@ -20,11 +19,6 @@ #include "base/threading/scoped_blocking_call.h" #include "base/threading/thread_task_runner_handle.h" #include "base/time/time.h" -#include "base/trace_event/memory_allocator_dump.h" -#include "base/trace_event/memory_dump_manager.h" -#include "base/trace_event/memory_dump_provider.h" -#include "base/trace_event/process_memory_dump.h" -#include "base/trace_event/trace_event.h" #include "build/build_config.h" #include "net/base/ip_address.h" #include "net/base/ip_endpoint.h" @@ -272,8 +266,6 @@ class DnsConfigServicePosix::Watcher { } void OnConfigChangedDelayed(bool succeeded) { - TRACE_HEAP_PROFILER_API_SCOPED_TASK_EXECUTION scoped_heap_context( - "net/dns/configchanged"); service_->OnConfigChanged(succeeded); } @@ -305,8 +297,6 @@ class DnsConfigServicePosix::ConfigReader : public SerialWorker { } void DoWork() override { - TRACE_HEAP_PROFILER_API_SCOPED_TASK_EXECUTION scoped_heap_context( - "net/dns/configreader"); base::TimeTicks start_time = base::TimeTicks::Now(); ConfigParsePosixResult result = ReadDnsConfig(&dns_config_); if (dns_config_for_testing_) { @@ -333,8 +323,6 @@ class DnsConfigServicePosix::ConfigReader : public SerialWorker { void OnWorkFinished() override { DCHECK(!IsCancelled()); - TRACE_HEAP_PROFILER_API_SCOPED_TASK_EXECUTION scoped_heap_context( - "net/dns/configreaderfinished"); if (success_) { service_->OnConfigRead(dns_config_); } else { @@ -359,54 +347,27 @@ class DnsConfigServicePosix::ConfigReader : public SerialWorker { }; // A SerialWorker that reads the HOSTS file and runs Callback. -class DnsConfigServicePosix::HostsReader - : public SerialWorker, - public base::trace_event::MemoryDumpProvider { +class DnsConfigServicePosix::HostsReader : public SerialWorker { public: explicit HostsReader(DnsConfigServicePosix* service) : service_(service), file_path_hosts_(service->file_path_hosts_), - success_(false), - hosts_size_(0) { - base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider( - this, "DnsConfigServicePosix::HostsReader", - base::ThreadTaskRunnerHandle::Get()); - } - - bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args, - base::trace_event::ProcessMemoryDump* pmd) override { - base::trace_event::MemoryAllocatorDump* dump = - pmd->CreateAllocatorDump("net/dns_config_service_posix_hosts_reader"); - dump->AddScalar("hosts_entry_count", - base::trace_event::MemoryAllocatorDump::kUnitsObjects, - hosts_.size()); - dump->AddScalar("hosts_file_size", - base::trace_event::MemoryAllocatorDump::kUnitsBytes, - hosts_size_); - return true; - } + success_(false) {} private: - ~HostsReader() override { - base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider( - this); - } + ~HostsReader() override {} void DoWork() override { - TRACE_HEAP_PROFILER_API_SCOPED_TASK_EXECUTION scoped_heap_context( - "net/dns/hostsreader"); base::TimeTicks start_time = base::TimeTicks::Now(); base::ScopedBlockingCall scoped_blocking_call( base::BlockingType::MAY_BLOCK); - success_ = ParseHostsFile(file_path_hosts_, &hosts_, &hosts_size_); + success_ = ParseHostsFile(file_path_hosts_, &hosts_); UMA_HISTOGRAM_BOOLEAN("AsyncDNS.HostParseResult", success_); UMA_HISTOGRAM_TIMES("AsyncDNS.HostsParseDuration", base::TimeTicks::Now() - start_time); } void OnWorkFinished() override { - TRACE_HEAP_PROFILER_API_SCOPED_TASK_EXECUTION scoped_heap_context( - "net/dns/hostsreaderfinished"); if (success_) { service_->OnHostsRead(hosts_); } else { @@ -423,7 +384,6 @@ class DnsConfigServicePosix::HostsReader // Written in DoWork, read in OnWorkFinished, no locking necessary. DnsHosts hosts_; bool success_; - int64_t hosts_size_; DISALLOW_COPY_AND_ASSIGN(HostsReader); }; diff --git a/chromium/net/dns/dns_config_service_win.cc b/chromium/net/dns/dns_config_service_win.cc index 2152cb7dd54..e6c99443075 100644 --- a/chromium/net/dns/dns_config_service_win.cc +++ b/chromium/net/dns/dns_config_service_win.cc @@ -698,8 +698,7 @@ class DnsConfigServiceWin::HostsReader : public SerialWorker { base::ScopedBlockingCall scoped_blocking_call( base::BlockingType::MAY_BLOCK); HostsParseWinResult result = HOSTS_PARSE_WIN_UNREADABLE_HOSTS_FILE; - int64_t file_size; - if (ParseHostsFile(path_, &hosts_, &file_size)) + if (ParseHostsFile(path_, &hosts_)) result = AddLocalhostEntries(&hosts_); success_ = (result == HOSTS_PARSE_WIN_OK); UMA_HISTOGRAM_ENUMERATION("AsyncDNS.HostsParseWin", diff --git a/chromium/net/dns/dns_hosts.cc b/chromium/net/dns/dns_hosts.cc index b9f1a27e9a6..8de7607c605 100644 --- a/chromium/net/dns/dns_hosts.cc +++ b/chromium/net/dns/dns_hosts.cc @@ -188,9 +188,7 @@ void ParseHosts(const std::string& contents, DnsHosts* dns_hosts) { ParseHostsWithCommaMode(contents, dns_hosts, comma_mode); } -bool ParseHostsFile(const base::FilePath& path, - DnsHosts* dns_hosts, - int64_t* file_size) { +bool ParseHostsFile(const base::FilePath& path, DnsHosts* dns_hosts) { dns_hosts->clear(); // Missing file indicates empty HOSTS. if (!base::PathExists(path)) @@ -213,7 +211,6 @@ bool ParseHostsFile(const base::FilePath& path, return false; ParseHosts(contents, dns_hosts); - *file_size = size; return true; } diff --git a/chromium/net/dns/dns_hosts.h b/chromium/net/dns/dns_hosts.h index 79f7b63eeb7..423258ba2dc 100644 --- a/chromium/net/dns/dns_hosts.h +++ b/chromium/net/dns/dns_hosts.h @@ -68,8 +68,9 @@ void NET_EXPORT_PRIVATE ParseHosts(const std::string& contents, // As above but reads the file pointed to by |path|. bool NET_EXPORT_PRIVATE ParseHostsFile(const base::FilePath& path, - DnsHosts* dns_hosts, - int64_t* file_size); + DnsHosts* dns_hosts); + + } // namespace net diff --git a/chromium/net/dns/dns_transaction.cc b/chromium/net/dns/dns_transaction.cc index 47906fdedfb..07fa7487b2a 100644 --- a/chromium/net/dns/dns_transaction.cc +++ b/chromium/net/dns/dns_transaction.cc @@ -43,11 +43,39 @@ #include "net/log/net_log_with_source.h" #include "net/socket/datagram_client_socket.h" #include "net/socket/stream_socket.h" +#include "net/traffic_annotation/network_traffic_annotation.h" namespace net { namespace { +constexpr net::NetworkTrafficAnnotationTag kTrafficAnnotation = + net::DefineNetworkTrafficAnnotation("dns_transaction", R"( + semantics { + sender: "DNS Transaction" + description: + "DNS Transaction implements a stub DNS resolver as defined in RFC " + "1034." + trigger: + "Any network request that may require DNS resolution, including " + "navigations, connecting to a proxy server, detecting proxy " + "settings, getting proxy config, certificate checking, and more." + data: + "Domain name that needs resolution." + destination: OTHER + destination_other: + "The connection is made to a DNS server based on user's network " + "settings." + } + policy { + cookies_allowed: NO + setting: + "This feature cannot be disabled. Without DNS Transactions Chrome " + "cannot resolve host names." + policy_exception_justification: + "Essential for Chrome's navigation." + })"); + // Count labels in the fully-qualified name in DNS format. int CountLabels(const std::string& name) { size_t count = 0; @@ -71,6 +99,26 @@ std::unique_ptr<base::Value> NetLogStartCallback( return std::move(dict); } +// Values are used in UMA histograms. Do not change existing values. +enum MalformedResponseResult { + MALFORMED_OK = 0, + MALFORMED_MALFORMED = 1, + MALFORMED_FAILED = 2, + MALFORMED_MAX +}; + +void RecordMalformedResponseHistogram(int net_error) { + MalformedResponseResult error_type; + if (net_error == OK) + error_type = MALFORMED_OK; + else if (net_error == ERR_DNS_MALFORMED_RESPONSE) + error_type = MALFORMED_MALFORMED; + else + error_type = MALFORMED_FAILED; + UMA_HISTOGRAM_ENUMERATION("Net.DNS.ResultAfterMalformedResponse", error_type, + MALFORMED_MAX); +} + // ---------------------------------------------------------------------------- // A single asynchronous DNS exchange, which consists of sending out a @@ -205,10 +253,15 @@ class DnsUDPAttempt : public DnsAttempt { } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE); set_result(rv); - // If we received a malformed response, and are now waiting for another one, - // indicate to the transaction that the server might be misbehaving. - if (rv == ERR_IO_PENDING && received_malformed_response_) - return ERR_DNS_MALFORMED_RESPONSE; + if (received_malformed_response_) { + // If we received a malformed response, and are now waiting for another + // one, indicate to the transaction that the server might be misbehaving. + if (rv == ERR_IO_PENDING) + return ERR_DNS_MALFORMED_RESPONSE; + + // This is a new response after the original malformed one. + RecordMalformedResponseHistogram(rv); + } if (rv == OK) { DCHECK_EQ(STATE_NONE, next_state_); UMA_HISTOGRAM_LONG_TIMES_100("AsyncDNS.UDPAttemptSuccess", @@ -222,10 +275,10 @@ class DnsUDPAttempt : public DnsAttempt { int DoSendQuery() { next_state_ = STATE_SEND_QUERY_COMPLETE; - return socket()->Write(query_->io_buffer(), - query_->io_buffer()->size(), - base::Bind(&DnsUDPAttempt::OnIOComplete, - base::Unretained(this))); + return socket()->Write( + query_->io_buffer(), query_->io_buffer()->size(), + base::Bind(&DnsUDPAttempt::OnIOComplete, base::Unretained(this)), + kTrafficAnnotation); } int DoSendQueryComplete(int rv) { @@ -263,6 +316,7 @@ class DnsUDPAttempt : public DnsAttempt { // Our solution is to make another attempt, in case the query truly // failed, but keep this attempt alive, in case it was a false alarm. received_malformed_response_ = true; + RecordMalformedResponseHistogram(ERR_DNS_MALFORMED_RESPONSE); next_state_ = STATE_READ_RESPONSE; return OK; } @@ -417,9 +471,9 @@ class DnsTCPAttempt : public DnsAttempt { if (buffer_->BytesRemaining() > 0) { next_state_ = STATE_SEND_LENGTH; return socket_->Write( - buffer_.get(), - buffer_->BytesRemaining(), - base::Bind(&DnsTCPAttempt::OnIOComplete, base::Unretained(this))); + buffer_.get(), buffer_->BytesRemaining(), + base::Bind(&DnsTCPAttempt::OnIOComplete, base::Unretained(this)), + kTrafficAnnotation); } buffer_ = new DrainableIOBuffer(query_->io_buffer(), query_->io_buffer()->size()); @@ -436,9 +490,9 @@ class DnsTCPAttempt : public DnsAttempt { if (buffer_->BytesRemaining() > 0) { next_state_ = STATE_SEND_QUERY; return socket_->Write( - buffer_.get(), - buffer_->BytesRemaining(), - base::Bind(&DnsTCPAttempt::OnIOComplete, base::Unretained(this))); + buffer_.get(), buffer_->BytesRemaining(), + base::Bind(&DnsTCPAttempt::OnIOComplete, base::Unretained(this)), + kTrafficAnnotation); } buffer_ = new DrainableIOBuffer(length_buffer_.get(), length_buffer_->size()); diff --git a/chromium/net/dns/dns_transaction_unittest.cc b/chromium/net/dns/dns_transaction_unittest.cc index faf2faa8731..ce7bea01b3e 100644 --- a/chromium/net/dns/dns_transaction_unittest.cc +++ b/chromium/net/dns/dns_transaction_unittest.cc @@ -12,11 +12,11 @@ #include "base/bind.h" #include "base/containers/circular_deque.h" #include "base/macros.h" -#include "base/message_loop/message_loop.h" #include "base/rand_util.h" #include "base/run_loop.h" #include "base/sys_byteorder.h" -#include "base/test/test_timeouts.h" +#include "base/test/scoped_task_environment.h" +#include "base/time/time.h" #include "net/base/ip_address.h" #include "net/dns/dns_protocol.h" #include "net/dns/dns_query.h" @@ -27,6 +27,7 @@ #include "net/log/net_log_with_source.h" #include "net/socket/socket_test_util.h" #include "net/test/gtest_util.h" +#include "net/test/net_test_suite.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -38,6 +39,8 @@ class NetLog; namespace { +base::TimeDelta kTimeout = base::TimeDelta::FromSeconds(1); + std::string DomainFromDot(const base::StringPiece& dotted) { std::string out; EXPECT_TRUE(DNSDomainFromDot(dotted, &out)); @@ -239,7 +242,6 @@ class TransactionHelper { qtype_(qtype), expected_answer_count_(expected_answer_count), cancel_in_callback_(false), - quit_in_callback_(false), completed_(false) {} // Mark that the transaction shall be destroyed immediately upon callback. @@ -247,11 +249,6 @@ class TransactionHelper { cancel_in_callback_ = true; } - // Mark to call MessageLoop::QuitWhenIdle() upon callback. - void set_quit_in_callback() { - quit_in_callback_ = true; - } - void StartTransaction(DnsTransactionFactory* factory) { EXPECT_EQ(NULL, transaction_.get()); transaction_ = factory->CreateTransaction( @@ -281,10 +278,6 @@ class TransactionHelper { return; } - // Tell MessageLoop to quit now, in case any ASSERT_* fails. - if (quit_in_callback_) - base::RunLoop::QuitCurrentWhenIdleDeprecated(); - if (expected_answer_count_ >= 0) { ASSERT_THAT(rv, IsOk()); ASSERT_TRUE(response != NULL); @@ -314,11 +307,16 @@ class TransactionHelper { return has_completed(); } - // Use when some of the responses are timeouts. - bool RunUntilDone(DnsTransactionFactory* factory) { - set_quit_in_callback(); - StartTransaction(factory); - base::RunLoop().Run(); + bool FastForwardByTimeout(DnsSession* session, + unsigned server_index, + int attempt) { + NetTestSuite::GetScopedTaskEnvironment()->FastForwardBy( + session->NextTimeout(server_index, attempt)); + return has_completed(); + } + + bool FastForwardAll() { + NetTestSuite::GetScopedTaskEnvironment()->FastForwardUntilNoTasksRemain(); return has_completed(); } @@ -328,7 +326,6 @@ class TransactionHelper { std::unique_ptr<DnsTransaction> transaction_; int expected_answer_count_; bool cancel_in_callback_; - bool quit_in_callback_; bool completed_; }; @@ -449,12 +446,14 @@ class DnsTransactionTest : public testing::Test { } void SetUp() override { + NetTestSuite::SetScopedTaskEnvironment( + base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME); // By default set one server, ConfigureNumServers(1); // and no retransmissions, config_.attempts = 1; - // but long enough timeout for memory tests. - config_.timeout = TestTimeouts::action_timeout(); + // and an arbitrary timeout. + config_.timeout = kTimeout; ConfigureFactory(); } @@ -463,6 +462,7 @@ class DnsTransactionTest : public testing::Test { for (size_t i = 0; i < socket_data_.size(); ++i) { EXPECT_TRUE(socket_data_[i]->GetProvider()->AllWriteDataConsumed()) << i; } + NetTestSuite::ResetScopedTaskEnvironment(); } protected: @@ -594,7 +594,6 @@ TEST_F(DnsTransactionTest, CancelFromCallback) { TEST_F(DnsTransactionTest, MismatchedResponseSync) { config_.attempts = 2; - config_.timeout = TestTimeouts::tiny_timeout(); ConfigureFactory(); // Attempt receives mismatched response followed by valid response. @@ -607,12 +606,11 @@ TEST_F(DnsTransactionTest, MismatchedResponseSync) { AddSocketData(std::move(data)); TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount); - EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get())); + EXPECT_TRUE(helper0.Run(transaction_factory_.get())); } TEST_F(DnsTransactionTest, MismatchedResponseAsync) { config_.attempts = 2; - config_.timeout = TestTimeouts::tiny_timeout(); ConfigureFactory(); // First attempt receives mismatched response followed by valid response. @@ -627,11 +625,10 @@ TEST_F(DnsTransactionTest, MismatchedResponseAsync) { AddQueryAndTimeout(kT0HostName, kT0Qtype); TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount); - EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get())); + EXPECT_TRUE(helper0.Run(transaction_factory_.get())); } TEST_F(DnsTransactionTest, MismatchedResponseFail) { - config_.timeout = TestTimeouts::tiny_timeout(); ConfigureFactory(); // Attempt receives mismatched response but times out because only one attempt @@ -640,12 +637,12 @@ TEST_F(DnsTransactionTest, MismatchedResponseFail) { kT0ResponseDatagram, arraysize(kT0ResponseDatagram)); TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_DNS_TIMED_OUT); - EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get())); + EXPECT_FALSE(helper0.Run(transaction_factory_.get())); + EXPECT_TRUE(helper0.FastForwardByTimeout(session_.get(), 0, 0)); } TEST_F(DnsTransactionTest, MismatchedResponseNxdomain) { config_.attempts = 2; - config_.timeout = TestTimeouts::tiny_timeout(); ConfigureFactory(); // First attempt receives mismatched response followed by valid NXDOMAIN @@ -679,8 +676,6 @@ TEST_F(DnsTransactionTest, NoDomain) { TEST_F(DnsTransactionTest, Timeout) { config_.attempts = 3; - // Use short timeout to speed up the test. - config_.timeout = TestTimeouts::tiny_timeout(); ConfigureFactory(); AddQueryAndTimeout(kT0HostName, kT0Qtype); @@ -688,8 +683,12 @@ TEST_F(DnsTransactionTest, Timeout) { AddQueryAndTimeout(kT0HostName, kT0Qtype); TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_DNS_TIMED_OUT); - EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get())); - EXPECT_TRUE(base::MessageLoop::current()->IsIdleForTesting()); + + // Finish when the third attempt times out. + EXPECT_FALSE(helper0.Run(transaction_factory_.get())); + EXPECT_FALSE(helper0.FastForwardByTimeout(session_.get(), 0, 0)); + EXPECT_FALSE(helper0.FastForwardByTimeout(session_.get(), 0, 1)); + EXPECT_TRUE(helper0.FastForwardByTimeout(session_.get(), 0, 2)); } TEST_F(DnsTransactionTest, ServerFallbackAndRotate) { @@ -698,8 +697,6 @@ TEST_F(DnsTransactionTest, ServerFallbackAndRotate) { // The next request should start from the next server. config_.rotate = true; ConfigureNumServers(3); - // Use short timeout to speed up the test. - config_.timeout = TestTimeouts::tiny_timeout(); ConfigureFactory(); // Responses for first request. @@ -716,7 +713,8 @@ TEST_F(DnsTransactionTest, ServerFallbackAndRotate) { TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_NAME_NOT_RESOLVED); TransactionHelper helper1(kT1HostName, kT1Qtype, ERR_NAME_NOT_RESOLVED); - EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get())); + EXPECT_FALSE(helper0.Run(transaction_factory_.get())); + EXPECT_TRUE(helper0.FastForwardAll()); EXPECT_TRUE(helper1.Run(transaction_factory_.get())); unsigned kOrder[] = { @@ -982,7 +980,6 @@ TEST_F(DnsTransactionTest, TCPMalformed) { } TEST_F(DnsTransactionTest, TCPTimeout) { - config_.timeout = TestTimeouts::tiny_timeout(); ConfigureFactory(); AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC); @@ -990,7 +987,8 @@ TEST_F(DnsTransactionTest, TCPTimeout) { kT0Qtype, ASYNC, true)); TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_DNS_TIMED_OUT); - EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get())); + EXPECT_FALSE(helper0.Run(transaction_factory_.get())); + EXPECT_TRUE(helper0.FastForwardAll()); } TEST_F(DnsTransactionTest, TCPReadReturnsZeroAsync) { @@ -1057,7 +1055,6 @@ TEST_F(DnsTransactionTest, TCPConnectionClosedSynchronous) { TEST_F(DnsTransactionTest, MismatchedThenNxdomainThenTCP) { config_.attempts = 2; - config_.timeout = TestTimeouts::tiny_timeout(); ConfigureFactory(); std::unique_ptr<DnsSocketData> data( new DnsSocketData(0 /* id */, kT0HostName, kT0Qtype, SYNCHRONOUS, false)); @@ -1080,7 +1077,6 @@ TEST_F(DnsTransactionTest, MismatchedThenNxdomainThenTCP) { TEST_F(DnsTransactionTest, MismatchedThenOkThenTCP) { config_.attempts = 2; - config_.timeout = TestTimeouts::tiny_timeout(); ConfigureFactory(); std::unique_ptr<DnsSocketData> data( new DnsSocketData(0 /* id */, kT0HostName, kT0Qtype, SYNCHRONOUS, false)); @@ -1104,7 +1100,6 @@ TEST_F(DnsTransactionTest, MismatchedThenOkThenTCP) { } TEST_F(DnsTransactionTest, InvalidQuery) { - config_.timeout = TestTimeouts::tiny_timeout(); ConfigureFactory(); TransactionHelper helper0(".", dns_protocol::kTypeA, ERR_INVALID_ARGUMENT); diff --git a/chromium/net/dns/host_cache.cc b/chromium/net/dns/host_cache.cc index 70e66a7f83b..41cab7cdf6e 100644 --- a/chromium/net/dns/host_cache.cc +++ b/chromium/net/dns/host_cache.cc @@ -418,19 +418,12 @@ size_t HostCache::max_entries() const { // static std::unique_ptr<HostCache> HostCache::CreateDefaultCache() { -// Cache capacity is determined by the field trial. #if defined(ENABLE_BUILT_IN_DNS) const size_t kDefaultMaxEntries = 1000; #else const size_t kDefaultMaxEntries = 100; #endif - const size_t kSaneMaxEntries = 1 << 20; - size_t max_entries = 0; - base::StringToSizeT(base::FieldTrialList::FindFullName("HostCacheSize"), - &max_entries); - if ((max_entries == 0) || (max_entries > kSaneMaxEntries)) - max_entries = kDefaultMaxEntries; - return std::make_unique<HostCache>(max_entries); + return std::make_unique<HostCache>(kDefaultMaxEntries); } void HostCache::EvictOneEntry(base::TimeTicks now) { @@ -551,4 +544,31 @@ void HostCache::RecordEraseAll(EraseReason reason, base::TimeTicks now) { RecordErase(reason, now, it.second); } +bool HostCache::HasEntry(base::StringPiece hostname, + HostCache::Entry::Source* source_out, + HostCache::EntryStaleness* stale_out) { + net::HostCache::Key cache_key; + hostname.CopyToString(&cache_key.hostname); + + const HostCache::Entry* entry = + LookupStale(cache_key, base::TimeTicks::Now(), stale_out); + if (!entry) { + // Might not have found the cache entry because the address_family or + // host_resolver_flags in cache_key do not match those used for the + // original DNS lookup. Try another common combination of address_family + // and host_resolver_flags in an attempt to find a matching cache entry. + cache_key.address_family = net::ADDRESS_FAMILY_IPV4; + cache_key.host_resolver_flags = + net::HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6; + entry = LookupStale(cache_key, base::TimeTicks::Now(), stale_out); + if (!entry) + return false; + } + + if (source_out != nullptr) + *source_out = entry->source(); + + return true; +} + } // namespace net diff --git a/chromium/net/dns/host_cache.h b/chromium/net/dns/host_cache.h index e131de9733d..cb9c6eafbd2 100644 --- a/chromium/net/dns/host_cache.h +++ b/chromium/net/dns/host_cache.h @@ -180,6 +180,16 @@ class NET_EXPORT HostCache { base::TimeTicks now, base::TimeDelta ttl); + // Checks whether an entry exists for |hostname|. + // If so, returns true and writes the source (e.g. DNS, HOSTS file, etc.) to + // |source_out| and the staleness to |stale_out| (if they are not null). + // It tries using two common address_family and host_resolver_flag + // combinations when performing lookups in the cache; this means false + // negatives are possible, but unlikely. + bool HasEntry(base::StringPiece hostname, + HostCache::Entry::Source* source_out, + HostCache::EntryStaleness* stale_out); + // Marks all entries as stale on account of a network change. void OnNetworkChange(); diff --git a/chromium/net/dns/host_resolver.h b/chromium/net/dns/host_resolver.h index d11564698d2..87cf01d51e1 100644 --- a/chromium/net/dns/host_resolver.h +++ b/chromium/net/dns/host_resolver.h @@ -180,6 +180,14 @@ class NET_EXPORT HostResolver { AddressList* addresses, const NetLogWithSource& net_log) = 0; + // Like |ResolveFromCache()|, but can return a stale result if the + // implementation supports it. Fills in |*stale_info| if a response is + // returned to indicate how stale (or not) it is. + virtual int ResolveStaleFromCache(const RequestInfo& info, + AddressList* addresses, + HostCache::EntryStaleness* stale_info, + const NetLogWithSource& source_net_log) = 0; + // Enable or disable the built-in asynchronous DnsClient. virtual void SetDnsClientEnabled(bool enabled); @@ -187,6 +195,17 @@ class NET_EXPORT HostResolver { // Used primarily to clear the cache and for getting debug information. virtual HostCache* GetHostCache(); + // Checks whether this HostResolver has cached a resolution for the given + // hostname (or IP address literal). If so, returns true and writes the source + // of the resolution (e.g. DNS, HOSTS file, etc.) to |source_out| and the + // staleness of the resolution to |stale_out| (if they are not null). + // It tries using two common address_family and host_resolver_flag + // combinations when checking the cache; this means false negatives are + // possible, but unlikely. + virtual bool HasCached(base::StringPiece hostname, + HostCache::Entry::Source* source_out, + HostCache::EntryStaleness* stale_out) const = 0; + // Returns the current DNS configuration |this| is using, as a Value, or // nullptr if it's configured to always use the system host resolver. virtual std::unique_ptr<base::Value> GetDnsConfigAsValue() const; diff --git a/chromium/net/dns/host_resolver_impl.cc b/chromium/net/dns/host_resolver_impl.cc index b9854252a1b..032ba4c69a6 100644 --- a/chromium/net/dns/host_resolver_impl.cc +++ b/chromium/net/dns/host_resolver_impl.cc @@ -36,8 +36,8 @@ #include "base/macros.h" #include "base/memory/ptr_util.h" #include "base/metrics/field_trial.h" +#include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" -#include "base/metrics/sparse_histogram.h" #include "base/single_thread_task_runner.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" @@ -766,8 +766,6 @@ class HostResolverImpl::ProcTask // mutate. void DoLookup(const base::TimeTicks& start_time, const uint32_t attempt_number) { - TRACE_HEAP_PROFILER_API_SCOPED_TASK_EXECUTION scoped_heap_context( - "net/dns/proctask"); AddressList results; int os_error = 0; int error = params_.resolver_proc->Resolve(key_.hostname, @@ -1524,8 +1522,8 @@ class HostResolverImpl::Job : public PrioritizedDispatcher::Job, } else { UmaAsyncDnsResolveStatus(RESOLVE_STATUS_PROC_SUCCESS); } - UMA_HISTOGRAM_SPARSE_SLOWLY("Net.DNS.DnsTask.Errors", - std::abs(dns_task_error_)); + base::UmaHistogramSparse("Net.DNS.DnsTask.Errors", + std::abs(dns_task_error_)); resolver_->OnDnsTaskResolve(dns_task_error_); } else { UMA_HISTOGRAM_LONG_TIMES_100("AsyncDNS.FallbackFail", duration); @@ -1711,11 +1709,9 @@ class HostResolverImpl::Job : public PrioritizedDispatcher::Job, if (category == RESOLVE_FAIL || category == RESOLVE_ABORT) { if (duration < base::TimeDelta::FromMilliseconds(10)) - UMA_HISTOGRAM_SPARSE_SLOWLY("Net.DNS.ResolveError.Fast", - std::abs(error)); + base::UmaHistogramSparse("Net.DNS.ResolveError.Fast", std::abs(error)); else - UMA_HISTOGRAM_SPARSE_SLOWLY("Net.DNS.ResolveError.Slow", - std::abs(error)); + base::UmaHistogramSparse("Net.DNS.ResolveError.Slow", std::abs(error)); } } @@ -2113,6 +2109,15 @@ HostCache* HostResolverImpl::GetHostCache() { return cache_.get(); } +bool HostResolverImpl::HasCached(base::StringPiece hostname, + HostCache::Entry::Source* source_out, + HostCache::EntryStaleness* stale_out) const { + if (!cache_) + return false; + + return cache_->HasEntry(hostname, source_out, stale_out); +} + std::unique_ptr<base::Value> HostResolverImpl::GetDnsConfigAsValue() const { // Check if async DNS is disabled. if (!dns_client_.get()) @@ -2574,8 +2579,8 @@ void HostResolverImpl::OnDnsTaskResolve(int net_error) { AbortDnsTasks(); UMA_HISTOGRAM_BOOLEAN("AsyncDNS.DnsClientEnabled", false); - UMA_HISTOGRAM_SPARSE_SLOWLY("AsyncDNS.DnsClientDisabledReason", - std::abs(net_error)); + base::UmaHistogramSparse("AsyncDNS.DnsClientDisabledReason", + std::abs(net_error)); } void HostResolverImpl::SetDnsClient(std::unique_ptr<DnsClient> dns_client) { diff --git a/chromium/net/dns/host_resolver_impl.h b/chromium/net/dns/host_resolver_impl.h index 5de489cabd2..58300e55ca8 100644 --- a/chromium/net/dns/host_resolver_impl.h +++ b/chromium/net/dns/host_resolver_impl.h @@ -141,17 +141,19 @@ class NET_EXPORT HostResolverImpl int ResolveFromCache(const RequestInfo& info, AddressList* addresses, const NetLogWithSource& source_net_log) override; + int ResolveStaleFromCache(const RequestInfo& info, + AddressList* addresses, + HostCache::EntryStaleness* stale_info, + const NetLogWithSource& source_net_log) override; void SetDnsClientEnabled(bool enabled) override; + HostCache* GetHostCache() override; + bool HasCached(base::StringPiece hostname, + HostCache::Entry::Source* source_out, + HostCache::EntryStaleness* stale_out) const override; + std::unique_ptr<base::Value> GetDnsConfigAsValue() const override; - // Like |ResolveFromCache()|, but can return a stale result if the - // implementation supports it. Fills in |*stale_info| if a response is - // returned to indicate how stale (or not) it is. - int ResolveStaleFromCache(const RequestInfo& info, - AddressList* addresses, - HostCache::EntryStaleness* stale_info, - const NetLogWithSource& source_net_log); // Returns the number of host cache entries that were restored, or 0 if there // is no cache. size_t LastRestoredCacheSize() const; diff --git a/chromium/net/dns/host_resolver_mojo.cc b/chromium/net/dns/host_resolver_mojo.cc index 4015d0af41b..b76cbf04a3f 100644 --- a/chromium/net/dns/host_resolver_mojo.cc +++ b/chromium/net/dns/host_resolver_mojo.cc @@ -107,10 +107,28 @@ int HostResolverMojo::ResolveFromCache(const RequestInfo& info, return ResolveFromCacheInternal(info, CacheKeyForRequest(info), addresses); } +int HostResolverMojo::ResolveStaleFromCache( + const RequestInfo& info, + AddressList* addresses, + HostCache::EntryStaleness* stale_info, + const NetLogWithSource& net_log) { + NOTREACHED(); + return ERR_UNEXPECTED; +} + HostCache* HostResolverMojo::GetHostCache() { return host_cache_.get(); } +bool HostResolverMojo::HasCached(base::StringPiece hostname, + HostCache::Entry::Source* source_out, + HostCache::EntryStaleness* stale_out) const { + if (!host_cache_) + return false; + + return host_cache_->HasEntry(hostname, source_out, stale_out); +} + int HostResolverMojo::ResolveFromCacheInternal(const RequestInfo& info, const HostCache::Key& key, AddressList* addresses) { diff --git a/chromium/net/dns/host_resolver_mojo.h b/chromium/net/dns/host_resolver_mojo.h index 602660adb8e..80920d2a979 100644 --- a/chromium/net/dns/host_resolver_mojo.h +++ b/chromium/net/dns/host_resolver_mojo.h @@ -43,7 +43,14 @@ class HostResolverMojo : public HostResolver { int ResolveFromCache(const RequestInfo& info, AddressList* addresses, const NetLogWithSource& source_net_log) override; + int ResolveStaleFromCache(const RequestInfo& info, + AddressList* addresses, + HostCache::EntryStaleness* stale_info, + const NetLogWithSource& source_net_log) override; HostCache* GetHostCache() override; + bool HasCached(base::StringPiece hostname, + HostCache::Entry::Source* source_out, + HostCache::EntryStaleness* stale_out) const override; private: class Job; diff --git a/chromium/net/dns/mapped_host_resolver.cc b/chromium/net/dns/mapped_host_resolver.cc index 4508df25828..2a409faaaae 100644 --- a/chromium/net/dns/mapped_host_resolver.cc +++ b/chromium/net/dns/mapped_host_resolver.cc @@ -43,6 +43,19 @@ int MappedHostResolver::ResolveFromCache(const RequestInfo& original_info, return impl_->ResolveFromCache(info, addresses, net_log); } +int MappedHostResolver::ResolveStaleFromCache( + const RequestInfo& original_info, + AddressList* addresses, + HostCache::EntryStaleness* stale_info, + const NetLogWithSource& net_log) { + RequestInfo info = original_info; + int rv = ApplyRules(&info); + if (rv != OK) + return rv; + + return impl_->ResolveStaleFromCache(info, addresses, stale_info, net_log); +} + void MappedHostResolver::SetDnsClientEnabled(bool enabled) { impl_->SetDnsClientEnabled(enabled); } @@ -51,6 +64,12 @@ HostCache* MappedHostResolver::GetHostCache() { return impl_->GetHostCache(); } +bool MappedHostResolver::HasCached(base::StringPiece hostname, + HostCache::Entry::Source* source_out, + HostCache::EntryStaleness* stale_out) const { + return impl_->HasCached(hostname, source_out, stale_out); +} + std::unique_ptr<base::Value> MappedHostResolver::GetDnsConfigAsValue() const { return impl_->GetDnsConfigAsValue(); } diff --git a/chromium/net/dns/mapped_host_resolver.h b/chromium/net/dns/mapped_host_resolver.h index 5ae459cbae5..559aa3e5ad8 100644 --- a/chromium/net/dns/mapped_host_resolver.h +++ b/chromium/net/dns/mapped_host_resolver.h @@ -54,8 +54,17 @@ class NET_EXPORT MappedHostResolver : public HostResolver { int ResolveFromCache(const RequestInfo& info, AddressList* addresses, const NetLogWithSource& net_log) override; + int ResolveStaleFromCache(const RequestInfo& info, + AddressList* addresses, + HostCache::EntryStaleness* stale_info, + const NetLogWithSource& source_net_log) override; void SetDnsClientEnabled(bool enabled) override; + HostCache* GetHostCache() override; + bool HasCached(base::StringPiece hostname, + HostCache::Entry::Source* source_out, + HostCache::EntryStaleness* stale_out) const override; + std::unique_ptr<base::Value> GetDnsConfigAsValue() const override; void SetNoIPv6OnWifi(bool no_ipv6_on_wifi) override; bool GetNoIPv6OnWifi() override; diff --git a/chromium/net/dns/mdns_client_impl.cc b/chromium/net/dns/mdns_client_impl.cc index a4902c47b62..04e2bb5ecd4 100644 --- a/chromium/net/dns/mdns_client_impl.cc +++ b/chromium/net/dns/mdns_client_impl.cc @@ -417,19 +417,18 @@ void MDnsClientImpl::Core::QueryCache( } MDnsClientImpl::MDnsClientImpl() - : clock_(new base::DefaultClock), - cleanup_timer_(new base::Timer(false, false)) { -} + : clock_(base::DefaultClock::GetInstance()), + cleanup_timer_(new base::Timer(false, false)) {} -MDnsClientImpl::MDnsClientImpl(std::unique_ptr<base::Clock> clock, +MDnsClientImpl::MDnsClientImpl(base::Clock* clock, std::unique_ptr<base::Timer> timer) - : clock_(std::move(clock)), cleanup_timer_(std::move(timer)) {} + : clock_(clock), cleanup_timer_(std::move(timer)) {} MDnsClientImpl::~MDnsClientImpl() = default; bool MDnsClientImpl::StartListening(MDnsSocketFactory* socket_factory) { DCHECK(!core_.get()); - core_.reset(new Core(clock_.get(), cleanup_timer_.get())); + core_.reset(new Core(clock_, cleanup_timer_.get())); if (!core_->Init(socket_factory)) { core_.reset(); return false; @@ -450,7 +449,7 @@ std::unique_ptr<MDnsListener> MDnsClientImpl::CreateListener( const std::string& name, MDnsListener::Delegate* delegate) { return std::unique_ptr<MDnsListener>( - new MDnsListenerImpl(rrtype, name, clock_.get(), delegate, this)); + new MDnsListenerImpl(rrtype, name, clock_, delegate, this)); } std::unique_ptr<MDnsTransaction> MDnsClientImpl::CreateTransaction( diff --git a/chromium/net/dns/mdns_client_impl.h b/chromium/net/dns/mdns_client_impl.h index ad478981b12..c35aaa8bd5d 100644 --- a/chromium/net/dns/mdns_client_impl.h +++ b/chromium/net/dns/mdns_client_impl.h @@ -209,11 +209,11 @@ class NET_EXPORT_PRIVATE MDnsClientImpl : public MDnsClient { FRIEND_TEST_ALL_PREFIXES(MDnsTest, CacheCleanupWithShortTTL); // Test constructor, takes a mock clock and mock timer. - MDnsClientImpl(std::unique_ptr<base::Clock> clock, + MDnsClientImpl(base::Clock* clock, std::unique_ptr<base::Timer> cleanup_timer); std::unique_ptr<Core> core_; - std::unique_ptr<base::Clock> clock_; + base::Clock* clock_; std::unique_ptr<base::Timer> cleanup_timer_; DISALLOW_COPY_AND_ASSIGN(MDnsClientImpl); diff --git a/chromium/net/dns/mdns_client_unittest.cc b/chromium/net/dns/mdns_client_unittest.cc index 76eb1064a07..a8dff273d7c 100644 --- a/chromium/net/dns/mdns_client_unittest.cc +++ b/chromium/net/dns/mdns_client_unittest.cc @@ -361,9 +361,9 @@ class PtrRecordCopyContainer { int ttl_; }; -class MockClock : public base::DefaultClock { +class MockClock : public base::Clock { public: - MockClock() : base::DefaultClock() {} + MockClock() = default; virtual ~MockClock() = default; MOCK_METHOD0(Now, base::Time()); @@ -557,15 +557,14 @@ TEST_F(MDnsTest, CacheCleanupWithShortTTL) { // Use a nonzero starting time as a base. base::Time start_time = base::Time() + base::TimeDelta::FromSeconds(1); - MockClock* clock = new MockClock; + MockClock clock; MockTimer* timer = new MockTimer; - test_client_.reset( - new MDnsClientImpl(base::WrapUnique(clock), base::WrapUnique(timer))); + test_client_.reset(new MDnsClientImpl(&clock, base::WrapUnique(timer))); test_client_->StartListening(&socket_factory_); EXPECT_CALL(*timer, StartObserver(_, _, _)).Times(1); - EXPECT_CALL(*clock, Now()) + EXPECT_CALL(clock, Now()) .Times(3) .WillRepeatedly(Return(start_time)) .RetiresOnSaturation(); @@ -600,10 +599,10 @@ TEST_F(MDnsTest, CacheCleanupWithShortTTL) { // Set the clock to 2.0s, which should clean up the 'privet' record, but not // the printer. The mock clock will change Now() mid-execution from 2s to 4s. // Note: expectations are FILO-ordered -- t+2 seconds is returned, then t+4. - EXPECT_CALL(*clock, Now()) + EXPECT_CALL(clock, Now()) .WillOnce(Return(start_time + base::TimeDelta::FromSeconds(4))) .RetiresOnSaturation(); - EXPECT_CALL(*clock, Now()) + EXPECT_CALL(clock, Now()) .WillOnce(Return(start_time + base::TimeDelta::FromSeconds(2))) .RetiresOnSaturation(); diff --git a/chromium/net/dns/mock_host_resolver.cc b/chromium/net/dns/mock_host_resolver.cc index 2bb24418fae..c146a1fc596 100644 --- a/chromium/net/dns/mock_host_resolver.cc +++ b/chromium/net/dns/mock_host_resolver.cc @@ -149,6 +149,18 @@ int MockHostResolverBase::ResolveFromCache(const RequestInfo& info, return rv; } +int MockHostResolverBase::ResolveStaleFromCache( + const RequestInfo& info, + AddressList* addresses, + HostCache::EntryStaleness* stale_info, + const NetLogWithSource& net_log) { + num_resolve_from_cache_++; + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + next_request_id_++; + int rv = ResolveFromIPLiteralOrCache(info, addresses); + return rv; +} + void MockHostResolverBase::DetachRequest(size_t id) { RequestMap::iterator it = requests_.find(id); CHECK(it != requests_.end()); @@ -159,6 +171,16 @@ HostCache* MockHostResolverBase::GetHostCache() { return cache_.get(); } +bool MockHostResolverBase::HasCached( + base::StringPiece hostname, + HostCache::Entry::Source* source_out, + HostCache::EntryStaleness* stale_out) const { + if (!cache_) + return false; + + return cache_->HasEntry(hostname, source_out, stale_out); +} + void MockHostResolverBase::ResolveAllPending() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK(ondemand_mode_); @@ -184,8 +206,10 @@ MockHostResolverBase::MockHostResolverBase(bool use_caching) } } -int MockHostResolverBase::ResolveFromIPLiteralOrCache(const RequestInfo& info, - AddressList* addresses) { +int MockHostResolverBase::ResolveFromIPLiteralOrCache( + const RequestInfo& info, + AddressList* addresses, + HostCache::EntryStaleness* stale_info) { IPAddress ip_address; if (ip_address.AssignFromIPLiteral(info.hostname())) { // This matches the behavior HostResolverImpl. @@ -204,7 +228,11 @@ int MockHostResolverBase::ResolveFromIPLiteralOrCache(const RequestInfo& info, HostCache::Key key(info.hostname(), info.address_family(), info.host_resolver_flags()); - const HostCache::Entry* entry = cache_->Lookup(key, base::TimeTicks::Now()); + const HostCache::Entry* entry; + if (stale_info) + entry = cache_->LookupStale(key, base::TimeTicks::Now(), stale_info); + else + entry = cache_->Lookup(key, base::TimeTicks::Now()); if (entry) { rv = entry->error(); if (rv == OK) @@ -501,6 +529,21 @@ int HangingHostResolver::ResolveFromCache(const RequestInfo& info, return ERR_DNS_CACHE_MISS; } +int HangingHostResolver::ResolveStaleFromCache( + const RequestInfo& info, + AddressList* addresses, + HostCache::EntryStaleness* stale_info, + const NetLogWithSource& net_log) { + return ERR_DNS_CACHE_MISS; +} + +bool HangingHostResolver::HasCached( + base::StringPiece hostname, + HostCache::Entry::Source* source_out, + HostCache::EntryStaleness* stale_out) const { + return false; +} + //----------------------------------------------------------------------------- ScopedDefaultHostResolverProc::ScopedDefaultHostResolverProc() = default; diff --git a/chromium/net/dns/mock_host_resolver.h b/chromium/net/dns/mock_host_resolver.h index 3576a38e0e5..ce43c8c2b86 100644 --- a/chromium/net/dns/mock_host_resolver.h +++ b/chromium/net/dns/mock_host_resolver.h @@ -91,7 +91,14 @@ class MockHostResolverBase int ResolveFromCache(const RequestInfo& info, AddressList* addresses, const NetLogWithSource& net_log) override; + int ResolveStaleFromCache(const RequestInfo& info, + AddressList* addresses, + HostCache::EntryStaleness* stale_info, + const NetLogWithSource& source_net_log) override; HostCache* GetHostCache() override; + bool HasCached(base::StringPiece hostname, + HostCache::Entry::Source* source_out, + HostCache::EntryStaleness* stale_out) const override; // Detach cancelled request. void DetachRequest(size_t id); @@ -129,8 +136,10 @@ class MockHostResolverBase // Resolve as IP or from |cache_| return cached error or // DNS_CACHE_MISS if failed. - int ResolveFromIPLiteralOrCache(const RequestInfo& info, - AddressList* addresses); + int ResolveFromIPLiteralOrCache( + const RequestInfo& info, + AddressList* addresses, + HostCache::EntryStaleness* stale_info = nullptr); // Resolve via |proc_|. int ResolveProc(const RequestInfo& info, AddressList* addresses); // Resolve request stored in |requests_|. Pass rv to callback. @@ -286,6 +295,13 @@ class HangingHostResolver : public HostResolver { int ResolveFromCache(const RequestInfo& info, AddressList* addresses, const NetLogWithSource& net_log) override; + int ResolveStaleFromCache(const RequestInfo& info, + AddressList* addresses, + HostCache::EntryStaleness* stale_info, + const NetLogWithSource& source_net_log) override; + bool HasCached(base::StringPiece hostname, + HostCache::Entry::Source* source_out, + HostCache::EntryStaleness* stale_out) const override; }; // This class sets the default HostResolverProc for a particular scope. The diff --git a/chromium/net/dns/mojo_host_struct_traits.cc b/chromium/net/dns/mojo_host_struct_traits.cc index 44b7efc441d..4ba742da3df 100644 --- a/chromium/net/dns/mojo_host_struct_traits.cc +++ b/chromium/net/dns/mojo_host_struct_traits.cc @@ -8,47 +8,12 @@ #include "base/memory/ptr_util.h" #include "net/base/address_list.h" +#include "net/interfaces/address_family_traits.h" #include "net/interfaces/ip_endpoint_struct_traits.h" namespace mojo { // static -bool EnumTraits<net::interfaces::AddressFamily, net::AddressFamily>::FromMojom( - net::interfaces::AddressFamily address_family, - net::AddressFamily* out) { - using net::interfaces::AddressFamily; - switch (address_family) { - case AddressFamily::UNSPECIFIED: - *out = net::ADDRESS_FAMILY_UNSPECIFIED; - return true; - case AddressFamily::IPV4: - *out = net::ADDRESS_FAMILY_IPV4; - return true; - case AddressFamily::IPV6: - *out = net::ADDRESS_FAMILY_IPV6; - return true; - } - return false; -} - -// static -net::interfaces::AddressFamily -EnumTraits<net::interfaces::AddressFamily, net::AddressFamily>::ToMojom( - net::AddressFamily address_family) { - using net::interfaces::AddressFamily; - switch (address_family) { - case net::ADDRESS_FAMILY_UNSPECIFIED: - return AddressFamily::UNSPECIFIED; - case net::ADDRESS_FAMILY_IPV4: - return AddressFamily::IPV4; - case net::ADDRESS_FAMILY_IPV6: - return AddressFamily::IPV6; - } - NOTREACHED(); - return AddressFamily::UNSPECIFIED; -} - -// static bool StructTraits<net::interfaces::HostResolverRequestInfoDataView, std::unique_ptr<net::HostResolver::RequestInfo>>:: Read(net::interfaces::HostResolverRequestInfoDataView data, diff --git a/chromium/net/dns/mojo_host_struct_traits.h b/chromium/net/dns/mojo_host_struct_traits.h index 29a5f6c7d6f..f39b844c41b 100644 --- a/chromium/net/dns/mojo_host_struct_traits.h +++ b/chromium/net/dns/mojo_host_struct_traits.h @@ -9,19 +9,12 @@ #include "mojo/public/cpp/bindings/enum_traits.h" #include "mojo/public/cpp/bindings/struct_traits.h" #include "net/dns/host_resolver.h" +#include "net/interfaces/address_family.mojom.h" #include "net/interfaces/host_resolver_service.mojom.h" namespace mojo { template <> -struct EnumTraits<net::interfaces::AddressFamily, net::AddressFamily> { - static net::interfaces::AddressFamily ToMojom( - net::AddressFamily address_family); - static bool FromMojom(net::interfaces::AddressFamily address_family, - net::AddressFamily* out); -}; - -template <> struct StructTraits<net::interfaces::HostResolverRequestInfoDataView, std::unique_ptr<net::HostResolver::RequestInfo>> { static base::StringPiece host( diff --git a/chromium/net/dns/serial_worker_unittest.cc b/chromium/net/dns/serial_worker_unittest.cc index d52c0fd4d67..fddb0cee717 100644 --- a/chromium/net/dns/serial_worker_unittest.cc +++ b/chromium/net/dns/serial_worker_unittest.cc @@ -70,7 +70,7 @@ class SerialWorkerTest : public testing::Test { protected: void BreakCallback(const std::string& breakpoint) { breakpoint_ = breakpoint; - base::RunLoop::QuitCurrentDeprecated(); + run_loop_->Quit(); } void BreakNow(const std::string& b) { @@ -80,7 +80,11 @@ class SerialWorkerTest : public testing::Test { } void RunUntilBreak(const std::string& b) { - base::RunLoop().Run(); + base::RunLoop run_loop; + ASSERT_FALSE(run_loop_); + run_loop_ = &run_loop; + run_loop_->Run(); + run_loop_ = nullptr; ASSERT_EQ(breakpoint_, b); } @@ -140,6 +144,9 @@ class SerialWorkerTest : public testing::Test { scoped_refptr<TestSerialWorker> worker_; std::string breakpoint_; + base::RunLoop* run_loop_ = nullptr; + + DISALLOW_COPY_AND_ASSIGN(SerialWorkerTest); }; TEST_F(SerialWorkerTest, ExecuteAndSerializeReads) { diff --git a/chromium/net/ftp/ftp_network_transaction.cc b/chromium/net/ftp/ftp_network_transaction.cc index 566bbe4f5ad..e8ec85ab330 100644 --- a/chromium/net/ftp/ftp_network_transaction.cc +++ b/chromium/net/ftp/ftp_network_transaction.cc @@ -254,11 +254,14 @@ int FtpNetworkTransaction::Stop(int error) { return OK; } -int FtpNetworkTransaction::Start(const FtpRequestInfo* request_info, - const CompletionCallback& callback, - const NetLogWithSource& net_log) { +int FtpNetworkTransaction::Start( + const FtpRequestInfo* request_info, + const CompletionCallback& callback, + const NetLogWithSource& net_log, + const NetworkTrafficAnnotationTag& traffic_annotation) { net_log_ = net_log; request_ = request_info; + traffic_annotation_ = MutableNetworkTrafficAnnotationTag(traffic_annotation); ctrl_response_buffer_ = std::make_unique<FtpCtrlResponseBuffer>(net_log_); @@ -736,8 +739,9 @@ int FtpNetworkTransaction::DoCtrlReadComplete(int result) { int FtpNetworkTransaction::DoCtrlWrite() { next_state_ = STATE_CTRL_WRITE_COMPLETE; - return ctrl_socket_->Write( - write_buf_.get(), write_buf_->BytesRemaining(), io_callback_); + return ctrl_socket_->Write(write_buf_.get(), write_buf_->BytesRemaining(), + io_callback_, + NetworkTrafficAnnotationTag(traffic_annotation_)); } int FtpNetworkTransaction::DoCtrlWriteComplete(int result) { diff --git a/chromium/net/ftp/ftp_network_transaction.h b/chromium/net/ftp/ftp_network_transaction.h index 9731ae7ad8a..a6769ce4bba 100644 --- a/chromium/net/ftp/ftp_network_transaction.h +++ b/chromium/net/ftp/ftp_network_transaction.h @@ -22,6 +22,7 @@ #include "net/ftp/ftp_response_info.h" #include "net/ftp/ftp_transaction.h" #include "net/log/net_log_with_source.h" +#include "net/traffic_annotation/network_traffic_annotation.h" namespace net { @@ -39,7 +40,8 @@ class NET_EXPORT_PRIVATE FtpNetworkTransaction : public FtpTransaction { // FtpTransaction methods: int Start(const FtpRequestInfo* request_info, const CompletionCallback& callback, - const NetLogWithSource& net_log) override; + const NetLogWithSource& net_log, + const NetworkTrafficAnnotationTag& traffic_annotation) override; int RestartWithAuth(const AuthCredentials& credentials, const CompletionCallback& callback) override; int Read(IOBuffer* buf, @@ -204,6 +206,7 @@ class NET_EXPORT_PRIVATE FtpNetworkTransaction : public FtpTransaction { NetLogWithSource net_log_; const FtpRequestInfo* request_; + MutableNetworkTrafficAnnotationTag traffic_annotation_; FtpResponseInfo response_; // Cancels the outstanding request on destruction. diff --git a/chromium/net/ftp/ftp_network_transaction_unittest.cc b/chromium/net/ftp/ftp_network_transaction_unittest.cc index 9ca3f5e040a..b8bc320b737 100644 --- a/chromium/net/ftp/ftp_network_transaction_unittest.cc +++ b/chromium/net/ftp/ftp_network_transaction_unittest.cc @@ -16,6 +16,7 @@ #include "net/ftp/ftp_request_info.h" #include "net/socket/socket_test_util.h" #include "net/test/gtest_util.h" +#include "net/traffic_annotation/network_traffic_annotation_test_helper.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/platform_test.h" @@ -819,9 +820,10 @@ class FtpNetworkTransactionTest mock_socket_factory_->AddSocketDataProvider(data_socket.get()); FtpRequestInfo request_info = GetRequestInfo(request); EXPECT_EQ(LOAD_STATE_IDLE, transaction_->GetLoadState()); - ASSERT_EQ(ERR_IO_PENDING, - transaction_->Start(&request_info, callback_.callback(), - NetLogWithSource())); + ASSERT_EQ( + ERR_IO_PENDING, + transaction_->Start(&request_info, callback_.callback(), + NetLogWithSource(), TRAFFIC_ANNOTATION_FOR_TESTS)); EXPECT_NE(LOAD_STATE_IDLE, transaction_->GetLoadState()); ASSERT_EQ(expected_result, callback_.WaitForResult()); if (expected_result == OK) { @@ -870,9 +872,10 @@ TEST_P(FtpNetworkTransactionTest, FailedLookup) { host_resolver_->set_rules(rules.get()); EXPECT_EQ(LOAD_STATE_IDLE, transaction_->GetLoadState()); - ASSERT_EQ(ERR_IO_PENDING, - transaction_->Start(&request_info, callback_.callback(), - NetLogWithSource())); + ASSERT_EQ( + ERR_IO_PENDING, + transaction_->Start(&request_info, callback_.callback(), + NetLogWithSource(), TRAFFIC_ANNOTATION_FOR_TESTS)); ASSERT_THAT(callback_.WaitForResult(), IsError(ERR_NAME_NOT_RESOLVED)); EXPECT_EQ(LOAD_STATE_IDLE, transaction_->GetLoadState()); } @@ -1141,9 +1144,10 @@ TEST_P(FtpNetworkTransactionTest, DownloadTransactionEvilPasvUnsafeHost) { FtpRequestInfo request_info = GetRequestInfo("ftp://host/file"); // Start the transaction. - ASSERT_EQ(ERR_IO_PENDING, - transaction_->Start(&request_info, callback_.callback(), - NetLogWithSource())); + ASSERT_EQ( + ERR_IO_PENDING, + transaction_->Start(&request_info, callback_.callback(), + NetLogWithSource(), TRAFFIC_ANNOTATION_FOR_TESTS)); ASSERT_THAT(callback_.WaitForResult(), IsOk()); // The transaction fires the callback when we can start reading data. That @@ -1336,9 +1340,10 @@ TEST_P(FtpNetworkTransactionTest, EvilRestartUser) { FtpRequestInfo request_info = GetRequestInfo("ftp://host/file"); - ASSERT_EQ(ERR_IO_PENDING, - transaction_->Start(&request_info, callback_.callback(), - NetLogWithSource())); + ASSERT_EQ( + ERR_IO_PENDING, + transaction_->Start(&request_info, callback_.callback(), + NetLogWithSource(), TRAFFIC_ANNOTATION_FOR_TESTS)); ASSERT_THAT(callback_.WaitForResult(), IsError(ERR_FTP_FAILED)); MockRead ctrl_reads[] = { @@ -1369,9 +1374,10 @@ TEST_P(FtpNetworkTransactionTest, EvilRestartPassword) { FtpRequestInfo request_info = GetRequestInfo("ftp://host/file"); - ASSERT_EQ(ERR_IO_PENDING, - transaction_->Start(&request_info, callback_.callback(), - NetLogWithSource())); + ASSERT_EQ( + ERR_IO_PENDING, + transaction_->Start(&request_info, callback_.callback(), + NetLogWithSource(), TRAFFIC_ANNOTATION_FOR_TESTS)); ASSERT_THAT(callback_.WaitForResult(), IsError(ERR_FTP_FAILED)); MockRead ctrl_reads[] = { diff --git a/chromium/net/ftp/ftp_transaction.h b/chromium/net/ftp/ftp_transaction.h index 1da3aeff205..f037b99b456 100644 --- a/chromium/net/ftp/ftp_transaction.h +++ b/chromium/net/ftp/ftp_transaction.h @@ -11,6 +11,7 @@ #include "net/base/io_buffer.h" #include "net/base/load_states.h" #include "net/base/net_export.h" +#include "net/traffic_annotation/network_traffic_annotation.h" namespace net { @@ -42,7 +43,8 @@ class NET_EXPORT_PRIVATE FtpTransaction { // Profiling information for the request is saved to |net_log| if non-NULL. virtual int Start(const FtpRequestInfo* request_info, const CompletionCallback& callback, - const NetLogWithSource& net_log) = 0; + const NetLogWithSource& net_log, + const NetworkTrafficAnnotationTag& traffic_annotation) = 0; // Restarts the FTP transaction with authentication credentials. virtual int RestartWithAuth(const AuthCredentials& credentials, diff --git a/chromium/net/http/OWNERS b/chromium/net/http/OWNERS index b15901669dd..b33c90cb2d0 100644 --- a/chromium/net/http/OWNERS +++ b/chromium/net/http/OWNERS @@ -1,2 +1,3 @@ +per-file http_cache_*=shivanisha@chromium.org per-file transport_security_state_static.*=elawrence@chromium.org -per-file transport_security_state_static.*=palmer@chromium.org
\ No newline at end of file +per-file transport_security_state_static.*=palmer@chromium.org diff --git a/chromium/net/http/http_basic_state.cc b/chromium/net/http/http_basic_state.cc index 0690de6b52f..cee4a407afa 100644 --- a/chromium/net/http/http_basic_state.cc +++ b/chromium/net/http/http_basic_state.cc @@ -23,12 +23,17 @@ HttpBasicState::HttpBasicState(std::unique_ptr<ClientSocketHandle> connection, : read_buf_(new GrowableIOBuffer()), connection_(std::move(connection)), using_proxy_(using_proxy), + can_send_early_(false), http_09_on_non_default_ports_enabled_( - http_09_on_non_default_ports_enabled) {} + http_09_on_non_default_ports_enabled) { + CHECK(connection_) << "ClientSocketHandle passed to HttpBasicState must " + "not be NULL. See crbug.com/790776"; +} HttpBasicState::~HttpBasicState() = default; int HttpBasicState::Initialize(const HttpRequestInfo* request_info, + bool can_send_early, RequestPriority priority, const NetLogWithSource& net_log, const CompletionCallback& callback) { @@ -39,6 +44,7 @@ int HttpBasicState::Initialize(const HttpRequestInfo* request_info, connection_.get(), request_info, read_buf_.get(), net_log)); parser_->set_http_09_on_non_default_ports_enabled( http_09_on_non_default_ports_enabled_); + can_send_early_ = can_send_early; return OK; } diff --git a/chromium/net/http/http_basic_state.h b/chromium/net/http/http_basic_state.h index c89beab1274..5ce7945e3fa 100644 --- a/chromium/net/http/http_basic_state.h +++ b/chromium/net/http/http_basic_state.h @@ -35,6 +35,7 @@ class NET_EXPORT_PRIVATE HttpBasicState { // Initialize() must be called before using any of the other methods. int Initialize(const HttpRequestInfo* request_info, + bool can_send_early, RequestPriority priority, const NetLogWithSource& net_log, const CompletionCallback& callback); @@ -43,6 +44,7 @@ class NET_EXPORT_PRIVATE HttpBasicState { bool using_proxy() const { return using_proxy_; } + bool can_send_early() const { return can_send_early_; } bool http_09_on_non_default_ports_enabled() const { return http_09_on_non_default_ports_enabled_; } @@ -69,6 +71,8 @@ class NET_EXPORT_PRIVATE HttpBasicState { const bool using_proxy_; + bool can_send_early_; + const bool http_09_on_non_default_ports_enabled_; GURL url_; diff --git a/chromium/net/http/http_basic_state_unittest.cc b/chromium/net/http/http_basic_state_unittest.cc index c0d337ab3e1..0d6621cc41c 100644 --- a/chromium/net/http/http_basic_state_unittest.cc +++ b/chromium/net/http/http_basic_state_unittest.cc @@ -46,7 +46,7 @@ TEST(HttpBasicStateTest, ReleaseConnectionWorks) { TEST(HttpBasicStateTest, InitializeWorks) { HttpBasicState state(std::make_unique<ClientSocketHandle>(), false, false); const HttpRequestInfo request_info; - EXPECT_EQ(OK, state.Initialize(&request_info, LOW, NetLogWithSource(), + EXPECT_EQ(OK, state.Initialize(&request_info, false, LOW, NetLogWithSource(), CompletionCallback())); EXPECT_TRUE(state.parser()); } @@ -54,7 +54,7 @@ TEST(HttpBasicStateTest, InitializeWorks) { TEST(HttpBasicStateTest, DeleteParser) { HttpBasicState state(std::make_unique<ClientSocketHandle>(), false, false); const HttpRequestInfo request_info; - state.Initialize(&request_info, LOW, NetLogWithSource(), + state.Initialize(&request_info, false, LOW, NetLogWithSource(), CompletionCallback()); EXPECT_TRUE(state.parser()); state.DeleteParser(); @@ -68,7 +68,7 @@ TEST(HttpBasicStateTest, GenerateRequestLineNoProxy) { HttpRequestInfo request_info; request_info.url = GURL("http://www.example.com/path?foo=bar#hoge"); request_info.method = "PUT"; - state.Initialize(&request_info, LOW, NetLogWithSource(), + state.Initialize(&request_info, false, LOW, NetLogWithSource(), CompletionCallback()); EXPECT_EQ("PUT /path?foo=bar HTTP/1.1\r\n", state.GenerateRequestLine()); } @@ -80,7 +80,7 @@ TEST(HttpBasicStateTest, GenerateRequestLineWithProxy) { HttpRequestInfo request_info; request_info.url = GURL("http://www.example.com/path?foo=bar#hoge"); request_info.method = "PUT"; - state.Initialize(&request_info, LOW, NetLogWithSource(), + state.Initialize(&request_info, false, LOW, NetLogWithSource(), CompletionCallback()); EXPECT_EQ("PUT http://www.example.com/path?foo=bar HTTP/1.1\r\n", state.GenerateRequestLine()); diff --git a/chromium/net/http/http_basic_stream.cc b/chromium/net/http/http_basic_stream.cc index 2fc6c4e500e..aada0abbb97 100644 --- a/chromium/net/http/http_basic_stream.cc +++ b/chromium/net/http/http_basic_stream.cc @@ -11,6 +11,7 @@ #include "net/http/http_response_body_drainer.h" #include "net/http/http_stream_parser.h" #include "net/socket/client_socket_handle.h" +#include "net/traffic_annotation/network_traffic_annotation.h" namespace net { @@ -24,10 +25,11 @@ HttpBasicStream::HttpBasicStream(std::unique_ptr<ClientSocketHandle> connection, HttpBasicStream::~HttpBasicStream() = default; int HttpBasicStream::InitializeStream(const HttpRequestInfo* request_info, + bool can_send_early, RequestPriority priority, const NetLogWithSource& net_log, const CompletionCallback& callback) { - state_.Initialize(request_info, priority, net_log, callback); + state_.Initialize(request_info, can_send_early, priority, net_log, callback); return OK; } @@ -42,7 +44,9 @@ int HttpBasicStream::SendRequest(const HttpRequestHeaders& headers, raw_headers.Add(it.name(), it.value()); request_headers_callback_.Run(std::move(raw_headers)); } - return parser()->SendRequest(state_.GenerateRequestLine(), headers, response, + // TODO(crbug.com/656607): Add propoer annotation. + return parser()->SendRequest(state_.GenerateRequestLine(), headers, + NO_TRAFFIC_ANNOTATION_BUG_656607, response, callback); } diff --git a/chromium/net/http/http_basic_stream.h b/chromium/net/http/http_basic_stream.h index d1f54930a3d..15b74c60235 100644 --- a/chromium/net/http/http_basic_stream.h +++ b/chromium/net/http/http_basic_stream.h @@ -40,6 +40,7 @@ class NET_EXPORT_PRIVATE HttpBasicStream : public HttpStream { // HttpStream methods: int InitializeStream(const HttpRequestInfo* request_info, + bool can_send_early, RequestPriority priority, const NetLogWithSource& net_log, const CompletionCallback& callback) override; diff --git a/chromium/net/http/http_cache.cc b/chromium/net/http/http_cache.cc index 0653b25b36a..f731201556c 100644 --- a/chromium/net/http/http_cache.cc +++ b/chromium/net/http/http_cache.cc @@ -321,7 +321,7 @@ HttpCache::HttpCache(std::unique_ptr<HttpTransactionFactory> network_layer, fail_conditionalization_for_test_(false), mode_(NORMAL), network_layer_(std::move(network_layer)), - clock_(new base::DefaultClock()), + clock_(base::DefaultClock::GetInstance()), weak_factory_(this) { HttpNetworkSession* session = network_layer_->GetSession(); // Session may be NULL in unittests. @@ -839,8 +839,10 @@ int HttpCache::DoneWithResponseHeaders(ActiveEntry* entry, // through done_headers_queue for performance benefit. (Also, in case of // writer transaction, the consumer sometimes depend on synchronous behaviour // e.g. while computing raw headers size. (crbug.com/711766)) - if ((transaction->mode() & Transaction::WRITE) && !entry->writers) { - AddTransactionToWriters(entry, transaction); + if ((transaction->mode() & Transaction::WRITE) && !entry->writers && + entry->readers.empty()) { + AddTransactionToWriters(entry, transaction, + CanTransactionJoinExistingWriters(transaction)); ProcessQueuedTransactions(entry); return OK; } @@ -1058,19 +1060,30 @@ void HttpCache::ProcessAddToEntryQueue(ActiveEntry* entry) { transaction->io_callback().Run(OK); } -bool HttpCache::CanTransactionJoinExistingWriters(Transaction* transaction) { - return (transaction->method() == "GET" && !transaction->partial()); +HttpCache::ParallelWritingPattern HttpCache::CanTransactionJoinExistingWriters( + Transaction* transaction) { + if (transaction->method() != "GET") + return PARALLEL_WRITING_NOT_JOIN_METHOD_NOT_GET; + if (transaction->partial()) + return PARALLEL_WRITING_NOT_JOIN_RANGE; + if (transaction->mode() == Transaction::READ) + return PARALLEL_WRITING_NOT_JOIN_READ_ONLY; + return PARALLEL_WRITING_JOIN; } void HttpCache::ProcessDoneHeadersQueue(ActiveEntry* entry) { - DCHECK(!entry->writers || entry->writers->CanAddWriters()); + ParallelWritingPattern writers_pattern; + DCHECK(!entry->writers || entry->writers->CanAddWriters(&writers_pattern)); DCHECK(!entry->done_headers_queue.empty()); Transaction* transaction = entry->done_headers_queue.front(); + ParallelWritingPattern parallel_writing_pattern = + CanTransactionJoinExistingWriters(transaction); if (IsWritingInProgress(entry)) { - if (!CanTransactionJoinExistingWriters(transaction) || - transaction->mode() == Transaction::READ) { + transaction->MaybeSetParallelWritingPatternForMetrics( + parallel_writing_pattern); + if (parallel_writing_pattern != PARALLEL_WRITING_JOIN) { // TODO(shivanisha): Returning from here instead of checking the next // transaction in the queue because the FIFO order is maintained // throughout, until it becomes a reader or writer. May be at this point @@ -1079,11 +1092,14 @@ void HttpCache::ProcessDoneHeadersQueue(ActiveEntry* entry) { // transactions. return; } - AddTransactionToWriters(entry, transaction); + AddTransactionToWriters(entry, transaction, parallel_writing_pattern); } else { // no writing in progress if (transaction->mode() & Transaction::WRITE) { if (transaction->partial()) { - AddTransactionToWriters(entry, transaction); + if (entry->readers.empty()) + AddTransactionToWriters(entry, transaction, parallel_writing_pattern); + else + return; } else { // Add the transaction to readers since the response body should have // already been written. (If it was the first writer about to start @@ -1093,10 +1109,14 @@ void HttpCache::ProcessDoneHeadersQueue(ActiveEntry* entry) { transaction->WriteModeTransactionAboutToBecomeReader(); auto return_val = entry->readers.insert(transaction); DCHECK(return_val.second); + transaction->MaybeSetParallelWritingPatternForMetrics( + PARALLEL_WRITING_NONE_CACHE_READ); } } else { // mode READ auto return_val = entry->readers.insert(transaction); DCHECK(return_val.second); + transaction->MaybeSetParallelWritingPatternForMetrics( + PARALLEL_WRITING_NONE_CACHE_READ); } } @@ -1108,21 +1128,26 @@ void HttpCache::ProcessDoneHeadersQueue(ActiveEntry* entry) { transaction->io_callback().Run(OK); } -void HttpCache::AddTransactionToWriters(ActiveEntry* entry, - Transaction* transaction) { +void HttpCache::AddTransactionToWriters( + ActiveEntry* entry, + Transaction* transaction, + ParallelWritingPattern parallel_writing_pattern) { if (!entry->writers) { entry->writers = std::make_unique<Writers>(this, entry); + transaction->MaybeSetParallelWritingPatternForMetrics( + PARALLEL_WRITING_CREATE); + } else { + ParallelWritingPattern writers_pattern; + DCHECK(entry->writers->CanAddWriters(&writers_pattern)); + DCHECK_EQ(PARALLEL_WRITING_JOIN, writers_pattern); } - DCHECK(entry->writers->CanAddWriters()); - Writers::TransactionInfo info(transaction->partial(), transaction->is_truncated(), *(transaction->GetResponseInfo())); - entry->writers->AddTransaction( - transaction, - !CanTransactionJoinExistingWriters(transaction) /* is_exclusive */, - transaction->priority(), info); + + entry->writers->AddTransaction(transaction, parallel_writing_pattern, + transaction->priority(), info); } bool HttpCache::CanTransactionWriteResponseHeaders(ActiveEntry* entry, @@ -1255,10 +1280,19 @@ void HttpCache::OnProcessQueuedTransactions(ActiveEntry* entry) { // If another transaction is writing the response, let validated transactions // wait till the response is complete. If the response is not yet started, the // done_headers_queue transaction should start writing it. - if ((!entry->writers || entry->writers->CanAddWriters()) && - !entry->done_headers_queue.empty()) { - ProcessDoneHeadersQueue(entry); - return; + if (!entry->done_headers_queue.empty()) { + ParallelWritingPattern reason = PARALLEL_WRITING_NONE; + if (entry->writers && !entry->writers->CanAddWriters(&reason)) { + if (reason != PARALLEL_WRITING_NONE) { + for (auto* done_headers_transaction : entry->done_headers_queue) { + done_headers_transaction->MaybeSetParallelWritingPatternForMetrics( + reason); + } + } + } else { + ProcessDoneHeadersQueue(entry); + return; + } } if (!entry->add_to_entry_queue.empty()) diff --git a/chromium/net/http/http_cache.h b/chromium/net/http/http_cache.h index 975812e6506..0dabe1b3c81 100644 --- a/chromium/net/http/http_cache.h +++ b/chromium/net/http/http_cache.h @@ -109,6 +109,36 @@ class NET_EXPORT HttpCache : public HttpTransactionFactory { int max_bytes_; }; + // Whether a transaction can join parallel writing or not is a function of the + // transaction as well as the current writers (if present). This enum + // captures that decision as well as when a Writers object is first created. + // This is also used to log metrics so should be consistent with the values in + // enums.xml and should only be appended to. + enum ParallelWritingPattern { + // Used as the default value till the transaction is in initial headers + // phase. + PARALLEL_WRITING_NONE, + // The transaction creates a writers object. This is only logged for + // transactions that did not fail to join existing writers earlier. + PARALLEL_WRITING_CREATE, + // The transaction joins existing writers. + PARALLEL_WRITING_JOIN, + // The transaction cannot join existing writers since either itself or + // existing writers instance is serving a range request. + PARALLEL_WRITING_NOT_JOIN_RANGE, + // The transaction cannot join existing writers since either itself or + // existing writers instance is serving a non GET request. + PARALLEL_WRITING_NOT_JOIN_METHOD_NOT_GET, + // The transaction cannot join existing writers since it does not have cache + // write privileges. + PARALLEL_WRITING_NOT_JOIN_READ_ONLY, + // Writers does not exist and the transaction does not need to create one + // since it is going to read from the cache. + PARALLEL_WRITING_NONE_CACHE_READ, + // On adding a value here, make sure to add in enums.xml as well. + PARALLEL_WRITING_MAX + }; + // The number of minutes after a resource is prefetched that it can be used // again without validation. static const int kPrefetchReuseMins = 5; @@ -170,10 +200,8 @@ class NET_EXPORT HttpCache : public HttpTransactionFactory { Mode mode() { return mode_; } // Get/Set the cache's clock. These are public only for testing. - void SetClockForTesting(std::unique_ptr<base::Clock> clock) { - clock_ = std::move(clock); - } - base::Clock* clock() const { return clock_.get(); } + void SetClockForTesting(base::Clock* clock) { clock_ = clock; } + base::Clock* clock() const { return clock_; } // Close currently active sockets so that fresh page loads will not use any // recycled connections. For sockets currently in use, they may not close @@ -477,10 +505,11 @@ class NET_EXPORT HttpCache : public HttpTransactionFactory { // already. void ProcessAddToEntryQueue(ActiveEntry* entry); - // Returns true if the transaction can join other transactions for writing to - // the cache simultaneously. It is only supported for GET requests and - // non-range requests. - bool CanTransactionJoinExistingWriters(Transaction* transaction); + // Returns if the transaction can join other transactions for writing to + // the cache simultaneously. It is only supported for non-Read only, + // GET requests which are not range requests. + ParallelWritingPattern CanTransactionJoinExistingWriters( + Transaction* transaction); // Invoked when a transaction that has already completed the response headers // phase can resume reading/writing the response body. It will invoke the IO @@ -489,7 +518,9 @@ class NET_EXPORT HttpCache : public HttpTransactionFactory { void ProcessDoneHeadersQueue(ActiveEntry* entry); // Adds a transaction to writers. - void AddTransactionToWriters(ActiveEntry* entry, Transaction* transaction); + void AddTransactionToWriters(ActiveEntry* entry, + Transaction* transaction, + ParallelWritingPattern parallel_writing_pattern); // Returns true if this transaction can write headers to the entry. bool CanTransactionWriteResponseHeaders(ActiveEntry* entry, @@ -566,7 +597,7 @@ class NET_EXPORT HttpCache : public HttpTransactionFactory { std::unique_ptr<PlaybackCacheMap> playback_cache_map_; // A clock that can be swapped out for testing. - std::unique_ptr<base::Clock> clock_; + base::Clock* clock_; THREAD_CHECKER(thread_checker_); diff --git a/chromium/net/http/http_cache_transaction.cc b/chromium/net/http/http_cache_transaction.cc index 7b491f92496..0dbacd48f37 100644 --- a/chromium/net/http/http_cache_transaction.cc +++ b/chromium/net/http/http_cache_transaction.cc @@ -19,8 +19,8 @@ #include "base/compiler_specific.h" #include "base/location.h" #include "base/macros.h" +#include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" -#include "base/metrics/sparse_histogram.h" #include "base/single_thread_task_runner.h" #include "base/strings/string_number_conversions.h" // For HexEncode. #include "base/strings/string_util.h" // For LowerCaseEqualsASCII. @@ -179,6 +179,7 @@ HttpCache::Transaction::Transaction(RequestPriority priority, HttpCache* cache) validation_cause_(VALIDATION_CAUSE_UNDEFINED), cant_conditionalize_zero_freshness_from_memhint_(false), recorded_histograms_(false), + parallel_writing_pattern_(PARALLEL_WRITING_NONE), moved_network_transaction_to_writers_(false), websocket_handshake_stream_base_create_helper_(NULL), in_do_loop_(false), @@ -558,10 +559,12 @@ void HttpCache::Transaction::PopulateNetErrorDetails( void HttpCache::Transaction::SetPriority(RequestPriority priority) { priority_ = priority; - if (network_trans_) { - DCHECK(!InWriters()); + + if (network_trans_) network_trans_->SetPriority(priority_); - } else if (InWriters()) { + + if (InWriters()) { + DCHECK(!network_trans_ || partial_); entry_->writers->UpdatePriority(); } } @@ -662,6 +665,15 @@ void HttpCache::Transaction::WriteModeTransactionAboutToBecomeReader() { } } +void HttpCache::Transaction::MaybeSetParallelWritingPatternForMetrics( + HttpCache::ParallelWritingPattern pattern) { + // It's possible a transaction could not join existing writers and then + // creates a new writers. In that case the original reason for not being able + // to join writers should be logged. + if (parallel_writing_pattern_ == PARALLEL_WRITING_NONE) + parallel_writing_pattern_ = pattern; +} + //----------------------------------------------------------------------------- // A few common patterns: (Foo* means Foo -> FooComplete) @@ -2982,11 +2994,14 @@ int HttpCache::Transaction::WriteResponseInfoToEntry(bool truncated) { io_buf_len_ = data->pickle()->size(); - // Summarize some info on cacheability in memory. - cache_->GetCurrentBackend()->SetEntryInMemoryData( - cache_key_, ComputeUnusablePerCachingHeaders() - ? HINT_UNUSABLE_PER_CACHING_HEADERS - : 0); + // Summarize some info on cacheability in memory. Don't do it if doomed + // since then |entry_| isn't definitive for |cache_key_|. + if (!entry_->doomed) { + cache_->GetCurrentBackend()->SetEntryInMemoryData( + cache_key_, ComputeUnusablePerCachingHeaders() + ? HINT_UNUSABLE_PER_CACHING_HEADERS + : 0); + } return entry_->disk_entry->WriteData(kResponseInfoIndex, 0, data.get(), io_buf_len_, io_callback_, true); @@ -3039,11 +3054,11 @@ int HttpCache::Transaction::OnCacheReadError(int result, bool restart) { DLOG(ERROR) << "ReadData failed: " << result; const int result_for_histogram = std::max(0, -result); if (restart) { - UMA_HISTOGRAM_SPARSE_SLOWLY("HttpCache.ReadErrorRestartable", - result_for_histogram); + base::UmaHistogramSparse("HttpCache.ReadErrorRestartable", + result_for_histogram); } else { - UMA_HISTOGRAM_SPARSE_SLOWLY("HttpCache.ReadErrorNonRestartable", - result_for_histogram); + base::UmaHistogramSparse("HttpCache.ReadErrorNonRestartable", + result_for_histogram); } // Avoid using this entry in the future. @@ -3236,6 +3251,9 @@ void HttpCache::Transaction::RecordHistograms() { DCHECK(!recorded_histograms_); recorded_histograms_ = true; + UMA_HISTOGRAM_ENUMERATION("HttpCache.ParallelWritingPattern", + parallel_writing_pattern_, PARALLEL_WRITING_MAX); + if (CacheEntryStatus::ENTRY_UNDEFINED == cache_entry_status_) return; diff --git a/chromium/net/http/http_cache_transaction.h b/chromium/net/http/http_cache_transaction.h index 385ab2ae7e6..fe8ac18463f 100644 --- a/chromium/net/http/http_cache_transaction.h +++ b/chromium/net/http/http_cache_transaction.h @@ -190,6 +190,12 @@ class NET_EXPORT_PRIVATE HttpCache::Transaction : public HttpTransaction { // entry has finished writing. void WriteModeTransactionAboutToBecomeReader(); + // Invoked when HttpCache decides whether this transaction should join + // parallel writing or create a new writers object. This is then used + // for logging metrics. Can be called repeatedly, but doesn't change once the + // value has been set to something other than PARALLEL_WRITING_NONE. + void MaybeSetParallelWritingPatternForMetrics(ParallelWritingPattern pattern); + private: static const size_t kNumValidationHeaders = 2; // Helper struct to pair a header name with its value, for @@ -624,6 +630,7 @@ class NET_EXPORT_PRIVATE HttpCache::Transaction : public HttpTransaction { base::TimeDelta stale_entry_age_; bool cant_conditionalize_zero_freshness_from_memhint_; bool recorded_histograms_; + ParallelWritingPattern parallel_writing_pattern_; NetworkTransactionInfo network_transaction_info_; diff --git a/chromium/net/http/http_cache_unittest.cc b/chromium/net/http/http_cache_unittest.cc index 4a6fbe801a6..f834fa62a41 100644 --- a/chromium/net/http/http_cache_unittest.cc +++ b/chromium/net/http/http_cache_unittest.cc @@ -22,6 +22,7 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" +#include "base/test/histogram_tester.h" #include "base/test/simple_test_clock.h" #include "base/trace_event/memory_allocator_dump.h" #include "base/trace_event/memory_dump_request_args.h" @@ -796,6 +797,8 @@ TEST(HttpCache, ReleaseBuffer) { TEST(HttpCache, SimpleGETWithDiskFailures) { MockHttpCache cache; + base::HistogramTester histograms; + const std::string histogram_name = "HttpCache.ParallelWritingPattern"; cache.disk_cache()->set_soft_failures(true); @@ -812,6 +815,11 @@ TEST(HttpCache, SimpleGETWithDiskFailures) { EXPECT_EQ(2, cache.network_layer()->transaction_count()); EXPECT_EQ(0, cache.disk_cache()->open_count()); EXPECT_EQ(2, cache.disk_cache()->create_count()); + + // Since the transactions were in headers phase when failed, + // PARALLEL_WRITING_NONE should be logged. + histograms.ExpectBucketCount( + histogram_name, static_cast<int>(HttpCache::PARALLEL_WRITING_NONE), 2); } // Tests that disk failures after the transaction has started don't cause the @@ -988,6 +996,8 @@ TEST(HttpCache, SimpleGET_LoadOnlyFromCache_Miss) { TEST(HttpCache, SimpleGET_LoadPreferringCache_Hit) { MockHttpCache cache; + base::HistogramTester histograms; + const std::string histogram_name = "HttpCache.ParallelWritingPattern"; // write to the cache RunTransactionTest(cache.http_cache(), kSimpleGET_Transaction); @@ -1001,6 +1011,12 @@ TEST(HttpCache, SimpleGET_LoadPreferringCache_Hit) { EXPECT_EQ(1, cache.network_layer()->transaction_count()); EXPECT_EQ(1, cache.disk_cache()->open_count()); EXPECT_EQ(1, cache.disk_cache()->create_count()); + + histograms.ExpectBucketCount( + histogram_name, static_cast<int>(HttpCache::PARALLEL_WRITING_CREATE), 1); + histograms.ExpectBucketCount( + histogram_name, + static_cast<int>(HttpCache::PARALLEL_WRITING_NONE_CACHE_READ), 1); } TEST(HttpCache, SimpleGET_LoadPreferringCache_Miss) { @@ -1721,6 +1737,8 @@ TEST(HttpCache, RangeGET_ParallelValidationNoMatchDoomEntry1) { // Tests parallel validation on range requests with non-overlapping ranges. TEST(HttpCache, RangeGET_ParallelValidationDifferentRanges) { + base::HistogramTester histograms; + const std::string histogram_name = "HttpCache.ParallelWritingPattern"; MockHttpCache cache; ScopedMockTransaction transaction(kRangeGET_TransactionOK); @@ -1815,6 +1833,56 @@ TEST(HttpCache, RangeGET_ParallelValidationDifferentRanges) { EXPECT_EQ(2, cache.network_layer()->transaction_count()); EXPECT_EQ(1, cache.disk_cache()->open_count()); EXPECT_EQ(1, cache.disk_cache()->create_count()); + + histograms.ExpectBucketCount( + histogram_name, + static_cast<int>(HttpCache::PARALLEL_WRITING_NOT_JOIN_RANGE), 1); + histograms.ExpectBucketCount( + histogram_name, static_cast<int>(HttpCache::PARALLEL_WRITING_CREATE), 2); +} + +// Tests that a request does not create Writers when readers is not empty. +TEST(HttpCache, RangeGET_DoNotCreateWritersWhenReaderExists) { + MockHttpCache cache; + + // Save a request in the cache so that the next request can become a + // reader. + MockTransaction transaction(kRangeGET_Transaction); + transaction.request_headers = EXTRA_HEADER; + AddMockTransaction(&transaction); + RunTransactionTest(cache.http_cache(), transaction); + + // Let this request be a reader since it doesn't need validation as per its + // load flag. + transaction.load_flags |= LOAD_SKIP_CACHE_VALIDATION; + MockHttpRequest request(transaction); + Context context; + context.result = cache.CreateTransaction(&context.trans); + ASSERT_THAT(context.result, IsOk()); + context.result = context.trans->Start(&request, context.callback.callback(), + NetLogWithSource()); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(1, cache.GetCountReaders(transaction.url)); + RemoveMockTransaction(&transaction); + + // A range request should now "not" create Writers while readers is still + // non-empty. + MockTransaction range_transaction(kRangeGET_Transaction); + range_transaction.request_headers = "Range: bytes = 0-9\r\n" EXTRA_HEADER; + AddMockTransaction(&range_transaction); + MockHttpRequest range_request(range_transaction); + Context range_context; + range_context.result = cache.CreateTransaction(&range_context.trans); + ASSERT_THAT(range_context.result, IsOk()); + range_context.result = range_context.trans->Start( + &range_request, range_context.callback.callback(), NetLogWithSource()); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(1, cache.GetCountReaders(transaction.url)); + EXPECT_FALSE(cache.IsWriterPresent(transaction.url)); + EXPECT_EQ(1, cache.GetCountDoneHeadersQueue(transaction.url)); + + RemoveMockTransaction(&range_transaction); } // Tests parallel validation on range requests can be successfully restarted @@ -2795,6 +2863,8 @@ TEST(HttpCache, SimpleGET_ParallelWritingCacheWriteFailed) { // like the code should disallow two POSTs without LOAD_ONLY_FROM_CACHE with the // same upload data identifier to map to the same entry. TEST(HttpCache, SimplePOST_ParallelWritingDisallowed) { + base::HistogramTester histograms; + const std::string histogram_name = "HttpCache.ParallelWritingPattern"; MockHttpCache cache; MockTransaction transaction(kSimplePOST_Transaction); @@ -2851,11 +2921,19 @@ TEST(HttpCache, SimplePOST_ParallelWritingDisallowed) { EXPECT_EQ(1, cache.network_layer()->transaction_count()); EXPECT_EQ(0, cache.disk_cache()->open_count()); EXPECT_EQ(1, cache.disk_cache()->create_count()); + + histograms.ExpectBucketCount( + histogram_name, + static_cast<int>(HttpCache::PARALLEL_WRITING_NOT_JOIN_METHOD_NOT_GET), 1); + histograms.ExpectBucketCount( + histogram_name, static_cast<int>(HttpCache::PARALLEL_WRITING_CREATE), 1); } // Tests the case when parallel writing succeeds. Tests both idle and waiting // transactions. TEST(HttpCache, SimpleGET_ParallelWritingSuccess) { + base::HistogramTester histograms; + const std::string histogram_name = "HttpCache.ParallelWritingPattern"; MockHttpCache cache; MockHttpRequest request(kSimpleGET_Transaction); @@ -2930,6 +3008,15 @@ TEST(HttpCache, SimpleGET_ParallelWritingSuccess) { auto& c = context_list[i]; ReadAndVerifyTransaction(c->trans.get(), kSimpleGET_Transaction); } + + // Verify metrics. + histograms.ExpectBucketCount( + histogram_name, static_cast<int>(HttpCache::PARALLEL_WRITING_CREATE), 1); + histograms.ExpectBucketCount( + histogram_name, static_cast<int>(HttpCache::PARALLEL_WRITING_JOIN), 2); + histograms.ExpectBucketCount( + histogram_name, + static_cast<int>(HttpCache::PARALLEL_WRITING_NOT_JOIN_READ_ONLY), 1); } // Tests that network transaction's info is saved correctly when a writer @@ -3428,6 +3515,77 @@ TEST(HttpCache, SimpleGET_DoomWithPending) { } } +TEST(HttpCache, DoomDoesNotSetHints) { + // Test that a doomed writer doesn't set in-memory index hints. + MockHttpCache cache; + cache.disk_cache()->set_support_in_memory_entry_data(true); + + // Request 1 is a normal one to a no-cache/no-etag resource, to potentially + // set a "this is unvalidatable" hint in the cache. We also need it to + // actually write out to the doomed entry after request 2 does its thing, + // so its transaction is paused. + MockTransaction no_cache_transaction(kSimpleGET_Transaction); + no_cache_transaction.response_headers = "Cache-Control: no-cache\n"; + AddMockTransaction(&no_cache_transaction); + MockHttpRequest request1(no_cache_transaction); + + Context c1; + c1.result = cache.CreateTransaction(&c1.trans); + ASSERT_THAT(c1.result, IsOk()); + c1.trans->SetBeforeNetworkStartCallback( + base::Bind([](bool* defer) { *defer = true; })); + c1.result = + c1.trans->Start(&request1, c1.callback.callback(), NetLogWithSource()); + ASSERT_THAT(c1.result, IsError(ERR_IO_PENDING)); + + // It starts, copies over headers info, but doesn't get to proceed. + base::RunLoop().RunUntilIdle(); + RemoveMockTransaction(&no_cache_transaction); + + // Request 2 sets LOAD_BYPASS_CACHE to force the first one to be doomed --- + // it'll want to be a writer. + MockHttpRequest request2(kSimpleGET_Transaction); + request2.load_flags = LOAD_BYPASS_CACHE; + + Context c2; + c2.result = cache.CreateTransaction(&c2.trans); + ASSERT_THAT(c2.result, IsOk()); + c2.result = + c2.trans->Start(&request2, c2.callback.callback(), NetLogWithSource()); + ASSERT_THAT(c2.result, IsError(ERR_IO_PENDING)); + + // Run Request2, then let the first one wrap up. + base::RunLoop().RunUntilIdle(); + c2.callback.WaitForResult(); + ReadAndVerifyTransaction(c2.trans.get(), kSimpleGET_Transaction); + + c1.trans->ResumeNetworkStart(); + c1.callback.WaitForResult(); + ReadAndVerifyTransaction(c1.trans.get(), no_cache_transaction); + + EXPECT_EQ(2, cache.network_layer()->transaction_count()); + EXPECT_EQ(0, cache.disk_cache()->open_count()); + EXPECT_EQ(2, cache.disk_cache()->create_count()); + + // Request 3 tries to read from cache, and it should successfully do so. It's + // run after the previous two transactions finish so it doesn't try to + // cooperate with them, and is entirely driven by the state of the cache. + MockHttpRequest request3(kSimpleGET_Transaction); + Context context3; + context3.result = cache.CreateTransaction(&context3.trans); + ASSERT_THAT(context3.result, IsOk()); + context3.result = context3.trans->Start( + &request3, context3.callback.callback(), NetLogWithSource()); + base::RunLoop().RunUntilIdle(); + ASSERT_THAT(context3.result, IsError(ERR_IO_PENDING)); + context3.result = context3.callback.WaitForResult(); + ReadAndVerifyTransaction(context3.trans.get(), kSimpleGET_Transaction); + + EXPECT_EQ(2, cache.network_layer()->transaction_count()); + EXPECT_EQ(1, cache.disk_cache()->open_count()); + EXPECT_EQ(2, cache.disk_cache()->create_count()); +} + // This is a test for http://code.google.com/p/chromium/issues/detail?id=4731. // We may attempt to delete an entry synchronously with the act of adding a new // transaction to said entry. @@ -4936,6 +5094,8 @@ TEST(HttpCache, SimplePOST_LoadOnlyFromCache_Miss) { TEST(HttpCache, SimplePOST_LoadOnlyFromCache_Hit) { MockHttpCache cache; + base::HistogramTester histograms; + const std::string histogram_name = "HttpCache.ParallelWritingPattern"; // Test that we hit the cache for POST requests. @@ -4965,6 +5125,10 @@ TEST(HttpCache, SimplePOST_LoadOnlyFromCache_Hit) { EXPECT_EQ(1, cache.network_layer()->transaction_count()); EXPECT_EQ(1, cache.disk_cache()->open_count()); EXPECT_EQ(1, cache.disk_cache()->create_count()); + + histograms.ExpectBucketCount( + histogram_name, + static_cast<int>(HttpCache::PARALLEL_WRITING_NONE_CACHE_READ), 1); } // Test that we don't hit the cache for POST requests if there is a byte range. @@ -8957,9 +9121,9 @@ TEST(HttpCache, SkipVaryCheckStar) { // transactions unless LOAD_SKIP_CACHE_VALIDATION is set. TEST(HttpCache, ValidLoadOnlyFromCache) { MockHttpCache cache; - base::SimpleTestClock* clock = new base::SimpleTestClock(); - cache.http_cache()->SetClockForTesting(base::WrapUnique(clock)); - cache.network_layer()->SetClock(clock); + base::SimpleTestClock clock; + cache.http_cache()->SetClockForTesting(&clock); + cache.network_layer()->SetClock(&clock); // Write a resource that will expire in 100 seconds. ScopedMockTransaction transaction(kSimpleGET_Transaction); @@ -8967,7 +9131,7 @@ TEST(HttpCache, ValidLoadOnlyFromCache) { RunTransactionTest(cache.http_cache(), transaction); // Move forward in time such that the cached response is no longer valid. - clock->Advance(base::TimeDelta::FromSeconds(101)); + clock.Advance(base::TimeDelta::FromSeconds(101)); // Skipping cache validation should still return a response. transaction.load_flags = LOAD_ONLY_FROM_CACHE | LOAD_SKIP_CACHE_VALIDATION; @@ -9844,9 +10008,8 @@ class HttpCachePrefetchValidationTest : public ::testing::Test { HttpCachePrefetchValidationTest() : transaction_(kSimpleGET_Transaction) { DCHECK_LT(kMaxAgeSecs, prefetch_reuse_mins() * kNumSecondsPerMinute); - clock_ = new base::SimpleTestClock(); - cache_.http_cache()->SetClockForTesting(base::WrapUnique(clock_)); - cache_.network_layer()->SetClock(clock_); + cache_.http_cache()->SetClockForTesting(&clock_); + cache_.network_layer()->SetClock(&clock_); transaction_.response_headers = "Cache-Control: max-age=100\n"; } @@ -9859,7 +10022,7 @@ class HttpCachePrefetchValidationTest : public ::testing::Test { } void AdvanceTime(int seconds) { - clock_->Advance(base::TimeDelta::FromSeconds(seconds)); + clock_.Advance(base::TimeDelta::FromSeconds(seconds)); } int prefetch_reuse_mins() { return HttpCache::kPrefetchReuseMins; } @@ -9874,7 +10037,7 @@ class HttpCachePrefetchValidationTest : public ::testing::Test { MockHttpCache cache_; ScopedMockTransaction transaction_; std::string response_headers_; - base::SimpleTestClock* clock_; + base::SimpleTestClock clock_; }; TEST_F(HttpCachePrefetchValidationTest, SkipValidationShortlyAfterPrefetch) { diff --git a/chromium/net/http/http_cache_writers.cc b/chromium/net/http/http_cache_writers.cc index 0fcf1c6af52..31b4f15b116 100644 --- a/chromium/net/http/http_cache_writers.cc +++ b/chromium/net/http/http_cache_writers.cc @@ -103,12 +103,14 @@ bool HttpCache::Writers::StopCaching(bool keep_entry) { return true; } -void HttpCache::Writers::AddTransaction(Transaction* transaction, - bool is_exclusive, - RequestPriority priority, - const TransactionInfo& info) { +void HttpCache::Writers::AddTransaction( + Transaction* transaction, + ParallelWritingPattern initial_writing_pattern, + RequestPriority priority, + const TransactionInfo& info) { DCHECK(transaction); - DCHECK(CanAddWriters()); + ParallelWritingPattern writers_pattern; + DCHECK(CanAddWriters(&writers_pattern)); DCHECK_EQ(0u, all_writers_.count(transaction)); @@ -117,6 +119,15 @@ void HttpCache::Writers::AddTransaction(Transaction* transaction, should_keep_entry_ = IsValidResponseForWriter(info.partial != nullptr, &(info.response_info)); + if (all_writers_.empty()) { + DCHECK_EQ(PARALLEL_WRITING_NONE, parallel_writing_pattern_); + parallel_writing_pattern_ = initial_writing_pattern; + if (parallel_writing_pattern_ != PARALLEL_WRITING_JOIN) + is_exclusive_ = true; + } else { + DCHECK_EQ(PARALLEL_WRITING_JOIN, parallel_writing_pattern_); + } + if (info.partial && !info.truncated) { DCHECK(!partial_do_not_truncate_); partial_do_not_truncate_ = true; @@ -125,11 +136,6 @@ void HttpCache::Writers::AddTransaction(Transaction* transaction, std::pair<Transaction*, TransactionInfo> writer(transaction, info); all_writers_.insert(writer); - if (is_exclusive) { - DCHECK_EQ(1u, all_writers_.size()); - is_exclusive_ = true; - } - priority_ = std::max(priority, priority_); if (network_transaction_) { network_transaction_->SetPriority(priority_); @@ -227,7 +233,8 @@ bool HttpCache::Writers::ContainsOnlyIdleWriters() const { return waiting_for_read_.empty() && !active_transaction_; } -bool HttpCache::Writers::CanAddWriters() { +bool HttpCache::Writers::CanAddWriters(ParallelWritingPattern* reason) { + *reason = PARALLEL_WRITING_NONE; // While cleaning up writers (truncation) we should delay adding new writers. // The caller can try again later. if (next_state_ == State::ASYNC_OP_COMPLETE_PRE_TRUNCATE || @@ -236,6 +243,7 @@ bool HttpCache::Writers::CanAddWriters() { return false; } + *reason = parallel_writing_pattern_; if (all_writers_.empty()) return true; diff --git a/chromium/net/http/http_cache_writers.h b/chromium/net/http/http_cache_writers.h index 9fbd265c193..2b45c1e0b85 100644 --- a/chromium/net/http/http_cache_writers.h +++ b/chromium/net/http/http_cache_writers.h @@ -78,15 +78,16 @@ class NET_EXPORT_PRIVATE HttpCache::Writers { // Adds an HttpCache::Transaction to Writers. // Should only be invoked if CanAddWriters() returns true. - // If |is_exclusive| is true, it makes writing an exclusive operation - // implying that Writers can contain at most one transaction till the - // completion of the response body. It is illegal to invoke with is_exclusive - // as true if there is already a transaction present. + // |parallel_writing_pattern| governs whether writing is an exclusive + // operation implying that Writers can contain at most one transaction till + // the completion of the response body. It is illegal to invoke with + // |parallel_writing_pattern| as PARALLEL_WRITING_NOT_JOIN* if there is + // already a transaction present. // |transaction| can be destroyed at any point and it should invoke // HttpCache::DoneWithEntry() during its destruction. This will also ensure // any pointers in |info| are not accessed after the transaction is destroyed. void AddTransaction(Transaction* transaction, - bool is_exclusive, + ParallelWritingPattern initial_writing_pattern, RequestPriority priority, const TransactionInfo& info); @@ -108,8 +109,9 @@ class NET_EXPORT_PRIVATE HttpCache::Writers { return all_writers_.count(const_cast<Transaction*>(transaction)) > 0; } - // Returns true if more writers can be added for shared writing. - bool CanAddWriters(); + // Returns true if more writers can be added for shared writing. Also fills in + // the |reason| for why a transaction cannot be added. + bool CanAddWriters(ParallelWritingPattern* reason); // Returns if only one transaction can be a member of writers. bool IsExclusive() const { return is_exclusive_; } @@ -274,6 +276,7 @@ class NET_EXPORT_PRIVATE HttpCache::Writers { // True if multiple transactions are not allowed e.g. for partial requests. bool is_exclusive_ = false; + ParallelWritingPattern parallel_writing_pattern_ = PARALLEL_WRITING_NONE; // Current priority of the request. It is always the maximum of all the writer // transactions. diff --git a/chromium/net/http/http_cache_writers_unittest.cc b/chromium/net/http/http_cache_writers_unittest.cc index cb05ec48c86..4d65c6294c9 100644 --- a/chromium/net/http/http_cache_writers_unittest.cc +++ b/chromium/net/http/http_cache_writers_unittest.cc @@ -90,7 +90,9 @@ class WritersTest : public testing::Test { return transaction; } - void CreateWritersAddTransaction(bool is_exclusive = false) { + void CreateWritersAddTransaction( + HttpCache::ParallelWritingPattern parallel_writing_pattern_ = + HttpCache::PARALLEL_WRITING_JOIN) { TestCompletionCallback callback; // Create and Start a mock network transaction. @@ -113,7 +115,7 @@ class WritersTest : public testing::Test { *(transaction->GetResponseInfo())); info.response_info = response_info_; - writers_->AddTransaction(transaction.get(), is_exclusive, + writers_->AddTransaction(transaction.get(), parallel_writing_pattern_, transaction->priority(), info); writers_->SetNetworkTransaction(transaction.get(), std::move(network_transaction)); @@ -121,9 +123,11 @@ class WritersTest : public testing::Test { transactions_.push_back(std::move(transaction)); } - void CreateWritersAddTransactionPriority(net::RequestPriority priority, - bool is_exclusive = false) { - CreateWritersAddTransaction(is_exclusive); + void CreateWritersAddTransactionPriority( + net::RequestPriority priority, + HttpCache::ParallelWritingPattern parallel_writing_pattern_ = + HttpCache::PARALLEL_WRITING_JOIN) { + CreateWritersAddTransaction(parallel_writing_pattern_); TestHttpCacheTransaction* transaction = transactions_.begin()->get(); transaction->SetPriority(priority); } @@ -140,8 +144,9 @@ class WritersTest : public testing::Test { transaction->is_truncated(), *(transaction->GetResponseInfo())); info.response_info = response_info_; - writers_->AddTransaction(transaction.get(), false, transaction->priority(), - info); + writers_->AddTransaction(transaction.get(), + HttpCache::PARALLEL_WRITING_JOIN, + transaction->priority(), info); transactions_.push_back(std::move(transaction)); } @@ -322,7 +327,7 @@ class WritersTest : public testing::Test { EXPECT_TRUE(writers_->IsEmpty()); // Cannot add more writers while we are in truncation pending state. - EXPECT_FALSE(writers_->CanAddWriters()); + EXPECT_FALSE(CanAddWriters()); // Complete the Read and the entry should be truncated. base::RunLoop().RunUntilIdle(); @@ -341,7 +346,7 @@ class WritersTest : public testing::Test { writers_->StopCaching(false /* keep_entry */); // Cannot add more writers while we are in network read only state. - EXPECT_FALSE(writers_->CanAddWriters()); + EXPECT_FALSE(CanAddWriters()); // Complete the Read and the entry should be truncated. base::RunLoop().RunUntilIdle(); @@ -438,6 +443,11 @@ class WritersTest : public testing::Test { EXPECT_FALSE(ShouldKeepEntry()); } + bool CanAddWriters() { + HttpCache::ParallelWritingPattern parallel_writing_pattern_; + return writers_->CanAddWriters(¶llel_writing_pattern_); + } + MockHttpCache cache_; std::unique_ptr<HttpCache::Writers> writers_; disk_cache::Entry* disk_entry_; @@ -476,10 +486,10 @@ TEST_F(WritersTest, AddManyTransactions) { // Tests that CanAddWriters should return false if it is writing exclusively. TEST_F(WritersTest, AddTransactionsExclusive) { - CreateWritersAddTransaction(true /* is_exclusive */); + CreateWritersAddTransaction(HttpCache::PARALLEL_WRITING_NOT_JOIN_RANGE); EXPECT_FALSE(writers_->IsEmpty()); - EXPECT_FALSE(writers_->CanAddWriters()); + EXPECT_FALSE(CanAddWriters()); } // Tests StopCaching should not stop caching if there are multiple writers. @@ -487,11 +497,11 @@ TEST_F(WritersTest, StopCachingMultipleWriters) { CreateWritersAddTransaction(); EXPECT_FALSE(writers_->IsEmpty()); - EXPECT_TRUE(writers_->CanAddWriters()); + EXPECT_TRUE(CanAddWriters()); AddTransactionToExistingWriters(); EXPECT_FALSE(StopCaching()); - EXPECT_TRUE(writers_->CanAddWriters()); + EXPECT_TRUE(CanAddWriters()); } // Tests StopCaching should stop caching if there is a single writer. @@ -500,7 +510,7 @@ TEST_F(WritersTest, StopCaching) { EXPECT_FALSE(writers_->IsEmpty()); EXPECT_TRUE(StopCaching()); - EXPECT_FALSE(writers_->CanAddWriters()); + EXPECT_FALSE(CanAddWriters()); } // Tests StopCaching should be successful when invoked mid-read. @@ -545,7 +555,7 @@ TEST_F(WritersTest, ReadMultiple) { CreateWritersAddTransaction(); EXPECT_FALSE(writers_->IsEmpty()); - EXPECT_TRUE(writers_->CanAddWriters()); + EXPECT_TRUE(CanAddWriters()); AddTransactionToExistingWriters(); AddTransactionToExistingWriters(); @@ -557,7 +567,7 @@ TEST_F(WritersTest, ReadMultipleDifferentBufferSizes) { CreateWritersAddTransaction(); EXPECT_FALSE(writers_->IsEmpty()); - EXPECT_TRUE(writers_->CanAddWriters()); + EXPECT_TRUE(CanAddWriters()); AddTransactionToExistingWriters(); std::vector<int> buffer_lengths{20, 10}; @@ -570,7 +580,7 @@ TEST_F(WritersTest, ReadMultipleDifferentBufferSizes1) { CreateWritersAddTransaction(); EXPECT_FALSE(writers_->IsEmpty()); - EXPECT_TRUE(writers_->CanAddWriters()); + EXPECT_TRUE(CanAddWriters()); AddTransactionToExistingWriters(); std::vector<int> buffer_lengths{10, 20}; @@ -583,7 +593,7 @@ TEST_F(WritersTest, ReadMultipleDeleteActiveTransaction) { CreateWritersAddTransaction(); EXPECT_FALSE(writers_->IsEmpty()); - EXPECT_TRUE(writers_->CanAddWriters()); + EXPECT_TRUE(CanAddWriters()); AddTransactionToExistingWriters(); AddTransactionToExistingWriters(); @@ -596,7 +606,7 @@ TEST_F(WritersTest, ReadMultipleDeleteActiveTransaction) { TEST_F(WritersTest, MidReadDeleteActiveTransaction) { CreateWritersAddTransaction(); EXPECT_FALSE(writers_->IsEmpty()); - EXPECT_TRUE(writers_->CanAddWriters()); + EXPECT_TRUE(CanAddWriters()); MidReadDeleteActiveTransaction(); } @@ -606,7 +616,7 @@ TEST_F(WritersTest, ReadMultipleDeleteWaitingTransaction) { CreateWritersAddTransaction(); EXPECT_FALSE(writers_->IsEmpty()); - EXPECT_TRUE(writers_->CanAddWriters()); + EXPECT_TRUE(CanAddWriters()); AddTransactionToExistingWriters(); AddTransactionToExistingWriters(); AddTransactionToExistingWriters(); @@ -620,7 +630,7 @@ TEST_F(WritersTest, ReadMultipleDeleteIdleTransaction) { CreateWritersAddTransaction(); EXPECT_FALSE(writers_->IsEmpty()); - EXPECT_TRUE(writers_->CanAddWriters()); + EXPECT_TRUE(CanAddWriters()); AddTransactionToExistingWriters(); AddTransactionToExistingWriters(); @@ -633,7 +643,7 @@ TEST_F(WritersTest, ReadMultipleCacheWriteFailed) { CreateWritersAddTransaction(); EXPECT_FALSE(writers_->IsEmpty()); - EXPECT_TRUE(writers_->CanAddWriters()); + EXPECT_TRUE(CanAddWriters()); AddTransactionToExistingWriters(); AddTransactionToExistingWriters(); @@ -658,7 +668,7 @@ TEST_F(WritersTest, ReadMultipleNetworkReadFailed) { CreateWritersAddTransaction(); EXPECT_FALSE(writers_->IsEmpty()); - EXPECT_TRUE(writers_->CanAddWriters()); + EXPECT_TRUE(CanAddWriters()); AddTransactionToExistingWriters(); AddTransactionToExistingWriters(); @@ -691,7 +701,7 @@ TEST_F(WritersTest, TruncateEntryFail) { // Set network read only. TEST_F(WritersTest, StopCachingWithKeepEntry) { - CreateWritersAddTransaction(true /* is exclusive */); + CreateWritersAddTransaction(HttpCache::PARALLEL_WRITING_NOT_JOIN_RANGE); EXPECT_FALSE(writers_->network_read_only()); writers_->StopCaching(true /* keep_entry */); @@ -700,7 +710,7 @@ TEST_F(WritersTest, StopCachingWithKeepEntry) { } TEST_F(WritersTest, StopCachingWithNotKeepEntry) { - CreateWritersAddTransaction(true /* is exclusive */); + CreateWritersAddTransaction(HttpCache::PARALLEL_WRITING_NOT_JOIN_RANGE); EXPECT_FALSE(writers_->network_read_only()); writers_->StopCaching(false /* keep_entry */); diff --git a/chromium/net/http/http_network_session.cc b/chromium/net/http/http_network_session.cc index bcced4e441f..4b1fe0d8ebe 100644 --- a/chromium/net/http/http_network_session.cc +++ b/chromium/net/http/http_network_session.cc @@ -5,7 +5,7 @@ #include "net/http/http_network_session.h" #include <inttypes.h> -#include <memory> + #include <utility> #include "base/atomic_sequence_num.h" @@ -125,14 +125,20 @@ HttpNetworkSession::Params::Params() quic_migrate_sessions_early(false), quic_migrate_sessions_on_network_change_v2(false), quic_migrate_sessions_early_v2(false), + quic_max_time_on_non_default_network( + base::TimeDelta::FromSeconds(kMaxTimeOnNonDefaultNetworkSecs)), + quic_max_migrations_to_non_default_network_on_path_degrading( + kMaxMigrationsToNonDefaultNetworkOnPathDegrading), quic_allow_server_migration(false), quic_allow_remote_alt_svc(false), quic_disable_bidirectional_streams(false), quic_force_hol_blocking(false), quic_race_cert_verification(false), quic_estimate_initial_rtt(false), + quic_headers_include_h2_stream_dependency(false), enable_token_binding(false), - http_09_on_non_default_ports_enabled(false) { + http_09_on_non_default_ports_enabled(false), + disable_idle_sockets_close_on_memory_pressure(false) { quic_supported_versions.push_back(QUIC_VERSION_39); } @@ -206,9 +212,12 @@ HttpNetworkSession::HttpNetworkSession(const Params& params, params.quic_migrate_sessions_early, params.quic_migrate_sessions_on_network_change_v2, params.quic_migrate_sessions_early_v2, + params.quic_max_time_on_non_default_network, + params.quic_max_migrations_to_non_default_network_on_path_degrading, params.quic_allow_server_migration, params.quic_race_cert_verification, params.quic_estimate_initial_rtt, + params.quic_headers_include_h2_stream_dependency, params.quic_connection_options, params.quic_client_connection_options, params.enable_token_binding), @@ -223,9 +232,8 @@ HttpNetworkSession::HttpNetworkSession(const Params& params, AddDefaultHttp2Settings(params.http2_settings), params.time_func, context.proxy_delegate), - http_stream_factory_(new HttpStreamFactoryImpl(this, false)), - http_stream_factory_for_websocket_(new HttpStreamFactoryImpl(this, true)), - network_stream_throttler_(new NetworkThrottleManagerImpl()), + http_stream_factory_(std::make_unique<HttpStreamFactoryImpl>(this)), + network_stream_throttler_(std::make_unique<NetworkThrottleManagerImpl>()), params_(params), context_(context) { DCHECK(proxy_service_); @@ -248,14 +256,20 @@ HttpNetworkSession::HttpNetworkSession(const Params& params, http_server_properties_->SetMaxServerConfigsStoredInProperties( params.quic_max_server_configs_stored_in_properties); - memory_pressure_listener_.reset(new base::MemoryPressureListener(base::Bind( - &HttpNetworkSession::OnMemoryPressure, base::Unretained(this)))); + if (!params_.disable_idle_sockets_close_on_memory_pressure) { + memory_pressure_listener_.reset( + new base::MemoryPressureListener(base::BindRepeating( + &HttpNetworkSession::OnMemoryPressure, base::Unretained(this)))); + } + base::MemoryCoordinatorClientRegistry::GetInstance()->Register(this); } HttpNetworkSession::~HttpNetworkSession() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); response_drainers_.clear(); + // TODO(bnc): CloseAllSessions() is also called in SpdySessionPool destructor, + // one of the two calls should be removed. spdy_session_pool_.CloseAllSessions(); base::MemoryCoordinatorClientRegistry::GetInstance()->Unregister(this); } @@ -359,6 +373,11 @@ std::unique_ptr<base::Value> HttpNetworkSession::QuicInfoToValue() const { params_.quic_migrate_sessions_on_network_change_v2); dict->SetBoolean("migrate_sessions_early_v2", params_.quic_migrate_sessions_early_v2); + dict->SetInteger("max_time_on_non_default_network_seconds", + params_.quic_max_time_on_non_default_network.InSeconds()); + dict->SetInteger( + "max_num_migrations_to_non_default_network_on_path_degrading", + params_.quic_max_migrations_to_non_default_network_on_path_degrading); dict->SetBoolean("allow_server_migration", params_.quic_allow_server_migration); dict->SetBoolean("estimate_initial_rtt", params_.quic_estimate_initial_rtt); @@ -480,10 +499,13 @@ ClientSocketPoolManager* HttpNetworkSession::GetSocketPoolManager( void HttpNetworkSession::OnMemoryPressure( base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) { + DCHECK(!params_.disable_idle_sockets_close_on_memory_pressure); + switch (memory_pressure_level) { case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE: - case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE: break; + + case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE: case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL: CloseIdleConnections(); break; diff --git a/chromium/net/http/http_network_session.h b/chromium/net/http/http_network_session.h index 59d19493752..2a20aad3a37 100644 --- a/chromium/net/http/http_network_session.h +++ b/chromium/net/http/http_network_session.h @@ -175,6 +175,13 @@ class NET_EXPORT HttpNetworkSession : public base::MemoryCoordinatorClient { // If true, connection migration v2 may be used to migrate active QUIC // sessions to alternative network if current network connectivity is poor. bool quic_migrate_sessions_early_v2; + // Maximum time the session could be on the non-default network before + // migrates back to default network. Defaults to + // kMaxTimeOnNonDefaultNetwork. + base::TimeDelta quic_max_time_on_non_default_network; + // Maximum number of migrations to the non-default network on path + // degrading per network for each session. + int quic_max_migrations_to_non_default_network_on_path_degrading; // If true, allows migration of QUIC connections to a server-specified // alternate server address. bool quic_allow_server_migration; @@ -189,6 +196,9 @@ class NET_EXPORT HttpNetworkSession : public base::MemoryCoordinatorClient { bool quic_race_cert_verification; // If true, estimate the initial RTT for QUIC connections based on network. bool quic_estimate_initial_rtt; + // If true, client headers will include HTTP/2 stream dependency info + // derived from the request priority. + bool quic_headers_include_h2_stream_dependency; // If non-empty, QUIC will only be spoken to hosts in this list. base::flat_set<std::string> quic_host_whitelist; @@ -198,6 +208,9 @@ class NET_EXPORT HttpNetworkSession : public base::MemoryCoordinatorClient { // Enable HTTP/0.9 for HTTP/HTTPS on ports other than the default one for // each protocol. bool http_09_on_non_default_ports_enabled; + + // If true, idle sockets won't be closed when memory pressure happens. + bool disable_idle_sockets_close_on_memory_pressure; }; // Structure with pointers to the dependencies of the HttpNetworkSession. @@ -277,9 +290,6 @@ class NET_EXPORT HttpNetworkSession : public base::MemoryCoordinatorClient { HttpStreamFactory* http_stream_factory() { return http_stream_factory_.get(); } - HttpStreamFactory* http_stream_factory_for_websocket() { - return http_stream_factory_for_websocket_.get(); - } NetworkThrottleManager* throttler() { return network_stream_throttler_.get(); } @@ -358,7 +368,6 @@ class NET_EXPORT HttpNetworkSession : public base::MemoryCoordinatorClient { QuicStreamFactory quic_stream_factory_; SpdySessionPool spdy_session_pool_; std::unique_ptr<HttpStreamFactory> http_stream_factory_; - std::unique_ptr<HttpStreamFactory> http_stream_factory_for_websocket_; std::map<HttpResponseBodyDrainer*, std::unique_ptr<HttpResponseBodyDrainer>> response_drainers_; std::unique_ptr<NetworkThrottleManager> network_stream_throttler_; diff --git a/chromium/net/http/http_network_session_peer.cc b/chromium/net/http/http_network_session_peer.cc index 9b33d98bac0..e9c629e8a92 100644 --- a/chromium/net/http/http_network_session_peer.cc +++ b/chromium/net/http/http_network_session_peer.cc @@ -29,11 +29,6 @@ void HttpNetworkSessionPeer::SetHttpStreamFactory( session_->http_stream_factory_.swap(http_stream_factory); } -void HttpNetworkSessionPeer::SetHttpStreamFactoryForWebSocket( - std::unique_ptr<HttpStreamFactory> http_stream_factory) { - session_->http_stream_factory_for_websocket_.swap(http_stream_factory); -} - void HttpNetworkSessionPeer::SetNetworkStreamThrottler( std::unique_ptr<NetworkThrottleManager> network_throttle_manager) { session_->network_stream_throttler_.swap(network_throttle_manager); diff --git a/chromium/net/http/http_network_session_peer.h b/chromium/net/http/http_network_session_peer.h index dae4f916df6..bb0d0c7dce3 100644 --- a/chromium/net/http/http_network_session_peer.h +++ b/chromium/net/http/http_network_session_peer.h @@ -29,8 +29,6 @@ class NET_EXPORT_PRIVATE HttpNetworkSessionPeer { void SetHttpStreamFactory( std::unique_ptr<HttpStreamFactory> http_stream_factory); - void SetHttpStreamFactoryForWebSocket( - std::unique_ptr<HttpStreamFactory> http_stream_factory_for_websocket); void SetNetworkStreamThrottler( std::unique_ptr<NetworkThrottleManager> network_throttle_manager); diff --git a/chromium/net/http/http_network_transaction.cc b/chromium/net/http/http_network_transaction.cc index a810d203821..44e52f436d4 100644 --- a/chromium/net/http/http_network_transaction.cc +++ b/chromium/net/http/http_network_transaction.cc @@ -86,6 +86,7 @@ HttpNetworkTransaction::HttpNetworkTransaction(RequestPriority priority, request_(NULL), priority_(priority), headers_valid_(false), + can_send_early_data_(false), request_headers_(), read_buf_len_(0), total_received_bytes_(0), @@ -133,6 +134,10 @@ int HttpNetworkTransaction::Start(const HttpRequestInfo* request_info, proxy_ssl_config_.rev_checking_enabled = false; } + if (request_info->method != "POST") { + can_send_early_data_ = true; + } + if (request_->load_flags & LOAD_PREFETCH) response_.unused_since_prefetch = true; @@ -858,12 +863,10 @@ int HttpNetworkTransaction::DoCreateStream() { DCHECK(!enable_alternative_services_); if (ForWebSocketHandshake()) { stream_request_ = - session_->http_stream_factory_for_websocket() - ->RequestWebSocketHandshakeStream( - *request_, priority_, server_ssl_config_, proxy_ssl_config_, - this, websocket_handshake_stream_base_create_helper_, - enable_ip_based_pooling_, enable_alternative_services_, - net_log_); + session_->http_stream_factory()->RequestWebSocketHandshakeStream( + *request_, priority_, server_ssl_config_, proxy_ssl_config_, this, + websocket_handshake_stream_base_create_helper_, + enable_ip_based_pooling_, enable_alternative_services_, net_log_); } else { stream_request_ = session_->http_stream_factory()->RequestStream( *request_, priority_, server_ssl_config_, proxy_ssl_config_, this, @@ -910,7 +913,8 @@ int HttpNetworkTransaction::DoInitStream() { stream_->GetRemoteEndpoint(&remote_endpoint_); - return stream_->InitializeStream(request_, priority_, net_log_, io_callback_); + return stream_->InitializeStream(request_, can_send_early_data_, priority_, + net_log_, io_callback_); } int HttpNetworkTransaction::DoInitStreamComplete(int result) { @@ -1048,7 +1052,7 @@ int HttpNetworkTransaction::BuildRequestHeaders( } else { request_headers_.SetHeader( HttpRequestHeaders::kContentLength, - base::Uint64ToString(request_->upload_data_stream->size())); + base::NumberToString(request_->upload_data_stream->size())); } } else if (request_->method == "POST" || request_->method == "PUT") { // An empty POST/PUT request still needs a content length. As for HEAD, @@ -1562,6 +1566,8 @@ int HttpNetworkTransaction::HandleIOError(int error) { break; case ERR_SPDY_PING_FAILED: case ERR_SPDY_SERVER_REFUSED_STREAM: + case ERR_SPDY_PUSHED_STREAM_NOT_AVAILABLE: + case ERR_SPDY_CLAIMED_PUSHED_STREAM_RESET_BY_SERVER: case ERR_QUIC_HANDSHAKE_FAILED: if (HasExceededMaxRetries()) break; diff --git a/chromium/net/http/http_network_transaction.h b/chromium/net/http/http_network_transaction.h index 866b5a28170..554a7258043 100644 --- a/chromium/net/http/http_network_transaction.h +++ b/chromium/net/http/http_network_transaction.h @@ -339,6 +339,9 @@ class NET_EXPORT_PRIVATE HttpNetworkTransaction // True if we've validated the headers that the stream parser has returned. bool headers_valid_; + // True if we can send the request over early data. + bool can_send_early_data_; + SSLConfig server_ssl_config_; SSLConfig proxy_ssl_config_; diff --git a/chromium/net/http/http_network_transaction_unittest.cc b/chromium/net/http/http_network_transaction_unittest.cc index 615019cca67..4f2f307f919 100644 --- a/chromium/net/http/http_network_transaction_unittest.cc +++ b/chromium/net/http/http_network_transaction_unittest.cc @@ -97,6 +97,7 @@ #include "net/test/gtest_util.h" #include "net/test/net_test_suite.h" #include "net/test/test_data_directory.h" +#include "net/traffic_annotation/network_traffic_annotation_test_helper.h" #include "net/websockets/websocket_handshake_stream_base.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -677,14 +678,18 @@ class CaptureGroupNameSocketPool : public ParentPool { return last_group_name_; } + bool socket_requested() const { return socket_requested_; } + int RequestSocket(const std::string& group_name, const void* socket_params, RequestPriority priority, + const SocketTag& socket_tag, ClientSocketPool::RespectLimits respect_limits, ClientSocketHandle* handle, const CompletionCallback& callback, const NetLogWithSource& net_log) override { last_group_name_ = group_name; + socket_requested_ = true; return ERR_IO_PENDING; } void CancelRequest(const std::string& group_name, @@ -708,6 +713,7 @@ class CaptureGroupNameSocketPool : public ParentPool { private: std::string last_group_name_; + bool socket_requested_ = false; }; typedef CaptureGroupNameSocketPool<TransportClientSocketPool> @@ -4484,6 +4490,225 @@ TEST_F(HttpNetworkTransactionTest, NonPermanentGenerateAuthTokenError) { session->CloseAllConnections(); } +// Proxy resolver that returns a proxy with the same host and port for different +// schemes, based on the path of the URL being requests. +class SameProxyWithDifferentSchemesProxyResolver : public ProxyResolver { + public: + SameProxyWithDifferentSchemesProxyResolver() {} + ~SameProxyWithDifferentSchemesProxyResolver() override {} + + static std::string ProxyHostPortPairAsString() { return "proxy.test:10000"; } + + static HostPortPair ProxyHostPortPair() { + return HostPortPair::FromString(ProxyHostPortPairAsString()); + } + + // ProxyResolver implementation. + int GetProxyForURL(const GURL& url, + ProxyInfo* results, + const CompletionCallback& callback, + std::unique_ptr<Request>* request, + const NetLogWithSource& /*net_log*/) override { + *results = ProxyInfo(); + if (url.path() == "/socks4") { + results->UsePacString("SOCKS " + ProxyHostPortPairAsString()); + return OK; + } + if (url.path() == "/socks5") { + results->UsePacString("SOCKS5 " + ProxyHostPortPairAsString()); + return OK; + } + if (url.path() == "/http") { + results->UsePacString("PROXY " + ProxyHostPortPairAsString()); + return OK; + } + if (url.path() == "/https") { + results->UsePacString("HTTPS " + ProxyHostPortPairAsString()); + return OK; + } + NOTREACHED(); + return ERR_NOT_IMPLEMENTED; + } + + private: + DISALLOW_COPY_AND_ASSIGN(SameProxyWithDifferentSchemesProxyResolver); +}; + +class SameProxyWithDifferentSchemesProxyResolverFactory + : public ProxyResolverFactory { + public: + SameProxyWithDifferentSchemesProxyResolverFactory() + : ProxyResolverFactory(false) {} + + int CreateProxyResolver( + const scoped_refptr<ProxyResolverScriptData>& pac_script, + std::unique_ptr<ProxyResolver>* resolver, + const CompletionCallback& callback, + std::unique_ptr<Request>* request) override { + *resolver = std::make_unique<SameProxyWithDifferentSchemesProxyResolver>(); + return OK; + } + + private: + DISALLOW_COPY_AND_ASSIGN(SameProxyWithDifferentSchemesProxyResolverFactory); +}; + +// Check that when different proxy schemes are all applied to a proxy at the +// same address, the sonnections are not grouped together. i.e., a request to +// foo.com using proxy.com as an HTTPS proxy won't use the same socket as a +// request to foo.com using proxy.com as an HTTP proxy. +TEST_F(HttpNetworkTransactionTest, SameDestinationForDifferentProxyTypes) { + session_deps_.proxy_service = std::make_unique<ProxyService>( + std::make_unique<ProxyConfigServiceFixed>( + ProxyConfig::CreateAutoDetect()), + std::make_unique<SameProxyWithDifferentSchemesProxyResolverFactory>(), + nullptr); + + std::unique_ptr<HttpNetworkSession> session = CreateSession(&session_deps_); + + MockWrite socks_writes[] = { + MockWrite(SYNCHRONOUS, kSOCKS4OkRequestLocalHostPort80, + kSOCKS4OkRequestLocalHostPort80Length), + MockWrite(SYNCHRONOUS, + "GET /socks4 HTTP/1.1\r\n" + "Host: test\r\n" + "Connection: keep-alive\r\n\r\n"), + }; + MockRead socks_reads[] = { + MockRead(SYNCHRONOUS, kSOCKS4OkReply, kSOCKS4OkReplyLength), + MockRead("HTTP/1.0 200 OK\r\n" + "Connection: keep-alive\r\n" + "Content-Length: 15\r\n\r\n" + "SOCKS4 Response"), + }; + StaticSocketDataProvider socks_data(socks_reads, arraysize(socks_reads), + socks_writes, arraysize(socks_writes)); + session_deps_.socket_factory->AddSocketDataProvider(&socks_data); + + const char kSOCKS5Request[] = { + 0x05, // Version + 0x01, // Command (CONNECT) + 0x00, // Reserved + 0x03, // Address type (DOMAINNAME) + 0x04, // Length of domain (4) + 't', 'e', 's', 't', // Domain string + 0x00, 0x50, // 16-bit port (80) + }; + MockWrite socks5_writes[] = { + MockWrite(ASYNC, kSOCKS5GreetRequest, kSOCKS5GreetRequestLength), + MockWrite(ASYNC, kSOCKS5Request, arraysize(kSOCKS5Request)), + MockWrite(SYNCHRONOUS, + "GET /socks5 HTTP/1.1\r\n" + "Host: test\r\n" + "Connection: keep-alive\r\n\r\n"), + }; + MockRead socks5_reads[] = { + MockRead(ASYNC, kSOCKS5GreetResponse, kSOCKS5GreetResponseLength), + MockRead(ASYNC, kSOCKS5OkResponse, kSOCKS5OkResponseLength), + MockRead("HTTP/1.0 200 OK\r\n" + "Connection: keep-alive\r\n" + "Content-Length: 15\r\n\r\n" + "SOCKS5 Response"), + }; + StaticSocketDataProvider socks5_data(socks5_reads, arraysize(socks5_reads), + socks5_writes, arraysize(socks5_writes)); + session_deps_.socket_factory->AddSocketDataProvider(&socks5_data); + + MockWrite http_writes[] = { + MockWrite(SYNCHRONOUS, + "GET http://test/http HTTP/1.1\r\n" + "Host: test\r\n" + "Proxy-Connection: keep-alive\r\n\r\n"), + }; + MockRead http_reads[] = { + MockRead("HTTP/1.1 200 OK\r\n" + "Proxy-Connection: keep-alive\r\n" + "Content-Length: 13\r\n\r\n" + "HTTP Response"), + }; + StaticSocketDataProvider http_data(http_reads, arraysize(http_reads), + http_writes, arraysize(http_writes)); + session_deps_.socket_factory->AddSocketDataProvider(&http_data); + + MockWrite https_writes[] = { + MockWrite(SYNCHRONOUS, + "GET http://test/https HTTP/1.1\r\n" + "Host: test\r\n" + "Proxy-Connection: keep-alive\r\n\r\n"), + }; + MockRead https_reads[] = { + MockRead("HTTP/1.1 200 OK\r\n" + "Proxy-Connection: keep-alive\r\n" + "Content-Length: 14\r\n\r\n" + "HTTPS Response"), + }; + StaticSocketDataProvider https_data(https_reads, arraysize(https_reads), + https_writes, arraysize(https_writes)); + session_deps_.socket_factory->AddSocketDataProvider(&https_data); + SSLSocketDataProvider ssl(SYNCHRONOUS, OK); + session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); + + struct TestCase { + GURL url; + std::string expected_response; + // How many idle sockets there should be in the SOCKS proxy socket pool + // after the test. + int expected_idle_socks_sockets; + // How many idle sockets there should be in the HTTP proxy socket pool after + // the test. + int expected_idle_http_sockets; + } const kTestCases[] = { + {GURL("http://test/socks4"), "SOCKS4 Response", 1, 0}, + {GURL("http://test/socks5"), "SOCKS5 Response", 2, 0}, + {GURL("http://test/http"), "HTTP Response", 2, 1}, + {GURL("http://test/https"), "HTTPS Response", 2, 2}, + }; + + for (const auto& test_case : kTestCases) { + HttpRequestInfo request; + request.method = "GET"; + request.url = test_case.url; + std::unique_ptr<HttpNetworkTransaction> trans = + std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, + session.get()); + TestCompletionCallback callback; + int rv = trans->Start(&request, callback.callback(), NetLogWithSource()); + EXPECT_THAT(callback.GetResult(rv), IsOk()); + + const HttpResponseInfo* response = trans->GetResponseInfo(); + ASSERT_TRUE(response); + ASSERT_TRUE(response->headers); + EXPECT_EQ(200, response->headers->response_code()); + std::string response_data; + EXPECT_THAT(ReadTransaction(trans.get(), &response_data), IsOk()); + EXPECT_EQ(test_case.expected_response, response_data); + + // Return the socket to the socket pool, so can make sure it's not used for + // the next requests. + trans.reset(); + base::RunLoop().RunUntilIdle(); + + // Check the number of idle sockets in the pool, to make sure that used + // sockets are indeed being returned to the socket pool. If each request + // doesn't return an idle socket to the pool, the test would incorrectly + // pass. + EXPECT_EQ( + test_case.expected_idle_socks_sockets, + session + ->GetSocketPoolForSOCKSProxy( + HttpNetworkSession::NORMAL_SOCKET_POOL, + SameProxyWithDifferentSchemesProxyResolver::ProxyHostPortPair()) + ->IdleSocketCount()); + EXPECT_EQ( + test_case.expected_idle_http_sockets, + session + ->GetSocketPoolForHTTPProxy( + HttpNetworkSession::NORMAL_SOCKET_POOL, + SameProxyWithDifferentSchemesProxyResolver::ProxyHostPortPair()) + ->IdleSocketCount()); + } +} + // Test the load timing for HTTPS requests with an HTTP proxy. TEST_F(HttpNetworkTransactionTest, HttpProxyLoadTimingNoPacTwoRequests) { HttpRequestInfo request1; @@ -6879,6 +7104,82 @@ TEST_F(HttpNetworkTransactionTest, FlushSocketPoolOnLowMemoryNotifications) { EXPECT_EQ(0, GetIdleSocketCountInTransportSocketPool(session.get())); } +// Disable idle socket closing on memory pressure. +// Grab a socket, use it, and put it back into the pool. Then, make +// low memory notification and ensure the socket pool is NOT flushed. +TEST_F(HttpNetworkTransactionTest, NoFlushSocketPoolOnLowMemoryNotifications) { + HttpRequestInfo request; + request.method = "GET"; + request.url = GURL("http://www.example.org/"); + request.load_flags = 0; + + // Disable idle socket closing on memory pressure. + session_deps_.disable_idle_sockets_close_on_memory_pressure = true; + std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_)); + + HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get()); + + MockRead data_reads[] = { + // A part of the response body is received with the response headers. + MockRead("HTTP/1.1 200 OK\r\nContent-Length: 11\r\n\r\nhel"), + // The rest of the response body is received in two parts. + MockRead("lo"), MockRead(" world"), + MockRead("junk"), // Should not be read!! + MockRead(SYNCHRONOUS, OK), + }; + + StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); + session_deps_.socket_factory->AddSocketDataProvider(&data); + + TestCompletionCallback callback; + + int rv = trans.Start(&request, callback.callback(), NetLogWithSource()); + EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); + + EXPECT_THAT(callback.GetResult(rv), IsOk()); + + const HttpResponseInfo* response = trans.GetResponseInfo(); + ASSERT_TRUE(response); + EXPECT_TRUE(response->headers); + std::string status_line = response->headers->GetStatusLine(); + EXPECT_EQ("HTTP/1.1 200 OK", status_line); + + // Make memory critical notification and ensure the transaction still has been + // operating right. + base::MemoryPressureListener::NotifyMemoryPressure( + base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL); + base::RunLoop().RunUntilIdle(); + + // Socket should not be flushed as long as it is not idle. + EXPECT_EQ(0, GetIdleSocketCountInTransportSocketPool(session.get())); + + std::string response_data; + rv = ReadTransaction(&trans, &response_data); + EXPECT_THAT(rv, IsOk()); + EXPECT_EQ("hello world", response_data); + + // Empty the current queue. This is necessary because idle sockets are + // added to the connection pool asynchronously with a PostTask. + base::RunLoop().RunUntilIdle(); + + // We now check to make sure the socket was added back to the pool. + EXPECT_EQ(1, GetIdleSocketCountInTransportSocketPool(session.get())); + + // Idle sockets should NOT be flushed on moderate memory pressure. + base::MemoryPressureListener::NotifyMemoryPressure( + base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(1, GetIdleSocketCountInTransportSocketPool(session.get())); + + // Idle sockets should NOT be flushed on critical memory pressure. + base::MemoryPressureListener::NotifyMemoryPressure( + base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(1, GetIdleSocketCountInTransportSocketPool(session.get())); +} + // Grab an SSL socket, use it, and put it back into the pool. Then, make // low memory notification and ensure the socket pool is flushed. TEST_F(HttpNetworkTransactionTest, FlushSSLSocketPoolOnLowMemoryNotifications) { @@ -8512,20 +8813,21 @@ TEST_F(HttpNetworkTransactionTest, CrossOriginSPDYProxyPush) { CreateMockWrite(stream2_priority, 3, ASYNC), }; + SpdySerializedFrame stream2_syn(spdy_util_.ConstructSpdyPush( + NULL, 0, 2, 1, "http://www.another-origin.com/foo.dat")); + SpdySerializedFrame stream1_reply( spdy_util_.ConstructSpdyGetReply(NULL, 0, 1)); SpdySerializedFrame stream1_body(spdy_util_.ConstructSpdyDataFrame(1, true)); - SpdySerializedFrame stream2_syn(spdy_util_.ConstructSpdyPush( - NULL, 0, 2, 1, "http://www.another-origin.com/foo.dat")); const char kPushedData[] = "pushed"; SpdySerializedFrame stream2_body(spdy_util_.ConstructSpdyDataFrame( 2, kPushedData, strlen(kPushedData), true)); MockRead spdy_reads[] = { - CreateMockRead(stream1_reply, 1, ASYNC), - CreateMockRead(stream2_syn, 2, ASYNC), + CreateMockRead(stream2_syn, 1, ASYNC), + CreateMockRead(stream1_reply, 2, ASYNC), CreateMockRead(stream1_body, 4, ASYNC), CreateMockRead(stream2_body, 5, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6), // Force a hang @@ -9644,44 +9946,42 @@ TEST_F(HttpNetworkTransactionTest, GroupNameForDirectConnections) { EXPECT_EQ(ERR_IO_PENDING, GroupNameTransactionHelper(tests[i].url, session.get())); - if (tests[i].ssl) + if (tests[i].ssl) { EXPECT_EQ(tests[i].expected_group_name, ssl_conn_pool->last_group_name_received()); - else + } else { EXPECT_EQ(tests[i].expected_group_name, transport_conn_pool->last_group_name_received()); + } + // When SSL proxy is in use, socket must be requested from |ssl_conn_pool|. + EXPECT_EQ(tests[i].ssl, ssl_conn_pool->socket_requested()); + // When SSL proxy is not in use, socket must be requested from + // |transport_conn_pool|. + EXPECT_EQ(!tests[i].ssl, transport_conn_pool->socket_requested()); } } TEST_F(HttpNetworkTransactionTest, GroupNameForHTTPProxyConnections) { const GroupNameTest tests[] = { { - "http_proxy", - "http://www.example.org/http_proxy_normal", - "www.example.org:80", - false, + "http_proxy", "http://www.example.org/http_proxy_normal", + "http_proxy/www.example.org:80", false, }, // SSL Tests { - "http_proxy", - "https://www.example.org/http_connect_ssl", - "ssl/www.example.org:443", - true, + "http_proxy", "https://www.example.org/http_connect_ssl", + "http_proxy/ssl/www.example.org:443", true, }, { - "http_proxy", - "https://host.with.alternate/direct", - "ssl/host.with.alternate:443", - true, + "http_proxy", "https://host.with.alternate/direct", + "http_proxy/ssl/host.with.alternate:443", true, }, { - "http_proxy", - "ftp://ftp.google.com/http_proxy_normal", - "ftp/ftp.google.com:21", - false, + "http_proxy", "ftp://ftp.google.com/http_proxy_normal", + "http_proxy/ftp/ftp.google.com:21", false, }, }; @@ -13411,7 +13711,6 @@ TEST_F(HttpNetworkTransactionTest, ProxyTunnelGetHangup) { }; MockRead data_reads1[] = { - MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ), MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"), MockRead(ASYNC, 0, 0), // EOF }; @@ -15430,6 +15729,7 @@ class FakeStream : public HttpStream, RequestPriority priority() const { return priority_; } int InitializeStream(const HttpRequestInfo* request_info, + bool can_send_early, RequestPriority priority, const NetLogWithSource& net_log, const CompletionCallback& callback) override { @@ -15683,10 +15983,12 @@ class FakeWebSocketBasicHandshakeStream : public WebSocketHandshakeStreamBase { // the fact that the WebSocket code is not compiled on iOS makes that // difficult. int InitializeStream(const HttpRequestInfo* request_info, + bool can_send_early, RequestPriority priority, const NetLogWithSource& net_log, const CompletionCallback& callback) override { - state_.Initialize(request_info, priority, net_log, callback); + state_.Initialize(request_info, can_send_early, priority, net_log, + callback); return OK; } @@ -15694,7 +15996,8 @@ class FakeWebSocketBasicHandshakeStream : public WebSocketHandshakeStreamBase { HttpResponseInfo* response, const CompletionCallback& callback) override { return parser()->SendRequest(state_.GenerateRequestLine(), request_headers, - response, callback); + TRAFFIC_ANNOTATION_FOR_TESTS, response, + callback); } int ReadResponseHeaders(const CompletionCallback& callback) override { @@ -15893,8 +16196,7 @@ TEST_F(HttpNetworkTransactionTest, CreateWebSocketHandshakeStream) { HttpNetworkSessionPeer peer(session.get()); FakeStreamFactory* fake_factory = new FakeStreamFactory(); FakeWebSocketStreamCreateHelper websocket_stream_create_helper; - peer.SetHttpStreamFactoryForWebSocket( - std::unique_ptr<HttpStreamFactory>(fake_factory)); + peer.SetHttpStreamFactory(std::unique_ptr<HttpStreamFactory>(fake_factory)); HttpRequestInfo request; HttpNetworkTransaction trans(LOW, session.get()); diff --git a/chromium/net/http/http_proxy_client_socket.cc b/chromium/net/http/http_proxy_client_socket.cc index 4be93e00bee..417a21b96cc 100644 --- a/chromium/net/http/http_proxy_client_socket.cc +++ b/chromium/net/http/http_proxy_client_socket.cc @@ -11,7 +11,6 @@ #include "net/base/auth.h" #include "net/base/host_port_pair.h" #include "net/base/io_buffer.h" -#include "net/base/proxy_delegate.h" #include "net/http/http_basic_stream.h" #include "net/http/http_network_session.h" #include "net/http/http_request_info.h" @@ -21,25 +20,24 @@ #include "net/log/net_log.h" #include "net/log/net_log_event_type.h" #include "net/socket/client_socket_handle.h" +#include "net/traffic_annotation/network_traffic_annotation.h" #include "url/gurl.h" namespace net { HttpProxyClientSocket::HttpProxyClientSocket( - ClientSocketHandle* transport_socket, + std::unique_ptr<ClientSocketHandle> transport_socket, const std::string& user_agent, const HostPortPair& endpoint, - const HostPortPair& proxy_server, HttpAuthController* http_auth_controller, bool tunnel, bool using_spdy, NextProto negotiated_protocol, - ProxyDelegate* proxy_delegate, bool is_https_proxy) : io_callback_(base::Bind(&HttpProxyClientSocket::OnIOComplete, base::Unretained(this))), next_state_(STATE_NONE), - transport_(transport_socket), + transport_(std::move(transport_socket)), endpoint_(endpoint), auth_(http_auth_controller), tunnel_(tunnel), @@ -47,9 +45,7 @@ HttpProxyClientSocket::HttpProxyClientSocket( negotiated_protocol_(negotiated_protocol), is_https_proxy_(is_https_proxy), redirect_has_load_timing_info_(false), - proxy_server_(proxy_server), - proxy_delegate_(proxy_delegate), - net_log_(transport_socket->socket()->NetLog()) { + net_log_(transport_->socket()->NetLog()) { // Synthesize the bits of a request that we actually use. request_.url = GURL("https://" + endpoint.ToString()); request_.method = "CONNECT"; @@ -207,6 +203,10 @@ int64_t HttpProxyClientSocket::GetTotalReceivedBytes() const { return transport_->socket()->GetTotalReceivedBytes(); } +void HttpProxyClientSocket::ApplySocketTag(const SocketTag& tag) { + return transport_->socket()->ApplySocketTag(tag); +} + int HttpProxyClientSocket::Read(IOBuffer* buf, int buf_len, const CompletionCallback& callback) { DCHECK(user_callback_.is_null()); @@ -227,12 +227,16 @@ int HttpProxyClientSocket::Read(IOBuffer* buf, int buf_len, return transport_->socket()->Read(buf, buf_len, callback); } -int HttpProxyClientSocket::Write(IOBuffer* buf, int buf_len, - const CompletionCallback& callback) { +int HttpProxyClientSocket::Write( + IOBuffer* buf, + int buf_len, + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& traffic_annotation) { DCHECK_EQ(STATE_DONE, next_state_); DCHECK(user_callback_.is_null()); - return transport_->socket()->Write(buf, buf_len, callback); + return transport_->socket()->Write(buf, buf_len, callback, + traffic_annotation); } int HttpProxyClientSocket::SetReceiveBufferSize(int32_t size) { @@ -396,10 +400,6 @@ int HttpProxyClientSocket::DoSendRequest() { HttpRequestHeaders authorization_headers; if (auth_->HaveAuth()) auth_->AddAuthorizationHeader(&authorization_headers); - if (proxy_delegate_) { - proxy_delegate_->OnBeforeTunnelRequest(proxy_server_, - &authorization_headers); - } std::string user_agent; if (!request_.extra_headers.GetHeader(HttpRequestHeaders::kUserAgent, &user_agent)) { @@ -417,8 +417,10 @@ int HttpProxyClientSocket::DoSendRequest() { parser_buf_ = new GrowableIOBuffer(); http_stream_parser_.reset(new HttpStreamParser( transport_.get(), &request_, parser_buf_.get(), net_log_)); - return http_stream_parser_->SendRequest( - request_line_, request_headers_, &response_, io_callback_); + // TODO(crbug.com/656607): Add propoer annotation. + return http_stream_parser_->SendRequest(request_line_, request_headers_, + NO_TRAFFIC_ANNOTATION_BUG_656607, + &response_, io_callback_); } int HttpProxyClientSocket::DoSendRequestComplete(int result) { @@ -446,13 +448,6 @@ int HttpProxyClientSocket::DoReadHeadersComplete(int result) { NetLogEventType::HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS, base::Bind(&HttpResponseHeaders::NetLogCallback, response_.headers)); - if (proxy_delegate_) { - proxy_delegate_->OnTunnelHeadersReceived( - HostPortPair::FromURL(request_.url), - proxy_server_, - *response_.headers); - } - switch (response_.headers->response_code()) { case 200: // OK if (http_stream_parser_->IsMoreDataBuffered()) diff --git a/chromium/net/http/http_proxy_client_socket.h b/chromium/net/http/http_proxy_client_socket.h index 7c05a29b6df..8444be2069f 100644 --- a/chromium/net/http/http_proxy_client_socket.h +++ b/chromium/net/http/http_proxy_client_socket.h @@ -23,6 +23,7 @@ #include "net/http/proxy_client_socket.h" #include "net/log/net_log_with_source.h" #include "net/socket/ssl_client_socket.h" +#include "net/traffic_annotation/network_traffic_annotation.h" namespace net { @@ -31,22 +32,19 @@ class GrowableIOBuffer; class HttpStream; class HttpStreamParser; class IOBuffer; -class ProxyDelegate; class NET_EXPORT_PRIVATE HttpProxyClientSocket : public ProxyClientSocket { public: // Takes ownership of |transport_socket|, which should already be connected // by the time Connect() is called. If tunnel is true then on Connect() // this socket will establish an Http tunnel. - HttpProxyClientSocket(ClientSocketHandle* transport_socket, + HttpProxyClientSocket(std::unique_ptr<ClientSocketHandle> transport_socket, const std::string& user_agent, const HostPortPair& endpoint, - const HostPortPair& proxy_server, HttpAuthController* http_auth_controller, bool tunnel, bool using_spdy, NextProto negotiated_protocol, - ProxyDelegate* proxy_delegate, bool is_https_proxy); // On destruction Disconnect() is called. @@ -76,6 +74,7 @@ class NET_EXPORT_PRIVATE HttpProxyClientSocket : public ProxyClientSocket { void ClearConnectionAttempts() override {} void AddConnectionAttempts(const ConnectionAttempts& attempts) override {} int64_t GetTotalReceivedBytes() const override; + void ApplySocketTag(const SocketTag& tag) override; // Socket implementation. int Read(IOBuffer* buf, @@ -83,7 +82,8 @@ class NET_EXPORT_PRIVATE HttpProxyClientSocket : public ProxyClientSocket { const CompletionCallback& callback) override; int Write(IOBuffer* buf, int buf_len, - const CompletionCallback& callback) override; + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& traffic_annotation) override; int SetReceiveBufferSize(int32_t size) override; int SetSendBufferSize(int32_t size) override; int GetPeerAddress(IPEndPoint* address) const override; @@ -161,11 +161,6 @@ class NET_EXPORT_PRIVATE HttpProxyClientSocket : public ProxyClientSocket { bool redirect_has_load_timing_info_; LoadTimingInfo redirect_load_timing_info_; - const HostPortPair proxy_server_; - - // This delegate must outlive this proxy client socket. - ProxyDelegate* proxy_delegate_; - const NetLogWithSource net_log_; DISALLOW_COPY_AND_ASSIGN(HttpProxyClientSocket); diff --git a/chromium/net/http/http_proxy_client_socket_fuzzer.cc b/chromium/net/http/http_proxy_client_socket_fuzzer.cc index 33c076f7284..ac9702ab767 100644 --- a/chromium/net/http/http_proxy_client_socket_fuzzer.cc +++ b/chromium/net/http/http_proxy_client_socket_fuzzer.cc @@ -64,10 +64,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { // is HTTPS. bool is_https_proxy = data_provider.ConsumeBool(); net::HttpProxyClientSocket socket( - socket_handle.release(), "Bond/007", net::HostPortPair("foo", 80), - net::HostPortPair("proxy", 42), auth_controller.get(), true /* tunnel */, - false /* using_spdy */, net::kProtoUnknown, nullptr /* proxy_delegate */, - is_https_proxy); + std::move(socket_handle), "Bond/007", net::HostPortPair("foo", 80), + auth_controller.get(), true /* tunnel */, false /* using_spdy */, + net::kProtoUnknown, is_https_proxy); int result = socket.Connect(callback.callback()); result = callback.GetResult(result); diff --git a/chromium/net/http/http_proxy_client_socket_pool.cc b/chromium/net/http/http_proxy_client_socket_pool.cc index ab7bbb30b67..1e3ec469be1 100644 --- a/chromium/net/http/http_proxy_client_socket_pool.cc +++ b/chromium/net/http/http_proxy_client_socket_pool.cc @@ -18,7 +18,6 @@ #include "base/values.h" #include "net/base/load_flags.h" #include "net/base/net_errors.h" -#include "net/base/proxy_delegate.h" #include "net/http/http_network_session.h" #include "net/http/http_proxy_client_socket_wrapper.h" #include "net/log/net_log_source_type.h" @@ -85,8 +84,7 @@ HttpProxySocketParams::HttpProxySocketParams( HttpAuthHandlerFactory* http_auth_handler_factory, SpdySessionPool* spdy_session_pool, QuicStreamFactory* quic_stream_factory, - bool tunnel, - ProxyDelegate* proxy_delegate) + bool tunnel) : transport_params_(transport_params), ssl_params_(ssl_params), quic_version_(quic_version), @@ -96,8 +94,7 @@ HttpProxySocketParams::HttpProxySocketParams( endpoint_(endpoint), http_auth_cache_(tunnel ? http_auth_cache : NULL), http_auth_handler_factory_(tunnel ? http_auth_handler_factory : NULL), - tunnel_(tunnel), - proxy_delegate_(proxy_delegate) { + tunnel_(tunnel) { // If doing a QUIC proxy, |quic_version| must not be QUIC_VERSION_UNSUPPORTED, // and |ssl_params| must be valid while |transport_params| is null. // Otherwise, |quic_version| must be QUIC_VERSION_UNSUPPORTED, and exactly @@ -105,6 +102,9 @@ HttpProxySocketParams::HttpProxySocketParams( DCHECK(quic_version_ == QUIC_VERSION_UNSUPPORTED ? (bool)transport_params != (bool)ssl_params : !transport_params && ssl_params); + // Exactly one of |transport_params_| and |ssl_params_| must be non-null. + DCHECK(transport_params_ || ssl_params_); + DCHECK(!transport_params_ || !ssl_params_); } const HostResolver::RequestInfo& HttpProxySocketParams::destination() const { @@ -120,6 +120,7 @@ HttpProxySocketParams::~HttpProxySocketParams() = default; HttpProxyConnectJob::HttpProxyConnectJob( const std::string& group_name, RequestPriority priority, + const SocketTag& socket_tag, ClientSocketPool::RespectLimits respect_limits, const scoped_refptr<HttpProxySocketParams>& params, const base::TimeDelta& timeout_duration, @@ -131,6 +132,7 @@ HttpProxyConnectJob::HttpProxyConnectJob( group_name, base::TimeDelta() /* The socket takes care of timeouts */, priority, + socket_tag, respect_limits, delegate, NetLogWithSource::Make(net_log, @@ -138,6 +140,7 @@ HttpProxyConnectJob::HttpProxyConnectJob( client_socket_(new HttpProxyClientSocketWrapper( group_name, priority, + socket_tag, respect_limits, timeout_duration, base::TimeDelta::FromSeconds(kHttpProxyConnectJobTimeoutInSeconds), @@ -153,7 +156,6 @@ HttpProxyConnectJob::HttpProxyConnectJob( params->spdy_session_pool(), params->quic_stream_factory(), params->tunnel(), - params->proxy_delegate(), this->net_log())) {} HttpProxyConnectJob::~HttpProxyConnectJob() = default; @@ -201,13 +203,16 @@ HttpProxyClientSocketPool::HttpProxyConnectJobFactory:: : transport_pool_(transport_pool), ssl_pool_(ssl_pool), network_quality_provider_(network_quality_provider), - transport_rtt_multiplier_(GetInt32Param("transport_rtt_multiplier", 5)), + ssl_http_rtt_multiplier_(GetInt32Param("ssl_http_rtt_multiplier", 5)), + non_ssl_http_rtt_multiplier_( + GetInt32Param("non_ssl_http_rtt_multiplier", 5)), min_proxy_connection_timeout_(base::TimeDelta::FromSeconds( GetInt32Param("min_proxy_connection_timeout_seconds", 8))), max_proxy_connection_timeout_(base::TimeDelta::FromSeconds( GetInt32Param("max_proxy_connection_timeout_seconds", 60))), net_log_(net_log) { - DCHECK_LT(0, transport_rtt_multiplier_); + DCHECK_LT(0, ssl_http_rtt_multiplier_); + DCHECK_LT(0, non_ssl_http_rtt_multiplier_); DCHECK_LE(base::TimeDelta(), min_proxy_connection_timeout_); DCHECK_LE(base::TimeDelta(), max_proxy_connection_timeout_); DCHECK_LE(min_proxy_connection_timeout_, max_proxy_connection_timeout_); @@ -218,23 +223,35 @@ HttpProxyClientSocketPool::HttpProxyConnectJobFactory::NewConnectJob( const std::string& group_name, const PoolBase::Request& request, ConnectJob::Delegate* delegate) const { + bool is_secure_connection = (request.params()->ssl_params() != nullptr); + return std::unique_ptr<ConnectJob>(new HttpProxyConnectJob( - group_name, request.priority(), request.respect_limits(), - request.params(), ConnectionTimeout(), transport_pool_, ssl_pool_, - delegate, net_log_)); + group_name, request.priority(), request.socket_tag(), + request.respect_limits(), request.params(), + ConnectionTimeoutWithConnectionProperty(is_secure_connection), + transport_pool_, ssl_pool_, delegate, net_log_)); } base::TimeDelta HttpProxyClientSocketPool::HttpProxyConnectJobFactory::ConnectionTimeout() const { + // Take a conservative approach: Return the timeout for the secure proxies + // which is higher than the connection timeout for the insecure proxies. + return ConnectionTimeoutWithConnectionProperty( + true /* is_secure_connection */); +} + +base::TimeDelta HttpProxyClientSocketPool::HttpProxyConnectJobFactory:: + ConnectionTimeoutWithConnectionProperty(bool is_secure_connection) const { if (IsInNetAdaptiveProxyConnectionTimeoutFieldTrial() && network_quality_provider_) { - base::Optional<base::TimeDelta> transport_rtt_estimate = - network_quality_provider_->GetTransportRTT(); - if (transport_rtt_estimate) { - base::TimeDelta timeout = base::TimeDelta::FromMilliseconds( - transport_rtt_multiplier_ * - transport_rtt_estimate.value().InMilliseconds()); + base::Optional<base::TimeDelta> http_rtt_estimate = + network_quality_provider_->GetHttpRTT(); + if (http_rtt_estimate) { + int32_t multiplier = is_secure_connection ? ssl_http_rtt_multiplier_ + : non_ssl_http_rtt_multiplier_; + base::TimeDelta timeout = base::TimeDelta::FromMicroseconds( + multiplier * http_rtt_estimate.value().InMicroseconds()); // Ensure that connection timeout is between // |min_proxy_connection_timeout_| and |max_proxy_connection_timeout_|. if (timeout < min_proxy_connection_timeout_) @@ -290,6 +307,7 @@ HttpProxyClientSocketPool::~HttpProxyClientSocketPool() = default; int HttpProxyClientSocketPool::RequestSocket(const std::string& group_name, const void* socket_params, RequestPriority priority, + const SocketTag& socket_tag, RespectLimits respect_limits, ClientSocketHandle* handle, const CompletionCallback& callback, @@ -298,7 +316,8 @@ int HttpProxyClientSocketPool::RequestSocket(const std::string& group_name, static_cast<const scoped_refptr<HttpProxySocketParams>*>(socket_params); return base_.RequestSocket(group_name, *casted_socket_params, priority, - respect_limits, handle, callback, net_log); + socket_tag, respect_limits, handle, callback, + net_log); } void HttpProxyClientSocketPool::RequestSockets( diff --git a/chromium/net/http/http_proxy_client_socket_pool.h b/chromium/net/http/http_proxy_client_socket_pool.h index 0df5e47f33e..09fa48d69c2 100644 --- a/chromium/net/http/http_proxy_client_socket_pool.h +++ b/chromium/net/http/http_proxy_client_socket_pool.h @@ -31,7 +31,6 @@ class HttpAuthHandlerFactory; class HttpProxyClientSocketWrapper; class NetLog; class NetworkQualityProvider; -class ProxyDelegate; class QuicStreamFactory; class SSLClientSocketPool; class SSLSocketParams; @@ -57,8 +56,7 @@ class NET_EXPORT_PRIVATE HttpProxySocketParams HttpAuthHandlerFactory* http_auth_handler_factory, SpdySessionPool* spdy_session_pool, QuicStreamFactory* quic_stream_factory, - bool tunnel, - ProxyDelegate* proxy_delegate); + bool tunnel); const scoped_refptr<TransportSocketParams>& transport_params() const { return transport_params_; @@ -82,10 +80,6 @@ class NET_EXPORT_PRIVATE HttpProxySocketParams const HostResolver::RequestInfo& destination() const; bool tunnel() const { return tunnel_; } - ProxyDelegate* proxy_delegate() const { - return proxy_delegate_; - } - private: friend class base::RefCounted<HttpProxySocketParams>; ~HttpProxySocketParams(); @@ -100,7 +94,6 @@ class NET_EXPORT_PRIVATE HttpProxySocketParams HttpAuthCache* const http_auth_cache_; HttpAuthHandlerFactory* const http_auth_handler_factory_; const bool tunnel_; - ProxyDelegate* proxy_delegate_; DISALLOW_COPY_AND_ASSIGN(HttpProxySocketParams); }; @@ -111,6 +104,7 @@ class HttpProxyConnectJob : public ConnectJob { public: HttpProxyConnectJob(const std::string& group_name, RequestPriority priority, + const SocketTag& socket_tag, ClientSocketPool::RespectLimits respect_limits, const scoped_refptr<HttpProxySocketParams>& params, const base::TimeDelta& timeout_duration, @@ -165,6 +159,7 @@ class NET_EXPORT_PRIVATE HttpProxyClientSocketPool int RequestSocket(const std::string& group_name, const void* connect_params, RequestPriority priority, + const SocketTag& socket_tag, RespectLimits respect_limits, ClientSocketHandle* handle, const CompletionCallback& callback, @@ -218,9 +213,13 @@ class NET_EXPORT_PRIVATE HttpProxyClientSocketPool bool CloseOneIdleConnection() override; private: + FRIEND_TEST_ALL_PREFIXES(HttpProxyClientSocketPoolTest, + ProxyPoolTimeoutWithConnectionProperty); + typedef ClientSocketPoolBase<HttpProxySocketParams> PoolBase; - class HttpProxyConnectJobFactory : public PoolBase::ConnectJobFactory { + class NET_EXPORT_PRIVATE HttpProxyConnectJobFactory + : public PoolBase::ConnectJobFactory { public: HttpProxyConnectJobFactory(TransportClientSocketPool* transport_pool, SSLClientSocketPool* ssl_pool, @@ -236,12 +235,30 @@ class NET_EXPORT_PRIVATE HttpProxyClientSocketPool base::TimeDelta ConnectionTimeout() const override; private: + FRIEND_TEST_ALL_PREFIXES(HttpProxyClientSocketPoolTest, + ProxyPoolTimeoutWithConnectionProperty); + + // Returns proxy connection timeout for secure proxies if + // |is_secure_connection| is true. Otherwise, returns timeout for insecure + // proxies. + base::TimeDelta ConnectionTimeoutWithConnectionProperty( + bool is_secure_connection) const; + TransportClientSocketPool* const transport_pool_; SSLClientSocketPool* const ssl_pool_; - NetworkQualityProvider* network_quality_provider_; - const int32_t transport_rtt_multiplier_; + NetworkQualityProvider* const network_quality_provider_; + + // For secure proxies, the connection timeout is set to + // |ssl_http_rtt_multiplier_| times the HTTP RTT estimate. For insecure + // proxies, the connection timeout is set to |non_ssl_http_rtt_multiplier_| + // times the HTTP RTT estimate. In either case, the connection timeout + // is clamped to be between |min_proxy_connection_timeout_| and + // |max_proxy_connection_timeout_|. + const int32_t ssl_http_rtt_multiplier_; + const int32_t non_ssl_http_rtt_multiplier_; const base::TimeDelta min_proxy_connection_timeout_; const base::TimeDelta max_proxy_connection_timeout_; + NetLog* net_log_; DISALLOW_COPY_AND_ASSIGN(HttpProxyConnectJobFactory); diff --git a/chromium/net/http/http_proxy_client_socket_pool_unittest.cc b/chromium/net/http/http_proxy_client_socket_pool_unittest.cc index 2cf01c156cd..c3c483693ab 100644 --- a/chromium/net/http/http_proxy_client_socket_pool_unittest.cc +++ b/chromium/net/http/http_proxy_client_socket_pool_unittest.cc @@ -17,10 +17,9 @@ #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "base/test/histogram_tester.h" +#include "build/build_config.h" #include "net/base/net_errors.h" -#include "net/base/proxy_delegate.h" #include "net/base/test_completion_callback.h" -#include "net/base/test_proxy_delegate.h" #include "net/http/http_network_session.h" #include "net/http/http_proxy_client_socket.h" #include "net/http/http_response_headers.h" @@ -28,6 +27,7 @@ #include "net/nqe/network_quality_estimator_test_util.h" #include "net/socket/client_socket_handle.h" #include "net/socket/next_proto.h" +#include "net/socket/socket_tag.h" #include "net/socket/socket_test_util.h" #include "net/spdy/chromium/spdy_test_util_common.h" #include "net/spdy/core/spdy_protocol.h" @@ -66,7 +66,7 @@ class HttpProxyClientSocketPoolTest HttpProxyClientSocketPoolTest() : transport_socket_pool_(kMaxSockets, kMaxSocketsPerGroup, - session_deps_.socket_factory.get()), + &socket_factory_), ssl_socket_pool_(kMaxSockets, kMaxSocketsPerGroup, session_deps_.cert_verifier.get(), @@ -75,7 +75,7 @@ class HttpProxyClientSocketPoolTest NULL /* cert_transparency_verifier */, NULL /* ct_policy_enforcer */, std::string() /* ssl_session_cache_shard */, - session_deps_.socket_factory.get(), + &socket_factory_, &transport_socket_pool_, NULL, NULL, @@ -98,7 +98,8 @@ class HttpProxyClientSocketPoolTest // connection timeout based on the network quality. void InitAdaptiveTimeoutFieldTrialWithParams( bool use_default_params, - int transport_rtt_multiplier, + int ssl_http_rtt_multiplier, + int non_ssl_http_rtt_multiplier, base::TimeDelta min_proxy_connection_timeout, base::TimeDelta max_proxy_connection_timeout) { std::string trial_name = "NetAdaptiveProxyConnectionTimeout"; @@ -106,8 +107,10 @@ class HttpProxyClientSocketPoolTest std::map<std::string, std::string> params; if (!use_default_params) { - params["transport_rtt_multiplier"] = - base::IntToString(transport_rtt_multiplier); + params["ssl_http_rtt_multiplier"] = + base::IntToString(ssl_http_rtt_multiplier); + params["non_ssl_http_rtt_multiplier"] = + base::IntToString(non_ssl_http_rtt_multiplier); params["min_proxy_connection_timeout_seconds"] = base::IntToString(min_proxy_connection_timeout.InSeconds()); params["max_proxy_connection_timeout_seconds"] = @@ -169,31 +172,24 @@ class HttpProxyClientSocketPoolTest // Returns the a correctly constructed HttpProxyParms // for the HTTP or HTTPS proxy. - scoped_refptr<HttpProxySocketParams> CreateParams( - bool tunnel, - ProxyDelegate* proxy_delegate) { - return scoped_refptr<HttpProxySocketParams>(new HttpProxySocketParams( + scoped_refptr<HttpProxySocketParams> CreateParams(bool tunnel) { + return base::MakeRefCounted<HttpProxySocketParams>( CreateHttpProxyParams(), CreateHttpsProxyParams(), QUIC_VERSION_UNSUPPORTED, std::string(), HostPortPair("www.google.com", tunnel ? 443 : 80), session_->http_auth_cache(), session_->http_auth_handler_factory(), - session_->spdy_session_pool(), session_->quic_stream_factory(), tunnel, - proxy_delegate)); + session_->spdy_session_pool(), session_->quic_stream_factory(), tunnel); } - scoped_refptr<HttpProxySocketParams> CreateTunnelParams( - ProxyDelegate* proxy_delegate) { - return CreateParams(true, proxy_delegate); + scoped_refptr<HttpProxySocketParams> CreateTunnelParams() { + return CreateParams(true); } - scoped_refptr<HttpProxySocketParams> CreateNoTunnelParams( - ProxyDelegate* proxy_delegate) { - return CreateParams(false, proxy_delegate); + scoped_refptr<HttpProxySocketParams> CreateNoTunnelParams() { + return CreateParams(false); } - MockClientSocketFactory* socket_factory() { - return session_deps_.socket_factory.get(); - } + MockTaggingClientSocketFactory* socket_factory() { return &socket_factory_; } void Initialize(MockRead* reads, size_t reads_count, MockWrite* writes, size_t writes_count, @@ -234,7 +230,13 @@ class HttpProxyClientSocketPoolTest TestNetworkQualityEstimator* estimator() { return &estimator_; } + MockTransportClientSocketPool* transport_socket_pool() { + return &transport_socket_pool_; + } + SSLClientSocketPool* ssl_socket_pool() { return &ssl_socket_pool_; } + private: + MockTaggingClientSocketFactory socket_factory_; SpdySessionDependencies session_deps_; TestNetworkQualityEstimator estimator_; @@ -268,17 +270,13 @@ INSTANTIATE_TEST_CASE_P(HttpProxyType, TEST_P(HttpProxyClientSocketPoolTest, NoTunnel) { Initialize(NULL, 0, NULL, 0, NULL, 0, NULL, 0); - std::unique_ptr<TestProxyDelegate> proxy_delegate(new TestProxyDelegate()); - int rv = handle_.Init("a", CreateNoTunnelParams(proxy_delegate.get()), LOW, + int rv = handle_.Init("a", CreateNoTunnelParams(), LOW, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, CompletionCallback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsOk()); EXPECT_TRUE(handle_.is_initialized()); ASSERT_TRUE(handle_.socket()); EXPECT_TRUE(handle_.socket()->IsConnected()); - EXPECT_FALSE(proxy_delegate->on_before_tunnel_request_called()); - EXPECT_FALSE(proxy_delegate->on_tunnel_headers_received_called()); - EXPECT_TRUE(proxy_delegate->on_tunnel_request_completed_called()); bool is_secure_proxy = GetParam() == HTTPS || GetParam() == SPDY; histogram_tester().ExpectTotalCount( @@ -292,7 +290,7 @@ TEST_P(HttpProxyClientSocketPoolTest, NoTunnel) { TEST_P(HttpProxyClientSocketPoolTest, SetSocketRequestPriorityOnInit) { Initialize(NULL, 0, NULL, 0, NULL, 0, NULL, 0); EXPECT_EQ( - OK, handle_.Init("a", CreateNoTunnelParams(NULL), HIGHEST, + OK, handle_.Init("a", CreateNoTunnelParams(), HIGHEST, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, CompletionCallback(), pool_.get(), NetLogWithSource())); EXPECT_EQ(HIGHEST, GetLastTransportRequestPriority()); @@ -332,7 +330,7 @@ TEST_P(HttpProxyClientSocketPoolTest, NeedAuth) { spdy_reads, arraysize(spdy_reads), spdy_writes, arraysize(spdy_writes)); - int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW, + int rv = handle_.Init("a", CreateTunnelParams(), LOW, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback_.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); @@ -366,9 +364,7 @@ TEST_P(HttpProxyClientSocketPoolTest, HaveAuth) { "CONNECT www.google.com:443 HTTP/1.1\r\n" "Host: www.google.com:443\r\n" "Proxy-Connection: keep-alive\r\n" - "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n" - "Foo: " + - proxy_host_port + "\r\n\r\n"; + "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"; MockWrite writes[] = { MockWrite(SYNCHRONOUS, 0, request.c_str()), }; @@ -380,21 +376,13 @@ TEST_P(HttpProxyClientSocketPoolTest, HaveAuth) { NULL, 0); AddAuthToCache(); - std::unique_ptr<TestProxyDelegate> proxy_delegate(new TestProxyDelegate()); - int rv = handle_.Init("a", CreateTunnelParams(proxy_delegate.get()), LOW, + int rv = handle_.Init("a", CreateTunnelParams(), LOW, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback_.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsOk()); EXPECT_TRUE(handle_.is_initialized()); ASSERT_TRUE(handle_.socket()); EXPECT_TRUE(handle_.socket()->IsConnected()); - proxy_delegate->VerifyOnTunnelHeadersReceived( - "www.google.com:443", - proxy_host_port.c_str(), - "HTTP/1.1 200 Connection Established"); - proxy_delegate->VerifyOnTunnelRequestCompleted( - "www.google.com:443", - proxy_host_port.c_str()); } TEST_P(HttpProxyClientSocketPoolTest, AsyncHaveAuth) { @@ -405,9 +393,7 @@ TEST_P(HttpProxyClientSocketPoolTest, AsyncHaveAuth) { "CONNECT www.google.com:443 HTTP/1.1\r\n" "Host: www.google.com:443\r\n" "Proxy-Connection: keep-alive\r\n" - "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n" - "Foo: " + - proxy_host_port + "\r\n\r\n"; + "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"; MockWrite writes[] = { MockWrite(ASYNC, 0, request.c_str()), }; @@ -431,8 +417,7 @@ TEST_P(HttpProxyClientSocketPoolTest, AsyncHaveAuth) { arraysize(spdy_writes)); AddAuthToCache(); - std::unique_ptr<TestProxyDelegate> proxy_delegate(new TestProxyDelegate()); - int rv = handle_.Init("a", CreateTunnelParams(proxy_delegate.get()), LOW, + int rv = handle_.Init("a", CreateTunnelParams(), LOW, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback_.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); @@ -443,9 +428,6 @@ TEST_P(HttpProxyClientSocketPoolTest, AsyncHaveAuth) { EXPECT_TRUE(handle_.is_initialized()); ASSERT_TRUE(handle_.socket()); EXPECT_TRUE(handle_.socket()->IsConnected()); - proxy_delegate->VerifyOnTunnelRequestCompleted( - "www.google.com:443", - proxy_host_port.c_str()); } // Make sure that HttpProxyConnectJob passes on its priority to its @@ -470,7 +452,7 @@ TEST_P(HttpProxyClientSocketPoolTest, EXPECT_EQ( ERR_IO_PENDING, - handle_.Init("a", CreateTunnelParams(NULL), MEDIUM, + handle_.Init("a", CreateTunnelParams(), MEDIUM, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback_.callback(), pool_.get(), NetLogWithSource())); EXPECT_EQ(MEDIUM, GetLastTransportRequestPriority()); @@ -486,7 +468,7 @@ TEST_P(HttpProxyClientSocketPoolTest, TCPError) { socket_factory()->AddSocketDataProvider(data_.get()); - int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW, + int rv = handle_.Init("a", CreateTunnelParams(), LOW, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback_.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); @@ -519,7 +501,7 @@ TEST_P(HttpProxyClientSocketPoolTest, SSLError) { } socket_factory()->AddSSLSocketDataProvider(ssl_data_.get()); - int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW, + int rv = handle_.Init("a", CreateTunnelParams(), LOW, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback_.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); @@ -551,7 +533,7 @@ TEST_P(HttpProxyClientSocketPoolTest, SslClientAuth) { } socket_factory()->AddSSLSocketDataProvider(ssl_data_.get()); - int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW, + int rv = handle_.Init("a", CreateTunnelParams(), LOW, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback_.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); @@ -594,7 +576,7 @@ TEST_P(HttpProxyClientSocketPoolTest, TunnelUnexpectedClose) { arraysize(spdy_writes)); AddAuthToCache(); - int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW, + int rv = handle_.Init("a", CreateTunnelParams(), LOW, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback_.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); @@ -634,7 +616,7 @@ TEST_P(HttpProxyClientSocketPoolTest, Tunnel1xxResponse) { Initialize(reads, arraysize(reads), writes, arraysize(writes), NULL, 0, NULL, 0); - int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW, + int rv = handle_.Init("a", CreateTunnelParams(), LOW, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback_.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); @@ -673,7 +655,7 @@ TEST_P(HttpProxyClientSocketPoolTest, TunnelSetupError) { arraysize(spdy_writes)); AddAuthToCache(); - int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW, + int rv = handle_.Init("a", CreateTunnelParams(), LOW, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback_.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); @@ -730,7 +712,7 @@ TEST_P(HttpProxyClientSocketPoolTest, TunnelSetupRedirect) { arraysize(spdy_writes)); AddAuthToCache(); - int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW, + int rv = handle_.Init("a", CreateTunnelParams(), LOW, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback_.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); @@ -783,104 +765,155 @@ TEST_P(HttpProxyClientSocketPoolTest, ProxyPoolTimeout) { // Tests the connection timeout values when the field trial parameters are // specified. TEST_P(HttpProxyClientSocketPoolTest, ProxyPoolTimeoutWithExperiment) { - int transport_rtt_multiplier = 2; - base::TimeDelta min_timeout = base::TimeDelta::FromSeconds(8); - base::TimeDelta max_timeout = base::TimeDelta::FromSeconds(20); + // Timeout should be kMultiplier times the HTTP RTT estimate. + const int kMultiplier = 4; + const base::TimeDelta kMinTimeout = base::TimeDelta::FromSeconds(8); + const base::TimeDelta kMaxTimeout = base::TimeDelta::FromSeconds(20); - InitAdaptiveTimeoutFieldTrialWithParams(false, transport_rtt_multiplier, - min_timeout, max_timeout); + InitAdaptiveTimeoutFieldTrialWithParams(false, kMultiplier, kMultiplier, + kMinTimeout, kMaxTimeout); EXPECT_LE(base::TimeDelta(), pool_->ConnectionTimeout()); - // Timeout should be |transport_rtt_multiplier| times the transport RTT - // estimate. - base::TimeDelta rtt_estimate = base::TimeDelta::FromSeconds(7); - estimator()->set_start_time_null_transport_rtt(rtt_estimate); - EXPECT_EQ(rtt_estimate + rtt_estimate, pool_->ConnectionTimeout()); - - // A change in RTT estimate should also change the connection timeout. - rtt_estimate = base::TimeDelta::FromSeconds(8); - estimator()->set_start_time_null_transport_rtt(rtt_estimate); - EXPECT_EQ(rtt_estimate + rtt_estimate, pool_->ConnectionTimeout()); + base::TimeDelta rtt_estimate = base::TimeDelta::FromSeconds(4); + estimator()->SetStartTimeNullHttpRtt(rtt_estimate); + base::TimeDelta expected_connection_timeout = kMultiplier * rtt_estimate; + EXPECT_EQ(expected_connection_timeout, pool_->ConnectionTimeout()); - // Connection timeout should not exceed |max_timeout|. + // Connection timeout should not exceed kMaxTimeout. rtt_estimate = base::TimeDelta::FromSeconds(25); - estimator()->set_start_time_null_transport_rtt(rtt_estimate); - EXPECT_EQ(max_timeout, pool_->ConnectionTimeout()); + estimator()->SetStartTimeNullHttpRtt(rtt_estimate); + EXPECT_EQ(kMaxTimeout, pool_->ConnectionTimeout()); - // Connection timeout should not be less than |min_timeout|. + // Connection timeout should not be less than kMinTimeout. rtt_estimate = base::TimeDelta::FromSeconds(0); - estimator()->set_start_time_null_transport_rtt(rtt_estimate); - EXPECT_EQ(min_timeout, pool_->ConnectionTimeout()); + estimator()->SetStartTimeNullHttpRtt(rtt_estimate); + EXPECT_EQ(kMinTimeout, pool_->ConnectionTimeout()); } // Tests the connection timeout values when the field trial parameters are // specified. TEST_P(HttpProxyClientSocketPoolTest, ProxyPoolTimeoutWithExperimentDifferentParams) { - int transport_rtt_multiplier = 3; - base::TimeDelta min_timeout = base::TimeDelta::FromSeconds(2); - base::TimeDelta max_timeout = base::TimeDelta::FromSeconds(30); + // Timeout should be kMultiplier times the HTTP RTT estimate. + const int kMultiplier = 3; + const base::TimeDelta kMinTimeout = base::TimeDelta::FromSeconds(2); + const base::TimeDelta kMaxTimeout = base::TimeDelta::FromSeconds(30); - InitAdaptiveTimeoutFieldTrialWithParams(false, transport_rtt_multiplier, - min_timeout, max_timeout); + InitAdaptiveTimeoutFieldTrialWithParams(false, kMultiplier, kMultiplier, + kMinTimeout, kMaxTimeout); EXPECT_LE(base::TimeDelta(), pool_->ConnectionTimeout()); - // Timeout should be |transport_rtt_multiplier| times the transport RTT - // estimate. base::TimeDelta rtt_estimate = base::TimeDelta::FromSeconds(2); - estimator()->set_start_time_null_transport_rtt(rtt_estimate); - EXPECT_EQ(rtt_estimate + rtt_estimate + rtt_estimate, - pool_->ConnectionTimeout()); + estimator()->SetStartTimeNullHttpRtt(rtt_estimate); + EXPECT_EQ(kMultiplier * rtt_estimate, pool_->ConnectionTimeout()); // A change in RTT estimate should also change the connection timeout. rtt_estimate = base::TimeDelta::FromSeconds(7); - estimator()->set_start_time_null_transport_rtt(rtt_estimate); - EXPECT_EQ(rtt_estimate + rtt_estimate + rtt_estimate, - pool_->ConnectionTimeout()); + estimator()->SetStartTimeNullHttpRtt(rtt_estimate); + EXPECT_EQ(kMultiplier * rtt_estimate, pool_->ConnectionTimeout()); - // Connection timeout should not exceed |max_timeout|. + // Connection timeout should not exceed kMaxTimeout. rtt_estimate = base::TimeDelta::FromSeconds(35); - estimator()->set_start_time_null_transport_rtt(rtt_estimate); - EXPECT_EQ(max_timeout, pool_->ConnectionTimeout()); + estimator()->SetStartTimeNullHttpRtt(rtt_estimate); + EXPECT_EQ(kMaxTimeout, pool_->ConnectionTimeout()); - // Connection timeout should not be less than |min_timeout|. + // Connection timeout should not be less than kMinTimeout. rtt_estimate = base::TimeDelta::FromSeconds(0); - estimator()->set_start_time_null_transport_rtt(rtt_estimate); - EXPECT_EQ(min_timeout, pool_->ConnectionTimeout()); + estimator()->SetStartTimeNullHttpRtt(rtt_estimate); + EXPECT_EQ(kMinTimeout, pool_->ConnectionTimeout()); +} + +TEST_P(HttpProxyClientSocketPoolTest, ProxyPoolTimeoutWithConnectionProperty) { + const int kSecureMultiplier = 3; + const int kNonSecureMultiplier = 5; + const base::TimeDelta kMinTimeout = base::TimeDelta::FromSeconds(2); + const base::TimeDelta kMaxTimeout = base::TimeDelta::FromSeconds(30); + + InitAdaptiveTimeoutFieldTrialWithParams( + false, kSecureMultiplier, kNonSecureMultiplier, kMinTimeout, kMaxTimeout); + + HttpProxyClientSocketPool::HttpProxyConnectJobFactory job_factory( + transport_socket_pool(), ssl_socket_pool(), estimator(), nullptr); + + const base::TimeDelta kRttEstimate = base::TimeDelta::FromSeconds(2); + estimator()->SetStartTimeNullHttpRtt(kRttEstimate); + // By default, connection timeout should return the timeout for secure + // proxies. + EXPECT_EQ(kSecureMultiplier * kRttEstimate, job_factory.ConnectionTimeout()); + EXPECT_EQ(kSecureMultiplier * kRttEstimate, + job_factory.ConnectionTimeoutWithConnectionProperty(true)); + EXPECT_EQ(kNonSecureMultiplier * kRttEstimate, + job_factory.ConnectionTimeoutWithConnectionProperty(false)); } // Tests the connection timeout values when the field trial parameters are not // specified. TEST_P(HttpProxyClientSocketPoolTest, ProxyPoolTimeoutWithExperimentDefaultParams) { - InitAdaptiveTimeoutFieldTrialWithParams(true, 0, base::TimeDelta(), + InitAdaptiveTimeoutFieldTrialWithParams(true, 0, 0, base::TimeDelta(), base::TimeDelta()); EXPECT_LE(base::TimeDelta(), pool_->ConnectionTimeout()); - // Timeout should be |transport_rtt_multiplier| times the transport RTT + // Timeout should be |http_rtt_multiplier| times the HTTP RTT // estimate. base::TimeDelta rtt_estimate = base::TimeDelta::FromMilliseconds(10); - estimator()->set_start_time_null_transport_rtt(rtt_estimate); - // Connection timeout should not be less than the transport RTT estimate. + estimator()->SetStartTimeNullHttpRtt(rtt_estimate); + // Connection timeout should not be less than the HTTP RTT estimate. EXPECT_LE(rtt_estimate, pool_->ConnectionTimeout()); // A change in RTT estimate should also change the connection timeout. rtt_estimate = base::TimeDelta::FromSeconds(10); - estimator()->set_start_time_null_transport_rtt(rtt_estimate); - // Connection timeout should not be less than the transport RTT estimate. + estimator()->SetStartTimeNullHttpRtt(rtt_estimate); + // Connection timeout should not be less than the HTTP RTT estimate. EXPECT_LE(rtt_estimate, pool_->ConnectionTimeout()); // Set RTT to a very large value. rtt_estimate = base::TimeDelta::FromMinutes(60); - estimator()->set_start_time_null_transport_rtt(rtt_estimate); + estimator()->SetStartTimeNullHttpRtt(rtt_estimate); EXPECT_GT(rtt_estimate, pool_->ConnectionTimeout()); // Set RTT to a very small value. rtt_estimate = base::TimeDelta::FromSeconds(0); - estimator()->set_start_time_null_transport_rtt(rtt_estimate); + estimator()->SetStartTimeNullHttpRtt(rtt_estimate); EXPECT_LT(rtt_estimate, pool_->ConnectionTimeout()); } // It would be nice to also test the timeouts in HttpProxyClientSocketPool. +// Test that SocketTag passed into HttpProxyClientSocketPool is applied to +// returned underlying TCP sockets. +#if defined(OS_ANDROID) +TEST_P(HttpProxyClientSocketPoolTest, Tag) { + Initialize(NULL, 0, NULL, 0, NULL, 0, NULL, 0); + SocketTag tag1(SocketTag::UNSET_UID, 0x12345678); + SocketTag tag2(getuid(), 0x87654321); + + // Verify requested socket is tagged properly. + int rv = handle_.Init("a", CreateNoTunnelParams(), LOW, tag1, + ClientSocketPool::RespectLimits::ENABLED, + CompletionCallback(), pool_.get(), NetLogWithSource()); + EXPECT_THAT(rv, IsOk()); + EXPECT_TRUE(handle_.is_initialized()); + ASSERT_TRUE(handle_.socket()); + EXPECT_TRUE(handle_.socket()->IsConnected()); + EXPECT_EQ(socket_factory()->GetLastProducedSocket()->tag(), tag1); + EXPECT_TRUE( + socket_factory()->GetLastProducedSocket()->tagged_before_connected()); + + // Verify reused socket is retagged properly. + StreamSocket* socket = handle_.socket(); + handle_.Reset(); + rv = handle_.Init("a", CreateNoTunnelParams(), LOW, tag2, + ClientSocketPool::RespectLimits::ENABLED, + CompletionCallback(), pool_.get(), NetLogWithSource()); + EXPECT_THAT(rv, IsOk()); + EXPECT_TRUE(handle_.socket()); + EXPECT_TRUE(handle_.socket()->IsConnected()); + EXPECT_EQ(handle_.socket(), socket); + EXPECT_EQ(socket_factory()->GetLastProducedSocket()->tag(), tag2); + handle_.socket()->Disconnect(); + handle_.Reset(); +} +#endif + } // namespace net diff --git a/chromium/net/http/http_proxy_client_socket_unittest.cc b/chromium/net/http/http_proxy_client_socket_unittest.cc new file mode 100644 index 00000000000..dd35006cebe --- /dev/null +++ b/chromium/net/http/http_proxy_client_socket_unittest.cc @@ -0,0 +1,44 @@ +// Copyright 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/http/http_proxy_client_socket.h" + +#include "build/build_config.h" +#include "net/base/address_list.h" +#include "net/base/host_port_pair.h" +#include "net/log/test_net_log.h" +#include "net/socket/next_proto.h" +#include "net/socket/socket_tag.h" +#include "net/socket/socket_test_util.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace net { + +namespace { + +TEST(HttpProxyClientSocketTest, Tag) { + StaticSocketDataProvider data; + TestNetLog log; + MockTaggingStreamSocket* tagging_sock = + new MockTaggingStreamSocket(std::unique_ptr<StreamSocket>( + new MockTCPClientSocket(AddressList(), &log, &data))); + + std::unique_ptr<ClientSocketHandle> connection(new ClientSocketHandle); + // |connection| takes ownership of |tagging_sock|, but keep a + // non-owning pointer to it. + connection->SetSocket(std::unique_ptr<StreamSocket>(tagging_sock)); + HttpProxyClientSocket socket(std::move(connection), "", HostPortPair(), + nullptr, false, false, NextProto(), false); + + EXPECT_EQ(tagging_sock->tag(), SocketTag()); +#if defined(OS_ANDROID) + SocketTag tag(0x12345678, 0x87654321); + socket.ApplySocketTag(tag); + EXPECT_EQ(tagging_sock->tag(), tag); +#endif // OS_ANDROID +} + +} // namespace + +} // namespace net diff --git a/chromium/net/http/http_proxy_client_socket_wrapper.cc b/chromium/net/http/http_proxy_client_socket_wrapper.cc index cd7a4d3db1f..4d769956cfa 100644 --- a/chromium/net/http/http_proxy_client_socket_wrapper.cc +++ b/chromium/net/http/http_proxy_client_socket_wrapper.cc @@ -12,7 +12,6 @@ #include "base/memory/weak_ptr.h" #include "base/metrics/histogram_macros.h" #include "base/values.h" -#include "net/base/proxy_delegate.h" #include "net/http/http_proxy_client_socket.h" #include "net/http/http_response_info.h" #include "net/log/net_log_event_type.h" @@ -20,11 +19,13 @@ #include "net/log/net_log_source_type.h" #include "net/quic/chromium/quic_proxy_client_socket.h" #include "net/socket/client_socket_handle.h" +#include "net/socket/socket_tag.h" #include "net/spdy/chromium/spdy_proxy_client_socket.h" #include "net/spdy/chromium/spdy_session.h" #include "net/spdy/chromium/spdy_session_pool.h" #include "net/spdy/chromium/spdy_stream.h" #include "net/ssl/ssl_cert_request_info.h" +#include "net/traffic_annotation/network_traffic_annotation.h" #include "url/gurl.h" namespace net { @@ -32,6 +33,7 @@ namespace net { HttpProxyClientSocketWrapper::HttpProxyClientSocketWrapper( const std::string& group_name, RequestPriority priority, + const SocketTag& socket_tag, ClientSocketPool::RespectLimits respect_limits, base::TimeDelta connect_timeout_duration, base::TimeDelta proxy_negotiation_timeout_duration, @@ -47,11 +49,11 @@ HttpProxyClientSocketWrapper::HttpProxyClientSocketWrapper( SpdySessionPool* spdy_session_pool, QuicStreamFactory* quic_stream_factory, bool tunnel, - ProxyDelegate* proxy_delegate, const NetLogWithSource& net_log) : next_state_(STATE_NONE), group_name_(group_name), priority_(priority), + initial_socket_tag_(socket_tag), respect_limits_(respect_limits), connect_timeout_duration_(connect_timeout_duration), proxy_negotiation_timeout_duration_(proxy_negotiation_timeout_duration), @@ -65,7 +67,6 @@ HttpProxyClientSocketWrapper::HttpProxyClientSocketWrapper( spdy_session_pool_(spdy_session_pool), has_restarted_(false), tunnel_(tunnel), - proxy_delegate_(proxy_delegate), using_spdy_(false), quic_stream_request_(quic_stream_factory), http_auth_controller_( @@ -186,7 +187,6 @@ int HttpProxyClientSocketWrapper::Connect(const CompletionCallback& callback) { connect_callback_ = callback; } else { connect_timer_.Stop(); - NotifyProxyDelegateOfCompletion(rv); } return rv; @@ -291,6 +291,19 @@ int64_t HttpProxyClientSocketWrapper::GetTotalReceivedBytes() const { return transport_socket_->GetTotalReceivedBytes(); } +void HttpProxyClientSocketWrapper::ApplySocketTag(const SocketTag& tag) { + // HttpProxyClientSocketPool only tags once connected, when transport_socket_ + // is set. Socket tagging is not supported with tunneling. Socket tagging is + // also not supported with proxy auth so ApplySocketTag() won't be called with + // a specific (non-default) tag when transport_socket_ is cleared by + // RestartWithAuth(). + if (tunnel_ || !transport_socket_) { + CHECK(tag == SocketTag()); + } else { + transport_socket_->ApplySocketTag(tag); + } +} + int HttpProxyClientSocketWrapper::Read(IOBuffer* buf, int buf_len, const CompletionCallback& callback) { @@ -299,11 +312,13 @@ int HttpProxyClientSocketWrapper::Read(IOBuffer* buf, return ERR_SOCKET_NOT_CONNECTED; } -int HttpProxyClientSocketWrapper::Write(IOBuffer* buf, - int buf_len, - const CompletionCallback& callback) { +int HttpProxyClientSocketWrapper::Write( + IOBuffer* buf, + int buf_len, + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& traffic_annotation) { if (transport_socket_) - return transport_socket_->Write(buf, buf_len, callback); + return transport_socket_->Write(buf, buf_len, callback, traffic_annotation); return ERR_SOCKET_NOT_CONNECTED; } @@ -337,7 +352,6 @@ void HttpProxyClientSocketWrapper::OnIOComplete(int result) { int rv = DoLoop(result); if (rv != ERR_IO_PENDING) { connect_timer_.Stop(); - NotifyProxyDelegateOfCompletion(rv); // May delete |this|. base::ResetAndReturn(&connect_callback_).Run(rv); } @@ -427,7 +441,8 @@ int HttpProxyClientSocketWrapper::DoTransportConnect() { next_state_ = STATE_TCP_CONNECT_COMPLETE; transport_socket_handle_.reset(new ClientSocketHandle()); return transport_socket_handle_->Init( - group_name_, transport_params_, priority_, respect_limits_, + group_name_, transport_params_, priority_, initial_socket_tag_, + respect_limits_, base::Bind(&HttpProxyClientSocketWrapper::OnIOComplete, base::Unretained(this)), transport_pool_, net_log_); @@ -466,7 +481,7 @@ int HttpProxyClientSocketWrapper::DoSSLConnect() { next_state_ = STATE_SSL_CONNECT_COMPLETE; transport_socket_handle_.reset(new ClientSocketHandle()); return transport_socket_handle_->Init( - group_name_, ssl_params_, priority_, respect_limits_, + group_name_, ssl_params_, priority_, initial_socket_tag_, respect_limits_, base::Bind(&HttpProxyClientSocketWrapper::OnIOComplete, base::Unretained(this)), ssl_pool_, net_log_); @@ -548,9 +563,8 @@ int HttpProxyClientSocketWrapper::DoHttpProxyConnect() { // Add a HttpProxy connection on top of the tcp socket. transport_socket_.reset(new HttpProxyClientSocket( - transport_socket_handle_.release(), user_agent_, endpoint_, - GetDestination().host_port_pair(), http_auth_controller_.get(), tunnel_, - using_spdy_, negotiated_protocol_, proxy_delegate_, + std::move(transport_socket_handle_), user_agent_, endpoint_, + http_auth_controller_.get(), tunnel_, using_spdy_, negotiated_protocol_, ssl_params_.get() != nullptr)); return transport_socket_->Connect(base::Bind( &HttpProxyClientSocketWrapper::OnIOComplete, base::Unretained(this))); @@ -703,14 +717,6 @@ int HttpProxyClientSocketWrapper::DoRestartWithAuthComplete(int result) { return result; } -void HttpProxyClientSocketWrapper::NotifyProxyDelegateOfCompletion(int result) { - if (!proxy_delegate_) - return; - - const HostPortPair& proxy_server = GetDestination().host_port_pair(); - proxy_delegate_->OnTunnelConnectCompleted(endpoint_, proxy_server, result); -} - void HttpProxyClientSocketWrapper::SetConnectTimer(base::TimeDelta delay) { connect_timer_.Stop(); connect_timer_.Start(FROM_HERE, delay, this, @@ -734,8 +740,6 @@ void HttpProxyClientSocketWrapper::ConnectTimeout() { } } - NotifyProxyDelegateOfCompletion(ERR_CONNECTION_TIMED_OUT); - CompletionCallback callback = connect_callback_; Disconnect(); callback.Run(ERR_CONNECTION_TIMED_OUT); diff --git a/chromium/net/http/http_proxy_client_socket_wrapper.h b/chromium/net/http/http_proxy_client_socket_wrapper.h index 26974540839..66774cbb448 100644 --- a/chromium/net/http/http_proxy_client_socket_wrapper.h +++ b/chromium/net/http/http_proxy_client_socket_wrapper.h @@ -26,6 +26,7 @@ #include "net/socket/ssl_client_socket_pool.h" #include "net/socket/transport_client_socket_pool.h" #include "net/spdy/chromium/spdy_session.h" +#include "net/traffic_annotation/network_traffic_annotation.h" namespace net { @@ -35,7 +36,6 @@ class HttpAuthCache; class HttpResponseInfo; class HttpStream; class IOBuffer; -class ProxyDelegate; class SpdySessionPool; class SSLClientSocketPool; class TransportClientSocketPool; @@ -57,6 +57,7 @@ class NET_EXPORT_PRIVATE HttpProxyClientSocketWrapper HttpProxyClientSocketWrapper( const std::string& group_name, RequestPriority priority, + const SocketTag& socket_tag, ClientSocketPool::RespectLimits respect_limits, base::TimeDelta connect_timeout_duration, base::TimeDelta proxy_negotiation_timeout_duration, @@ -72,7 +73,6 @@ class NET_EXPORT_PRIVATE HttpProxyClientSocketWrapper SpdySessionPool* spdy_session_pool, QuicStreamFactory* quic_stream_factory, bool tunnel, - ProxyDelegate* proxy_delegate, const NetLogWithSource& net_log); // On destruction Disconnect() is called. @@ -108,6 +108,7 @@ class NET_EXPORT_PRIVATE HttpProxyClientSocketWrapper void ClearConnectionAttempts() override; void AddConnectionAttempts(const ConnectionAttempts& attempts) override; int64_t GetTotalReceivedBytes() const override; + void ApplySocketTag(const SocketTag& tag) override; // Socket implementation. int Read(IOBuffer* buf, @@ -115,7 +116,8 @@ class NET_EXPORT_PRIVATE HttpProxyClientSocketWrapper const CompletionCallback& callback) override; int Write(IOBuffer* buf, int buf_len, - const CompletionCallback& callback) override; + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& traffic_annotation) override; int SetReceiveBufferSize(int32_t size) override; int SetSendBufferSize(int32_t size) override; int GetPeerAddress(IPEndPoint* address) const override; @@ -169,8 +171,6 @@ class NET_EXPORT_PRIVATE HttpProxyClientSocketWrapper int DoRestartWithAuth(); int DoRestartWithAuthComplete(int result); - void NotifyProxyDelegateOfCompletion(int result); - void SetConnectTimer(base::TimeDelta duration); void ConnectTimeout(); @@ -180,6 +180,7 @@ class NET_EXPORT_PRIVATE HttpProxyClientSocketWrapper const std::string group_name_; RequestPriority priority_; + const SocketTag initial_socket_tag_; ClientSocketPool::RespectLimits respect_limits_; const base::TimeDelta connect_timeout_duration_; const base::TimeDelta proxy_negotiation_timeout_duration_; @@ -197,7 +198,6 @@ class NET_EXPORT_PRIVATE HttpProxyClientSocketWrapper bool has_restarted_; const bool tunnel_; - ProxyDelegate* const proxy_delegate_; bool using_spdy_; NextProto negotiated_protocol_; diff --git a/chromium/net/http/http_proxy_client_socket_wrapper_unittest.cc b/chromium/net/http/http_proxy_client_socket_wrapper_unittest.cc index 63398086c1c..9d5e034bf1e 100644 --- a/chromium/net/http/http_proxy_client_socket_wrapper_unittest.cc +++ b/chromium/net/http/http_proxy_client_socket_wrapper_unittest.cc @@ -7,8 +7,8 @@ #include <cstdio> #include <memory> -#include "net/cert/cert_verifier.h" -#include "net/cert/multi_log_ct_verifier.h" +#include "net/cert/do_nothing_ct_verifier.h" +#include "net/cert/mock_cert_verifier.h" #include "net/dns/mock_host_resolver.h" #include "net/http/http_auth_cache.h" #include "net/http/http_auth_handler_factory.h" @@ -21,6 +21,7 @@ #include "net/quic/core/quic_versions.h" #include "net/quic/test_tools/mock_clock.h" #include "net/quic/test_tools/mock_random.h" +#include "net/socket/socket_tag.h" #include "net/socket/socket_test_util.h" #include "net/ssl/channel_id_service.h" #include "net/ssl/default_channel_id_store.h" @@ -58,7 +59,7 @@ class MockSSLConfigService : public SSLConfigService { namespace test { class HttpProxyClientSocketWrapperTest - : public ::testing::TestWithParam<QuicTransportVersion> { + : public ::testing::TestWithParam<std::tuple<QuicTransportVersion, bool>> { protected: static const bool kFin = true; static const bool kIncludeVersion = true; @@ -68,22 +69,25 @@ class HttpProxyClientSocketWrapperTest : proxy_host_port_(kProxyHost, kProxyPort), endpoint_host_port_(kOriginHost, kOriginPort), ssl_config_service_(new MockSSLConfigService()), - cert_verifier_(CertVerifier::CreateDefault()), + cert_verifier_(new MockCertVerifier()), channel_id_service_( new ChannelIDService(new DefaultChannelIDStore(nullptr))), - cert_transparency_verifier_(new MultiLogCTVerifier()), + cert_transparency_verifier_(new DoNothingCTVerifier()), random_generator_(0), - quic_version_(GetParam()), + quic_version_(std::get<0>(GetParam())), + client_headers_include_h2_stream_dependency_(std::get<1>(GetParam())), client_maker_(quic_version_, 0, &clock_, kProxyHost, - Perspective::IS_CLIENT), + Perspective::IS_CLIENT, + client_headers_include_h2_stream_dependency_), server_maker_(quic_version_, 0, &clock_, kProxyHost, - Perspective::IS_SERVER), + Perspective::IS_SERVER, + false), header_stream_offset_(0), response_offset_(0), store_server_configs_in_properties_(false), @@ -125,9 +129,11 @@ class HttpProxyClientSocketWrapperTest /*connect_using_default_network=*/true, migrate_sessions_on_network_change_, migrate_sessions_early_, migrate_sessions_on_network_change_v2_, migrate_sessions_early_v2_, + base::TimeDelta::FromSeconds(kMaxTimeOnNonDefaultNetworkSecs), + kMaxMigrationsToNonDefaultNetworkOnPathDegrading, allow_server_migration_, race_cert_verification_, estimate_initial_rtt_, - connection_options_, client_connection_options_, - /*enable_token_binding=*/false)); + client_headers_include_h2_stream_dependency_, connection_options_, + client_connection_options_, /*enable_token_binding=*/false)); } void PopulateConnectRequestIR(SpdyHeaderBlock* block) { @@ -149,7 +155,7 @@ class HttpProxyClientSocketWrapperTest return client_maker_.MakeRequestHeadersPacket( packet_number, kClientDataStreamId1, kIncludeVersion, !kFin, ConvertRequestPriorityToQuicPriority(DEFAULT_PRIORITY), - std::move(block), nullptr, &header_stream_offset_); + std::move(block), 0, nullptr, &header_stream_offset_); } std::unique_ptr<QuicReceivedPacket> ConstructServerConnectReplyPacket( @@ -197,15 +203,16 @@ class HttpProxyClientSocketWrapperTest scoped_refptr<SSLConfigService> ssl_config_service_; MockClientSocketFactory socket_factory_; HttpServerPropertiesImpl http_server_properties_; - std::unique_ptr<CertVerifier> cert_verifier_; + std::unique_ptr<MockCertVerifier> cert_verifier_; CTPolicyEnforcer ct_policy_enforcer_; std::unique_ptr<ChannelIDService> channel_id_service_; TransportSecurityState transport_security_state_; - std::unique_ptr<CTVerifier> cert_transparency_verifier_; + std::unique_ptr<DoNothingCTVerifier> cert_transparency_verifier_; MockCryptoClientStreamFactory crypto_client_stream_factory_; MockRandom random_generator_; - QuicTransportVersion quic_version_; + const QuicTransportVersion quic_version_; + const bool client_headers_include_h2_stream_dependency_; QuicTestPacketMaker client_maker_; QuicTestPacketMaker server_maker_; QuicStreamOffset header_stream_offset_; @@ -260,6 +267,7 @@ TEST_P(HttpProxyClientSocketWrapperTest, QuicProxy) { client_socket_wrapper_.reset(new HttpProxyClientSocketWrapper( /*group_name=*/std::string(), /*requiest_priority=*/DEFAULT_PRIORITY, + /*socket_tag=*/SocketTag(), /*respect_limits=*/ClientSocketPool::RespectLimits::DISABLED, /*connect_timeout_duration=*/base::TimeDelta::FromHours(1), /*proxy_negotiation_timeout_duration=*/base::TimeDelta::FromHours(1), @@ -267,7 +275,7 @@ TEST_P(HttpProxyClientSocketWrapperTest, QuicProxy) { /*transport_params=*/nullptr, ssl_params, quic_version_, kUserAgent, endpoint_host_port_, &http_auth_cache_, http_auth_handler_factory_.get(), /*spdy_session_pool=*/nullptr, quic_stream_factory_.get(), - /*tunnel=*/true, /*proxy_delegate=*/nullptr, net_log_)); + /*tunnel=*/true, net_log_)); TestCompletionCallback callback; client_socket_wrapper_->Connect(callback.callback()); @@ -279,9 +287,11 @@ TEST_P(HttpProxyClientSocketWrapperTest, QuicProxy) { EXPECT_TRUE(mock_quic_data_.AllWriteDataConsumed()); } -INSTANTIATE_TEST_CASE_P(Version, - HttpProxyClientSocketWrapperTest, - ::testing::ValuesIn(AllSupportedTransportVersions())); +INSTANTIATE_TEST_CASE_P( + VersionIncludeStreamDependencySequnece, + HttpProxyClientSocketWrapperTest, + ::testing::Combine(::testing::ValuesIn(AllSupportedTransportVersions()), + ::testing::Bool())); }; // namespace test }; // namespace net diff --git a/chromium/net/http/http_request_info.h b/chromium/net/http/http_request_info.h index ceca265be3b..419227ca2a4 100644 --- a/chromium/net/http/http_request_info.h +++ b/chromium/net/http/http_request_info.h @@ -10,6 +10,7 @@ #include "net/base/net_export.h" #include "net/base/privacy_mode.h" #include "net/http/http_request_headers.h" +#include "net/socket/socket_tag.h" #include "url/gurl.h" namespace net { @@ -56,6 +57,9 @@ struct NET_EXPORT HttpRequestInfo { // If present, the host of the referrer whose TokenBindingID should be // included in a referred TokenBinding. std::string token_binding_referrer; + + // Tag applied to all sockets used to service request. + SocketTag socket_tag; }; } // namespace net diff --git a/chromium/net/http/http_response_body_drainer_unittest.cc b/chromium/net/http/http_response_body_drainer_unittest.cc index 9c5dfa89a2d..c3a0fafacdb 100644 --- a/chromium/net/http/http_response_body_drainer_unittest.cc +++ b/chromium/net/http/http_response_body_drainer_unittest.cc @@ -88,6 +88,7 @@ class MockHttpStream : public HttpStream { // HttpStream implementation. int InitializeStream(const HttpRequestInfo* request_info, + bool can_send_early, RequestPriority priority, const NetLogWithSource& net_log, const CompletionCallback& callback) override { diff --git a/chromium/net/http/http_security_headers_unittest.cc b/chromium/net/http/http_security_headers_unittest.cc index 1171e333269..8ca4ccab489 100644 --- a/chromium/net/http/http_security_headers_unittest.cc +++ b/chromium/net/http/http_security_headers_unittest.cc @@ -37,12 +37,12 @@ std::string GetTestPinImpl(uint8_t label, HashValueTag tag, bool quoted) { reinterpret_cast<char*>(hash_value.data()), hash_value.size()), &base64); std::string ret; - switch (hash_value.tag) { + switch (hash_value.tag()) { case HASH_VALUE_SHA256: ret = "pin-sha256="; break; default: - NOTREACHED() << "Unknown HashValueTag " << hash_value.tag; + NOTREACHED() << "Unknown HashValueTag " << hash_value.tag(); return std::string("ERROR"); } if (quoted) diff --git a/chromium/net/http/http_server_properties.h b/chromium/net/http/http_server_properties.h index b8efe93258d..22f0a5db0f5 100644 --- a/chromium/net/http/http_server_properties.h +++ b/chromium/net/http/http_server_properties.h @@ -13,6 +13,7 @@ #include <tuple> #include <vector> +#include "base/callback.h" #include "base/containers/mru_cache.h" #include "base/macros.h" #include "base/time/time.h" @@ -313,8 +314,10 @@ class NET_EXPORT HttpServerProperties { HttpServerProperties() {} virtual ~HttpServerProperties() {} - // Deletes all data. - virtual void Clear() = 0; + // Deletes all data. If |callback| is non-null, flushes data to disk + // and invokes the callback asynchronously once changes have been written to + // disk. + virtual void Clear(base::OnceClosure callback) = 0; // Returns true if |server| supports a network protocol which honors // request prioritization. diff --git a/chromium/net/http/http_server_properties_impl.cc b/chromium/net/http/http_server_properties_impl.cc index 37248e625b1..ccd60cb109a 100644 --- a/chromium/net/http/http_server_properties_impl.cc +++ b/chromium/net/http/http_server_properties_impl.cc @@ -21,7 +21,9 @@ namespace net { HttpServerPropertiesImpl::HttpServerPropertiesImpl(base::TickClock* clock) - : broken_alternative_services_(this, clock ? clock : &default_clock_), + : broken_alternative_services_( + this, + clock ? clock : base::DefaultTickClock::GetInstance()), quic_server_info_map_(kDefaultMaxQuicServerEntries), max_server_configs_stored_in_properties_(kDefaultMaxQuicServerEntries) { canonical_suffixes_.push_back(".ggpht.com"); @@ -175,7 +177,7 @@ HttpServerPropertiesImpl::recently_broken_alternative_services() const { return broken_alternative_services_.recently_broken_alternative_services(); } -void HttpServerPropertiesImpl::Clear() { +void HttpServerPropertiesImpl::Clear(base::OnceClosure callback) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); spdy_servers_map_.Clear(); alternative_service_map_.Clear(); @@ -185,6 +187,11 @@ void HttpServerPropertiesImpl::Clear() { server_network_stats_map_.Clear(); quic_server_info_map_.Clear(); canonical_server_info_map_.clear(); + + if (!callback.is_null()) { + base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, + std::move(callback)); + } } bool HttpServerPropertiesImpl::SupportsRequestPriority( diff --git a/chromium/net/http/http_server_properties_impl.h b/chromium/net/http/http_server_properties_impl.h index dbb0ffdd096..7967e86adc9 100644 --- a/chromium/net/http/http_server_properties_impl.h +++ b/chromium/net/http/http_server_properties_impl.h @@ -13,6 +13,7 @@ #include <string> #include <vector> +#include "base/callback.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/threading/thread_checker.h" @@ -86,7 +87,7 @@ class NET_EXPORT HttpServerPropertiesImpl // HttpServerProperties methods: // ----------------------------- - void Clear() override; + void Clear(base::OnceClosure callback) override; bool SupportsRequestPriority(const url::SchemeHostPort& server) override; bool GetSupportsSpdy(const url::SchemeHostPort& server) override; void SetSupportsSpdy(const url::SchemeHostPort& server, @@ -176,8 +177,6 @@ class NET_EXPORT HttpServerPropertiesImpl // have an entry associated with |server|, the method will add one. void UpdateCanonicalServerInfoMap(const QuicServerId& server); - base::DefaultTickClock default_clock_; - SpdyServersMap spdy_servers_map_; Http11ServerHostPortSet http11_servers_; diff --git a/chromium/net/http/http_server_properties_impl_unittest.cc b/chromium/net/http/http_server_properties_impl_unittest.cc index 32f80acf5c9..c3b04f60ae3 100644 --- a/chromium/net/http/http_server_properties_impl_unittest.cc +++ b/chromium/net/http/http_server_properties_impl_unittest.cc @@ -280,9 +280,21 @@ TEST_F(SpdyServerPropertiesTest, Clear) { EXPECT_TRUE(impl_.SupportsRequestPriority(spdy_server_google)); EXPECT_TRUE(impl_.SupportsRequestPriority(spdy_server_mail)); - impl_.Clear(); + base::RunLoop run_loop; + bool callback_invoked_ = false; + impl_.Clear(base::BindOnce( + [](bool* callback_invoked, base::OnceClosure quit_closure) { + *callback_invoked = true; + std::move(quit_closure).Run(); + }, + &callback_invoked_, run_loop.QuitClosure())); EXPECT_FALSE(impl_.SupportsRequestPriority(spdy_server_google)); EXPECT_FALSE(impl_.SupportsRequestPriority(spdy_server_mail)); + + // Callback should be run asynchronously. + EXPECT_FALSE(callback_invoked_); + run_loop.Run(); + EXPECT_TRUE(callback_invoked_); } TEST_F(SpdyServerPropertiesTest, MRUOfSpdyServersMap) { @@ -329,7 +341,7 @@ TEST_F(AlternateProtocolServerPropertiesTest, Basic) { EXPECT_EQ(alternative_service, alternative_service_info_vector[0].alternative_service()); - impl_.Clear(); + impl_.Clear(base::OnceClosure()); EXPECT_FALSE(HasAlternativeService(test_server)); } @@ -933,7 +945,7 @@ TEST_F(AlternateProtocolServerPropertiesTest, ClearWithCanonical) { "bar.c.youtube.com", 1234); SetAlternativeService(canonical_server, canonical_alternative_service); - impl_.Clear(); + impl_.Clear(base::OnceClosure()); EXPECT_FALSE(HasAlternativeService(test_server)); } @@ -1093,7 +1105,7 @@ TEST_F(SupportsQuicServerPropertiesTest, SetSupportsQuic) { EXPECT_TRUE(impl_.GetSupportsQuic(&address)); EXPECT_EQ(actual_address, address); - impl_.Clear(); + impl_.Clear(base::OnceClosure()); EXPECT_FALSE(impl_.GetSupportsQuic(&address)); } @@ -1186,7 +1198,7 @@ TEST_F(ServerNetworkStatsServerPropertiesTest, SetServerNetworkStats) { // Https server should have nothing set for server network stats. EXPECT_EQ(NULL, impl_.GetServerNetworkStats(foo_https_server)); - impl_.Clear(); + impl_.Clear(base::OnceClosure()); EXPECT_EQ(NULL, impl_.GetServerNetworkStats(foo_http_server)); EXPECT_EQ(NULL, impl_.GetServerNetworkStats(foo_https_server)); } @@ -1305,7 +1317,7 @@ TEST_F(QuicServerInfoServerPropertiesTest, SetQuicServerInfo) { EXPECT_EQ(1u, impl_.quic_server_info_map().size()); EXPECT_EQ(quic_server_info1, *(impl_.GetQuicServerInfo(quic_server_id))); - impl_.Clear(); + impl_.Clear(base::OnceClosure()); EXPECT_EQ(0u, impl_.quic_server_info_map().size()); EXPECT_EQ(nullptr, impl_.GetQuicServerInfo(quic_server_id)); } diff --git a/chromium/net/http/http_server_properties_manager.cc b/chromium/net/http/http_server_properties_manager.cc index 389487143e3..af84c1d48ba 100644 --- a/chromium/net/http/http_server_properties_manager.cc +++ b/chromium/net/http/http_server_properties_manager.cc @@ -86,6 +86,16 @@ struct ServerPref { ServerNetworkStats server_network_stats; }; +QuicServerId QuicServerIdFromString(const std::string& str) { + GURL url(str); + if (!url.is_valid()) { + return QuicServerId(); + } + return QuicServerId(HostPortPair::FromURL(url), url.path_piece() == "/private" + ? PRIVACY_MODE_ENABLED + : PRIVACY_MODE_DISABLED); +} + } // namespace //////////////////////////////////////////////////////////////////////////////// @@ -98,7 +108,7 @@ HttpServerPropertiesManager::HttpServerPropertiesManager( NetLog* net_log, base::TickClock* clock) : pref_delegate_(std::move(pref_delegate)), - clock_(clock ? clock : &default_clock_), + clock_(clock ? clock : base::DefaultTickClock::GetInstance()), net_log_( NetLogWithSource::Make(net_log, NetLogSourceType::HTTP_SERVER_PROPERTIES)) { @@ -106,9 +116,9 @@ HttpServerPropertiesManager::HttpServerPropertiesManager( DCHECK(pref_delegate_); DCHECK(clock_); - pref_delegate_->StartListeningForUpdates( - base::Bind(&HttpServerPropertiesManager::OnHttpServerPropertiesChanged, - base::Unretained(this))); + pref_delegate_->StartListeningForUpdates(base::BindRepeating( + &HttpServerPropertiesManager::OnHttpServerPropertiesChanged, + base::Unretained(this))); net_log_.BeginEvent(NetLogEventType::HTTP_SERVER_PROPERTIES_INITIALIZATION); http_server_properties_impl_.reset(new HttpServerPropertiesImpl(clock_)); @@ -117,7 +127,7 @@ HttpServerPropertiesManager::HttpServerPropertiesManager( HttpServerPropertiesManager::~HttpServerPropertiesManager() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); // Flush settings on destruction. - UpdatePrefsFromCache(); + UpdatePrefsFromCache(base::OnceClosure()); } // static @@ -131,11 +141,11 @@ void HttpServerPropertiesManager::SetVersion( http_server_properties_dict->SetInteger(kVersionKey, version_number); } -void HttpServerPropertiesManager::Clear() { +void HttpServerPropertiesManager::Clear(base::OnceClosure callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - http_server_properties_impl_->Clear(); - UpdatePrefsFromCache(); + http_server_properties_impl_->Clear(base::OnceClosure()); + UpdatePrefsFromCache(std::move(callback)); } bool HttpServerPropertiesManager::SupportsRequestPriority( @@ -773,7 +783,6 @@ bool HttpServerPropertiesManager::ParseAlternativeServiceInfoDictOfServer( alternative_service_info->set_alternative_service(alternative_service); // Expiration is optional, defaults to one day. - base::Time expiration; if (!dict.HasKey(kExpirationKey)) { alternative_service_info->set_expiration(base::Time::Now() + base::TimeDelta::FromDays(1)); @@ -928,9 +937,8 @@ bool HttpServerPropertiesManager::AddToQuicServerInfoMap( it.Advance()) { // Get quic_server_id. const std::string& quic_server_id_str = it.key(); - QuicServerId quic_server_id; - QuicHostnameUtils::StringToQuicServerId(quic_server_id_str, - &quic_server_id); + + QuicServerId quic_server_id = QuicServerIdFromString(quic_server_id_str); if (quic_server_id.host().empty()) { DVLOG(1) << "Malformed http_server_properties for quic server: " << quic_server_id_str; @@ -969,15 +977,17 @@ void HttpServerPropertiesManager::ScheduleUpdatePrefs(Location location) { return; network_prefs_update_timer_.Start( - FROM_HERE, kUpdatePrefsDelay, this, - &HttpServerPropertiesManager::UpdatePrefsFromCache); + FROM_HERE, kUpdatePrefsDelay, + base::Bind(&HttpServerPropertiesManager::UpdatePrefsFromCache, + base::Unretained(this), base::Passed(base::OnceClosure()))); // TODO(rtenneti): Delete the following histogram after collecting some data. UMA_HISTOGRAM_ENUMERATION("Net.HttpServerProperties.UpdatePrefs", location, HttpServerPropertiesManager::NUM_LOCATIONS); } -void HttpServerPropertiesManager::UpdatePrefsFromCache() { +void HttpServerPropertiesManager::UpdatePrefsFromCache( + base::OnceClosure callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); typedef base::MRUCache<url::SchemeHostPort, ServerPref> ServerPrefMap; @@ -1105,7 +1115,8 @@ void HttpServerPropertiesManager::UpdatePrefsFromCache() { &http_server_properties_dict); setting_prefs_ = true; - pref_delegate_->SetServerProperties(http_server_properties_dict); + pref_delegate_->SetServerProperties(http_server_properties_dict, + std::move(callback)); setting_prefs_ = false; net_log_.AddEvent(NetLogEventType::HTTP_SERVER_PROPERTIES_UPDATE_PREFS, diff --git a/chromium/net/http/http_server_properties_manager.h b/chromium/net/http/http_server_properties_manager.h index b77b9057c5d..5f346262100 100644 --- a/chromium/net/http/http_server_properties_manager.h +++ b/chromium/net/http/http_server_properties_manager.h @@ -11,6 +11,7 @@ #include <string> #include <vector> +#include "base/callback.h" #include "base/compiler_specific.h" #include "base/gtest_prod_util.h" #include "base/macros.h" @@ -51,13 +52,17 @@ class NET_EXPORT HttpServerPropertiesManager : public HttpServerProperties { // Returns nullptr if the pref system has no data for the server properties. virtual const base::DictionaryValue* GetServerProperties() const = 0; - // Sets the server properties to the given value. - virtual void SetServerProperties(const base::DictionaryValue& value) = 0; + // Sets the server properties to the given value. If |callback| is + // non-empty, flushes data to persistent storage and invokes |callback| + // asynchronously when complete. + virtual void SetServerProperties(const base::DictionaryValue& value, + base::OnceClosure callback) = 0; // Starts listening for external storage changes. There will only be one // callback active at a time. The first time the |callback| is invoked is // expected to mean the initial pref store values have been loaded. - virtual void StartListeningForUpdates(const base::Closure& callback) = 0; + virtual void StartListeningForUpdates( + const base::RepeatingClosure& callback) = 0; }; // Create an instance of the HttpServerPropertiesManager. @@ -83,7 +88,7 @@ class NET_EXPORT HttpServerPropertiesManager : public HttpServerProperties { // HttpServerProperties methods: // ---------------------------------- - void Clear() override; + void Clear(base::OnceClosure callback) override; bool SupportsRequestPriority(const url::SchemeHostPort& server) override; bool GetSupportsSpdy(const url::SchemeHostPort& server) override; void SetSupportsSpdy(const url::SchemeHostPort& server, @@ -182,8 +187,9 @@ class NET_EXPORT HttpServerPropertiesManager : public HttpServerProperties { void ScheduleUpdatePrefs(Location location); // Update prefs::kHttpServerProperties in preferences with the cached data - // from |http_server_properties_impl_|. - void UpdatePrefsFromCache(); + // from |http_server_properties_impl_|. Invokes |callback| when changes have + // been committed, if non-null. + void UpdatePrefsFromCache(base::OnceClosure callback); private: FRIEND_TEST_ALL_PREFIXES(HttpServerPropertiesManagerTest, @@ -253,8 +259,6 @@ class NET_EXPORT HttpServerPropertiesManager : public HttpServerProperties { recently_broken_alternative_services, base::DictionaryValue* http_server_properties_dict); - base::DefaultTickClock default_clock_; - // Used to post cache update tasks. base::OneShotTimer pref_cache_update_timer_; diff --git a/chromium/net/http/http_server_properties_manager_unittest.cc b/chromium/net/http/http_server_properties_manager_unittest.cc index e5eea969abc..20e835cf060 100644 --- a/chromium/net/http/http_server_properties_manager_unittest.cc +++ b/chromium/net/http/http_server_properties_manager_unittest.cc @@ -46,7 +46,8 @@ class MockPrefDelegate : public net::HttpServerPropertiesManager::PrefDelegate { const base::DictionaryValue* GetServerProperties() const override { return &prefs_; } - void SetServerProperties(const base::DictionaryValue& value) override { + void SetServerProperties(const base::DictionaryValue& value, + base::OnceClosure callback) override { prefs_.Clear(); prefs_.MergeDictionary(&value); ++num_pref_updates_; @@ -54,6 +55,7 @@ class MockPrefDelegate : public net::HttpServerPropertiesManager::PrefDelegate { prefs_changed_callback_.Run(); if (!extra_prefs_changed_callback_.is_null()) extra_prefs_changed_callback_.Run(); + set_properties_callback_ = std::move(callback); } void StartListeningForUpdates(const base::Closure& callback) override { CHECK(prefs_changed_callback_.is_null()); @@ -80,12 +82,20 @@ class MockPrefDelegate : public net::HttpServerPropertiesManager::PrefDelegate { extra_prefs_changed_callback_ = callback; } + // Returns the base::OnceCallback, if any, passed to the last call to + // SetServerProperties(). + base::OnceClosure GetSetPropertiesCallback() { + return std::move(set_properties_callback_); + } + private: base::DictionaryValue prefs_; base::Closure prefs_changed_callback_; base::Closure extra_prefs_changed_callback_; int num_pref_updates_ = 0; + base::OnceClosure set_properties_callback_; + DISALLOW_COPY_AND_ASSIGN(MockPrefDelegate); }; @@ -104,10 +114,11 @@ class HttpServerPropertiesManagerTest : public testing::TestWithParam<int> { advertised_versions_ = HttpNetworkSession::Params().quic_supported_versions; pref_delegate_ = new MockPrefDelegate; - net_test_task_runner_clock_ = test_task_runner_->GetMockTickClock(); + clock_ = test_task_runner_->GetMockTickClock(); + net_test_task_runner_clock_ = clock_.get(); http_server_props_manager_ = std::make_unique<HttpServerPropertiesManager>( base::WrapUnique(pref_delegate_), /*net_log=*/nullptr, - net_test_task_runner_clock_.get()); + net_test_task_runner_clock_); EXPECT_FALSE(http_server_props_manager_->IsInitialized()); pref_delegate_->SetPrefs(base::DictionaryValue()); @@ -140,7 +151,11 @@ class HttpServerPropertiesManagerTest : public testing::TestWithParam<int> { // Overrides the main thread's message loop with a mock tick clock. base::ScopedMockTimeMessageLoopTaskRunner test_task_runner_; - std::unique_ptr<base::TickClock> net_test_task_runner_clock_; + // TODO(tzik): Remove |clock_| after updating GetMockTickClock to own the + // instance. + std::unique_ptr<base::TickClock> clock_; + + base::TickClock* net_test_task_runner_clock_; private: DISALLOW_COPY_AND_ASSIGN(HttpServerPropertiesManagerTest); @@ -802,8 +817,14 @@ TEST_P(HttpServerPropertiesManagerTest, Clear) { // Clear http server data, which should instantly update prefs. EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates()); - http_server_props_manager_->Clear(); + bool callback_invoked_ = false; + http_server_props_manager_->Clear( + base::BindOnce([](bool* callback_invoked) { *callback_invoked = true; }, + &callback_invoked_)); EXPECT_EQ(1, pref_delegate_->GetAndClearNumPrefUpdates()); + EXPECT_FALSE(callback_invoked_); + std::move(pref_delegate_->GetSetPropertiesCallback()).Run(); + EXPECT_TRUE(callback_invoked_); EXPECT_FALSE(http_server_props_manager_->IsAlternativeServiceBroken( broken_alternative_service)); diff --git a/chromium/net/http/http_stream.h b/chromium/net/http/http_stream.h index 1763722ab02..35146de3c60 100644 --- a/chromium/net/http/http_stream.h +++ b/chromium/net/http/http_stream.h @@ -51,9 +51,12 @@ class NET_EXPORT_PRIVATE HttpStream { // Initialize stream. Must be called before calling SendRequest(). // The consumer should ensure that request_info points to a valid value till // final response headers are received; after that point, the HttpStream - // will not access |*request_info| and it may be deleted. + // will not access |*request_info| and it may be deleted. If |can_send_early| + // is true, this stream may send data early without confirming the handshake + // if this is a resumption of a previously established connection. // Returns a net error code, possibly ERR_IO_PENDING. virtual int InitializeStream(const HttpRequestInfo* request_info, + bool can_send_early, RequestPriority priority, const NetLogWithSource& net_log, const CompletionCallback& callback) = 0; diff --git a/chromium/net/http/http_stream_factory_impl.cc b/chromium/net/http/http_stream_factory_impl.cc index caaaa315110..ffc73e280a6 100644 --- a/chromium/net/http/http_stream_factory_impl.cc +++ b/chromium/net/http/http_stream_factory_impl.cc @@ -31,17 +31,10 @@ namespace net { -HttpStreamFactoryImpl::HttpStreamFactoryImpl(HttpNetworkSession* session, - bool for_websockets) - : session_(session), - job_factory_(new JobFactory()), - for_websockets_(for_websockets), - last_logged_job_controller_count_(0) {} - -HttpStreamFactoryImpl::~HttpStreamFactoryImpl() { - UMA_HISTOGRAM_COUNTS_1M("Net.JobControllerSet.CountOfJobControllerAtShutDown", - job_controller_set_.size()); -} +HttpStreamFactoryImpl::HttpStreamFactoryImpl(HttpNetworkSession* session) + : session_(session), job_factory_(new JobFactory()) {} + +HttpStreamFactoryImpl::~HttpStreamFactoryImpl() {} std::unique_ptr<HttpStreamRequest> HttpStreamFactoryImpl::RequestStream( const HttpRequestInfo& request_info, @@ -52,11 +45,10 @@ std::unique_ptr<HttpStreamRequest> HttpStreamFactoryImpl::RequestStream( bool enable_ip_based_pooling, bool enable_alternative_services, const NetLogWithSource& net_log) { - DCHECK(!for_websockets_); return RequestStreamInternal( request_info, priority, server_ssl_config, proxy_ssl_config, delegate, - nullptr, HttpStreamRequest::HTTP_STREAM, enable_ip_based_pooling, - enable_alternative_services, net_log); + nullptr, HttpStreamRequest::HTTP_STREAM, false /* is_websocket */, + enable_ip_based_pooling, enable_alternative_services, net_log); } std::unique_ptr<HttpStreamRequest> @@ -70,12 +62,11 @@ HttpStreamFactoryImpl::RequestWebSocketHandshakeStream( bool enable_ip_based_pooling, bool enable_alternative_services, const NetLogWithSource& net_log) { - DCHECK(for_websockets_); DCHECK(create_helper); return RequestStreamInternal( request_info, priority, server_ssl_config, proxy_ssl_config, delegate, - create_helper, HttpStreamRequest::HTTP_STREAM, enable_ip_based_pooling, - enable_alternative_services, net_log); + create_helper, HttpStreamRequest::HTTP_STREAM, true /* is_websocket */, + enable_ip_based_pooling, enable_alternative_services, net_log); } std::unique_ptr<HttpStreamRequest> @@ -88,12 +79,12 @@ HttpStreamFactoryImpl::RequestBidirectionalStreamImpl( bool enable_ip_based_pooling, bool enable_alternative_services, const NetLogWithSource& net_log) { - DCHECK(!for_websockets_); DCHECK(request_info.url.SchemeIs(url::kHttpsScheme)); return RequestStreamInternal( request_info, priority, server_ssl_config, proxy_ssl_config, delegate, - nullptr, HttpStreamRequest::BIDIRECTIONAL_STREAM, enable_ip_based_pooling, + nullptr, HttpStreamRequest::BIDIRECTIONAL_STREAM, + false /* is_websocket */, enable_ip_based_pooling, enable_alternative_services, net_log); } @@ -106,14 +97,13 @@ std::unique_ptr<HttpStreamRequest> HttpStreamFactoryImpl::RequestStreamInternal( WebSocketHandshakeStreamBase::CreateHelper* websocket_handshake_stream_create_helper, HttpStreamRequest::StreamType stream_type, + bool is_websocket, bool enable_ip_based_pooling, bool enable_alternative_services, const NetLogWithSource& net_log) { - AddJobControllerCountToHistograms(); - auto job_controller = std::make_unique<JobController>( this, delegate, session_, job_factory_.get(), request_info, - /* is_preconnect = */ false, enable_ip_based_pooling, + /* is_preconnect = */ false, is_websocket, enable_ip_based_pooling, enable_alternative_services, server_ssl_config, proxy_ssl_config); JobController* job_controller_raw_ptr = job_controller.get(); job_controller_set_.insert(std::move(job_controller)); @@ -127,8 +117,6 @@ void HttpStreamFactoryImpl::PreconnectStreams( const HttpRequestInfo& request_info) { DCHECK(request_info.url.is_valid()); - AddJobControllerCountToHistograms(); - SSLConfig server_ssl_config; SSLConfig proxy_ssl_config; session_->GetSSLConfig(request_info, &server_ssl_config, &proxy_ssl_config); @@ -136,11 +124,10 @@ void HttpStreamFactoryImpl::PreconnectStreams( server_ssl_config.verify_ev_cert = true; proxy_ssl_config.verify_ev_cert = true; - DCHECK(!for_websockets_); - auto job_controller = std::make_unique<JobController>( this, nullptr, session_, job_factory_.get(), request_info, /* is_preconnect = */ true, + /* is_websocket = */ false, /* enable_ip_based_pooling = */ true, /* enable_alternative_services = */ true, server_ssl_config, proxy_ssl_config); @@ -244,45 +231,6 @@ bool HttpStreamFactoryImpl::ProxyServerSupportsPriorities( scheme_host_port); } -void HttpStreamFactoryImpl::AddJobControllerCountToHistograms() { - // Only log the count of JobControllers when the count is hitting one of the - // boundaries for the first time which is a multiple of 1000: 1000, 2000, - // 3000, etc. - if (job_controller_set_.size() % 1000 != 0 || - job_controller_set_.size() <= last_logged_job_controller_count_) { - return; - } - last_logged_job_controller_count_ = job_controller_set_.size(); - - UMA_HISTOGRAM_COUNTS_1M("Net.JobControllerSet.CountOfJobController", - job_controller_set_.size()); - - size_t num_controllers_with_request = 0; - size_t num_controllers_for_preconnect = 0; - for (const auto& job_controller : job_controller_set_) { - // Additionally log the states of the jobs. - job_controller->LogHistograms(); - // For a preconnect controller, it should have exactly the main job. - if (job_controller->is_preconnect()) { - num_controllers_for_preconnect++; - continue; - } - // For non-preconnects. - if (job_controller->HasPendingRequest()) - num_controllers_with_request++; - } - UMA_HISTOGRAM_COUNTS_1M( - "Net.JobControllerSet.CountOfJobController.Preconnect", - num_controllers_for_preconnect); - UMA_HISTOGRAM_COUNTS_1M( - "Net.JobControllerSet.CountOfJobController.NonPreconnect.PendingRequest", - num_controllers_with_request); - UMA_HISTOGRAM_COUNTS_1M( - "Net.JobControllerSet.CountOfJobController.NonPreconnect.RequestGone", - job_controller_set_.size() - num_controllers_for_preconnect - - num_controllers_with_request); -} - void HttpStreamFactoryImpl::DumpMemoryStats( base::trace_event::ProcessMemoryDump* pmd, const std::string& parent_absolute_name) const { diff --git a/chromium/net/http/http_stream_factory_impl.h b/chromium/net/http/http_stream_factory_impl.h index 058d702a440..30480ed5347 100644 --- a/chromium/net/http/http_stream_factory_impl.h +++ b/chromium/net/http/http_stream_factory_impl.h @@ -36,10 +36,7 @@ class NET_EXPORT_PRIVATE HttpStreamFactoryImpl : public HttpStreamFactory { class NET_EXPORT_PRIVATE JobController; class NET_EXPORT_PRIVATE JobFactory; class NET_EXPORT_PRIVATE Request; - // RequestStream may only be called if |for_websockets| is false. - // RequestWebSocketHandshakeStream may only be called if |for_websockets| - // is true. - HttpStreamFactoryImpl(HttpNetworkSession* session, bool for_websockets); + HttpStreamFactoryImpl(HttpNetworkSession* session); ~HttpStreamFactoryImpl() override; // HttpStreamFactory interface @@ -126,6 +123,7 @@ class NET_EXPORT_PRIVATE HttpStreamFactoryImpl : public HttpStreamFactory { HttpStreamRequest::Delegate* delegate, WebSocketHandshakeStreamBase::CreateHelper* create_helper, HttpStreamRequest::StreamType stream_type, + bool is_websocket, bool enable_ip_based_pooling, bool enable_alternative_services, const NetLogWithSource& net_log); @@ -157,11 +155,6 @@ class NET_EXPORT_PRIVATE HttpStreamFactoryImpl : public HttpStreamFactory { // priorities. bool ProxyServerSupportsPriorities(const ProxyInfo& proxy_info) const; - // Adds the count of JobControllers that are not completed to UMA histogram if - // the count is a multiple of 100: 100, 200, 400, etc. Break down - // JobControllers count based on the type of JobController. - void AddJobControllerCountToHistograms(); - HttpNetworkSession* const session_; // All Requests/Preconnects are assigned with a JobController to manage @@ -178,11 +171,6 @@ class NET_EXPORT_PRIVATE HttpStreamFactoryImpl : public HttpStreamFactory { // preconnects should be skipped. std::set<PreconnectingProxyServer> preconnecting_proxy_servers_; - const bool for_websockets_; - - // The count of JobControllers that was most recently logged to histograms. - size_t last_logged_job_controller_count_; - DISALLOW_COPY_AND_ASSIGN(HttpStreamFactoryImpl); }; diff --git a/chromium/net/http/http_stream_factory_impl_job.cc b/chromium/net/http/http_stream_factory_impl_job.cc index 8b1a2a49a23..0a5801a0835 100644 --- a/chromium/net/http/http_stream_factory_impl_job.cc +++ b/chromium/net/http/http_stream_factory_impl_job.cc @@ -165,6 +165,7 @@ HttpStreamFactoryImpl::Job::Job(Delegate* delegate, NextProto alternative_protocol, QuicTransportVersion quic_version, const ProxyServer& alternative_proxy_server, + bool is_websocket, bool enable_ip_based_pooling, NetLog* net_log) : request_info_(request_info), @@ -177,11 +178,11 @@ HttpStreamFactoryImpl::Job::Job(Delegate* delegate, io_callback_(base::Bind(&Job::OnIOComplete, base::Unretained(this))), connection_(new ClientSocketHandle), session_(session), - state_(STATE_NONE), next_state_(STATE_NONE), destination_(destination), origin_url_(origin_url), alternative_proxy_server_(alternative_proxy_server), + is_websocket_(is_websocket), enable_ip_based_pooling_(enable_ip_based_pooling), delegate_(delegate), job_type_(job_type), @@ -195,11 +196,13 @@ HttpStreamFactoryImpl::Job::Job(Delegate* delegate, using_spdy_(false), should_reconsider_proxy_(false), quic_request_(session_->quic_stream_factory()), + expect_on_quic_host_resolution_(false), using_existing_quic_session_(false), establishing_tunnel_(false), was_alpn_negotiated_(false), negotiated_protocol_(kProtoUnknown), num_streams_(0), + pushed_stream_id_(kNoPushedStreamFound), spdy_session_direct_( !(proxy_info.is_https() && origin_url_.SchemeIs(url::kHttpScheme))), spdy_session_key_(using_quic_ @@ -244,6 +247,9 @@ HttpStreamFactoryImpl::Job::Job(Delegate* delegate, if (using_quic_) { DCHECK(session_->IsQuicEnabled()); } + if (job_type_ == PRECONNECT || is_websocket_) { + DCHECK(request_info_.socket_tag == SocketTag()); + } } HttpStreamFactoryImpl::Job::~Job() { @@ -367,20 +373,6 @@ const ProxyInfo& HttpStreamFactoryImpl::Job::proxy_info() const { return proxy_info_; } -void HttpStreamFactoryImpl::Job::LogHistograms() const { - if (job_type_ == MAIN) { - UMA_HISTOGRAM_ENUMERATION("Net.HttpStreamFactoryJob.Main.NextState", - next_state_, STATE_MAX); - UMA_HISTOGRAM_ENUMERATION("Net.HttpStreamFactoryJob.Main.State", state_, - STATE_MAX); - } else if (job_type_ == ALTERNATIVE) { - UMA_HISTOGRAM_ENUMERATION("Net.HttpStreamFactoryJob.Alt.NextState", - next_state_, STATE_MAX); - UMA_HISTOGRAM_ENUMERATION("Net.HttpStreamFactoryJob.Alt.State", state_, - STATE_MAX); - } -} - void HttpStreamFactoryImpl::Job::GetSSLInfo(SSLInfo* ssl_info) { DCHECK(using_ssl_); DCHECK(!establishing_tunnel_); @@ -433,12 +425,12 @@ bool HttpStreamFactoryImpl::Job::CanUseExistingSpdySession() const { } // We need to make sure that if a spdy session was created for - // https://somehost/ that we don't use that session for http://somehost:443/. + // https://somehost/ then we do not use that session for http://somehost:443/. // The only time we can use an existing session is if the request URL is - // https (the normal case) or if we're connection to a SPDY proxy. + // https (the normal case) or if we are connecting to a SPDY proxy. // https://crbug.com/133176 - // TODO(ricea): Add "wss" back to this list when SPDY WebSocket support is - // working. + // TODO(bnc): Add kWssScheme back to this list when WebSockets over HTTP/2 is + // implemented. https://crbug.com/801564. return origin_url_.SchemeIs(url::kHttpsScheme) || proxy_info_.proxy_server().is_https(); } @@ -446,7 +438,7 @@ bool HttpStreamFactoryImpl::Job::CanUseExistingSpdySession() const { void HttpStreamFactoryImpl::Job::OnStreamReadyCallback() { DCHECK(stream_.get()); DCHECK_NE(job_type_, PRECONNECT); - DCHECK(!delegate_->for_websockets()); + DCHECK(!is_websocket_); MaybeCopyConnectionAttemptsFromSocketOrHandle(); @@ -457,7 +449,7 @@ void HttpStreamFactoryImpl::Job::OnStreamReadyCallback() { void HttpStreamFactoryImpl::Job::OnWebSocketHandshakeStreamReadyCallback() { DCHECK(websocket_stream_); DCHECK_NE(job_type_, PRECONNECT); - DCHECK(delegate_->for_websockets()); + DCHECK(is_websocket_); MaybeCopyConnectionAttemptsFromSocketOrHandle(); @@ -657,7 +649,7 @@ void HttpStreamFactoryImpl::Job::RunLoop(int result) { base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::Bind(&Job::OnNewSpdySessionReadyCallback, ptr_factory_.GetWeakPtr())); - } else if (delegate_->for_websockets()) { + } else if (is_websocket_) { DCHECK(websocket_stream_); base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::Bind(&Job::OnWebSocketHandshakeStreamReadyCallback, @@ -694,8 +686,6 @@ int HttpStreamFactoryImpl::Job::DoLoop(int result) { int rv = result; do { State state = next_state_; - // Added to investigate crbug.com/711721. - state_ = state; next_state_ = STATE_NONE; switch (state) { case STATE_START: @@ -841,9 +831,10 @@ void HttpStreamFactoryImpl::Job::ResumeInitConnection() { int HttpStreamFactoryImpl::Job::DoInitConnection() { net_log_.BeginEvent(NetLogEventType::HTTP_STREAM_JOB_INIT_CONNECTION); int result = DoInitConnectionImpl(); - if (result != ERR_SPDY_SESSION_ALREADY_EXISTS) + if (result != ERR_SPDY_SESSION_ALREADY_EXISTS && + !expect_on_quic_host_resolution_) { delegate_->OnConnectionInitialized(this, result); - + } return result; } @@ -913,13 +904,14 @@ int HttpStreamFactoryImpl::Job::DoInitConnectionImpl() { net_log_, &net_error_details_, io_callback_); if (rv == OK) { using_existing_quic_session_ = true; - } else { + } else if (rv == ERR_IO_PENDING) { // There's no available QUIC session. Inform the delegate how long to // delay the main job. - if (rv == ERR_IO_PENDING) { - delegate_->MaybeSetWaitTimeForMainJob( - quic_request_.GetTimeDelayForWaitingJob()); - } + delegate_->MaybeSetWaitTimeForMainJob( + quic_request_.GetTimeDelayForWaitingJob()); + expect_on_quic_host_resolution_ = + quic_request_.WaitForHostResolution(base::BindRepeating( + &Job::OnQuicHostResolution, base::Unretained(this))); } return rv; } @@ -928,9 +920,9 @@ int HttpStreamFactoryImpl::Job::DoInitConnectionImpl() { // connection this request can pool to. If so, then go straight to using // that. if (CanUseExistingSpdySession()) { - existing_spdy_session_ = - session_->spdy_session_pool()->push_promise_index()->Find( - spdy_session_key_, origin_url_); + session_->spdy_session_pool()->push_promise_index()->ClaimPushedStream( + spdy_session_key_, origin_url_, request_info_, &existing_spdy_session_, + &pushed_stream_id_); if (!existing_spdy_session_) { existing_spdy_session_ = session_->spdy_session_pool()->FindAvailableSession( @@ -961,7 +953,8 @@ int HttpStreamFactoryImpl::Job::DoInitConnectionImpl() { } if (job_type_ == PRECONNECT) { - DCHECK(!delegate_->for_websockets()); + DCHECK(!is_websocket_); + DCHECK(request_info_.socket_tag == SocketTag()); return PreconnectSocketsForHttpRequest( GetSocketGroup(), destination_, request_info_.extra_headers, request_info_.load_flags, priority_, session_, proxy_info_, @@ -977,7 +970,8 @@ int HttpStreamFactoryImpl::Job::DoInitConnectionImpl() { ? base::Bind(&Job::OnHostResolution, session_->spdy_session_pool(), spdy_session_key_, enable_ip_based_pooling_) : OnHostResolutionCallback(); - if (delegate_->for_websockets()) { + if (is_websocket_) { + DCHECK(request_info_.socket_tag == SocketTag()); SSLConfig websocket_server_ssl_config = server_ssl_config_; websocket_server_ssl_config.alpn_protos.clear(); return InitSocketHandleForWebSocketRequest( @@ -992,8 +986,14 @@ int HttpStreamFactoryImpl::Job::DoInitConnectionImpl() { GetSocketGroup(), destination_, request_info_.extra_headers, request_info_.load_flags, priority_, session_, proxy_info_, expect_spdy_, quic_version_, server_ssl_config_, proxy_ssl_config_, - request_info_.privacy_mode, net_log_, connection_.get(), - resolution_callback, io_callback_); + request_info_.privacy_mode, request_info_.socket_tag, net_log_, + connection_.get(), resolution_callback, io_callback_); +} + +void HttpStreamFactoryImpl::Job::OnQuicHostResolution(int result) { + DCHECK(expect_on_quic_host_resolution_); + expect_on_quic_host_resolution_ = false; + delegate_->OnConnectionInitialized(this, result); } int HttpStreamFactoryImpl::Job::DoInitConnectionComplete(int result) { @@ -1105,7 +1105,7 @@ int HttpStreamFactoryImpl::Job::DoInitConnectionComplete(int result) { // Quic session is closed before stream can be created. return ERR_CONNECTION_CLOSED; } - stream_.reset(new QuicHttpStream(std::move(session))); + stream_ = std::make_unique<QuicHttpStream>(std::move(session)); } next_state_ = STATE_NONE; return OK; @@ -1146,9 +1146,9 @@ int HttpStreamFactoryImpl::Job::DoWaitingUserAction(int result) { int HttpStreamFactoryImpl::Job::SetSpdyHttpStreamOrBidirectionalStreamImpl( base::WeakPtr<SpdySession> session, bool direct) { - // TODO(ricea): Restore the code for WebSockets over SPDY once it's - // implemented. - if (delegate_->for_websockets()) + // TODO(bnc): Restore the code for WebSockets over HTTP/2 once it is + // implemented. https://crbug.com/801564. + if (is_websocket_) return ERR_NOT_IMPLEMENTED; if (stream_type_ == HttpStreamRequest::BIDIRECTIONAL_STREAM) { bidirectional_stream_impl_ = std::make_unique<BidirectionalStreamSpdyImpl>( @@ -1162,8 +1162,8 @@ int HttpStreamFactoryImpl::Job::SetSpdyHttpStreamOrBidirectionalStreamImpl( bool use_relative_url = direct || request_info_.url.SchemeIs(url::kHttpsScheme); - stream_ = std::make_unique<SpdyHttpStream>(session, use_relative_url, - net_log_.source()); + stream_ = std::make_unique<SpdyHttpStream>( + session, pushed_stream_id_, use_relative_url, net_log_.source()); return OK; } @@ -1186,7 +1186,7 @@ int HttpStreamFactoryImpl::Job::DoCreateStream() { bool using_proxy = (proxy_info_.is_http() || proxy_info_.is_https()) && (request_info_.url.SchemeIs(url::kHttpScheme) || request_info_.url.SchemeIs(url::kFtpScheme)); - if (delegate_->for_websockets()) { + if (is_websocket_) { DCHECK_NE(job_type_, PRECONNECT); DCHECK(delegate_->websocket_handshake_stream_create_helper()); websocket_stream_ = @@ -1205,9 +1205,9 @@ int HttpStreamFactoryImpl::Job::DoCreateStream() { // It is possible that a pushed stream has been opened by a server since last // time Job checked above. if (!existing_spdy_session_) { - existing_spdy_session_ = - session_->spdy_session_pool()->push_promise_index()->Find( - spdy_session_key_, origin_url_); + session_->spdy_session_pool()->push_promise_index()->ClaimPushedStream( + spdy_session_key_, origin_url_, request_info_, &existing_spdy_session_, + &pushed_stream_id_); // It is also possible that an HTTP/2 connection has been established since // last time Job checked above. if (!existing_spdy_session_) { @@ -1472,12 +1472,13 @@ HttpStreamFactoryImpl::JobFactory::CreateMainJob( const SSLConfig& proxy_ssl_config, HostPortPair destination, GURL origin_url, + bool is_websocket, bool enable_ip_based_pooling, NetLog* net_log) { return std::make_unique<HttpStreamFactoryImpl::Job>( delegate, job_type, session, request_info, priority, proxy_info, server_ssl_config, proxy_ssl_config, destination, origin_url, - kProtoUnknown, QUIC_VERSION_UNSUPPORTED, ProxyServer(), + kProtoUnknown, QUIC_VERSION_UNSUPPORTED, ProxyServer(), is_websocket, enable_ip_based_pooling, net_log); } @@ -1495,12 +1496,13 @@ HttpStreamFactoryImpl::JobFactory::CreateAltSvcJob( GURL origin_url, NextProto alternative_protocol, QuicTransportVersion quic_version, + bool is_websocket, bool enable_ip_based_pooling, NetLog* net_log) { return std::make_unique<HttpStreamFactoryImpl::Job>( delegate, job_type, session, request_info, priority, proxy_info, server_ssl_config, proxy_ssl_config, destination, origin_url, - alternative_protocol, quic_version, ProxyServer(), + alternative_protocol, quic_version, ProxyServer(), is_websocket, enable_ip_based_pooling, net_log); } @@ -1517,13 +1519,14 @@ HttpStreamFactoryImpl::JobFactory::CreateAltProxyJob( HostPortPair destination, GURL origin_url, const ProxyServer& alternative_proxy_server, + bool is_websocket, bool enable_ip_based_pooling, NetLog* net_log) { return std::make_unique<HttpStreamFactoryImpl::Job>( delegate, job_type, session, request_info, priority, proxy_info, server_ssl_config, proxy_ssl_config, destination, origin_url, kProtoUnknown, QUIC_VERSION_UNSUPPORTED, alternative_proxy_server, - enable_ip_based_pooling, net_log); + is_websocket, enable_ip_based_pooling, net_log); } } // namespace net diff --git a/chromium/net/http/http_stream_factory_impl_job.h b/chromium/net/http/http_stream_factory_impl_job.h index 3fdec071b95..aa87699644b 100644 --- a/chromium/net/http/http_stream_factory_impl_job.h +++ b/chromium/net/http/http_stream_factory_impl_job.h @@ -152,8 +152,6 @@ class HttpStreamFactoryImpl::Job { websocket_handshake_stream_create_helper() = 0; virtual void MaybeSetWaitTimeForMainJob(const base::TimeDelta& delay) = 0; - - virtual bool for_websockets() = 0; }; // Job is owned by |delegate|, hence |delegate| is valid for the lifetime of @@ -192,6 +190,7 @@ class HttpStreamFactoryImpl::Job { NextProto alternative_protocol, QuicTransportVersion quic_version, const ProxyServer& alternative_proxy_server, + bool is_websocket, bool enable_ip_based_pooling, NetLog* net_log); virtual ~Job(); @@ -254,10 +253,6 @@ class HttpStreamFactoryImpl::Job { bool should_reconsider_proxy() const { return should_reconsider_proxy_; } - // TODO(xunjieli): Added to investigate crbug.com/711721. Remove when no - // longer needed. - void LogHistograms() const; - NetErrorDetails* net_error_details() { return &net_error_details_; } private: @@ -318,6 +313,11 @@ class HttpStreamFactoryImpl::Job { int StartInternal(); int DoInitConnectionImpl(); + // If this is a QUIC alt job, then this function is called when host + // resolution completes. It's called with the next result after host + // resolution, not the result of host resolution itself. + void OnQuicHostResolution(int result); + // Each of these methods corresponds to a State value. Those with an input // argument receive the result from the previous state. If a method returns // ERR_IO_PENDING, then the result from OnIOComplete will be passed to the @@ -337,7 +337,7 @@ class HttpStreamFactoryImpl::Job { void ResumeInitConnection(); // Creates a SpdyHttpStream or a BidirectionalStreamImpl from the given values // and sets to |stream_| or |bidirectional_stream_impl_| respectively. Does - // nothing if |stream_factory_| is for WebSockets. + // nothing if |stream_factory_| is for WebSocket. int SetSpdyHttpStreamOrBidirectionalStreamImpl( base::WeakPtr<SpdySession> session, bool direct); @@ -415,9 +415,6 @@ class HttpStreamFactoryImpl::Job { std::unique_ptr<ClientSocketHandle> connection_; HttpNetworkSession* const session_; - // |state_| is only used for LogHistograms(). - State state_; - State next_state_; // The server we are trying to reach, could be that of the origin or of the @@ -432,6 +429,9 @@ class HttpStreamFactoryImpl::Job { // request. const ProxyServer alternative_proxy_server_; + // True if request is for Websocket. + const bool is_websocket_; + // Enable pooling to a SpdySession with matching IP and certificate // even if the SpdySessionKey is different. const bool enable_ip_based_pooling_; @@ -464,6 +464,10 @@ class HttpStreamFactoryImpl::Job { QuicStreamRequest quic_request_; + // Only valid for a QUIC job. Set when a QUIC connection is started. If true, + // then OnQuicHostResolution() is expected to be called in the future. + bool expect_on_quic_host_resolution_; + // True if this job used an existing QUIC session. bool using_existing_quic_session_; @@ -491,6 +495,12 @@ class HttpStreamFactoryImpl::Job { // Initialized when we have an existing SpdySession. base::WeakPtr<SpdySession> existing_spdy_session_; + // Once Job claims a pushed stream on a SpdySession, |pushed_stream_id_| is + // the ID of the claimed stream, and |existing_spdy_session_| points to that + // SpdySession. Otherwise |pushed_stream_id_| is set to kNoPushedStreamFound + // (but |existing_spdy_session_| can still be non-null). + SpdyStreamId pushed_stream_id_; + // True if not connecting to an Https proxy for an Http url. const bool spdy_session_direct_; @@ -527,6 +537,7 @@ class HttpStreamFactoryImpl::JobFactory { const SSLConfig& proxy_ssl_config, HostPortPair destination, GURL origin_url, + bool is_websocket, bool enable_ip_based_pooling, NetLog* net_log); @@ -543,6 +554,7 @@ class HttpStreamFactoryImpl::JobFactory { GURL origin_url, NextProto alternative_protocol, QuicTransportVersion quic_version, + bool is_websocket, bool enable_ip_based_pooling, NetLog* net_log); @@ -558,6 +570,7 @@ class HttpStreamFactoryImpl::JobFactory { HostPortPair destination, GURL origin_url, const ProxyServer& alternative_proxy_server, + bool is_websocket, bool enable_ip_based_pooling, NetLog* net_log); }; diff --git a/chromium/net/http/http_stream_factory_impl_job_controller.cc b/chromium/net/http/http_stream_factory_impl_job_controller.cc index e5631fece20..0722a6393d7 100644 --- a/chromium/net/http/http_stream_factory_impl_job_controller.cc +++ b/chromium/net/http/http_stream_factory_impl_job_controller.cc @@ -7,6 +7,7 @@ #include <string> #include <utility> +#include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" @@ -64,6 +65,7 @@ HttpStreamFactoryImpl::JobController::JobController( JobFactory* job_factory, const HttpRequestInfo& request_info, bool is_preconnect, + bool is_websocket, bool enable_ip_based_pooling, bool enable_alternative_services, const SSLConfig& server_ssl_config, @@ -74,6 +76,7 @@ HttpStreamFactoryImpl::JobController::JobController( request_(nullptr), delegate_(delegate), is_preconnect_(is_preconnect), + is_websocket_(is_websocket), enable_ip_based_pooling_(enable_ip_based_pooling), enable_alternative_services_(enable_alternative_services), alternative_job_net_error_(OK), @@ -83,7 +86,7 @@ HttpStreamFactoryImpl::JobController::JobController( bound_job_(nullptr), can_start_alternative_proxy_job_(true), next_state_(STATE_RESOLVE_PROXY), - pac_request_(nullptr), + proxy_resolve_request_(nullptr), io_callback_( base::Bind(&JobController::OnIOComplete, base::Unretained(this))), request_info_(request_info), @@ -105,17 +108,13 @@ HttpStreamFactoryImpl::JobController::~JobController() { main_job_.reset(); alternative_job_.reset(); bound_job_ = nullptr; - if (pac_request_) { + if (proxy_resolve_request_) { DCHECK_EQ(STATE_RESOLVE_PROXY_COMPLETE, next_state_); - session_->proxy_service()->CancelPacRequest(pac_request_); + session_->proxy_service()->CancelRequest(proxy_resolve_request_); } net_log_.EndEvent(NetLogEventType::HTTP_STREAM_JOB_CONTROLLER); } -bool HttpStreamFactoryImpl::JobController::for_websockets() { - return factory_->for_websockets_; -} - std::unique_ptr<HttpStreamFactoryImpl::Request> HttpStreamFactoryImpl::JobController::Start( HttpStreamRequest::Delegate* delegate, @@ -160,7 +159,7 @@ void HttpStreamFactoryImpl::JobController::Preconnect(int num_streams) { LoadState HttpStreamFactoryImpl::JobController::GetLoadState() const { DCHECK(request_); if (next_state_ == STATE_RESOLVE_PROXY_COMPLETE) - return session_->proxy_service()->GetLoadState(pac_request_); + return session_->proxy_service()->GetLoadState(proxy_resolve_request_); if (bound_job_) return bound_job_->GetLoadState(); if (main_job_) @@ -210,7 +209,7 @@ void HttpStreamFactoryImpl::JobController::OnStreamReadyOnPooledConnection( const ProxyInfo& proxy_info, std::unique_ptr<HttpStream> stream) { DCHECK(request_->completed()); - DCHECK(!factory_->for_websockets_); + DCHECK(!is_websocket_); DCHECK_EQ(HttpStreamRequest::HTTP_STREAM, request_->stream_type()); main_job_.reset(); @@ -227,7 +226,7 @@ void HttpStreamFactoryImpl::JobController:: const ProxyInfo& used_proxy_info, std::unique_ptr<BidirectionalStreamImpl> stream) { DCHECK(request_->completed()); - DCHECK(!factory_->for_websockets_); + DCHECK(!is_websocket_); DCHECK_EQ(HttpStreamRequest::BIDIRECTIONAL_STREAM, request_->stream_type()); main_job_.reset(); @@ -257,7 +256,7 @@ void HttpStreamFactoryImpl::JobController::OnStreamReady( if (!request_) return; - DCHECK(!factory_->for_websockets_); + DCHECK(!is_websocket_); DCHECK_EQ(HttpStreamRequest::HTTP_STREAM, request_->stream_type()); OnJobSucceeded(job); DCHECK(request_->completed()); @@ -285,7 +284,7 @@ void HttpStreamFactoryImpl::JobController::OnBidirectionalStreamImplReady( std::unique_ptr<BidirectionalStreamImpl> stream = job->ReleaseBidirectionalStream(); DCHECK(stream); - DCHECK(!factory_->for_websockets_); + DCHECK(!is_websocket_); DCHECK_EQ(HttpStreamRequest::BIDIRECTIONAL_STREAM, request_->stream_type()); OnJobSucceeded(job); @@ -305,7 +304,7 @@ void HttpStreamFactoryImpl::JobController::OnWebSocketHandshakeStreamReady( if (!request_) return; - DCHECK(factory_->for_websockets_); + DCHECK(is_websocket_); DCHECK_EQ(HttpStreamRequest::HTTP_STREAM, request_->stream_type()); DCHECK(stream); @@ -494,9 +493,9 @@ void HttpStreamFactoryImpl::JobController::OnNewSpdySessionReady( MarkRequestComplete(was_alpn_negotiated, negotiated_protocol, using_spdy); - if (for_websockets()) { - // TODO(ricea): Re-instate this code when WebSockets over SPDY is - // implemented. + if (is_websocket_) { + // TODO(bnc): Re-instate this code when WebSockets over HTTP/2 is + // implemented. https://crbug.com/801564. NOTREACHED(); } else if (job->stream_type() == HttpStreamRequest::BIDIRECTIONAL_STREAM) { std::unique_ptr<BidirectionalStreamImpl> bidirectional_stream_impl = @@ -680,13 +679,6 @@ bool HttpStreamFactoryImpl::JobController::HasPendingAltJob() const { return alternative_job_.get() != nullptr; } -void HttpStreamFactoryImpl::JobController::LogHistograms() const { - if (main_job_) - main_job_->LogHistograms(); - if (alternative_job_) - alternative_job_->LogHistograms(); -} - size_t HttpStreamFactoryImpl::JobController::EstimateMemoryUsage() const { return base::trace_event::EstimateMemoryUsage(main_job_) + base::trace_event::EstimateMemoryUsage(alternative_job_); @@ -745,7 +737,7 @@ int HttpStreamFactoryImpl::JobController::DoLoop(int rv) { } int HttpStreamFactoryImpl::JobController::DoResolveProxy() { - DCHECK(!pac_request_); + DCHECK(!proxy_resolve_request_); DCHECK(session_); next_state_ = STATE_RESOLVE_PROXY_COMPLETE; @@ -760,13 +752,13 @@ int HttpStreamFactoryImpl::JobController::DoResolveProxy() { return session_->proxy_service()->ResolveProxy( origin_url, request_info_.method, &proxy_info_, io_callback_, - &pac_request_, session_->context().proxy_delegate, net_log_); + &proxy_resolve_request_, session_->context().proxy_delegate, net_log_); } int HttpStreamFactoryImpl::JobController::DoResolveProxyComplete(int rv) { DCHECK_NE(ERR_IO_PENDING, rv); - pac_request_ = nullptr; + proxy_resolve_request_ = nullptr; net_log_.AddEvent( NetLogEventType::HTTP_STREAM_JOB_CONTROLLER_PROXY_SERVER_RESOLVED, base::Bind( @@ -824,12 +816,12 @@ int HttpStreamFactoryImpl::JobController::DoCreateJobs() { this, PRECONNECT, session_, request_info_, IDLE, proxy_info_, server_ssl_config_, proxy_ssl_config_, alternative_destination, origin_url, alternative_service_info_.protocol(), quic_version, - enable_ip_based_pooling_, session_->net_log()); + is_websocket_, enable_ip_based_pooling_, session_->net_log()); } else { main_job_ = job_factory_->CreateMainJob( this, PRECONNECT, session_, request_info_, IDLE, proxy_info_, server_ssl_config_, proxy_ssl_config_, destination, origin_url, - enable_ip_based_pooling_, session_->net_log()); + is_websocket_, enable_ip_based_pooling_, session_->net_log()); } main_job_->Preconnect(num_streams_); return OK; @@ -837,7 +829,7 @@ int HttpStreamFactoryImpl::JobController::DoCreateJobs() { main_job_ = job_factory_->CreateMainJob( this, MAIN, session_, request_info_, priority_, proxy_info_, server_ssl_config_, proxy_ssl_config_, destination, origin_url, - enable_ip_based_pooling_, net_log_.net_log()); + is_websocket_, enable_ip_based_pooling_, net_log_.net_log()); // Alternative Service can only be set for HTTPS requests while Alternative // Proxy is set for HTTP requests. if (alternative_service_info_.protocol() != kProtoUnknown) { @@ -855,7 +847,7 @@ int HttpStreamFactoryImpl::JobController::DoCreateJobs() { this, ALTERNATIVE, session_, request_info_, priority_, proxy_info_, server_ssl_config_, proxy_ssl_config_, alternative_destination, origin_url, alternative_service_info_.protocol(), quic_version, - enable_ip_based_pooling_, net_log_.net_log()); + is_websocket_, enable_ip_based_pooling_, net_log_.net_log()); main_job_is_blocked_ = true; alternative_job_->Start(request_->stream_type()); @@ -870,7 +862,7 @@ int HttpStreamFactoryImpl::JobController::DoCreateJobs() { alternative_job_ = job_factory_->CreateAltProxyJob( this, ALTERNATIVE, session_, request_info_, priority_, alternative_proxy_info, server_ssl_config_, proxy_ssl_config_, - destination, origin_url, alternative_proxy_server, + destination, origin_url, alternative_proxy_server, is_websocket_, enable_ip_based_pooling_, net_log_.net_log()); can_start_alternative_proxy_job_ = false; @@ -921,7 +913,7 @@ void HttpStreamFactoryImpl::JobController::OrphanUnboundJob() { RemoveRequestFromSpdySessionRequestMap(); if (bound_job_->job_type() == MAIN && alternative_job_) { - DCHECK(!for_websockets()); + DCHECK(!is_websocket_); // Allow |alternative_job_| to run to completion, rather than resetting it // to check if there is any broken alternative service to report. // OnOrphanedJobComplete() will clean up |this| when the job completes. @@ -998,7 +990,7 @@ void HttpStreamFactoryImpl::JobController::ReportBrokenAlternativeService() { int error_to_report = alternative_job_net_error_; alternative_job_net_error_ = OK; - UMA_HISTOGRAM_SPARSE_SLOWLY("Net.AlternateServiceFailed", -error_to_report); + base::UmaHistogramSparse("Net.AlternateServiceFailed", -error_to_report); if (error_to_report == ERR_NETWORK_CHANGED || error_to_report == ERR_INTERNET_DISCONNECTED) { @@ -1228,12 +1220,7 @@ bool HttpStreamFactoryImpl::JobController:: return false; } - ProxyDelegate* proxy_delegate = session_->context().proxy_delegate; - if (!proxy_delegate) - return false; - proxy_delegate->GetAlternativeProxy(url, proxy_info.proxy_server(), - alternative_proxy_server); - + *alternative_proxy_server = proxy_info.alternative_proxy(); if (!alternative_proxy_server->is_valid()) return false; @@ -1286,7 +1273,7 @@ int HttpStreamFactoryImpl::JobController::ReconsiderProxyAfterError(Job* job, int error) { // ReconsiderProxyAfterError() should only be called when the last job fails. DCHECK(!(alternative_job_ && main_job_)); - DCHECK(!pac_request_); + DCHECK(!proxy_resolve_request_); DCHECK(session_); if (!job->should_reconsider_proxy()) @@ -1311,7 +1298,7 @@ int HttpStreamFactoryImpl::JobController::ReconsiderProxyAfterError(Job* job, int rv = session_->proxy_service()->ReconsiderProxyAfterError( origin_url, request_info_.method, error, &proxy_info_, io_callback_, - &pac_request_, session_->context().proxy_delegate, net_log_); + &proxy_resolve_request_, session_->context().proxy_delegate, net_log_); if (rv == OK || rv == ERR_IO_PENDING) { if (!job->using_quic()) RemoveRequestFromSpdySessionRequestMap(); diff --git a/chromium/net/http/http_stream_factory_impl_job_controller.h b/chromium/net/http/http_stream_factory_impl_job_controller.h index ddd4dc07c9c..48d5cc65e76 100644 --- a/chromium/net/http/http_stream_factory_impl_job_controller.h +++ b/chromium/net/http/http_stream_factory_impl_job_controller.h @@ -35,6 +35,7 @@ class HttpStreamFactoryImpl::JobController JobFactory* job_factory, const HttpRequestInfo& request_info, bool is_preconnect, + bool is_websocket, bool enable_ip_based_pooling, bool enable_alternative_services, const SSLConfig& server_ssl_config, @@ -42,8 +43,6 @@ class HttpStreamFactoryImpl::JobController ~JobController() override; - bool for_websockets() override; - // Used in tests only for verification purpose. const Job* main_job() const { return main_job_.get(); } const Job* alternative_job() const { return alternative_job_.get(); } @@ -192,10 +191,6 @@ class HttpStreamFactoryImpl::JobController // Returns true if |this| has a pending alternative job that is not completed. bool HasPendingAltJob() const; - // TODO(xunjieli): Added to investigate crbug.com/711721. Remove when no - // longer needed. - void LogHistograms() const; - // Returns the estimated memory usage in bytes. size_t EstimateMemoryUsage() const; @@ -331,6 +326,9 @@ class HttpStreamFactoryImpl::JobController // True if this JobController is used to preconnect streams. const bool is_preconnect_; + // True if request is for Websocket. + const bool is_websocket_; + // Enable pooling to a SpdySession with matching IP and certificate even if // the SpdySessionKey is different. const bool enable_ip_based_pooling_; @@ -373,7 +371,7 @@ class HttpStreamFactoryImpl::JobController bool can_start_alternative_proxy_job_; State next_state_; - ProxyService::PacRequest* pac_request_; + ProxyService::Request* proxy_resolve_request_; CompletionCallback io_callback_; const HttpRequestInfo request_info_; ProxyInfo proxy_info_; diff --git a/chromium/net/http/http_stream_factory_impl_job_controller_unittest.cc b/chromium/net/http/http_stream_factory_impl_job_controller_unittest.cc index df7a00d97b1..48bfe8c0b56 100644 --- a/chromium/net/http/http_stream_factory_impl_job_controller_unittest.cc +++ b/chromium/net/http/http_stream_factory_impl_job_controller_unittest.cc @@ -15,6 +15,7 @@ #include "base/test/scoped_feature_list.h" #include "base/test/scoped_mock_time_message_loop_task_runner.h" #include "base/test/scoped_task_environment.h" +#include "base/test/test_mock_time_task_runner.h" #include "base/threading/platform_thread.h" #include "net/base/test_proxy_delegate.h" #include "net/dns/mock_host_resolver.h" @@ -244,8 +245,9 @@ class HttpStreamFactoryImplJobControllerTest : public ::testing::Test { if (create_job_controller_) { job_controller_ = new HttpStreamFactoryImpl::JobController( factory_, &request_delegate_, session_.get(), &job_factory_, - request_info, is_preconnect_, enable_ip_based_pooling_, - enable_alternative_services_, SSLConfig(), SSLConfig()); + request_info, is_preconnect_, false /* is_websocket */, + enable_ip_based_pooling_, enable_alternative_services_, SSLConfig(), + SSLConfig()); HttpStreamFactoryImplPeer::AddJobController(factory_, job_controller_); } } @@ -303,8 +305,12 @@ class HttpStreamFactoryImplJobControllerTest : public ::testing::Test { MockClock clock_; MockRandom random_generator_{0}; QuicTestPacketMaker client_maker_{ - HttpNetworkSession::Params().quic_supported_versions[0], 0, &clock_, - kServerHostname, Perspective::IS_CLIENT}; + HttpNetworkSession::Params().quic_supported_versions[0], + 0, + &clock_, + kServerHostname, + Perspective::IS_CLIENT, + false}; protected: BoundTestNetLog net_log_; @@ -433,8 +439,9 @@ class JobControllerReconsiderProxyAfterErrorTest HttpStreamFactoryImpl::JobController* job_controller = new HttpStreamFactoryImpl::JobController( factory_, &request_delegate_, session_.get(), &default_job_factory_, - request_info, is_preconnect_, enable_ip_based_pooling_, - enable_alternative_services_, SSLConfig(), SSLConfig()); + request_info, is_preconnect_, false /* is_websocket */, + enable_ip_based_pooling_, enable_alternative_services_, SSLConfig(), + SSLConfig()); HttpStreamFactoryImplPeer::AddJobController(factory_, job_controller); return job_controller->Start(&request_delegate_, nullptr, net_log_.bound(), HttpStreamRequest::HTTP_STREAM, @@ -546,18 +553,6 @@ TEST_P(JobControllerReconsiderProxyAfterErrorTest, ReconsiderProxyAfterError) { // as invalid so that it is not used for subsequent requests. EXPECT_FALSE( test_proxy_delegate_raw->alternative_proxy_server().is_valid()); - - if (set_alternative_proxy_server) { - // GetAlternativeProxy should be called only once for the first - // request. - EXPECT_EQ(1, - test_proxy_delegate_raw->get_alternative_proxy_invocations()); - } else { - // Alternative proxy server job is never started. So, ProxyDelegate is - // queried once per request. - EXPECT_EQ(2, - test_proxy_delegate_raw->get_alternative_proxy_invocations()); - } } EXPECT_TRUE(HttpStreamFactoryImplPeer::IsJobControllerDeleted(factory_)); } @@ -1375,12 +1370,18 @@ TEST_F(HttpStreamFactoryImplJobControllerTest, InvalidPortForQuic) { base::RunLoop().RunUntilIdle(); } -TEST_F(HttpStreamFactoryImplJobControllerTest, DelayedTCP) { - base::ScopedMockTimeMessageLoopTaskRunner test_task_runner; - auto failing_resolver = std::make_unique<MockHostResolver>(); - failing_resolver->set_ondemand_mode(true); - failing_resolver->rules()->AddSimulatedFailure("*google.com"); - session_deps_.host_resolver = std::move(failing_resolver); +// Verifies that the main job is not resumed until after the alt job completes +// host resolution. +TEST_F(HttpStreamFactoryImplJobControllerTest, HostResolutionHang) { + scoped_refptr<base::TestMockTimeTaskRunner> test_task_runner( + new base::TestMockTimeTaskRunner()); + base::TestMockTimeTaskRunner::ScopedContext test_task_runner_context( + test_task_runner.get()); + + auto hanging_resolver = std::make_unique<MockHostResolver>(); + hanging_resolver->set_ondemand_mode(true); + hanging_resolver->set_synchronous_mode(false); + session_deps_.host_resolver = std::move(hanging_resolver); HttpRequestInfo request_info; request_info.method = "GET"; @@ -1388,6 +1389,13 @@ TEST_F(HttpStreamFactoryImplJobControllerTest, DelayedTCP) { Initialize(request_info); + // handshake will fail asynchronously after mock data is unpaused. + MockQuicData quic_data; + quic_data.AddRead(ASYNC, ERR_IO_PENDING); // Pause + quic_data.AddRead(ASYNC, ERR_FAILED); + quic_data.AddWrite(ASYNC, ERR_FAILED); + quic_data.AddSocketDataToFactory(session_deps_.socket_factory.get()); + // Enable delayed TCP and set time delay for waiting job. QuicStreamFactory* quic_stream_factory = session_->quic_stream_factory(); quic_stream_factory->set_require_confirmation(false); @@ -1400,35 +1408,116 @@ TEST_F(HttpStreamFactoryImplJobControllerTest, DelayedTCP) { AlternativeService alternative_service(kProtoQUIC, server.host(), 443); SetAlternativeService(request_info, alternative_service); + // This prevents handshake from immediately succeeding. + crypto_client_stream_factory_.set_handshake_mode( + MockCryptoClientStream::COLD_START); + request_ = job_controller_->Start(&request_delegate_, nullptr, net_log_.bound(), HttpStreamRequest::HTTP_STREAM, DEFAULT_PRIORITY); + EXPECT_TRUE(job_controller_->main_job()); EXPECT_TRUE(job_controller_->alternative_job()); - EXPECT_TRUE(job_controller_->main_job()->is_waiting()); + EXPECT_TRUE(JobControllerPeer::main_job_is_blocked(job_controller_)); - // The alternative job stalls as host resolution hangs when creating the QUIC - // request and controller should resume the main job after delay. + // Since the alt job has not finished host resolution, there should be no + // delayed task posted to resume the main job. + EXPECT_CALL(*job_factory_.main_job(), Resume()).Times(0); + test_task_runner->FastForwardBy(base::TimeDelta::FromMicroseconds(50)); + EXPECT_TRUE(JobControllerPeer::main_job_is_blocked(job_controller_)); + + // Allow alt job host resolution to complete. + session_deps_.host_resolver->ResolveAllPending(); + + // Task to resume main job in 15 microseconds should be posted. EXPECT_TRUE(test_task_runner->HasPendingTask()); - EXPECT_EQ(1u, test_task_runner->GetPendingTaskCount()); + EXPECT_CALL(*job_factory_.main_job(), Resume()).Times(0); + test_task_runner->FastForwardBy(base::TimeDelta::FromMicroseconds(14)); EXPECT_CALL(*job_factory_.main_job(), Resume()).Times(1); - test_task_runner->FastForwardBy(base::TimeDelta::FromMicroseconds(15)); - EXPECT_FALSE(test_task_runner->HasPendingTask()); + test_task_runner->FastForwardBy(base::TimeDelta::FromMicroseconds(1)); EXPECT_TRUE(job_controller_->main_job()); EXPECT_TRUE(job_controller_->alternative_job()); + EXPECT_FALSE(JobControllerPeer::main_job_is_blocked(job_controller_)); + EXPECT_TRUE(JobControllerPeer::main_job_is_resumed(job_controller_)); - // |alternative_job| fails but should not report status to Request. + // Unpause mock quic data. + // Will cause |alternative_job| to fail, but its failure should not be + // reported to Request. EXPECT_CALL(request_delegate_, OnStreamFailed(_, _, _)).Times(0); - - EXPECT_FALSE(JobControllerPeer::main_job_is_blocked(job_controller_)); // OnStreamFailed will post a task to resume the main job immediately but // won't call Resume() on the main job since it's been resumed already. EXPECT_CALL(*job_factory_.main_job(), Resume()).Times(0); - // Now unblock Resolver so that alternate job (and QuicStreamFactory::Job) can - // be cleaned up. - session_deps_.host_resolver->ResolveAllPending(); - EXPECT_EQ(1u, test_task_runner->GetPendingTaskCount()); + quic_data.GetSequencedSocketData()->Resume(); + test_task_runner->FastForwardUntilNoTasksRemain(); + // Alt job should be cleaned up + EXPECT_FALSE(job_controller_->alternative_job()); +} + +TEST_F(HttpStreamFactoryImplJobControllerTest, DelayedTCP) { + scoped_refptr<base::TestMockTimeTaskRunner> test_task_runner( + new base::TestMockTimeTaskRunner()); + base::TestMockTimeTaskRunner::ScopedContext test_task_runner_context( + test_task_runner.get()); + + auto immediate_resolver = std::make_unique<MockHostResolver>(); + immediate_resolver->set_synchronous_mode(true); + session_deps_.host_resolver = std::move(immediate_resolver); + + HttpRequestInfo request_info; + request_info.method = "GET"; + request_info.url = GURL("https://www.google.com"); + + Initialize(request_info); + + // Handshake will fail asynchronously after mock data is unpaused. + MockQuicData quic_data; + quic_data.AddRead(ASYNC, ERR_IO_PENDING); // Pause + quic_data.AddRead(ASYNC, ERR_FAILED); + quic_data.AddWrite(ASYNC, ERR_FAILED); + quic_data.AddSocketDataToFactory(session_deps_.socket_factory.get()); + + // Enable delayed TCP and set time delay for waiting job. + QuicStreamFactory* quic_stream_factory = session_->quic_stream_factory(); + quic_stream_factory->set_require_confirmation(false); + ServerNetworkStats stats1; + stats1.srtt = base::TimeDelta::FromMicroseconds(10); + session_->http_server_properties()->SetServerNetworkStats( + url::SchemeHostPort(GURL("https://www.google.com")), stats1); + + url::SchemeHostPort server(request_info.url); + AlternativeService alternative_service(kProtoQUIC, server.host(), 443); + SetAlternativeService(request_info, alternative_service); + + // This prevents handshake from immediately succeeding. + crypto_client_stream_factory_.set_handshake_mode( + MockCryptoClientStream::COLD_START); + + request_ = + job_controller_->Start(&request_delegate_, nullptr, net_log_.bound(), + HttpStreamRequest::HTTP_STREAM, DEFAULT_PRIORITY); + + EXPECT_TRUE(job_controller_->main_job()); + EXPECT_TRUE(job_controller_->alternative_job()); + EXPECT_TRUE(job_controller_->main_job()->is_waiting()); + // Main job is not blocked but hasn't resumed yet; it should resume in 15us. + EXPECT_FALSE(JobControllerPeer::main_job_is_blocked(job_controller_)); + EXPECT_FALSE(JobControllerPeer::main_job_is_resumed(job_controller_)); + + // Task to resume main job in 15us should be posted. + EXPECT_TRUE(test_task_runner->HasPendingTask()); + EXPECT_CALL(*job_factory_.main_job(), Resume()).Times(0); + test_task_runner->FastForwardBy(base::TimeDelta::FromMicroseconds(14)); + EXPECT_CALL(*job_factory_.main_job(), Resume()).Times(1); + test_task_runner->FastForwardBy(base::TimeDelta::FromMicroseconds(1)); + + EXPECT_TRUE(job_controller_->main_job()); + EXPECT_TRUE(job_controller_->alternative_job()); + EXPECT_TRUE(JobControllerPeer::main_job_is_resumed(job_controller_)); + + // Unpause mock quic data and run all remaining tasks. Alt-job should fail + // and be cleaned up. + quic_data.GetSequencedSocketData()->Resume(); test_task_runner->FastForwardUntilNoTasksRemain(); EXPECT_FALSE(job_controller_->alternative_job()); } @@ -1510,8 +1599,7 @@ TEST_F(HttpStreamFactoryImplJobControllerTest, ResumeMainJobLaterCanceled) { // Reset task environment back to the default type. // TODO(xunjieli): Remove this temporary workaround once crbug.com/791831 is // fixed. - NetTestSuite::SetScopedTaskEnvironment( - base::test::ScopedTaskEnvironment::MainThreadType::IO); + NetTestSuite::ResetScopedTaskEnvironment(); } // Test that main job is blocked for kMaxDelayTimeForMainJob(3s) if @@ -1519,15 +1607,17 @@ TEST_F(HttpStreamFactoryImplJobControllerTest, ResumeMainJobLaterCanceled) { // which would potentially delay the main job for a extremely long time in // delayed tcp case. TEST_F(HttpStreamFactoryImplJobControllerTest, DelayedTCPWithLargeSrtt) { - // Overrides the main thread's message loop with a mock tick clock so that we - // could verify the main job is resumed with appropriate delay. - base::ScopedMockTimeMessageLoopTaskRunner test_task_runner; + scoped_refptr<base::TestMockTimeTaskRunner> test_task_runner( + new base::TestMockTimeTaskRunner()); + base::TestMockTimeTaskRunner::ScopedContext test_task_runner_context( + test_task_runner.get()); + // The max delay time should be in sync with .cc file. base::TimeDelta kMaxDelayTimeForMainJob = base::TimeDelta::FromSeconds(3); - auto failing_resolver = std::make_unique<MockHostResolver>(); - failing_resolver->set_ondemand_mode(true); - failing_resolver->rules()->AddSimulatedFailure("*google.com"); - session_deps_.host_resolver = std::move(failing_resolver); + + auto immediate_resolver = std::make_unique<MockHostResolver>(); + immediate_resolver->set_synchronous_mode(true); + session_deps_.host_resolver = std::move(immediate_resolver); HttpRequestInfo request_info; request_info.method = "GET"; @@ -1535,7 +1625,14 @@ TEST_F(HttpStreamFactoryImplJobControllerTest, DelayedTCPWithLargeSrtt) { Initialize(request_info); - // Enable delayed TCP and set a extremely large time delay for waiting job. + // handshake will fail asynchronously after mock data is unpaused. + MockQuicData quic_data; + quic_data.AddRead(ASYNC, ERR_IO_PENDING); // Pause + quic_data.AddRead(ASYNC, ERR_FAILED); + quic_data.AddWrite(ASYNC, ERR_FAILED); + quic_data.AddSocketDataToFactory(session_deps_.socket_factory.get()); + + // Enable delayed TCP and set time delay for waiting job. QuicStreamFactory* quic_stream_factory = session_->quic_stream_factory(); quic_stream_factory->set_require_confirmation(false); ServerNetworkStats stats1; @@ -1543,47 +1640,53 @@ TEST_F(HttpStreamFactoryImplJobControllerTest, DelayedTCPWithLargeSrtt) { session_->http_server_properties()->SetServerNetworkStats( url::SchemeHostPort(GURL("https://www.google.com")), stats1); - // Set a SPDY alternative service for the server. url::SchemeHostPort server(request_info.url); AlternativeService alternative_service(kProtoQUIC, server.host(), 443); SetAlternativeService(request_info, alternative_service); + // This prevents handshake from immediately succeeding. + crypto_client_stream_factory_.set_handshake_mode( + MockCryptoClientStream::COLD_START); + request_ = job_controller_->Start(&request_delegate_, nullptr, net_log_.bound(), HttpStreamRequest::HTTP_STREAM, DEFAULT_PRIORITY); + EXPECT_TRUE(job_controller_->main_job()); EXPECT_TRUE(job_controller_->alternative_job()); - EXPECT_TRUE(job_controller_->main_job()->is_waiting()); + // Main job is not blocked but hasn't resumed yet; it should resume in 3s. + EXPECT_FALSE(JobControllerPeer::main_job_is_blocked(job_controller_)); + EXPECT_FALSE(JobControllerPeer::main_job_is_resumed(job_controller_)); - // The alternative job stalls as host resolution hangs when creating the QUIC - // request and controller should resume the main job after delay. + // Task to resume main job in 3 seconds should be posted. EXPECT_TRUE(test_task_runner->HasPendingTask()); - EXPECT_EQ(1u, test_task_runner->GetPendingTaskCount()); - + EXPECT_CALL(*job_factory_.main_job(), Resume()).Times(0); + test_task_runner->FastForwardBy(kMaxDelayTimeForMainJob - + base::TimeDelta::FromMicroseconds(1)); EXPECT_CALL(*job_factory_.main_job(), Resume()).Times(1); - // Move forward the task runner with kMaxDelayTimeForMainJob and verify the - // main job is resumed. - test_task_runner->FastForwardBy(kMaxDelayTimeForMainJob); - EXPECT_FALSE(test_task_runner->HasPendingTask()); + test_task_runner->FastForwardBy(base::TimeDelta::FromMicroseconds(1)); - // Now unblock Resolver so that alternate job (and QuicStreamFactory::Job) can - // be cleaned up. - session_deps_.host_resolver->ResolveAllPending(); - EXPECT_EQ(1u, test_task_runner->GetPendingTaskCount()); + EXPECT_TRUE(job_controller_->main_job()); + EXPECT_TRUE(job_controller_->alternative_job()); + EXPECT_TRUE(JobControllerPeer::main_job_is_resumed(job_controller_)); + + // Unpause mock quic data and run all remaining tasks. Alt-job should fail + // and be cleaned up. + quic_data.GetSequencedSocketData()->Resume(); test_task_runner->FastForwardUntilNoTasksRemain(); EXPECT_FALSE(job_controller_->alternative_job()); } TEST_F(HttpStreamFactoryImplJobControllerTest, ResumeMainJobImmediatelyOnStreamFailed) { - // Overrides the main thread's message loop with a mock tick clock so that we - // could verify the main job is resumed with appropriate delay. - base::ScopedMockTimeMessageLoopTaskRunner test_task_runner; + scoped_refptr<base::TestMockTimeTaskRunner> test_task_runner( + new base::TestMockTimeTaskRunner()); + base::TestMockTimeTaskRunner::ScopedContext test_task_runner_context( + test_task_runner.get()); - auto failing_resolver = std::make_unique<MockHostResolver>(); - failing_resolver->set_ondemand_mode(true); - failing_resolver->rules()->AddSimulatedFailure("*google.com"); - session_deps_.host_resolver = std::move(failing_resolver); + auto immediate_resolver = std::make_unique<MockHostResolver>(); + immediate_resolver->set_synchronous_mode(true); + session_deps_.host_resolver = std::move(immediate_resolver); HttpRequestInfo request_info; request_info.method = "GET"; @@ -1591,6 +1694,13 @@ TEST_F(HttpStreamFactoryImplJobControllerTest, Initialize(request_info); + // handshake will fail asynchronously after mock data is unpaused. + MockQuicData quic_data; + quic_data.AddRead(ASYNC, ERR_IO_PENDING); // Pause + quic_data.AddRead(ASYNC, ERR_FAILED); + quic_data.AddWrite(ASYNC, ERR_FAILED); + quic_data.AddSocketDataToFactory(session_deps_.socket_factory.get()); + // Enable delayed TCP and set time delay for waiting job. QuicStreamFactory* quic_stream_factory = session_->quic_stream_factory(); quic_stream_factory->set_require_confirmation(false); @@ -1599,44 +1709,48 @@ TEST_F(HttpStreamFactoryImplJobControllerTest, session_->http_server_properties()->SetServerNetworkStats( url::SchemeHostPort(GURL("https://www.google.com")), stats1); - // Set a SPDY alternative service for the server. url::SchemeHostPort server(request_info.url); AlternativeService alternative_service(kProtoQUIC, server.host(), 443); SetAlternativeService(request_info, alternative_service); - // The alternative job stalls as host resolution hangs when creating the QUIC - // request and controller should resume the main job with delay. - // OnStreamFailed should resume the main job immediately. + // This prevents handshake from immediately succeeding. + crypto_client_stream_factory_.set_handshake_mode( + MockCryptoClientStream::COLD_START); + request_ = job_controller_->Start(&request_delegate_, nullptr, net_log_.bound(), HttpStreamRequest::HTTP_STREAM, DEFAULT_PRIORITY); + EXPECT_TRUE(job_controller_->main_job()); EXPECT_TRUE(job_controller_->alternative_job()); - EXPECT_TRUE(job_controller_->main_job()->is_waiting()); + // Main job is not blocked but hasn't resumed yet; it's scheduled to resume + // in 15us. + EXPECT_FALSE(JobControllerPeer::main_job_is_blocked(job_controller_)); + EXPECT_FALSE(JobControllerPeer::main_job_is_resumed(job_controller_)); + // Task to resume main job in 15us should be posted. EXPECT_TRUE(test_task_runner->HasPendingTask()); - EXPECT_EQ(1u, test_task_runner->GetPendingTaskCount()); - // |alternative_job| fails but should not report status to Request. - EXPECT_CALL(request_delegate_, OnStreamFailed(_, _, _)).Times(0); - // Now unblock Resolver to fail the alternate job. - session_deps_.host_resolver->ResolveAllPending(); - EXPECT_EQ(2u, test_task_runner->GetPendingTaskCount()); + EXPECT_CALL(*job_factory_.main_job(), Resume()).Times(0); + test_task_runner->FastForwardBy(base::TimeDelta::FromMicroseconds(1)); - // Verify the main job will be resumed immediately. + // Now unpause the mock quic data to fail the alt job. This should immediately + // resume the main job. EXPECT_CALL(*job_factory_.main_job(), Resume()).Times(1); - // Execute tasks that have no remaining delay. Tasks with nonzero delay will - // remain queued. - test_task_runner->RunUntilIdle(); + quic_data.GetSequencedSocketData()->Resume(); + test_task_runner->FastForwardBy(base::TimeDelta()); + + EXPECT_TRUE(job_controller_->main_job()); + EXPECT_FALSE(job_controller_->alternative_job()); + EXPECT_TRUE(JobControllerPeer::main_job_is_resumed(job_controller_)); // Verify there is another task to resume main job with delay but should // not call Resume() on the main job as main job has been resumed. EXPECT_TRUE(test_task_runner->HasPendingTask()); - EXPECT_EQ(1u, test_task_runner->GetPendingTaskCount()); EXPECT_CALL(*job_factory_.main_job(), Resume()).Times(0); test_task_runner->FastForwardBy(base::TimeDelta::FromMicroseconds(15)); - EXPECT_FALSE(test_task_runner->HasPendingTask()); - EXPECT_FALSE(job_controller_->alternative_job()); + + test_task_runner->FastForwardUntilNoTasksRemain(); } // Verifies that the alternative proxy server job is not created if the URL @@ -1660,7 +1774,6 @@ TEST_F(HttpStreamFactoryImplJobControllerTest, HttpsURL) { EXPECT_CALL(*job_factory_.main_job(), Resume()).Times(0); base::RunLoop().RunUntilIdle(); - EXPECT_EQ(0, test_proxy_delegate()->get_alternative_proxy_invocations()); } // Verifies that the alternative proxy server job is not created if the main job @@ -1685,31 +1798,37 @@ TEST_F(HttpStreamFactoryImplJobControllerTest, HttpURLWithNoProxy) { EXPECT_CALL(*job_factory_.main_job(), Resume()).Times(0); base::RunLoop().RunUntilIdle(); - - EXPECT_EQ(0, test_proxy_delegate()->get_alternative_proxy_invocations()); } // Verifies that the main job is resumed properly after a delay when the // alternative proxy server job hangs. TEST_F(HttpStreamFactoryImplJobControllerTest, DelayedTCPAlternativeProxy) { - // Overrides the main thread's message loop with a mock tick clock so that we - // could verify the main job is resumed with appropriate delay. - base::ScopedMockTimeMessageLoopTaskRunner test_task_runner; + scoped_refptr<base::TestMockTimeTaskRunner> test_task_runner( + new base::TestMockTimeTaskRunner()); + base::TestMockTimeTaskRunner::ScopedContext test_task_runner_context( + test_task_runner.get()); - auto failing_resolver = std::make_unique<MockHostResolver>(); - failing_resolver->set_ondemand_mode(true); - failing_resolver->rules()->AddSimulatedFailure("*myproxy.org"); - session_deps_.host_resolver = std::move(failing_resolver); + auto immediate_resolver = std::make_unique<MockHostResolver>(); + immediate_resolver->set_synchronous_mode(true); + session_deps_.host_resolver = std::move(immediate_resolver); UseAlternativeProxy(); HttpRequestInfo request_info; request_info.method = "GET"; - request_info.url = GURL("http://mail.example.org/"); + request_info.url = GURL("http://www.mail.example.org/"); + Initialize(request_info); EXPECT_TRUE(test_proxy_delegate()->alternative_proxy_server().is_quic()); + // Handshake will fail asynchronously after mock data is unpaused. + MockQuicData quic_data; + quic_data.AddRead(ASYNC, ERR_IO_PENDING); // Pause + quic_data.AddRead(ASYNC, ERR_FAILED); + quic_data.AddWrite(ASYNC, ERR_FAILED); + quic_data.AddSocketDataToFactory(session_deps_.socket_factory.get()); + // Enable delayed TCP and set time delay for waiting job. QuicStreamFactory* quic_stream_factory = session_->quic_stream_factory(); quic_stream_factory->set_require_confirmation(false); @@ -1718,32 +1837,39 @@ TEST_F(HttpStreamFactoryImplJobControllerTest, DelayedTCPAlternativeProxy) { session_->http_server_properties()->SetServerNetworkStats( url::SchemeHostPort(GURL("https://myproxy.org")), stats1); + url::SchemeHostPort server(request_info.url); + AlternativeService alternative_service(kProtoQUIC, server.host(), 443); + SetAlternativeService(request_info, alternative_service); + + // This prevents handshake from immediately succeeding. + crypto_client_stream_factory_.set_handshake_mode( + MockCryptoClientStream::COLD_START); + request_ = job_controller_->Start(&request_delegate_, nullptr, net_log_.bound(), HttpStreamRequest::HTTP_STREAM, DEFAULT_PRIORITY); + EXPECT_TRUE(job_controller_->main_job()); - EXPECT_TRUE(job_controller_->main_job()->is_waiting()); EXPECT_TRUE(job_controller_->alternative_job()); - // The main job is unblocked but is resumed one message loop iteration later. + EXPECT_TRUE(job_controller_->main_job()->is_waiting()); + // Main job is not blocked but hasn't resumed yet; it should resume in 15us. EXPECT_FALSE(JobControllerPeer::main_job_is_blocked(job_controller_)); EXPECT_FALSE(JobControllerPeer::main_job_is_resumed(job_controller_)); - EXPECT_EQ(1u, test_task_runner->GetPendingTaskCount()); - // Move forward the delay and verify the main job is resumed. + // Task to resume main job in 15us should be posted. + EXPECT_TRUE(test_task_runner->HasPendingTask()); + EXPECT_CALL(*job_factory_.main_job(), Resume()).Times(0); + test_task_runner->FastForwardBy(base::TimeDelta::FromMicroseconds(14)); EXPECT_CALL(*job_factory_.main_job(), Resume()).Times(1); - test_task_runner->FastForwardBy(base::TimeDelta::FromMicroseconds(15)); - EXPECT_FALSE(JobControllerPeer::main_job_is_blocked(job_controller_)); - EXPECT_TRUE(JobControllerPeer::main_job_is_resumed(job_controller_)); + test_task_runner->FastForwardBy(base::TimeDelta::FromMicroseconds(1)); - test_task_runner->RunUntilIdle(); - EXPECT_TRUE(test_proxy_delegate()->alternative_proxy_server().is_valid()); - EXPECT_EQ(1, test_proxy_delegate()->get_alternative_proxy_invocations()); - EXPECT_FALSE(test_task_runner->HasPendingTask()); + EXPECT_TRUE(job_controller_->main_job()); + EXPECT_TRUE(job_controller_->alternative_job()); + EXPECT_TRUE(JobControllerPeer::main_job_is_resumed(job_controller_)); - // Now unblock Resolver so that alternate job (and QuicStreamFactory::Job) can - // be cleaned up. - session_deps_.host_resolver->ResolveAllPending(); - EXPECT_EQ(1u, test_task_runner->GetPendingTaskCount()); + // Unpause mock quic data and run all remaining tasks. Alt-job should fail + // and be cleaned up. + quic_data.GetSequencedSocketData()->Resume(); test_task_runner->FastForwardUntilNoTasksRemain(); EXPECT_FALSE(job_controller_->alternative_job()); } @@ -1789,7 +1915,6 @@ TEST_F(HttpStreamFactoryImplJobControllerTest, FailAlternativeProxy) { // The alternative proxy server should be marked as bad. EXPECT_FALSE(test_proxy_delegate()->alternative_proxy_server().is_valid()); - EXPECT_EQ(1, test_proxy_delegate()->get_alternative_proxy_invocations()); request_.reset(); EXPECT_TRUE(HttpStreamFactoryImplPeer::IsJobControllerDeleted(factory_)); } @@ -1836,7 +1961,6 @@ TEST_F(HttpStreamFactoryImplJobControllerTest, // The alternative proxy server should not be marked as bad. EXPECT_TRUE(test_proxy_delegate()->alternative_proxy_server().is_valid()); - EXPECT_EQ(1, test_proxy_delegate()->get_alternative_proxy_invocations()); request_.reset(); EXPECT_TRUE(HttpStreamFactoryImplPeer::IsJobControllerDeleted(factory_)); } @@ -1987,8 +2111,9 @@ TEST_F(JobControllerLimitMultipleH2Requests, MultipleRequests) { HttpStreamFactoryImpl::JobController* job_controller = new HttpStreamFactoryImpl::JobController( factory_, request_delegates[i].get(), session_.get(), &job_factory_, - request_info, is_preconnect_, enable_ip_based_pooling_, - enable_alternative_services_, SSLConfig(), SSLConfig()); + request_info, is_preconnect_, false /* is_websocket */, + enable_ip_based_pooling_, enable_alternative_services_, SSLConfig(), + SSLConfig()); HttpStreamFactoryImplPeer::AddJobController(factory_, job_controller); auto request = job_controller->Start( request_delegates[i].get(), nullptr, net_log_.bound(), @@ -2060,8 +2185,9 @@ TEST_F(JobControllerLimitMultipleH2Requests, MultipleRequestsFirstRequestHang) { HttpStreamFactoryImpl::JobController* job_controller = new HttpStreamFactoryImpl::JobController( factory_, request_delegates[i].get(), session_.get(), &job_factory_, - request_info, is_preconnect_, enable_ip_based_pooling_, - enable_alternative_services_, SSLConfig(), SSLConfig()); + request_info, is_preconnect_, false /* is_websocket */, + enable_ip_based_pooling_, enable_alternative_services_, SSLConfig(), + SSLConfig()); HttpStreamFactoryImplPeer::AddJobController(factory_, job_controller); auto request = job_controller->Start( request_delegates[i].get(), nullptr, net_log_.bound(), @@ -2132,8 +2258,9 @@ TEST_F(JobControllerLimitMultipleH2Requests, HttpStreamFactoryImpl::JobController* job_controller = new HttpStreamFactoryImpl::JobController( factory_, request_delegates[i].get(), session_.get(), &job_factory_, - request_info, is_preconnect_, enable_ip_based_pooling_, - enable_alternative_services_, SSLConfig(), SSLConfig()); + request_info, is_preconnect_, false /* is_websocket */, + enable_ip_based_pooling_, enable_alternative_services_, SSLConfig(), + SSLConfig()); HttpStreamFactoryImplPeer::AddJobController(factory_, job_controller); auto request = job_controller->Start( request_delegates[i].get(), nullptr, net_log_.bound(), @@ -2185,8 +2312,9 @@ TEST_F(JobControllerLimitMultipleH2Requests, MultiplePreconnects) { HttpStreamFactoryImpl::JobController* job_controller = new HttpStreamFactoryImpl::JobController( factory_, request_delegates[i].get(), session_.get(), &job_factory_, - request_info, is_preconnect_, enable_ip_based_pooling_, - enable_alternative_services_, SSLConfig(), SSLConfig()); + request_info, is_preconnect_, false /* is_websocket */, + enable_ip_based_pooling_, enable_alternative_services_, SSLConfig(), + SSLConfig()); HttpStreamFactoryImplPeer::AddJobController(factory_, job_controller); job_controller->Preconnect(1); EXPECT_TRUE(job_controller->main_job()); @@ -2231,8 +2359,9 @@ TEST_F(JobControllerLimitMultipleH2Requests, H1NegotiatedForFirstRequest) { HttpStreamFactoryImpl::JobController* job_controller = new HttpStreamFactoryImpl::JobController( factory_, request_delegates[i].get(), session_.get(), &job_factory_, - request_info, is_preconnect_, enable_ip_based_pooling_, - enable_alternative_services_, SSLConfig(), SSLConfig()); + request_info, is_preconnect_, false /* is_websocket */, + enable_ip_based_pooling_, enable_alternative_services_, SSLConfig(), + SSLConfig()); HttpStreamFactoryImplPeer::AddJobController(factory_, job_controller); auto request = job_controller->Start( request_delegates[i].get(), nullptr, net_log_.bound(), @@ -2291,8 +2420,9 @@ TEST_F(JobControllerLimitMultipleH2Requests, QuicJobNotThrottled) { HttpStreamFactoryImpl::JobController* job_controller = new HttpStreamFactoryImpl::JobController( factory_, &request_delegate_, session_.get(), &default_job_factory, - request_info, is_preconnect_, enable_ip_based_pooling_, - enable_alternative_services_, SSLConfig(), SSLConfig()); + request_info, is_preconnect_, false /* is_websocket */, + enable_ip_based_pooling_, enable_alternative_services_, SSLConfig(), + SSLConfig()); HttpStreamFactoryImplPeer::AddJobController(factory_, job_controller); request_ = job_controller->Start(&request_delegate_, nullptr, net_log_.bound(), @@ -2385,6 +2515,7 @@ class HttpStreamFactoryImplJobControllerPreconnectTest job_controller_ = new HttpStreamFactoryImpl::JobController( factory_, &request_delegate_, session_.get(), &job_factory_, request_info_, /* is_preconnect = */ true, + /* is_websocket = */ false, /* enable_ip_based_pooling = */ true, /* enable_alternative_services = */ true, SSLConfig(), SSLConfig()); HttpStreamFactoryImplPeer::AddJobController(factory_, job_controller_); diff --git a/chromium/net/http/http_stream_factory_impl_request_unittest.cc b/chromium/net/http/http_stream_factory_impl_request_unittest.cc index 612b136d851..7e965679077 100644 --- a/chromium/net/http/http_stream_factory_impl_request_unittest.cc +++ b/chromium/net/http/http_stream_factory_impl_request_unittest.cc @@ -42,6 +42,7 @@ TEST_F(HttpStreamFactoryImplRequestTest, SetPriority) { auto job_controller = std::make_unique<HttpStreamFactoryImpl::JobController>( factory, &request_delegate, session.get(), &job_factory, request_info, /* is_preconnect = */ false, + /* is_websocket = */ false, /* enable_ip_based_pooling = */ true, /* enable_alternative_services = */ true, SSLConfig(), SSLConfig()); HttpStreamFactoryImpl::JobController* job_controller_raw_ptr = diff --git a/chromium/net/http/http_stream_factory_impl_unittest.cc b/chromium/net/http/http_stream_factory_impl_unittest.cc index b6a1a482d5e..b7ff5492b8c 100644 --- a/chromium/net/http/http_stream_factory_impl_unittest.cc +++ b/chromium/net/http/http_stream_factory_impl_unittest.cc @@ -50,6 +50,7 @@ #include "net/socket/client_socket_handle.h" #include "net/socket/mock_client_socket_pool_manager.h" #include "net/socket/next_proto.h" +#include "net/socket/socket_tag.h" #include "net/socket/socket_test_util.h" #include "net/spdy/chromium/spdy_session.h" #include "net/spdy/chromium/spdy_session_pool.h" @@ -99,6 +100,7 @@ class MockWebSocketHandshakeStream : public WebSocketHandshakeStreamBase { // HttpStream methods int InitializeStream(const HttpRequestInfo* request_info, + bool can_send_early, RequestPriority priority, const NetLogWithSource& net_log, const CompletionCallback& callback) override { @@ -157,7 +159,7 @@ class MockWebSocketHandshakeStream : public WebSocketHandshakeStreamBase { class MockHttpStreamFactoryImplForPreconnect : public HttpStreamFactoryImpl { public: explicit MockHttpStreamFactoryImplForPreconnect(HttpNetworkSession* session) - : HttpStreamFactoryImpl(session, false), + : HttpStreamFactoryImpl(session), preconnect_done_(false), waiting_for_preconnect_(false) {} @@ -388,6 +390,7 @@ class CapturePreconnectsSocketPool : public ParentPool { int RequestSocket(const std::string& group_name, const void* socket_params, RequestPriority priority, + const SocketTag& socket_tag, ClientSocketPool::RespectLimits respect_limits, ClientSocketHandle* handle, const CompletionCallback& callback, @@ -1021,16 +1024,6 @@ TEST_F(HttpStreamFactoryTest, WithQUICAlternativeProxyMarkedAsBad) { // If alternative proxy server was specified, it should have been marked // as invalid so that it is not used for subsequent requests. EXPECT_FALSE(test_proxy_delegate.alternative_proxy_server().is_valid()); - - if (set_alternative_proxy_server) { - // GetAlternativeProxy should be called only once for the first - // request. - EXPECT_EQ(1, test_proxy_delegate.get_alternative_proxy_invocations()); - } else { - // Alternative proxy server job is never started. So, ProxyDelegate is - // queried once per request. - EXPECT_EQ(2, test_proxy_delegate.get_alternative_proxy_invocations()); - } } } } @@ -1126,10 +1119,6 @@ TEST_F(HttpStreamFactoryTest, WithQUICAlternativeProxyNotMarkedAsBad) { // Alternative proxy server should be marked as invalid so that it is // not used for subsequent requests. EXPECT_FALSE(test_proxy_delegate.alternative_proxy_server().is_quic()); - - // GetAlternativeProxy should be called only once per request. - EXPECT_EQ(static_cast<int>(i + 1), - test_proxy_delegate.get_alternative_proxy_invocations()); } } } @@ -1818,12 +1807,11 @@ TEST_F(HttpStreamFactoryTest, RequestWebSocketBasicHandshakeStream) { StreamRequestWaiter waiter; WebSocketStreamCreateHelper create_helper; std::unique_ptr<HttpStreamRequest> request( - session->http_stream_factory_for_websocket() - ->RequestWebSocketHandshakeStream( - request_info, DEFAULT_PRIORITY, ssl_config, ssl_config, &waiter, - &create_helper, - /* enable_ip_based_pooling = */ true, - /* enable_alternative_services = */ true, NetLogWithSource())); + session->http_stream_factory()->RequestWebSocketHandshakeStream( + request_info, DEFAULT_PRIORITY, ssl_config, ssl_config, &waiter, + &create_helper, + /* enable_ip_based_pooling = */ true, + /* enable_alternative_services = */ true, NetLogWithSource())); waiter.WaitForStream(); EXPECT_TRUE(waiter.stream_done()); EXPECT_TRUE(nullptr == waiter.stream()); @@ -1863,12 +1851,11 @@ TEST_F(HttpStreamFactoryTest, RequestWebSocketBasicHandshakeStreamOverSSL) { StreamRequestWaiter waiter; WebSocketStreamCreateHelper create_helper; std::unique_ptr<HttpStreamRequest> request( - session->http_stream_factory_for_websocket() - ->RequestWebSocketHandshakeStream( - request_info, DEFAULT_PRIORITY, ssl_config, ssl_config, &waiter, - &create_helper, - /* enable_ip_based_pooling = */ true, - /* enable_alternative_services = */ true, NetLogWithSource())); + session->http_stream_factory()->RequestWebSocketHandshakeStream( + request_info, DEFAULT_PRIORITY, ssl_config, ssl_config, &waiter, + &create_helper, + /* enable_ip_based_pooling = */ true, + /* enable_alternative_services = */ true, NetLogWithSource())); waiter.WaitForStream(); EXPECT_TRUE(waiter.stream_done()); EXPECT_TRUE(nullptr == waiter.stream()); @@ -1906,12 +1893,11 @@ TEST_F(HttpStreamFactoryTest, RequestWebSocketBasicHandshakeStreamOverProxy) { StreamRequestWaiter waiter; WebSocketStreamCreateHelper create_helper; std::unique_ptr<HttpStreamRequest> request( - session->http_stream_factory_for_websocket() - ->RequestWebSocketHandshakeStream( - request_info, DEFAULT_PRIORITY, ssl_config, ssl_config, &waiter, - &create_helper, - /* enable_ip_based_pooling = */ true, - /* enable_alternative_services = */ true, NetLogWithSource())); + session->http_stream_factory()->RequestWebSocketHandshakeStream( + request_info, DEFAULT_PRIORITY, ssl_config, ssl_config, &waiter, + &create_helper, + /* enable_ip_based_pooling = */ true, + /* enable_alternative_services = */ true, NetLogWithSource())); waiter.WaitForStream(); EXPECT_TRUE(waiter.stream_done()); EXPECT_TRUE(nullptr == waiter.stream()); @@ -2081,7 +2067,7 @@ TEST_F(HttpStreamFactoryTest, NewSpdySessionCloseIdleH2Sockets) { ssl_config, PRIVACY_MODE_DISABLED, 0, false)); std::string group_name = "ssl/" + host_port_pair.ToString(); int rv = connection->Init( - group_name, ssl_params, MEDIUM, + group_name, ssl_params, MEDIUM, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), session->GetSSLSocketPool(HttpNetworkSession::NORMAL_SOCKET_POOL), NetLogWithSource()); @@ -2236,20 +2222,25 @@ TEST_F(HttpStreamFactoryTest, RequestBidirectionalStreamImpl) { class HttpStreamFactoryBidirectionalQuicTest : public ::testing::Test, - public ::testing::WithParamInterface<QuicTransportVersion> { + public ::testing::WithParamInterface< + std::tuple<QuicTransportVersion, bool>> { protected: HttpStreamFactoryBidirectionalQuicTest() : default_url_(kDefaultUrl), - client_packet_maker_(GetParam(), + version_(std::get<0>(GetParam())), + client_headers_include_h2_stream_dependency_(std::get<1>(GetParam())), + client_packet_maker_(version_, 0, &clock_, "www.example.org", - Perspective::IS_CLIENT), - server_packet_maker_(GetParam(), + Perspective::IS_CLIENT, + client_headers_include_h2_stream_dependency_), + server_packet_maker_(version_, 0, &clock_, "www.example.org", - Perspective::IS_SERVER), + Perspective::IS_SERVER, + false), random_generator_(0), proxy_service_(ProxyService::CreateDirect()), ssl_config_service_(new SSLConfigServiceDefaults) { @@ -2267,7 +2258,9 @@ class HttpStreamFactoryBidirectionalQuicTest void Initialize() { params_.enable_quic = true; params_.quic_supported_versions = - test::SupportedTransportVersions(GetParam()); + test::SupportedTransportVersions(version_); + params_.quic_headers_include_h2_stream_dependency = + client_headers_include_h2_stream_dependency_; HttpNetworkSession::Context session_context; session_context.http_server_properties = &http_server_properties_; @@ -2320,10 +2313,12 @@ class HttpStreamFactoryBidirectionalQuicTest const GURL default_url_; QuicStreamId GetNthClientInitiatedStreamId(int n) { - return test::GetNthClientInitiatedStreamId(GetParam(), n); + return test::GetNthClientInitiatedStreamId(version_, n); } private: + const QuicTransportVersion version_; + const bool client_headers_include_h2_stream_dependency_; MockClock clock_; test::QuicTestPacketMaker client_packet_maker_; test::QuicTestPacketMaker server_packet_maker_; @@ -2343,9 +2338,11 @@ class HttpStreamFactoryBidirectionalQuicTest HttpNetworkSession::Params params_; }; -INSTANTIATE_TEST_CASE_P(Version, - HttpStreamFactoryBidirectionalQuicTest, - ::testing::ValuesIn(AllSupportedTransportVersions())); +INSTANTIATE_TEST_CASE_P( + VersionIncludeStreamDependencySequnece, + HttpStreamFactoryBidirectionalQuicTest, + ::testing::Combine(::testing::ValuesIn(AllSupportedTransportVersions()), + ::testing::Bool())); TEST_P(HttpStreamFactoryBidirectionalQuicTest, RequestBidirectionalStreamImplQuicAlternative) { @@ -2360,7 +2357,8 @@ TEST_P(HttpStreamFactoryBidirectionalQuicTest, 2, GetNthClientInitiatedStreamId(0), /*should_include_version=*/true, /*fin=*/true, priority, client_packet_maker().GetRequestHeaders("GET", "https", "/"), - &spdy_headers_frame_length, &header_stream_offset)); + /*parent_stream_id=*/0, &spdy_headers_frame_length, + &header_stream_offset)); size_t spdy_response_headers_frame_length; mock_quic_data.AddRead(server_packet_maker().MakeResponseHeadersPacket( 1, GetNthClientInitiatedStreamId(0), /*should_include_version=*/false, @@ -2486,7 +2484,8 @@ TEST_P(HttpStreamFactoryBidirectionalQuicTest, 2, GetNthClientInitiatedStreamId(0), /*should_include_version=*/true, /*fin=*/true, priority, client_packet_maker().GetRequestHeaders("GET", "https", "/"), - &spdy_headers_frame_length, &header_stream_offset)); + /*parent_stream_id=*/0, &spdy_headers_frame_length, + &header_stream_offset)); size_t spdy_response_headers_frame_length; mock_quic_data.AddRead(server_packet_maker().MakeResponseHeadersPacket( 1, GetNthClientInitiatedStreamId(0), /*should_include_version=*/false, diff --git a/chromium/net/http/http_stream_factory_test_util.cc b/chromium/net/http/http_stream_factory_test_util.cc index 264030e342c..b3c0fae11e6 100644 --- a/chromium/net/http/http_stream_factory_test_util.cc +++ b/chromium/net/http/http_stream_factory_test_util.cc @@ -29,6 +29,7 @@ MockHttpStreamFactoryImplJob::MockHttpStreamFactoryImplJob( NextProto alternative_protocol, QuicTransportVersion quic_version, const ProxyServer& alternative_proxy_server, + bool is_websocket, bool enable_ip_based_pooling, NetLog* net_log) : HttpStreamFactoryImpl::Job(delegate, @@ -44,6 +45,7 @@ MockHttpStreamFactoryImplJob::MockHttpStreamFactoryImplJob( alternative_protocol, quic_version, alternative_proxy_server, + is_websocket, enable_ip_based_pooling, net_log) { DCHECK(!is_waiting()); @@ -69,6 +71,7 @@ std::unique_ptr<HttpStreamFactoryImpl::Job> TestJobFactory::CreateMainJob( const SSLConfig& proxy_ssl_config, HostPortPair destination, GURL origin_url, + bool is_websocket, bool enable_ip_based_pooling, NetLog* net_log) { if (override_main_job_url_) @@ -77,8 +80,8 @@ std::unique_ptr<HttpStreamFactoryImpl::Job> TestJobFactory::CreateMainJob( auto main_job = std::make_unique<MockHttpStreamFactoryImplJob>( delegate, job_type, session, request_info, priority, proxy_info, SSLConfig(), SSLConfig(), destination, origin_url, kProtoUnknown, - QUIC_VERSION_UNSUPPORTED, ProxyServer(), enable_ip_based_pooling, - net_log); + QUIC_VERSION_UNSUPPORTED, ProxyServer(), is_websocket, + enable_ip_based_pooling, net_log); // Keep raw pointer to Job but pass ownership. main_job_ = main_job.get(); @@ -99,12 +102,14 @@ std::unique_ptr<HttpStreamFactoryImpl::Job> TestJobFactory::CreateAltSvcJob( GURL origin_url, NextProto alternative_protocol, QuicTransportVersion quic_version, + bool is_websocket, bool enable_ip_based_pooling, NetLog* net_log) { auto alternative_job = std::make_unique<MockHttpStreamFactoryImplJob>( delegate, job_type, session, request_info, priority, proxy_info, SSLConfig(), SSLConfig(), destination, origin_url, alternative_protocol, - quic_version, ProxyServer(), enable_ip_based_pooling, net_log); + quic_version, ProxyServer(), is_websocket, enable_ip_based_pooling, + net_log); // Keep raw pointer to Job but pass ownership. alternative_job_ = alternative_job.get(); @@ -124,12 +129,13 @@ std::unique_ptr<HttpStreamFactoryImpl::Job> TestJobFactory::CreateAltProxyJob( HostPortPair destination, GURL origin_url, const ProxyServer& alternative_proxy_server, + bool is_websocket, bool enable_ip_based_pooling, NetLog* net_log) { auto alternative_job = std::make_unique<MockHttpStreamFactoryImplJob>( delegate, job_type, session, request_info, priority, proxy_info, SSLConfig(), SSLConfig(), destination, origin_url, kProtoUnknown, - QUIC_VERSION_UNSUPPORTED, alternative_proxy_server, + QUIC_VERSION_UNSUPPORTED, alternative_proxy_server, is_websocket, enable_ip_based_pooling, net_log); // Keep raw pointer to Job but pass ownership. diff --git a/chromium/net/http/http_stream_factory_test_util.h b/chromium/net/http/http_stream_factory_test_util.h index 238cc508744..b22d53a7a59 100644 --- a/chromium/net/http/http_stream_factory_test_util.h +++ b/chromium/net/http/http_stream_factory_test_util.h @@ -120,6 +120,7 @@ class MockHttpStreamFactoryImplJob : public HttpStreamFactoryImpl::Job { NextProto alternative_protocol, QuicTransportVersion quic_version, const ProxyServer& alternative_proxy_server, + bool is_websocket, bool enable_ip_based_pooling, NetLog* net_log); @@ -147,6 +148,7 @@ class TestJobFactory : public HttpStreamFactoryImpl::JobFactory { const SSLConfig& proxy_ssl_config, HostPortPair destination, GURL origin_url, + bool is_websocket, bool enable_ip_based_pooling, NetLog* net_log) override; @@ -163,6 +165,7 @@ class TestJobFactory : public HttpStreamFactoryImpl::JobFactory { GURL origin_url, NextProto alternative_protocol, QuicTransportVersion quic_version, + bool is_websocket, bool enable_ip_based_pooling, NetLog* net_log) override; @@ -178,6 +181,7 @@ class TestJobFactory : public HttpStreamFactoryImpl::JobFactory { HostPortPair destination, GURL origin_url, const ProxyServer& alternative_proxy_server, + bool is_websocket, bool enable_ip_based_pooling, NetLog* net_log) override; diff --git a/chromium/net/http/http_stream_parser.cc b/chromium/net/http/http_stream_parser.cc index ced3da36322..b192b80ce9e 100644 --- a/chromium/net/http/http_stream_parser.cc +++ b/chromium/net/http/http_stream_parser.cc @@ -207,16 +207,20 @@ HttpStreamParser::HttpStreamParser(ClientSocketHandle* connection, sent_last_chunk_(false), upload_error_(OK), weak_ptr_factory_(this) { + CHECK(connection_) << "ClientSocketHandle passed to HttpStreamParser must " + "not be NULL. See crbug.com/790776"; io_callback_ = base::Bind(&HttpStreamParser::OnIOComplete, weak_ptr_factory_.GetWeakPtr()); } HttpStreamParser::~HttpStreamParser() = default; -int HttpStreamParser::SendRequest(const std::string& request_line, - const HttpRequestHeaders& headers, - HttpResponseInfo* response, - const CompletionCallback& callback) { +int HttpStreamParser::SendRequest( + const std::string& request_line, + const HttpRequestHeaders& headers, + const NetworkTrafficAnnotationTag& traffic_annotation, + HttpResponseInfo* response, + const CompletionCallback& callback) { DCHECK_EQ(STATE_NONE, io_state_); DCHECK(callback_.is_null()); DCHECK(!callback.is_null()); @@ -228,6 +232,7 @@ int HttpStreamParser::SendRequest(const std::string& request_line, DVLOG(1) << __func__ << "() request_line = \"" << request_line << "\"" << " headers = \"" << headers.ToString() << "\""; + traffic_annotation_ = MutableNetworkTrafficAnnotationTag(traffic_annotation); response_ = response; // Put the peer's IP address and port into the response. @@ -455,8 +460,9 @@ int HttpStreamParser::DoSendHeaders() { response_->request_time = base::Time::Now(); io_state_ = STATE_SEND_HEADERS_COMPLETE; - return connection_->socket() - ->Write(request_headers_.get(), bytes_remaining, io_callback_); + return connection_->socket()->Write( + request_headers_.get(), bytes_remaining, io_callback_, + NetworkTrafficAnnotationTag(traffic_annotation_)); } int HttpStreamParser::DoSendHeadersComplete(int result) { @@ -503,10 +509,9 @@ int HttpStreamParser::DoSendHeadersComplete(int result) { int HttpStreamParser::DoSendBody() { if (request_body_send_buf_->BytesRemaining() > 0) { io_state_ = STATE_SEND_BODY_COMPLETE; - return connection_->socket() - ->Write(request_body_send_buf_.get(), - request_body_send_buf_->BytesRemaining(), - io_callback_); + return connection_->socket()->Write( + request_body_send_buf_.get(), request_body_send_buf_->BytesRemaining(), + io_callback_, NetworkTrafficAnnotationTag(traffic_annotation_)); } if (request_->upload_data_stream->is_chunked() && sent_last_chunk_) { diff --git a/chromium/net/http/http_stream_parser.h b/chromium/net/http/http_stream_parser.h index 6a0248202c2..56f5dae8775 100644 --- a/chromium/net/http/http_stream_parser.h +++ b/chromium/net/http/http_stream_parser.h @@ -21,6 +21,7 @@ #include "net/base/net_export.h" #include "net/log/net_log_with_source.h" #include "net/ssl/token_binding.h" +#include "net/traffic_annotation/network_traffic_annotation.h" namespace net { @@ -61,6 +62,7 @@ class NET_EXPORT_PRIVATE HttpStreamParser { // some additional functionality int SendRequest(const std::string& request_line, const HttpRequestHeaders& headers, + const NetworkTrafficAnnotationTag& traffic_annotation, HttpResponseInfo* response, const CompletionCallback& callback); @@ -284,6 +286,8 @@ class NET_EXPORT_PRIVATE HttpStreamParser { // Error received when uploading the body, if any. int upload_error_; + MutableNetworkTrafficAnnotationTag traffic_annotation_; + base::WeakPtrFactory<HttpStreamParser> weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(HttpStreamParser); diff --git a/chromium/net/http/http_stream_parser_fuzzer.cc b/chromium/net/http/http_stream_parser_fuzzer.cc index f31d0edeacc..cb509f33d5d 100644 --- a/chromium/net/http/http_stream_parser_fuzzer.cc +++ b/chromium/net/http/http_stream_parser_fuzzer.cc @@ -25,6 +25,7 @@ #include "net/log/test_net_log.h" #include "net/socket/client_socket_handle.h" #include "net/socket/fuzzed_socket.h" +#include "net/traffic_annotation/network_traffic_annotation_test_helper.h" #include "url/gurl.h" // Fuzzer for HttpStreamParser. @@ -52,9 +53,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { bound_test_net_log.bound()); net::HttpResponseInfo response_info; - int result = - parser.SendRequest("GET / HTTP/1.1\r\n", net::HttpRequestHeaders(), - &response_info, callback.callback()); + int result = parser.SendRequest( + "GET / HTTP/1.1\r\n", net::HttpRequestHeaders(), + TRAFFIC_ANNOTATION_FOR_TESTS, &response_info, callback.callback()); result = callback.GetResult(result); if (net::OK != result) return 0; diff --git a/chromium/net/http/http_stream_parser_unittest.cc b/chromium/net/http/http_stream_parser_unittest.cc index 0ad717f10b1..7b6de3d8b1e 100644 --- a/chromium/net/http/http_stream_parser_unittest.cc +++ b/chromium/net/http/http_stream_parser_unittest.cc @@ -32,6 +32,7 @@ #include "net/socket/client_socket_handle.h" #include "net/socket/socket_test_util.h" #include "net/test/gtest_util.h" +#include "net/traffic_annotation/network_traffic_annotation_test_helper.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "url/gurl.h" @@ -138,7 +139,8 @@ TEST(HttpStreamParser, DataReadErrorSynchronous) { HttpResponseInfo response; TestCompletionCallback callback; - int result = parser.SendRequest("POST / HTTP/1.1\r\n", headers, &response, + int result = parser.SendRequest("POST / HTTP/1.1\r\n", headers, + TRAFFIC_ANNOTATION_FOR_TESTS, &response, callback.callback()); EXPECT_THAT(callback.GetResult(result), IsError(ERR_FAILED)); @@ -179,7 +181,8 @@ TEST(HttpStreamParser, DataReadErrorAsynchronous) { HttpResponseInfo response; TestCompletionCallback callback; - int result = parser.SendRequest("POST / HTTP/1.1\r\n", headers, &response, + int result = parser.SendRequest("POST / HTTP/1.1\r\n", headers, + TRAFFIC_ANNOTATION_FOR_TESTS, &response, callback.callback()); EXPECT_THAT(result, IsError(ERR_IO_PENDING)); @@ -255,7 +258,8 @@ TEST(HttpStreamParser, InitAsynchronousUploadDataStream) { HttpResponseInfo response; TestCompletionCallback callback1; - int result1 = parser.SendRequest("POST / HTTP/1.1\r\n", headers, &response, + int result1 = parser.SendRequest("POST / HTTP/1.1\r\n", headers, + TRAFFIC_ANNOTATION_FOR_TESTS, &response, callback1.callback()); EXPECT_EQ(ERR_IO_PENDING, result1); base::RunLoop().RunUntilIdle(); @@ -438,7 +442,8 @@ TEST(HttpStreamParser, SentBytesNoHeaders) { HttpResponseInfo response; TestCompletionCallback callback; EXPECT_EQ(OK, parser.SendRequest("GET / HTTP/1.1\r\n", HttpRequestHeaders(), - &response, callback.callback())); + TRAFFIC_ANNOTATION_FOR_TESTS, &response, + callback.callback())); EXPECT_EQ(CountWriteBytes(writes, arraysize(writes)), parser.sent_bytes()); } @@ -469,7 +474,8 @@ TEST(HttpStreamParser, SentBytesWithHeaders) { HttpResponseInfo response; TestCompletionCallback callback; - EXPECT_EQ(OK, parser.SendRequest("GET / HTTP/1.1\r\n", headers, &response, + EXPECT_EQ(OK, parser.SendRequest("GET / HTTP/1.1\r\n", headers, + TRAFFIC_ANNOTATION_FOR_TESTS, &response, callback.callback())); EXPECT_EQ(CountWriteBytes(writes, arraysize(writes)), parser.sent_bytes()); @@ -501,7 +507,8 @@ TEST(HttpStreamParser, SentBytesWithHeadersMultiWrite) { HttpResponseInfo response; TestCompletionCallback callback; - EXPECT_EQ(OK, parser.SendRequest("GET / HTTP/1.1\r\n", headers, &response, + EXPECT_EQ(OK, parser.SendRequest("GET / HTTP/1.1\r\n", headers, + TRAFFIC_ANNOTATION_FOR_TESTS, &response, callback.callback())); EXPECT_EQ(CountWriteBytes(writes, arraysize(writes)), parser.sent_bytes()); @@ -533,7 +540,8 @@ TEST(HttpStreamParser, SentBytesWithErrorWritingHeaders) { HttpResponseInfo response; TestCompletionCallback callback; EXPECT_EQ(ERR_CONNECTION_RESET, - parser.SendRequest("GET / HTTP/1.1\r\n", headers, &response, + parser.SendRequest("GET / HTTP/1.1\r\n", headers, + TRAFFIC_ANNOTATION_FOR_TESTS, &response, callback.callback())); EXPECT_EQ(CountWriteBytes(writes, arraysize(writes)), parser.sent_bytes()); @@ -572,7 +580,8 @@ TEST(HttpStreamParser, SentBytesPost) { HttpResponseInfo response; TestCompletionCallback callback; - EXPECT_EQ(OK, parser.SendRequest("POST / HTTP/1.1\r\n", headers, &response, + EXPECT_EQ(OK, parser.SendRequest("POST / HTTP/1.1\r\n", headers, + TRAFFIC_ANNOTATION_FOR_TESTS, &response, callback.callback())); EXPECT_EQ(CountWriteBytes(writes, arraysize(writes)), parser.sent_bytes()); @@ -616,6 +625,7 @@ TEST(HttpStreamParser, SentBytesChunkedPostError) { HttpResponseInfo response; TestCompletionCallback callback; EXPECT_EQ(ERR_IO_PENDING, parser.SendRequest("POST / HTTP/1.1\r\n", headers, + TRAFFIC_ANNOTATION_FOR_TESTS, &response, callback.callback())); base::RunLoop().RunUntilIdle(); @@ -685,7 +695,8 @@ TEST(HttpStreamParser, AsyncSingleChunkAndAsyncSocket) { // complete asynchronously. ASSERT_EQ(ERR_IO_PENDING, parser.SendRequest("GET /one.html HTTP/1.1\r\n", request_headers, - &response_info, callback.callback())); + TRAFFIC_ANNOTATION_FOR_TESTS, &response_info, + callback.callback())); // Complete the initial request write. Callback should not have been invoked. base::RunLoop().RunUntilIdle(); @@ -765,7 +776,8 @@ TEST(HttpStreamParser, SyncSingleChunkAndAsyncSocket) { // complete asynchronously. ASSERT_EQ(ERR_IO_PENDING, parser.SendRequest("GET /one.html HTTP/1.1\r\n", request_headers, - &response_info, callback.callback())); + TRAFFIC_ANNOTATION_FOR_TESTS, &response_info, + callback.callback())); ASSERT_THAT(callback.WaitForResult(), IsOk()); // Attempt to read the response status and the response headers. @@ -845,7 +857,8 @@ TEST(HttpStreamParser, AsyncChunkAndAsyncSocketWithMultipleChunks) { // complete asynchronously. ASSERT_EQ(ERR_IO_PENDING, parser.SendRequest("GET /one.html HTTP/1.1\r\n", request_headers, - &response_info, callback.callback())); + TRAFFIC_ANNOTATION_FOR_TESTS, &response_info, + callback.callback())); ASSERT_FALSE(callback.have_result()); // Sending the request and the first chunk completes. @@ -929,7 +942,8 @@ TEST(HttpStreamParser, AsyncEmptyChunkedUpload) { // complete asynchronously. ASSERT_EQ(ERR_IO_PENDING, parser.SendRequest("GET /one.html HTTP/1.1\r\n", request_headers, - &response_info, callback.callback())); + TRAFFIC_ANNOTATION_FOR_TESTS, &response_info, + callback.callback())); // Now append the terminal 0-byte "chunk". upload_stream.AppendData(nullptr, 0, true); @@ -1004,7 +1018,8 @@ TEST(HttpStreamParser, SyncEmptyChunkedUpload) { // complete asynchronously. ASSERT_EQ(ERR_IO_PENDING, parser.SendRequest("GET /one.html HTTP/1.1\r\n", request_headers, - &response_info, callback.callback())); + TRAFFIC_ANNOTATION_FOR_TESTS, &response_info, + callback.callback())); // Complete writing the request headers and body. ASSERT_THAT(callback.WaitForResult(), IsOk()); @@ -1101,6 +1116,7 @@ TEST(HttpStreamParser, TruncatedHeaders) { HttpResponseInfo response_info; TestCompletionCallback callback; ASSERT_EQ(OK, parser.SendRequest("GET / HTTP/1.1\r\n", request_headers, + TRAFFIC_ANNOTATION_FOR_TESTS, &response_info, callback.callback())); int rv = parser.ReadResponseHeaders(callback.callback()); @@ -1158,7 +1174,8 @@ TEST(HttpStreamParser, Websocket101Response) { HttpResponseInfo response_info; TestCompletionCallback callback; ASSERT_EQ(OK, parser.SendRequest("GET / HTTP/1.1\r\n", request_headers, - &response_info, callback.callback())); + TRAFFIC_ANNOTATION_FOR_TESTS, &response_info, + callback.callback())); EXPECT_THAT(parser.ReadResponseHeaders(callback.callback()), IsOk()); ASSERT_TRUE(response_info.headers.get()); @@ -1236,6 +1253,7 @@ class SimpleGetRunner { TestCompletionCallback callback; ASSERT_EQ(OK, parser_->SendRequest("GET / HTTP/1.1\r\n", request_headers_, + TRAFFIC_ANNOTATION_FOR_TESTS, &response_info_, callback.callback())); } @@ -1673,8 +1691,10 @@ TEST(HttpStreamParser, ReadAfterUnownedObjectsDestroyed) { std::unique_ptr<HttpRequestHeaders> request_headers(new HttpRequestHeaders()); std::unique_ptr<HttpResponseInfo> response_info(new HttpResponseInfo()); TestCompletionCallback callback; - ASSERT_EQ(OK, parser.SendRequest("GET /foo.html HTTP/1.1\r\n", - *request_headers, response_info.get(), callback.callback())); + ASSERT_EQ( + OK, parser.SendRequest("GET /foo.html HTTP/1.1\r\n", *request_headers, + TRAFFIC_ANNOTATION_FOR_TESTS, response_info.get(), + callback.callback())); ASSERT_THAT(parser.ReadResponseHeaders(callback.callback()), IsOk()); // If the object that owns the HttpStreamParser is deleted, it takes the diff --git a/chromium/net/http/proxy_connect_redirect_http_stream.cc b/chromium/net/http/proxy_connect_redirect_http_stream.cc index 2fc8eb8b0a3..699d71aad59 100644 --- a/chromium/net/http/proxy_connect_redirect_http_stream.cc +++ b/chromium/net/http/proxy_connect_redirect_http_stream.cc @@ -22,6 +22,7 @@ ProxyConnectRedirectHttpStream::~ProxyConnectRedirectHttpStream() = default; int ProxyConnectRedirectHttpStream::InitializeStream( const HttpRequestInfo* request_info, + bool can_send_early, RequestPriority priority, const NetLogWithSource& net_log, const CompletionCallback& callback) { diff --git a/chromium/net/http/proxy_connect_redirect_http_stream.h b/chromium/net/http/proxy_connect_redirect_http_stream.h index 5df1ffa25e6..285a9b4e8d4 100644 --- a/chromium/net/http/proxy_connect_redirect_http_stream.h +++ b/chromium/net/http/proxy_connect_redirect_http_stream.h @@ -29,6 +29,7 @@ class ProxyConnectRedirectHttpStream : public HttpStream { // marked one. int InitializeStream(const HttpRequestInfo* request_info, + bool can_send_early, RequestPriority priority, const NetLogWithSource& net_log, const CompletionCallback& callback) override; diff --git a/chromium/net/http/transport_security_persister_unittest.cc b/chromium/net/http/transport_security_persister_unittest.cc index 3ad29887f51..f18c4ae7a01 100644 --- a/chromium/net/http/transport_security_persister_unittest.cc +++ b/chromium/net/http/transport_security_persister_unittest.cc @@ -283,7 +283,7 @@ TEST_F(TransportSecurityPersisterTest, PublicKeyPins) { TransportSecurityState::PKPState new_pkp_state; EXPECT_TRUE(state_.GetDynamicPKPState(kTestDomain, &new_pkp_state)); EXPECT_EQ(1u, new_pkp_state.spki_hashes.size()); - EXPECT_EQ(sha256.tag, new_pkp_state.spki_hashes[0].tag); + EXPECT_EQ(sha256.tag(), new_pkp_state.spki_hashes[0].tag()); EXPECT_EQ(0, memcmp(new_pkp_state.spki_hashes[0].data(), sha256.data(), sha256.size())); EXPECT_EQ(report_uri, new_pkp_state.report_uri); diff --git a/chromium/net/http/transport_security_state.cc b/chromium/net/http/transport_security_state.cc index a433afd0217..6eaa321ef4b 100644 --- a/chromium/net/http/transport_security_state.cc +++ b/chromium/net/http/transport_security_state.cc @@ -12,8 +12,8 @@ #include "base/build_time.h" #include "base/json/json_writer.h" #include "base/logging.h" +#include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" -#include "base/metrics/sparse_histogram.h" #include "base/stl_util.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" @@ -72,8 +72,7 @@ bool IsDynamicExpectCTEnabled() { void RecordUMAForHPKPReportFailure(const GURL& report_uri, int net_error, int http_response_code) { - UMA_HISTOGRAM_SPARSE_SLOWLY("Net.PublicKeyPinReportSendingFailure2", - -net_error); + base::UmaHistogramSparse("Net.PublicKeyPinReportSendingFailure2", -net_error); } std::string TimeToISO8601(const base::Time& t) { @@ -143,7 +142,7 @@ bool GetHPKPReport(const HostPortPair& host_port_pair, for (const auto& hash_value : pkp_state.spki_hashes) { std::string known_pin; - switch (hash_value.tag) { + switch (hash_value.tag()) { case HASH_VALUE_SHA256: known_pin += "pin-sha256="; break; @@ -901,6 +900,9 @@ TransportSecurityState::CheckCTRequirements( ExpectCTState state; if (is_issued_by_known_root && IsDynamicExpectCTEnabled() && GetDynamicExpectCTState(hostname, &state)) { + UMA_HISTOGRAM_ENUMERATION( + "Net.ExpectCTHeader.PolicyComplianceOnConnectionSetup", + policy_compliance, ct::CTPolicyCompliance::CT_POLICY_MAX); 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, @@ -947,9 +949,12 @@ TransportSecurityState::CheckCTRequirements( const base::Time epoch = base::Time::UnixEpoch(); const CTRequiredPolicies& ct_required_policies = GetCTRequiredPolicies(); + + bool found = false; for (const auto& restricted_ca : ct_required_policies) { - if (epoch + restricted_ca.effective_date > - validated_certificate_chain->valid_start()) { + if (!restricted_ca.effective_date.is_zero() && + (epoch + restricted_ca.effective_date > + validated_certificate_chain->valid_start())) { // The candidate cert is not subject to the CT policy, because it // was issued before the effective CT date. continue; @@ -964,15 +969,21 @@ TransportSecurityState::CheckCTRequirements( // Found a match, indicating this certificate is potentially // restricted. Determine if any of the hashes are on the exclusion // list as exempt from the CT requirement. - if (IsAnySHA256HashInSortedArray(public_key_hashes, + if (restricted_ca.exceptions && + IsAnySHA256HashInSortedArray(public_key_hashes, restricted_ca.exceptions, restricted_ca.exceptions_length)) { // Found an excluded sub-CA; CT is not required. - return default_response; + continue; } - // No exception found. This certificate must conform to the CT policy. - return complies ? CT_REQUIREMENTS_MET : CT_REQUIREMENTS_NOT_MET; + + // No exception found. This certificate must conform to the CT policy. The + // compliance state is treated as additive - it must comply with all + // stated policies. + found = true; } + if (found) + return complies ? CT_REQUIREMENTS_MET : CT_REQUIREMENTS_NOT_MET; return default_response; } @@ -1507,6 +1518,9 @@ void TransportSecurityState::ProcessExpectCTHeader( // public root or did not comply with CT policy. if (!ssl_info.is_issued_by_known_root) return; + UMA_HISTOGRAM_ENUMERATION( + "Net.ExpectCTHeader.PolicyComplianceOnHeaderProcessing", + ssl_info.ct_policy_compliance, ct::CTPolicyCompliance::CT_POLICY_MAX); if (ssl_info.ct_policy_compliance != ct::CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS) { // If an Expect-CT header is observed over a non-compliant connection, the diff --git a/chromium/net/http/transport_security_state_ct_policies.inc b/chromium/net/http/transport_security_state_ct_policies.inc index d01cbd2ad7b..f7ea8e51ef5 100644 --- a/chromium/net/http/transport_security_state_ct_policies.inc +++ b/chromium/net/http/transport_security_state_ct_policies.inc @@ -20,7 +20,8 @@ struct CTRequiredPolicy { size_t roots_length; // The date at which enforcement should begin, relative to the Unix - // Epoch. + // Epoch. If equivalent to zero (base::TimeDelta()), then it is enforced + // for all certificates. base::TimeDelta effective_date; // However, if a certificate ALSO chains to or through one of @@ -33,7 +34,7 @@ struct CTRequiredPolicy { size_t exceptions_length; }; -typedef CTRequiredPolicy CTRequiredPolicies[1]; +typedef CTRequiredPolicy CTRequiredPolicies[2]; const CTRequiredPolicies& GetCTRequiredPolicies() { static const CTRequiredPolicy kCTRequiredPolicies[] = { @@ -41,8 +42,12 @@ const CTRequiredPolicies& GetCTRequiredPolicies() { { kSymantecRoots, kSymantecRootsLength, // 1 June 2016, 00:00:00 GMT. - base::TimeDelta::FromSeconds(1464739200), kSymantecExceptions, - kSymantecExceptionsLength, + base::TimeDelta::FromSeconds(1464739200), + kSymantecExceptions, kSymantecExceptionsLength, + }, + { + kSymantecManagedCAs, kSymantecManagedCAsLength, + base::TimeDelta(), nullptr, 0 }, }; diff --git a/chromium/net/http/transport_security_state_static.json b/chromium/net/http/transport_security_state_static.json index 0e18132ed4e..5a6fea71063 100644 --- a/chromium/net/http/transport_security_state_static.json +++ b/chromium/net/http/transport_security_state_static.json @@ -275,15 +275,15 @@ "expect_staple_report_uri": "https://report.badssl.com/expect-staple" }, - // eTLDs - // At the moment, this only includes Google-owned gTLDs, - // but other gTLDs and eTLDs are welcome to preload if they are interested. - { "name": "google", "policy": "public-suffix", "mode": "force-https", "include_subdomains": true, "pins": "google" }, + // gTLDs and eTLDs are welcome to preload if they are interested. + { "name": "app", "policy": "public-suffix", "mode": "force-https", "include_subdomains": true }, + { "name": "bank", "policy": "public-suffix", "mode": "force-https", "include_subdomains": true }, + { "name": "chrome", "policy": "public-suffix", "mode": "force-https", "include_subdomains": true }, { "name": "dev", "policy": "public-suffix", "mode": "force-https", "include_subdomains": true }, { "name": "foo", "policy": "public-suffix", "mode": "force-https", "include_subdomains": true }, + { "name": "google", "policy": "public-suffix", "mode": "force-https", "include_subdomains": true, "pins": "google" }, + { "name": "insurance", "policy": "public-suffix", "mode": "force-https", "include_subdomains": true }, { "name": "page", "policy": "public-suffix", "mode": "force-https", "include_subdomains": true }, - { "name": "app", "policy": "public-suffix", "mode": "force-https", "include_subdomains": true }, - { "name": "chrome", "policy": "public-suffix", "mode": "force-https", "include_subdomains": true }, // Google domains using Expect-CT. { @@ -364,6 +364,7 @@ { "name": "groups.google.com", "policy": "google", "mode": "force-https", "include_subdomains": true, "pins": "google" }, { "name": "gvt2.com", "policy": "google", "mode": "force-https", "include_subdomains": true, "pins": "google" }, { "name": "gvt3.com", "policy": "google", "mode": "force-https", "include_subdomains": true, "pins": "google" }, + { "name": "developer.android.com", "policy": "google", "mode": "force-https", "include_subdomains": true, "pins": "google" }, { "name": "market.android.com", "policy": "google", "mode": "force-https", "include_subdomains": true, "pins": "google" }, { "name": "translate.googleapis.com", "policy": "google", "mode": "force-https", "include_subdomains": true, "pins": "google" }, { "name": "withgoogle.com", "policy": "google", "mode": "force-https", "include_subdomains": true, "pins": "google" }, @@ -639,6 +640,7 @@ { "name": "googleweblight.com", "policy": "google", "include_subdomains": true, "pins": "google" }, { "name": "google.ws", "policy": "google", "include_subdomains": true, "pins": "google" }, { "name": "gstatic.com", "policy": "google", "include_subdomains": true, "pins": "google" }, + { "name": "gvt1.com", "policy": "google", "include_subdomains": true, "pins": "google" }, { "name": "static.googleadsserving.cn", "policy": "google", "include_subdomains": true, "pins": "google" }, { "name": "urchin.com", "policy": "google", "include_subdomains": true, "pins": "google" }, { @@ -650,9 +652,6 @@ { "name": "youtu.be", "policy": "google", "include_subdomains": true, "pins": "google" }, { "name": "youtube-nocookie.com", "policy": "google", "include_subdomains": true, "pins": "google" }, { "name": "ytimg.com", "policy": "google", "include_subdomains": true, "pins": "google" }, - // Exclude the learn.doubleclick.net subdomain because it uses a different - // CA. - { "name": "learn.doubleclick.net", "policy": "google", "include_subdomains": true }, // Enforce HSTS and public key pins for Yahoo domains. { "name": "at.search.yahoo.com", "policy": "custom", "mode": "force-https", "include_subdomains": false, "pins": "yahoo" }, @@ -2049,7 +2048,6 @@ { "name": "leonklingele.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "madars.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "magneticanvil.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "mimeit.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "mobilcom-debitel-empfehlen.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "morethanadream.lv", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "narodniki.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -3341,7 +3339,6 @@ { "name": "endlesshorizon.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "entrepreneur.or.id", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "eol34.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "eroticen.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "eucl3d.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "firmapi.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "freeweibo.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -3772,7 +3769,6 @@ { "name": "sifls.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "smkn1lengkong.sch.id", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "ssldecoder.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "startupsort.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "sx3.no", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "tech-seminar.jp", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "tncnanet.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -5311,7 +5307,6 @@ { "name": "jonathancarter.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "jonfor.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "jorgemesa.me", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "josephrees.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "joyofcookingandbaking.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "kachlikova2.cz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "kanotijd.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -5416,7 +5411,6 @@ { "name": "ronwo.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "rootwpn.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "russmarshall.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "rww.name", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "saltercane.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "saveyour.biz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "scienceathome.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -6944,7 +6938,6 @@ { "name": "tsumi.it", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "tty.space", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "tuvalie.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "tuxcall.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "ty2u.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "uat-activesg.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "ukrgadget.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -7359,7 +7352,6 @@ { "name": "kleinerarchitekturfuehrer.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "klicktojob.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "kmkz.jp", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "kojima-life.co.jp", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "kolmann.eu", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "krasota.ru", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "krmela.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -7706,7 +7698,6 @@ { "name": "xn--3lqp21gwna.xn--fiqs8s", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "xn--3lqt7ir4md4tzwa.cn", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "xn--3lqt7ir4md4tzwa.xn--fiqs8s", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "xn--jobbrse-d1a.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "xn--qckss0j.tk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "xqin.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "xuri.me", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -8454,7 +8445,6 @@ { "name": "polypet.com.sg", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "posylka.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "ppro.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "prezola.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "pro-link.eu", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "projectarmy.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "punknews.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -9377,7 +9367,6 @@ { "name": "dentallaborgeraeteservice.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "dentystabirmingham.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "derchris.me", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "deregowski.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "desiccantpackets.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "designgears.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "designthinking.or.jp", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -10078,7 +10067,6 @@ { "name": "lanbyte.se", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "langbein.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "lansinoh.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "laposte.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "lasnaves.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "latinphone.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "lauftreff-himmelgeist.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -11233,7 +11221,6 @@ { "name": "waylaydesign.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "wdt.cz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "wealthcentral.com.au", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "wealthfactory.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "wealthreport.com.au", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "wear2work.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "wearandcare.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -12343,7 +12330,6 @@ { "name": "svatba-frantovi.cz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "sumoatm.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "tails.com.ar", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "tabelfirme.ro", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "sv-turm-hohenlimburg.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "taravancil.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "tangibilizing.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -15814,7 +15800,6 @@ { "name": "itilo.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "jamessmith.me.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "justmy.website", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "johnmcgovern.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "karmaassurance.ca", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "jiyuu-ni.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "joe-pagan.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -16034,7 +16019,6 @@ { "name": "magnets.jp", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "mfxbe.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "miegl.cz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "lmkts.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "logicio.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "lwl12.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "mockmyapp.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -17651,7 +17635,6 @@ { "name": "mariehane.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "mdma.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "matthewkenny.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "meledia.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "marksouthall.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "kinniyaonlus.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "martins.im", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -18243,7 +18226,6 @@ { "name": "xn--yoamomisuasbcn-ynb.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "yuzu.tk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "zlc1994.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "xuwei.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "woufbox.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "zenycosta.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "worldsbeststory.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -18601,7 +18583,6 @@ { "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 }, - { "name": "businesshub.cz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "c3vo.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "card-toka.jp", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "achterstieg.dedyn.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -19920,7 +19901,6 @@ { "name": "politik-bei-uns.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "pm13-media.cz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "principia-journal.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "pornbase.info", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "practicepanther.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "pozytywnyplan.pl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "personalizedtouch.co", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -22550,7 +22530,6 @@ { "name": "planktonholland.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "premiership-predictors.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "pikeitservices.com.au", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "pnyxnet.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "pottshome.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "philia-sa.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "proxybay.eu.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -25760,7 +25739,6 @@ { "name": "fitea.cz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "fivestepfunnels.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "fixmyalarmpanel.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "fixvoltage.ru", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "fktpm.ru", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "flairbros.at", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "flaretechnologies.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -26440,7 +26418,6 @@ { "name": "kineto.space", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "kingclass.cn", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "kingdomcrc.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "kingopen.cn", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "kintoandar.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "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 }, @@ -26880,7 +26857,6 @@ { "name": "mplanetphl.fr", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "mpy.ovh", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "mr-anderson.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "mrhack.cz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "mrx.one", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "mscenter.cf", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "mshemailmarketer.com.au", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -27879,7 +27855,6 @@ { "name": "sugarcitycon.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "suiranfes.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "sumguy.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "sungo.wtf", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "sunsmartresorts.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "supa.sexy", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "supercalorias.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -28050,7 +28025,6 @@ { "name": "tiste.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "titusetcompagnies.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "tjandpals.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "tjullrich.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "tkacz.pro", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "tkts.cl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "tkusano.jp", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -31212,7 +31186,6 @@ { "name": "pokemontabletopadventures.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "portalcarriers.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "pixelfou.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "popcultureshack.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "plut.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "plaque-funeraire.fr", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "phdwuda.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -31279,7 +31252,6 @@ { "name": "privacynow.eu", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "promods.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "privacyscore.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "polkam.go.id", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "propepper.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "prodinger.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "plantastique.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -32000,7 +31972,6 @@ { "name": "thisoldearth.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "tommic.eu", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "top-opakowania.pl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "truehealthreport.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "tavolaquadrada.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "topeng-emas.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "treinonerd.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -34317,7 +34288,6 @@ { "name": "sonoecoracao.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "sobelift.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "staxflax.tk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "studentshare.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "stephsolis.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "steinbergmedia.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "soldout-app.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -34916,7 +34886,6 @@ { "name": "ripmixmake.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "00001.am", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "pascalmathis.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "zqwqz.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "scrumbleship.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "sidpod.ru", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "saintaardvarkthecarpeted.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -35075,7 +35044,6 @@ { "name": "globalprojetores.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "great.nagoya", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "grouphomes.com.au", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "gym-old.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "halitopuroprodutos.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "hanys.xyz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "haogoodair.ca", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -36586,7 +36554,6 @@ { "name": "dnfc.rocks", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "dockerm.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "documaniatv.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "doesnotscale.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "domengrad.ru", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "domian.cz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "dominik-schlueter.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -37337,7 +37304,6 @@ { "name": "owl-stat.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "owlishmedia.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "paazmaya.fi", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "pagalworld.la", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "painlessproperty.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "paktolos.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "pantallasled.com.mx", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -37466,7 +37432,6 @@ { "name": "ref1oct.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "refficience.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "refreshliving.us", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "reimu.ink", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "reismil.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "reneleu.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "replicaswiss.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -37810,10 +37775,6 @@ { "name": "votercircle.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "voyagesdetective.fr", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "vozami.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "vpls.co.th", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "vpls.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "vpls.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "vplssolutions.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "vranjske.co.rs", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "vsamsonov.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "vuzi.fr", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -39550,7 +39511,6 @@ { "name": "m.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ma-musique.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "maaya.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "machineryhouse.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "maciespartyhire.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mactools.com.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "madbouncycastles.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -40213,7 +40173,6 @@ { "name": "mncr.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "monolithindustries.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "mystatus24.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "nil2.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ortho-graz.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "os24.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "oyesunn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -41107,7 +41066,6 @@ { "name": "docs.tw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dokan-e.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dolci-delizie.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "dongkexue.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dont.watch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dotjs.party", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "dragonsunited.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -41492,7 +41450,6 @@ { "name": "urcentral.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "vaindil.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "vales.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "vampyrium.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "vapecom-shop.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "vectro.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "venninvestorplatform.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -41542,7 +41499,6 @@ { "name": "xchating.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "xdavidhu.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "xfce.space", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "xiaowutou.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "xingiahanvisa.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "xlboo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "xn--mgbmmp7eub.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -41557,6 +41513,2676 @@ { "name": "zhima.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "zivagold.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "zlcp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "100pounds.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "123termpapers.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "2333666.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "3queens.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "3queens.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "3vlnaeet.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "5000yz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "506pay.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "6lo.zgora.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aaron.xin", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ac.milan.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "accessoripersmartphone.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "acemypaper.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "acordes.online", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "activeworld.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "adorade.ro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "africanimpact.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "agoodmind.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "agoravox.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "agoravox.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "agoravox.tv", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "agr.asia", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ahoy.travel", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aigenpul.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "albertify.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aliaswp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alttrackr.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "amalfirock.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "amato.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "amministratorecondominio.roma.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "andronika.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "anhaffen.lu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "antama.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "anthro.id", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "anynode.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aomonk.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "apio.systems", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aporia.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aquabar.co.il", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "areallyneatwebsite.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "artea.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "arteaga.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "asiesvenezuela.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "assadrivesloirecher.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "assistenzamicroonde.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ateliers-veronese-nantes.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "atheoryofchange.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aulaschrank.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aurosa.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "auskunftsbegehren.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "autoscuola.roma.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "autosearch.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "avalon-studios.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "avova.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "babyphototime.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "balconnr.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "balconsverdun.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bankofrealty.review", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "baobeiglass.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "baustils.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bcradio.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "beautybear.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bennygommers.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bgr34.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bilsho.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bipyo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bleep.zone", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "blm.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bluefinger.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bngs.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bologna-disinfestazioni.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bonprix.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bookingapp.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bouk.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "brainwork.space", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "brammingfys.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bran.soy", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "brandweertrainingen.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bravehearts.org.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bridgevest.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "brokervalues.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bsdunix.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "buy-thing.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "calafont.cat", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "calidoinvierno.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "calypso-tour.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "canerkorkmaz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "canmipai.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cash-4x4.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "catuniverse.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "causae.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cazaviajes.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chapiteauxduleman.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chasing-coins.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chcsct.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cheapestgamecards.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cheapestgamecards.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cheapestgamecards.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cheapestgamecards.fi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cheapestgamecards.no", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "childvisitationassistance.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "class.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "claster.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "clearance365.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "climaencusco.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "code-judge.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "colorlifesupport.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "comphare.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "crag.com.tw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "crowdliminal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "crypto-armory.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "curvissa.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cutephil.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cy.technology", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "danielsteiner.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "danna-salary.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "daravk.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dcards.in.th", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "deai-life.biz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dealapp.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "degoulet.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "delitto.top", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "derattizzazione.name", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "derattizzazioni.biz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "derattizzazioni.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "detekenmuze.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "detoxetmoi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "detuinmuze.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "developyourelement.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dierabenmutti.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "digitalbox.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "digitalwasteland.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "direct2uk.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dirtygeek.ovh", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "disinfestando.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "disinfestazione.brescia.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "distribuidoracristal.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "doctafit.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dorth.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "doypacky.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dpisecuretests.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dragonprogrammer.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dukefox.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "e9a.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "economias.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "edholm.pub", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "edsh.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "edv-bv.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eff-bee-eye.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "egarden.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "electricalagoura.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "elguadia.faith", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "elitesensual.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "elucron.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "empower.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "enpalmademallorca.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "epiteugma.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eppelblei.lu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eppelpress.lu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eroticforce.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eru.im", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esailinggear.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "escortshotsexy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "espressivo.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "exteriorservices.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "faidanoi.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "faithindemocracy.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "falcibiosystems.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "falcoz.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fatowltees.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fburl.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ferret.zone", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "find-mba.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "finflix.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fioulmarket.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "flowersbylegacy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fm992.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "foreversummertime.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "framedpaws.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "freelanceshipping.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "freemans.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "freeshkre.li", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "friederes.lu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fsk.fo", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "funarena.com.ua", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "funinbeds.org.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gambitboard.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ganztagplus.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gastoudererenda.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gatomix.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gazflynn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gcbit.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "geekshirts.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "geekz.sk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "geloofindemocratie.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gensenwedding.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "geocommunicator.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "getcleartouch.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "getticker.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "giardinaggio.napoli.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gifts365.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "giochiecodici.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gitesdeshautescourennes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "global-village.koeln", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "goodyearsotn.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "goubi.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gpio.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "grandjunctionbrewing.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "grattan.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "grayowlworks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "grendel.no", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "grinnellplans.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "grootinadvies.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "groupe-neurologique-nord.lu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "guhei.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "guillaume-briand.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ha6.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "haccp.roma.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "handynummer.online", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "haqaza.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "harilova.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "healthery.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hearty.taipei", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hightimes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hilhorst-uitvaartverzorging.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hiresteve.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "homebasedsalons.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "homoglyph.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hr98.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hub385.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "humblebee.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "humblebee.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "humblebee.co.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "humblebee.com.ph", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "humblebee.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "humblebee.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "humblebee.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "humblebee.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "humblebee.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "humblebee.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "humblebee.me.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "humblebee.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "humblebee.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "humblebeeshop.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hypothyroidmom.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ibwc.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "idolshop.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "igd.chat", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "igk.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ik-life.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "imaginetricks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "imgup.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "inanyevent.london", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "infomegastore.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "infomisto.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "infotolium.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "institutmaupertuis.hopto.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "investcountry.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "irstaxforumsonline.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "isaackabel.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "isaackabel.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "isaackabel.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "isaackabel.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "isaackabel.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "it-shamans.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "itad.top", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jakpremyslet.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "janschaumann.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jdncr.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jeuxetcodes.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jinanshen.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jkest.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "joliettech.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jonathanschle.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "joshlovephotography.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "juegosycodigos.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jugh.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "juliedecubber.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jumboquid.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kaleidoscope.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kansaiyamamoto.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "katalogakci.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kcore.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "keakon.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "keldan.fo", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kevlar.pw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "khasiatmanfaat.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kisiselveri.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "klimaloven.no", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kniwweler.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "koreaboo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "krautomat.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kruisselbrink.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "laassari.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "labcoat.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "landinfo.no", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lascana.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lebarbatruc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ledeguisement.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lemonop.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lenguajedeprogramacion.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lib64.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lifescience-japan.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "linostassi.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "livecards.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "livecards.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "livecards.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "livekarten.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "livekarten.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lixtick.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "llm-guide.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "loeildansledoigt.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "logicchen.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lolnames.gg", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lon-so.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lookagain.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lookbetweenthelines.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "losebellyfat.pro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lostandcash.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lsvih.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lucassoler.com.ar", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "luckyfrog.hk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lukestebbing.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lunis.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lunorian.is", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lusynth.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lv5.top", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lyoness.digital", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "magnificentdata.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "maispa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "maplenorth.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "marlonlosurdopictures.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mcfedries.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "medcrowd.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "meddigital.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "media-access.online", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "meiqia.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "meiqia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mes-finances.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mia.ac", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "micromata.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mijn-financien.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mindwork.space", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "minei.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "minerstat.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "minor.news", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "modaperuimport.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mojeco2.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mondedesnovels.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "monotsuku.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "moodifiers.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mosaicadvisors.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "moskeedieren.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "motezazer.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "movie-infos.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "muffet.pw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "multibase.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "myhatsuden.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mymommyworld.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "n-design.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "na.hn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "namazvakitleri.com.tr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nani.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "natchmatch.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nationalcprfoundation.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "natlec.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "naturalkitchen.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ncc-qualityandsafety.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "needle.net.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "needle.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "neko.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nerfroute.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nerpa-club.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "netnik.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "neutralvehicle.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nightmoose.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ninebytes.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ninfora.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "noovell.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "northern-lakes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nunnun.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nutrifyyourself.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nyanco.space", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "occmon.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "oducs.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "offbyinfinity.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "office-morimoto.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "omoteura.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "one-resource.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "onepointzero.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "organisatieteam.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "origamika.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "oscarmashauri.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "overstemmen.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "parkwayminyan.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "paulward.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pbqs.site", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pcmkrembangan.or.id", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pcrypt.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pedicurean.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "perrone.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "petlife.vet", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "philippe-mignotte.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "photolium.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pianetatatuaggi.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pidginhost.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pirateproxy.ist", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pixelution.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "plumbingbenoni.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pmarques.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ponzi.life", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pottersheartministry.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "prakhar.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "primotiles.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "primotilesandbathrooms.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "privacyforjournalists.org.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "progeon.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "proggersession.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "projectforge.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "purplebricksplc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pyjiaoyi.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "qimiao.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "quarryhillrentals.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "quatrefoiscent.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "quehacerencusco.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "r-ay.club", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ravenger.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "raw-diets.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rcmlinx.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rechtenliteratuurleiden.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "remejeanne.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rentacaramerica.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "retrowave.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "reverse.design", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rittau.biz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rittau.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ritzlux.com.tw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rixter.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "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": "ruri.io", "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 }, + { "name": "sana-store.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sana-store.sk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sandyrobsonhypnotherapy.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sanilodge.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sbsnursery.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sci-internet.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "scp500.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "searchgov.gov.il", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sebastiaandouma.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "selectel.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shawnstarrcustomhomes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shieldcomputer.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shutter-shower.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "siciliadisinfestazioni.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sinsojb.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "skyquid.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "slides.zone", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "solonotizie24.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "soohealthy.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "soopure.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sorellecollection.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "spilogkoder.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sportparks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sportparks.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "squadlinx.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ssuiteoffice.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ssuitesoft.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stackhub.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "standardequipment.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stanthonymaryclaret.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stevenz.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stimmgabel.lu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stuarts.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stucydee.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "studionowystyl.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stuudium.life", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stuudium.pro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "suluvir.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "superbdistribute.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "supersec.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "suseasky.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sveinerik.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "swattransport.ae", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "swimwear365.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tabledusud.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tabledusud.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "taichi-jade.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tailandfur.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "techview.link", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "techviewforum.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tejarat98.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thebit.link", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "theoverfly.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thestyle.city", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thewebdexter.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thinkmarketing.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thoroquel.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tintenprofi.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "todocracy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "todoscomciro.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tolle-wolke.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tommy-bordas.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tomravinmd.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "toxicboot.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tracfinancialservices.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tracinsurance.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "trickedguys.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tronflix.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "trunk-show.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tune-web.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "uel-thompson-okanagan.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "unblocked.vc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "unsacsurledos.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "utahfireinfo.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vagaerg.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vagaerg.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vampyrium.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "varcare.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "velonustraduction.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vendserve.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vernonatvclub.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vik.im", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "violet-letter.delivery", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vize.ai", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vliegensvlug.services", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vvdbronckhorst.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vww-8522.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "w10club.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "walravensax.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "webdesignerinwarwickshire.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "webdesignssussex.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wellsplasticsurgery.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "whatsahoy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "whoimg.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "willywangstory.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "witt-international.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wiz.farm", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wlog.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "worldchess.london", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "worldnettps.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wot-tudasbazis.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wvw-8522.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xdty.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xeedbeam.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xjpvictor.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xn--dragni-g1a.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xn--o77hka.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xn--r77hya.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yamashita-clinic.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ybin.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yogabhawnamission.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "youcaitian.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "young-sheldon.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yurinet.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "z-coder.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zenics.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zoomseoservices.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "00100010.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "00120012.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "00130013.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "00140014.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "00150015.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "00160016.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "00180018.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "00190019.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "00330033.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "00440044.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "00550055.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "00660066.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "00770077.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "00880088.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "00990099.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "110110110.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "112112112.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "113113113.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "118118118.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "1481481.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "1481481.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "1481482.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "1481482.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "1481483.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "1481483.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "1481485.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "1481485.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "1481486.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "1481486.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "168bet9.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "168bo9.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "168bo9.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "168esb.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "174343.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "1day1ac.red", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "2333blog.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "233boy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "24hourscienceprojects.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "2fl.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "2li.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "304squadron.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "3839.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "404.guide", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "439050.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "4flex.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "5214889.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "5214889.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "52b9.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "52b9.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "5310899.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "5310899.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "53ningen.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "546802.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "598598598.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "788da.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "7bwin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "81uc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "8888esb.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "8901178.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "8901178.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "8910899.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "8910899.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "8917168.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "8917168.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "8917818.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "8917818.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "8951889.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "8951889.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "8992088.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "8992088.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "9617818.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "9617818.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "9696178.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "9696178.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "9bingo.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "a-1basements.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aa6688.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "abckam.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aboutyou.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aboutyou.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aboutyou.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aboutyou.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aboutyou.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "abstractbarista.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "abstractbarista.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "accredit.ly", "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": "actom.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "adamcoffee.net", "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 }, + { "name": "adminwerk.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "advancyte.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "agelesscitizen.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "agelesscitizens.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "agoravm.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "agouraelectrician.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ai1989.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aimerworld.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aimrom.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "akcounselingservices.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alainodea.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alcoholapi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alexsinnott.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alextjam.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alibababee.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "allenosgood.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "allenscaravans.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "allgrass.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "allgrass.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "allgreenturf.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "allincoin.shop", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alljamin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "allpropertyservices.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "allseasons-cleaning.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "allsync.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "allsync.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alpinechaletrental.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alpinetrek.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alpiniste.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "altaplana.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "altitudemoversdenver.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "altruistgroup.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alwaysonssl.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alzonaprinting.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 }, + { "name": "america.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ameriikanpoijat.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "amielucha.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "amitpatra.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ammanagingdirectors.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "amosng.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "andariegocusco.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "andys-place.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ankya9.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ansermfg.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "antennisti.milano.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "anthony.codes", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "antyblokada.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "apache-portal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "apination.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "appformacpc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "apps4all.sytes.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "archivero.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "arcridge.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "areqgaming.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "arimarie.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "arlingtonwine.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "armedpoet.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aromacos.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "artboja.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "arteaga.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "arteaga.tech", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "arteaga.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "arteaga.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "artecat.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "artisansoftaste.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "artmarketingnews.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ashlocklawgroup.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "asspinter.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "astal.rs", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "atac.no", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ateamsport.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "atedificacion.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "atelierdeloulou.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "atheist-refugees.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "attac.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "audividi.shop", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "augix.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aupasdecourses.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aurelienaltarriba.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "auroware.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "austinuniversityhouse.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "australianarmedforces.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "australianimmigrationadvisors.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "autocrypt.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "autopapo.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "autostock.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "autres-talents.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "av0ndale.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "avanet.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "avatarrecruit.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "avexon.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "avia-krasnoyarsk.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "avia-ufa.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aviapoisk.kz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "avietech.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "awxg.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ayon.group", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b0618.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b0618.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b0868.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b0868.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b1236.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b1758.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b1758.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b1768.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b1768.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b1788.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b1788.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b1rd.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b2486.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b2486.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b5189.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b5189.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b5289.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b5289.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b5989.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b5989.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b61688.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b8591.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b8591.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b8979.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b8979.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9018.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9018.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9108.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9108.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9110.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9112.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9112.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b911gt.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b911gt.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9168.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b91688.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b91688.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b91688.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b91688.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9175.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9175.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9258.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9258.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9318.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9318.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9418.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9418.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9428.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9428.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9453.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9453.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9468.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9468.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9488.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9488.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9498.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9498.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9518.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9518.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9518.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9518.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9520.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9528.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9528.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9538.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9538.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9568.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9586.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9588.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b95888.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9589.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9598.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9598.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9658.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9658.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b96899.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9758.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9758.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9818.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9818.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9858.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9858.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9880.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9883.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9884.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9885.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9886.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9886.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9887.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9888.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b98886.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9889.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9920.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9930.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9948.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9948.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b99520.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9960.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9970.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9980.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b99881.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b99882.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b99883.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b99885.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b99886.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9best.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9best.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9king.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9king.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9king.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9winner.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9winner.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "b9winner.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bachata.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "baka-gamer.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ballinarsl.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bamboorelay.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "banduhn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "banknet.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bao-in.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bao-in.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "baodan666.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "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": "bat909.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bat9vip.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bat9vip.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "batvip9.net", "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.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bbswin9.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bbxin9.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bbxin9.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bcdonadio.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bcdonadio.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bcodeur.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "be9418.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "be9418.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "be9418.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "be9418.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "be9458.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "be9458.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "be9458.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "be9458.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "be958.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "be958.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "be958.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "be958.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "be9966.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bealpha.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bebout.domains", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "beerview.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bellthrogh.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bellthrough.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "benevisim.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "benjii.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "benriya.shiga.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "benzi.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bergfreunde.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bergfreunde.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bergfreunde.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bergfreunde.fi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bergfreunde.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bergfreunde.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bergfreunde.no", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bergfreunde.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "berodes.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bessettenotaire.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bestattorney.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bestbatteriesonline.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bestesb.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bestesb.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bestinductioncooktop.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bestoffert.club", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bet-99.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bet-99.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bet168wy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bet168wy.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bet909.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bet990.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bet9bet9.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "betgo9.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "betterjapanese.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "betwin9.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "betwin9.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "beylikduzum.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "beylikduzuvaillant.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bh.sb", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bicecontracting.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bihub.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "biletyplus.by", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "biletyplus.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "biletyplus.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "biletyplus.ua", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bill-nye-the.science", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "binbin9.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "binbin9.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bingo9.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "binkanhada.biz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "biocheminee.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "birgitandmerlin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bistrotdelagare.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bitcoinwalletscript.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bitenose.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bitenose.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bitgrapes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bitxel.com.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bjl5689.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bjl5689.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bkhayes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "blackislegroup.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "blackscreen.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "blazing.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bling9.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bling999.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bling999.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bling999.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "blip.website", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "blobfolio.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "blockshopauto.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "blok56.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bludnykoren.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "blueblou.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bluecardlottery.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bluedeck.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "blunderify.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bluproducts.com.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bmriv.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bo1689.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bo1689.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bo9club.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bo9club.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bo9club.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bo9fun.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bo9fun.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bo9game.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bo9game.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bo9king.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "boards.ie", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bodypainting.waw.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bolgarnyelv.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bondingwithbaby.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "booksearch.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bopiweb.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bordes.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "boredhackers.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "boundarybrighton.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bovenwebdesign.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bozit.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bramburek.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bramstaps.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "breatheav.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "breatheproduction.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "briandwells.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "brownihc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "brztec.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bsa157.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bsd-box.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bsdes.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bserved.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "budget.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bulario.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "burtplasticsurgery.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "buryit.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "busybee360.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "buybike.shop", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "buycarpet.shop", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "buycook.shop", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "buyhealth.shop", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "buyjewel.shop", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "buyplussize.shop", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "buyprofessional.shop", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "buywine.shop", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "buywood.shop", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bx-web.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bytema.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bytema.sk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bythen.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bywin9.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "caarecord.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cadams.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cadra.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "calcedge.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "campingskyhooks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "canglong.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "canker.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "canterbury.ws", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "canx.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "captainark.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "car-rental24.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "carlscatering.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "carolinaclimatecontrolsc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cartadeviajes.cl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cartadeviajes.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cartadeviajes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cartadeviajes.com.ar", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cartadeviajes.com.ve", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cartadeviajes.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cartadeviajes.ec", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cartadeviajes.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cartadeviajes.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cartadeviajes.mx", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cartadeviajes.pe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cartadeviajes.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "casacameo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "caseplus-daem.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cashsector.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "casino-trio.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "caspar.ai", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cayounglab.co.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cdbtech.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cdsdigital.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "centralebigmat.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cerberusinformatica.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cercevelet.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "certifiednurses.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cfpa-formation.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "changes.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chaosriftgames.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chasse-et-plaisir.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chd-expert.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "checkspf.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cheladmin.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chemicalcrux.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chemiphys.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cherie-belle.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cherylsoleway.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chiboard.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chikazawa.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chinwag.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chloca.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chrisaitch.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "christopherkennelly.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chriswald.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cidersus.com.ec", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "circulatedigital.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "civicunicorn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "civicunicorn.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ckenelley.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ckenelly.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ckenely.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ckenneley.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ckennelley.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ckennely.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "claritysrv.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "clash.lol", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "classroomcountdown.co.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "clazzrooms.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cleansewellness.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "clearbreezesecuritydoors.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "clicksaveandprint.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "clinicminds.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "clnc.to", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "clorophilla.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "club-duomo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "clubcall.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "clubiconkenosha.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cmdtelecom.net.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cmrss.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cocktail-shaken.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cocubes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cokebar.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "coldstreamcreekfarm.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "collectorknives.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "coltonrb.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "comidasperuanas.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "commco.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "comoeliminarlaspapulasperladasenelglande.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "comosatisfaceraunhombreenlacamaydejarloloco.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "compeat.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "compusolve.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "concertsenboite.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "conory.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "contentdesign.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "convergencela.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cookeatup.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "coolprylar.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "corintech.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "corporateclash.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "corpsepaint.life", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "corrbee.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cosmechic.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "couscous.recipes", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "creatieven.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "creativeconceptsvernon.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "creato.top", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "creatujoya.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "creditreporttips.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cribcore.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "crimevictims.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cronologie.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "crose.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "crypteianetworks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cryptolinc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "csehnyelv.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "csgoswap.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ctcue.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cubix.host", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cueca.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cumplegenial.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cupcakesandcrinoline.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cupcao.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cybercrew.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cyberseguranca.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cyelint.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cygnaltech.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "czfa.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "d-msg.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dabuttonfactory.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "damienpontifex.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "daminiphysio.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "darknetlive.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "datacave.is", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "daverandom.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "davidbranco.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "davidbrito.tech", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "deanisa.ninja", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "decaffeinated.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "decs.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dedg3.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "deeps.cat", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "deeps.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dekonix.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "delfino.cr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "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 }, + { "name": "digitalcitizen.life", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "digitalcitizen.ro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "digitalfishfun.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dildoexperten.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "direct-sel.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "directspa.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dischempharmacie.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "disinfestazioni.venezia.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "distiduffer.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dj-leszwolle.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "djcursuszwolle.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "djursland-psykologen.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dnscrawler.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "doc-justice.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "doesburg-comp.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dogcontrol.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "domen-reg.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dominique-haas.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "domquixoteepi.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dongxuwang.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dotshule.ug", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "doubleaste.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "downrightcute.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dp.cx", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dreadd.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dreax.win", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dreischneidiger.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "drillingsupplystore.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "drmtransit.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dronnet.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "drugs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "drvr.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dsmjs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dsouzamusic.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dsrw.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dubai-company.ae", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dunklau.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "duoquadragintien.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "durfteparticiperen.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dusnan.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dustplanet.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dzytdl.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "e-tech-solution.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "e-techsolution.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "e-techsolutions.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "e-vo-linka.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "e1488.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "e4metech.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "e52888.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "e52888.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "e53888.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "e53888.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "e59888.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "e59888.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eagle.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eaglemessaging.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eastsidecottages.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "easycontentplan.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ebene-bpo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ebizarts.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ecodedi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eddokloosterman.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "edehsa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "edincmovie.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "edservicing.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "edxn.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "egrp365.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ekati.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ekb-avia.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ekyu.moe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "electric-vault.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "electricalagourahills.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "electricalcalabasas.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "electricalcamarillo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "electricalconejovalley.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eleicoes2018.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "elektronickakancelar.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eleonorengland.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eline168.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "elviraszabo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "elvispresley.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "elwix.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "elysiria.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "empyrean-advisors.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "emvoiceapp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "en4u.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "enderbycamping.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "endoftenancycleaninglondon.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "enginx.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ensemble-vos-idees.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "entheorie.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "enviatufoto.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "epa.com.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ephesusbreeze.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "epreskripce.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "equinetherapy.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eroimatome.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eroma.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "erwinpaal.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "es888.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "es8888.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "es888999.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "es999.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "es9999.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb-in.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb-top.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb-top.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb111.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb116.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb1314.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb1668.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb168168.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb168168.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb168168.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb168168.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb1688.biz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb1688.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb1688.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb1688.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb1688.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb16888.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb1711.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb1711.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb1788.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb1788.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb1788.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb1788.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb17888.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb2013.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb2013.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb2099.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb2099.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb222.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb258.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb325.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb325.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb333.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb336.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb369.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb433.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb518.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb553.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb555.biz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb555.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb555.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb556.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb5889.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb5889.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb6.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb666.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb666.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb66666.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb677.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb688.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb68888.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb775.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb777.biz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb777.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb777.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb777.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb777.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb777.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb777.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb886.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb888.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb8886.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb9527.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb9588.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb9588.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb9588.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb9588.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb999.biz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb999.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb999.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb999.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esb999.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esba11.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esba11.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esba11.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esba11.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esba11.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esball-in.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esball-in.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esball.bz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esball.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esball.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esball.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esball.mx", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esball.online", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esball.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esball.win", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esball.ws", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esball518.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esball518.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esball518.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esball518.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esball888.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esballs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esbbon.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esbbon.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esbfun.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esbfun.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esbgood.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esbin.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esbjon.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esbjon.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esbm4.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esbm5.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esmoney.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "esmoney.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "etech-solution.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "etech-solution.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "etech-solutions.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "etechsolution.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ethandelany.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eurolocarno.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "europeantimberconnectors.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "europeos.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "euroskano.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eurousa.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "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 }, + { "name": "exatmiseis.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "exchaser.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "exploringenderby.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "extreme.co.th", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eyona.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "f2h.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "f3nws.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "facekungfu.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "factcool.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "faerb.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fanboi.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "faradome.ws", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "farmaciamedicom.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fastvistorias.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "faui2k17.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fbiic.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fbtholdings.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fedemo.top", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "federatedbank.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fedpartnership.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "feeriedesign-event.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "feetpa.ws", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "felger-times.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "feng-in.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "feng-in.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "feudaltactics.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "feuerwehr-mehring.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ffiec.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fibo-forex.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "filanthropystar.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "finchnest.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fingerscrossed.style", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fintry.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "firefly-iii.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fireworkcoaching.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fitfitup.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fiveboosts.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fixvoltage.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "flamero.fi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "flangaapis.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fleurenplume.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "flextribly.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fliino.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fliino.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fliino.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fliino.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "flipbell.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "flirtycourts.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "flmortgagebank.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "florenceapp.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "floro.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "flowinvoice.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "flugsportvereinigungcelle.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fluhrers.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fluitbeurt.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fmussatmd.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "focuspointtechnologies.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "forbid.life", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "force-des-maths.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fordlibrarymuseum.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "forecastcity.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "forfunssake.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "forpc.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fotonjan.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fowlsmurf.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "francescoservida.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "frankenhost.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "frankslaughterinsurance.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "frederikvig.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "freelancecollab.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "freepnglogos.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "frejasdal.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "frosthall.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "frugal-millennial.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fs-community.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fu-li88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fu-li88.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fullhost.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "futurehack.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fwest98.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gaff-rig.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "galle.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gamecdn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ganaenergia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ganasoku.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gaudeamus-folklor.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gavinsblog.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gayukai.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gazachallenge.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "generalinsuranceservices.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "generationsweldom.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "geojs.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "georgewbushlibrary.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "getenergized2018.kpn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "getpagespeed.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "getteamninja.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gfms.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gfw.moe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ghid-pitesti.ro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "giethoorn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gigime.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ginza-luce.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gites-alizea.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gkvsc.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "glaciernursery.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gladystudio.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "globalgovernancewatch.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "god-esb.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "godbo9.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "godbo9.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "godbo9.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "godesb.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "goedkopeonesies.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "goetic.space", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "goozp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "goquiq.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gorgias.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gorognyelv.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gotrail.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gowin9.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gowin9.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "grahamcluley.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gram.tips", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "grandcafetwist.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gratiswifivoorjegasten.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "greatagain.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "greenitpark.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "grengine.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "grexx.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "grexx.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "grifomarchetti.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "grimstveit.no", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "groenewoud.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gruenderwoche-dresden.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "grumpygamers.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "guiacidade.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "guideline.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "guidelines.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "guishem.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gumannp.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gumballs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "guoliang.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gutschein-spezialist.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "h1z1swap.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ha-kunamatata.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "habbixed.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "habitat-domotique.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "habview.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "haccp.bergamo.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hakase.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hamon.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hanoibuffet.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hansbijster.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "haptemic.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "has-no-email-set.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hasecuritysolutions.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hashimoto-jimusho.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hayleishop.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hdnastudio.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "healey.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "health.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "healthfinder.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "healthypeople.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hearty.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hearty.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hebocon.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "heijdel.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "heinemann.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "heinemeier.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "heistheguy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "helpfute.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "helpverif.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "helpwithmybank.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "henkboelman.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hermann.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "herrenmuehle-wein.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "heute.training", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "heyjournal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hf-tekst.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hf51.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hibari.moe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hideout.agency", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hightechgadgets.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hipnoseinstitute.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hireprofs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hitokoto-mania.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hiyobi.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hl8999.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hnyp.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hoaas.no", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hochzeitsgezwitscher.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hodnos.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "homepage.shiga.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "homyremedies.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "honeycreeper.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hoorr.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hope-line-earth.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "horizonmoto.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "horvatnyelvkonyv.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hotesb.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hotesb.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "housekeeperlondon.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "howgoodwasmysex.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hstspreload.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hua-in.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hua-li88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hua-li88.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "huangting.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hubrecht.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hui-in.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hui-in.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "huislijn.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "humboldtmfg.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hunstoncanoeclub.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "huntexpired.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hyperactive.am", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hztgzz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "i-scream.space", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "i5y.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "iainsimms.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "iainsimms.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "iane-ccs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ich-hab-die-schnauze-voll-von-der-suche-nach-ner-kurzen-domain.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "icnsoft.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ideapaisajistas.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ideasenfoto.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "idered.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "idesignstudio.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "idrissi.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ig.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "iha6.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ikkbb.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ikkev.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "imeid.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "immaternity.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "imponet.com.ar", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "imprenta-es.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "inetsoftware.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "infinite.hosting", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "infruction.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ing89.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ing89.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ingatlanneked.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ingi.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "inmoodforsex.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "inspirationconcepts.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "instamojo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "intergenx.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "intergenx.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "intergenx.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "intergenx.org.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "interiery-waters.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "interiorprofesional.com.ar", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "interspot.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "invitethemhome.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "invuelto.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "iodine.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "iplayradio.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ironhide.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "isaaczais.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "iskkk.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "istheinternetonfire.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "it-maker.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "iwch.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "iworos.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "iyassu.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "izzys.casa", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "j0bs.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jakob-server.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jamalfi.bio", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "janhermann.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jape.today", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jastrow.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "javiermixdjs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jaysenjohnson.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jci.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jdgonzalez95.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jedayoshi.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jeepeg.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jenniferchan.id.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jetapi.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jetbrains.pw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jexler.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jfsa.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jiid.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jing-in.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jing-in.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jiosongs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jldp.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jlot.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jobers.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jobers.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "joblab.com.ua", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "joel.coffee", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "joeyhoer.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "johannes-bugenhagen.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "johanneskonrad.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "johego.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jonespayne.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jonincharacter.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jonlu.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "joonatoona.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jose-alexand.re", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "joshuadmiller.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "journalof.tech", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jselby.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "judge2020.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "judge2020.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "juliohernandezgt.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jungundwild-design.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "juridiqueo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "justiceo.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "justinrudio.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jzachpearson.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "k38.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "k4r.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kaeru-seitai.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kai.cool", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kakuto.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kalamos-psychiatrie.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kaleidoskop-freiburg.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kalwestelectric.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kamppailusali.fi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kana-mono.biz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kanag.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kanr.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kanzakiranko.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kanzlei-myca.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kaotik4266.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kargl.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "keematdekho.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kescher.site", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kfirba.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kidsareatrip.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kin.life", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kinderjugendfreizeitverein.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kirwandigital.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kissesb.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kissesb.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kivitelezesbiztositas.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "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 }, + { "name": "konventa.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kopio.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kopjethee.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "koppelvlak.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "korben.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kostal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kotly-marten.com.ua", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kouten-jp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "koval.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kowalstwo.com.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kpforme.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kraftzeiten.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kraken.site", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "krasnodar-avia.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "krausen.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kreditkarte-fuer-backpacker.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kryptomodkingz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kupinska.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kuroinu.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kwench.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kyprexxo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "la-compagnie-des-elfes.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "laatjeniethackmaken.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "laboutiquedejuliette.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "labrat.mobi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lachosetypo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ladyanna.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lafcheta.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lagit.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lalalab.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lalunecreative.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lamaisondelatransformationculturelle.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lamereabizix.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "langstreckensaufen.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lanternhealth.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lassesworld.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lassesworld.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "launchpadder2.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lauraofrank.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lauriemilne.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "laut.digital", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "law.co.il", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lc-cs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lcrmscp.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "le-drive-de-just-vet.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "leaderoftheresistance.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "leaderoftheresistance.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "leadquest.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "learnforestry.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lecoinchocolat.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ledlampor365.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "legaleus.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lengyelnyelvoktatas.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lengyelul.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "leodraxler.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "leonauto.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lesaffre.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lesh.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "letempsdunefleur.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "leviaan.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lhajn.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lian-in.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lian-in.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "liang-li88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "liang-li88.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "librarytools.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "libre-service.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lichttechnik-tumler.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lieblingsholz.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lieuu.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lifeinsurances.pro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lifeinsurances24.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "light-up.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "limbo.services", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "limn.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lincnaarzorg.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "linux.im", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "linuxincluded.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "liquimoly.market", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "littlegreece.ae", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "liufengyu.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "livelifewithintent.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "localdata.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "locomotive.net.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lojadarenda.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lojavirtualfc.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "loket.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "loli.ski", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "losangelestown.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lovebo9.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lovebo9.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lovingpenguin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lswim.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ltaake.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lucaslarson.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ludum.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "luedeke-bremen.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lufu.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lui.pink", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lxd.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lycly.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lyscnd.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mackiehouse.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "maddreefer.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "madridartcollection.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "maelstrom-fury.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mahraartisan.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "maisonpaulmier.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "makemyvape.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "makeurbiz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "malone.link", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mamaasia.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mamafit.club", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mamuko.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "manageathome.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mantabiofuel.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "marcelinofranchini.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "marcelinofranchini.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "marcelinofranchini.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "marcelinofranchini.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "marco-goltz.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "marjoriecarvalho.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mark-armstrong-gaming.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "marketingco.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "marketingromania.ro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "marklauman.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "marpa-wohnen.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "marshyplay.live", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "martijnhielema.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "marustat.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "math.hamburg", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "matrixim.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mattari-app.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mattmcshane.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mauricedb.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "maxpl0it.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mchan.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mcpaoffice.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "md-clinica.com.ua", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mdlayher.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mediarocks.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "medinside.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "medinside.li", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "medinsider.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "medinsider.li", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "medschat.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "medvet.com.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "melopie.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "memo.ee", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mendozagenevieve.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mennace.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "menntagatt.is", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "metro-web.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "meujeitodigital.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "meyash.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mfen.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mfxer.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "miaonagemi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "michal-s.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "micomi.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "midkam.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mikewritesstuff.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mikhirev.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "min.kiwi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "minehattan.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "minerva2015.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ministeriumfuerinternet.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "minu.link", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mirabalphoto.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mirrorsedgearchive.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mirrorsedgearchive.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mitigationcommission.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mixer.cash", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mjscustomcreations.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mlmjam.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mlpvector.club", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mms.is", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mobilebingoclub.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mobilecasinoclub.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mobilemalin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mobimalin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mobmp4.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mobmp4.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mobmp4.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mockerel.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "modding-forum.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "modelclub-draveil.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "moebel-vergleichen.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "moisesbarrio.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "momfulfilled.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "momy-genealogie.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mon-mobile.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "monalyse.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "monicabeckstrom.no", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "monodukuri.cafe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "monodzukuri.cafe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "monozukuri.cafe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "moodforsex.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "moolah.rocks", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "moonbot.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "moreal.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "morepopcorn.co.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "motowilliams.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "movienized.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mozartgroup.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mrbuckykat.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mrknee.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mrparker.pw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mufibot.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mushman.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mustafaturhan.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "myabcm.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mycareersfuture.sg", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "myessaygeek.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mygreatlakes.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mymarketingcourses.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mypaperdone.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "myref.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mysexydate24.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mysongbird.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mytun.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "n64chan.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nakada4610.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nameme.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "namskra.is", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "naomi.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nataniel-perissier.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nationalbank.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nationalbanknet.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nay.moe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nba669.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nba686.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nbad.al", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nc-beautypro.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nc-formation.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nc-network.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "necio.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "neilfarrington.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nekox.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "neocyd.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "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 }, + { "name": "net-masters.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nethask.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "netsparker.com.tr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nettamente.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "neurolab.no", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "news4c.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ngc.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nhsuites.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nicholaswilliams.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nickscomputers.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nightsi.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nikkasystems.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nimidam.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ninepints.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nirjonmela.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "noelblog.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "noise.agency", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "noisetor.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nolimits.net.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nomenclator.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nordlichter-brv.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "norichanmama.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "normanschwaneberg.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "northokanaganbookkeeping.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "novgorod-avia.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "novosibavia.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nsa.ovh", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nsapwn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nutriciametabolics-shop.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nutrishop.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "o8b.club", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "oclausen.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "octo.im", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "octohost.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ohohrazi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "oisd.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "olgui.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "oliveoil.bot", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "oliverclausen.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "oliviervaillancourt.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ollies.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "onahonavi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ondcp.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "oneidentity.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "onetly.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "oni.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "online-calculator.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "online-stopwatch.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "online.net.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "onlyesb.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "onlyesb.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "onsgenoegen-waz.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "onspring.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "opalesurfcasting.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "openclima.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "opentuition.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "operationforever.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "oppag.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "optm.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "orbitdefence.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "oregonmu.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "orum.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "osla.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "osmre.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "otus-magnum.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ouowo.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pablo.scot", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pablo.sh", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pabloarteaga.com.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pabloarteaga.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pabloarteaga.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pabloarteaga.nom.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pabloarteaga.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pabloarteaga.science", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pabloarteaga.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pacifique-web.nc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "packshot-creator.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "padron.com.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pagalworld.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pagalworld.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pagalworld.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pagalworld.la", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "paincareehr.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "paket.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "palawan.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "palazzotalamo.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pangci.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "papapa-members.club", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "papotage.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "paradependentesquimicos.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "parisderriere.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pasearch.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "passvanille-reservation.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "patentados.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "patika-biztositas.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "paulmeier.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pay.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pb.ax", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pcdocjim.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "peaceispossible.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pearlcohen.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "peddy.dyndns.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pedro.com.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pelotonimports.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "penguinprotocols.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "penispumpen.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pepper.dog", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "perm-avia.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "permajackofstlouis.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "petit-archer.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pflan.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pflegesalon-siebke.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pi-net.dedyn.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pierreprinetti.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pimpmypaper.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pinklittlenotebook.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pixiv.cat", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pixloc.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "plagiarismcheck.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "planer.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "planetanim.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "plannedlink.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "planujemywesele.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "plasticsurgerynola.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "playreal.city", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "plerion.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pm25.im", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pmgnet.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pneu01.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pneu74.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pocakdrops.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pocakking.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pocitacezababku.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pocket-lint.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pohlmann.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pointworksacademy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "policereferencecheck.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pomfeed.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pomozmruczkom.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "poolspondsandwaterscapes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "popcultureshack.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "port.im", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "posijson.stream", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "powerserg.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "powersergholdings.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "powertothebuilder.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pozlife.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "praktijkdevecht.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pritchett.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "privatecapsecurity.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pro-esb.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pro-esb.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "prodware.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "proesb.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "proesb.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "projectl1b1t1na.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "promotioncentre.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "proteogenix-products.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "protocol.ai", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "prylarprylar.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "psdsuc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pthsec.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "publicinquiry.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pulpproject.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "punchunique.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "purplehippie.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "putman-it.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "puzzlage.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pvda.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pvpctutorials.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pycycle.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pzsearch.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "qc.immo", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "qclt.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "qruiser.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "quanwuji.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "quartix.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "quartzclinical.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "quilmo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "quimsertek.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "qwdqwd.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "qwq.moe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "r1ch.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "radartatska.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "radartek.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "radiorsvp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rammstein-portugal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rangsmo.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ranyeh.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "raphrfg.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rapidemobile.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rapidflow.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "raucris.ro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "raviparekh.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "raystark.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "raywin168.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "raywin168.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "raywin88.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "recipex.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "red-trigger.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "red2fred2.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "redactieco.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "regency-fire.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "regency-fire.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "regisearch.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "registerra.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "renewmedispa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "resfriatech.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "reviewninja.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "richamorindonesia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ricky.capital", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ristrutturazioneappartamento.roma.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rizalpalawan.gov.ph", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rlnunez.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "robertnemec.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "robertocasares.no-ip.biz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "roboth.am", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rodarion.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "roelbazuin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "roligprylar.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rollercoasteritalia.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rollingbarge.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rook-playz.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "roopakv.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rootkea.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ropd.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "roseparkhouse.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rosetiger.life", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rostov-avia.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ruaneattorneys.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ruobr.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rushyo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rwx.ovh", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "s-n-unso.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "s-s-paint.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "s3cases.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "s44.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sabtunes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "saintw.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sajamstudija.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "salon1.ee", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "samanthasicecream.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "samara-avia.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sandiegotown.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sapphireblue.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sarahplusdrei.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sasrobotics.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sativatunja.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "saxeandthecity.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sbrouwer.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "schollbox.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "schwerkraftlabor.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "scib.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "scicomm.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "scijinks.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "scrapmalin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "screenmachine.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sdxcentral.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sean-wright.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "season.moe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sebastianpedersen.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sebasveeke.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sec.red", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sec455.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sec530.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sec555.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "secureim.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "seehimnaked.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "seehimnude.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "seehisnudes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "seobutler.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sergiozygmunt.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "servida.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "setenforce.one", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sevenicealimentos.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sexdocka.nu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sharelovenotsecrets.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shaunandamyswedding.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shico.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shiga1.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shihadwiki.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shouttag.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shteiman.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shura.eu.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "silerfamily.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sim-minaoshi.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "simhaf.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "simplyregister.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sinclairinat0r.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sinn.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sipsik.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sjaakgilsingfashion.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "skanword.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "skedda.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "skepneklaw.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "skiddle.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "skippy.dog", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sknclinics.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "skolagatt.is", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "skyderby.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "slashcrypto.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sleepstar.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "slonep.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "smadav.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "smalle-voet.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "smartcpa.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "smilingmiao.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "smx.net.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "socialtrends.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "societe-chablaisienne-de-revetements.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "societe-chablaisienne-de-revetements.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sodadigital.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "softart.club", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sokouchousa.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "solvingproblems.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sommefeldt.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sompani.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sonicdoe.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sorenam.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sortesim.com.br", "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 }, + { "name": "spcx.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "specialtyalloys.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "speechdrop.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "speedof.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "speedway.com.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "spellchecker.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "spindrift.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "splintermail.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "spoluck.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sponsormatch.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "spookyinternet.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "spot-lumiere-led.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "spotrebitelskecentrum.sk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sr-33.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ssbgportal.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ssc8689.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ssc8689.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ssdservers.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ssready.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "staktrace.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "startle.cloud", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stdev.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "steamhours.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stemapp.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "steuerberater-essen-steele.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stevemonteyne.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stickeramoi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stiffordacademy.org.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stouter.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "striata.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stuudium.cloud", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stuudium.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "subrosr.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "succesprojekter.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sudo.org.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sunfulong.blog", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sunriseafricarelief.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "super-demarche.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "supperclub.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "surfocal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "suroil.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "swallsoft.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "swallsoft.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "swap.gg", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sweep.cards", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sweet-orr.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sweets-mimatsu.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "swisstechtalks.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "swordfighting.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sym01.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "symetria.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "systemadmin.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "systemd.eu.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "szerbnyelvkonyv.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "szlovaknyelv.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "szlovennyelv.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tacklinglife.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tadluedtke.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tai-in.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tai-in.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "takebackyourstate.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "takebackyourstate.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "takebackyourstate.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tangsisi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "taniafitness.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "taniafitness.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tanie-uslugi-ksiegowe.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tariff.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tass.nu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tbys.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tchaka.top", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "teambodyproject.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "teamninjaapp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "techdroid.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "techformator.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "technosuport.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tecnologiasurbanas.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "telefonogratuito.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "telfordwhitehouse.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tematicas.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tennisapp.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tenpo-iku.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tenzer.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "termax.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "terra.fitness", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tfreeman.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "theadultswiki.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "theconcordbridge.azurewebsites.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "theemasphere.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thefasterweb.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thefengshuioffice.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thegemriverside.com.vn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thehiddenbay.ws", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "theplaidpoodle.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thesaurus.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thesignacademy.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thesmallbusinesswebsiteguy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thewarrencenter.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thewoolroom.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thinegen.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thisdot.site", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thomas.love", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thriveweb.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tigit.co.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tiglitub.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "timetech.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "timothybjacobs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tinlc.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tiny.ee", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "titanpointe.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tju.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "to2mbn.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tobias-kleinmann.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tobyx.is", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "todacarreira.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "toekomstperspectief.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tokinoha.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tokky.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tomaspatera.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tomlowenthal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tomosm.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "toolkits.design", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "toothdoc.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "top-esb.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "topbilan.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "topesb.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "topicdesk.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "toponlinecasinosites.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "topwindowcleaners.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "torngalaxy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "torte.roma.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "totodil.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "totolabs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "touchweb.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "touhou.fm", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tourtrektrip.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tovp.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "toyota-kinenkan.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "trackingstream.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "trade-arcade.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "travel1x1.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "travellovers.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "treaslockbox.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "treetopsecurity.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tribly.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "troomcafe.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "trouver-son-chemin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "troykelly.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "trustednetworks.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tryfm.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "trygarciniaslimdiet.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ttyystudio.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "turnaroundforum.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tutorme.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tuwaner.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tuza.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tv-programme.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tv-programme.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "txbi.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "uahs.org.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "uhlhosting.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ultimate-uk.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ultrasite.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "umbriel.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "unblock-zh.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "unccelearn.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "unefleur.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "unidevgroup.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "unifiednetwork.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "uno.fi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "upperroommission.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "urbanmic.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "urth.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "usbr.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "utcast-mate.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "utgifter.no", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "valudo.st", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vanderbiltcisa.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vantagepointpreneed.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vasilikieleftheriou.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vats.im", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vatsim-uk.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vatsim.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vaughanrisher.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vcps.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vega-motor.com.ua", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vegalengd.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vegguide.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "veit.zone", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ventilateurs-plafond.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "veraandsteve.date", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "verbier-lechable.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vernonfigureskatingclub.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "very-kids.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "victoreriksson.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "victoreriksson.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "victoreriksson.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "victoreriksson.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "victoreriksson.nu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "victoreriksson.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vidadu.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vidb.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "videoload.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "videospornogratis.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "villamariaamalfi.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vinogradovka.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vintagebandfestival.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vintagesouthernpicks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vipesball.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vipesball.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vipesball.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vipesball.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "visit-montenegro.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vizija-nepremicnine.si", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vjhfoundation.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vmstan.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "volbyzive.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vrijgezellenfeestzwolle.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vucdn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vynedmusic.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "w50.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "w84.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wai-in.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "waka168.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "waka168.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "waka88.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wakfu.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wakiminblog.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "waltzmanplasticsurgery.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "walvi.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wannaridecostarica.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "warcraftjournal.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wasatchcrest.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "waylee.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "web-demarche.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "webdesignlabor.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "webev.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "websitesabq.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "webwednesday.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "weiltoast.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "weld.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wen-in.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wen-in.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "werkenvoorphiladelphia.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wezl.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "whistler-transfers.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "whitehousedrugpolicy.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "whoasome.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "whocybered.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "willowtree.school", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wisak.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "woktoss.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "woodcoin.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "woonboulevardvolendam.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "worf.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "workissime.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "workshopszwolle.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "workshopzwolle.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "worldcareers.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wpformation.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wphelpwithhomework.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "writemyessay.today", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wrmea.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wuxiaohen.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wybar.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wzfetish.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xanadu-taxi.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xilegames.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xin-in.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xin-in.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xing-in.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xinghuokeji.xin", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xn--lnakuten-9za.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xn--n8jubz39q0g0afpa985c.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xn--pckqk6xk43lunk.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xn--zr9h.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xn--zr9h.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xn--zr9h.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xn--zr9h.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xnu.kr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xsec.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xuan-li88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xuan-li88.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xxxlbox.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yacineboumaza.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yakaz.cl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yakaz.com.ar", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yakaz.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yakaz.com.mx", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yakaz.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yakaz.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yakaz.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yakaz.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yannick.cloud", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yao-in.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yao-in.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ybscareers.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yenibilgi.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yetishirt.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yimgo.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yocchan1513.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yoga-alliance-teacher-training.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yongbin.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yourfriendlytech.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ysx.me.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yubico.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yubikey.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yuema.net.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yummylooks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yurisviridov.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yusu.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yutang.vn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yvetteerasmus.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "yzcloud.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "z-latko.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zacharyschneider.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zachschneider.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zaem.tv", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zaghyr.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zalohovaniburian.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zargescases.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zekesnider.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zeroseteatacado.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zgan.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zhiwei.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zhuweiyou.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zitseng.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zorki.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zrnieckapresny.sk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zuan-in.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zyciedogorynogami.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zyrillezuno.com", "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, @@ -41627,6 +44253,8 @@ { "name": "mitm-software.badssl.com", "policy": "custom", "mode": "force-https", "include_subdomains": true }, { "name": "www.hyatt.com", "policy": "custom", "mode": "force-https", "include_subdomains": true }, { "name": "connect.facebook.net", "policy": "custom", "mode": "force-https", "include_subdomains": true }, + { "name": "bing.com", "policy": "custom", "mode": "force-https", "include_subdomains": true }, + { "name": "fan.gov", "policy": "custom", "mode": "force-https", "include_subdomains": true }, // No subdomains { "name": "wordpress.com", "policy": "custom", "mode": "force-https", "include_subdomains": false }, { "name": "www.wordpress.com", "policy": "custom", "mode": "force-https", "include_subdomains": false }, @@ -41635,11 +44263,12 @@ { "name": "swehack.org", "policy": "custom", "mode": "force-https", "include_subdomains": true, "pins": "swehackCom" }, { "name": "ncsccs.com", "policy": "custom", "mode": "force-https", "include_subdomains": true, "pins": "ncsccs" }, { "name": "themathematician.uk", "policy": "custom", "mode": "force-https", "include_subdomains": true, "pins": "ncsccs" }, - // TODO(lgarron): hstspreload.org can't scan IPv6-only sites due to Google + // TODO(elawrence): hstspreload.org can't scan IPv6-only sites due to Google // Cloud limitations. Move these entries to the bulk entries once they can // be handled automatically: github.com/chromium/hstspreload.org/issues/43 // IPv6 { "name": "ipv6only.network", "policy": "custom", "mode": "force-https", "include_subdomains": true }, + { "name": "trinity.fr.eu.org", "policy": "custom", "mode": "force-https", "include_subdomains": true }, // Expect-CT/Expect-Staple { "name": "crt.sh", "policy": "custom", @@ -41827,6 +44456,7 @@ { "name": "safecar.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true }, { "name": "famep.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true }, { "name": "nationalmall.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true }, + { "name": "mytuleap.com", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true }, // END OF ETLD-OWNER REQUESTED ENTRIES // To avoid trailing comma changes from showing up in diffs, we place a diff --git a/chromium/net/http/transport_security_state_unittest.cc b/chromium/net/http/transport_security_state_unittest.cc index d7a0df28483..c1569892b3d 100644 --- a/chromium/net/http/transport_security_state_unittest.cc +++ b/chromium/net/http/transport_security_state_unittest.cc @@ -246,7 +246,7 @@ void CheckHPKPReport( const HashValueVector& known_pins) { std::unique_ptr<base::Value> value(base::JSONReader::Read(report)); ASSERT_TRUE(value); - ASSERT_TRUE(value->IsType(base::Value::Type::DICTIONARY)); + ASSERT_TRUE(value->is_dict()); base::DictionaryValue* report_dict; ASSERT_TRUE(value->GetAsDictionary(&report_dict)); @@ -311,7 +311,7 @@ void CheckSerializedExpectStapleReport(const std::string& report, const std::string& cert_status) { std::unique_ptr<base::Value> value(base::JSONReader::Read(report)); ASSERT_TRUE(value); - ASSERT_TRUE(value->IsType(base::Value::Type::DICTIONARY)); + ASSERT_TRUE(value->is_dict()); base::DictionaryValue* report_dict; ASSERT_TRUE(value->GetAsDictionary(&report_dict)); @@ -2220,8 +2220,8 @@ TEST_F(TransportSecurityStateTest, RequireCTConsultsDelegate) { ASSERT_TRUE(cert); HashValueVector hashes; - hashes.push_back(HashValue( - X509Certificate::CalculateFingerprint256(cert->os_cert_handle()))); + hashes.push_back( + HashValue(X509Certificate::CalculateFingerprint256(cert->cert_buffer()))); { TransportSecurityState state; @@ -2357,11 +2357,11 @@ TEST_F(TransportSecurityStateTest, RequireCTForSymantec) { ImportCertFromFile(GetTestCertsDirectory(), "post_june_2016.pem"); ASSERT_TRUE(after_cert); - SHA256HashValue symantec_hash_value = { + const SHA256HashValue symantec_hash_value = { {0xb2, 0xde, 0xf5, 0x36, 0x2a, 0xd3, 0xfa, 0xcd, 0x04, 0xbd, 0x29, 0x04, 0x7a, 0x43, 0x84, 0x4f, 0x76, 0x70, 0x34, 0xea, 0x48, 0x92, 0xf8, 0x0e, 0x56, 0xbe, 0xe6, 0x90, 0x24, 0x3e, 0x25, 0x02}}; - SHA256HashValue google_hash_value = { + const SHA256HashValue google_hash_value = { {0xec, 0x72, 0x29, 0x69, 0xcb, 0x64, 0x20, 0x0a, 0xb6, 0x63, 0x8f, 0x68, 0xac, 0x53, 0x8e, 0x40, 0xab, 0xab, 0x5b, 0x19, 0xa6, 0x48, 0x56, 0x61, 0x04, 0x2a, 0x10, 0x61, 0xc4, 0x61, 0x27, 0x76}}; @@ -2473,6 +2473,93 @@ TEST_F(TransportSecurityStateTest, RequireCTForSymantec) { ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS)); } +// Tests that Certificate Transparency is required for all of the Symantec +// Managed CAs, regardless of when the certificate was issued. +TEST_F(TransportSecurityStateTest, RequireCTForSymantecManagedCAs) { + const SHA256HashValue symantec_hash_value = { + {0xb2, 0xde, 0xf5, 0x36, 0x2a, 0xd3, 0xfa, 0xcd, 0x04, 0xbd, 0x29, + 0x04, 0x7a, 0x43, 0x84, 0x4f, 0x76, 0x70, 0x34, 0xea, 0x48, 0x92, + 0xf8, 0x0e, 0x56, 0xbe, 0xe6, 0x90, 0x24, 0x3e, 0x25, 0x02}}; + const SHA256HashValue managed_hash_value = { + {0x7c, 0xac, 0x9a, 0x0f, 0xf3, 0x15, 0x38, 0x77, 0x50, 0xba, 0x8b, + 0xaf, 0xdb, 0x1c, 0x2b, 0xc2, 0x9b, 0x3f, 0x0b, 0xba, 0x16, 0x36, + 0x2c, 0xa9, 0x3a, 0x90, 0xf8, 0x4d, 0xa2, 0xdf, 0x5f, 0x3e}}; + + TransportSecurityState state; + + HashValueVector hashes; + hashes.push_back(HashValue(symantec_hash_value)); + hashes.push_back(HashValue(managed_hash_value)); + + // All certificates, both before and after the pre-existing 1 June 2016 + // date, are expected to be compliant. + scoped_refptr<X509Certificate> before_cert = + ImportCertFromFile(GetTestCertsDirectory(), "pre_june_2016.pem"); + ASSERT_TRUE(before_cert); + + 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_ENOUGH_SCTS)); + 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)); + 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)); + 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)); + + scoped_refptr<X509Certificate> after_cert = + ImportCertFromFile(GetTestCertsDirectory(), "post_june_2016.pem"); + ASSERT_TRUE(after_cert); + + 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_ENOUGH_SCTS)); + 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)); + 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)); + 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)); +} + // Tests that dynamic Expect-CT state is cleared from ClearDynamicData(). TEST_F(TransportSecurityStateTest, DynamicExpectCTStateCleared) { base::test::ScopedFeatureList feature_list; @@ -3104,6 +3191,8 @@ TEST_F(TransportSecurityStateStaticTest, IsPreloaded) { const std::string google = "google"; const std::string www_google = "www.google"; const std::string foo = "foo"; + const std::string bank = "example.bank"; + const std::string insurance = "sub.example.insurance"; TransportSecurityState state; TransportSecurityState::STSState sts_state; @@ -3115,6 +3204,10 @@ TEST_F(TransportSecurityStateStaticTest, IsPreloaded) { EXPECT_TRUE(GetStaticDomainState(&state, google, &sts_state, &pkp_state)); EXPECT_TRUE(GetStaticDomainState(&state, www_google, &sts_state, &pkp_state)); EXPECT_TRUE(GetStaticDomainState(&state, foo, &sts_state, &pkp_state)); + EXPECT_TRUE(GetStaticDomainState(&state, bank, &sts_state, &pkp_state)); + EXPECT_TRUE(sts_state.include_subdomains); + EXPECT_TRUE(GetStaticDomainState(&state, insurance, &sts_state, &pkp_state)); + EXPECT_TRUE(sts_state.include_subdomains); EXPECT_FALSE( GetStaticDomainState(&state, a_www_paypal, &sts_state, &pkp_state)); EXPECT_FALSE( @@ -3347,6 +3440,9 @@ TEST_F(TransportSecurityStateStaticTest, Preloaded) { EXPECT_TRUE(StaticShouldRedirect("crate.io")); EXPECT_TRUE(StaticShouldRedirect("foo.crate.io")); + + EXPECT_TRUE(StaticShouldRedirect("sub.bank")); + EXPECT_TRUE(StaticShouldRedirect("sub.insurance")); } TEST_F(TransportSecurityStateStaticTest, PreloadedPins) { @@ -3498,7 +3594,7 @@ TEST_F(TransportSecurityStateStaticTest, OptionalHSTSCertPins) { EXPECT_TRUE(HasStaticPublicKeyPins("googlesyndication.com")); EXPECT_TRUE(HasStaticPublicKeyPins("doubleclick.net")); EXPECT_TRUE(HasStaticPublicKeyPins("ad.doubleclick.net")); - EXPECT_FALSE(HasStaticPublicKeyPins("learn.doubleclick.net")); + EXPECT_TRUE(HasStaticPublicKeyPins("redirector.gvt1.com")); EXPECT_TRUE(HasStaticPublicKeyPins("a.googlegroups.com")); } diff --git a/chromium/net/http2/decoder/decode_buffer_test.cc b/chromium/net/http2/decoder/decode_buffer_test.cc index b982d4c9aef..2f1abdd2c30 100644 --- a/chromium/net/http2/decoder/decode_buffer_test.cc +++ b/chromium/net/http2/decoder/decode_buffer_test.cc @@ -43,7 +43,7 @@ struct TestStruct { class DecodeBufferTest : public ::testing::Test { public: - DecodeBufferTest() {} + DecodeBufferTest() = default; protected: Http2Random random_; diff --git a/chromium/net/http2/decoder/http2_frame_decoder_listener_test_util.cc b/chromium/net/http2/decoder/http2_frame_decoder_listener_test_util.cc index 9159b6cdc5b..74c59eebccb 100644 --- a/chromium/net/http2/decoder/http2_frame_decoder_listener_test_util.cc +++ b/chromium/net/http2/decoder/http2_frame_decoder_listener_test_util.cc @@ -9,8 +9,8 @@ namespace net { -FailingHttp2FrameDecoderListener::FailingHttp2FrameDecoderListener() {} -FailingHttp2FrameDecoderListener::~FailingHttp2FrameDecoderListener() {} +FailingHttp2FrameDecoderListener::FailingHttp2FrameDecoderListener() = default; +FailingHttp2FrameDecoderListener::~FailingHttp2FrameDecoderListener() = default; bool FailingHttp2FrameDecoderListener::OnFrameHeader( const Http2FrameHeader& header) { @@ -196,7 +196,7 @@ LoggingHttp2FrameDecoderListener::LoggingHttp2FrameDecoderListener() LoggingHttp2FrameDecoderListener::LoggingHttp2FrameDecoderListener( Http2FrameDecoderListener* wrapped) : wrapped_(wrapped) {} -LoggingHttp2FrameDecoderListener::~LoggingHttp2FrameDecoderListener() {} +LoggingHttp2FrameDecoderListener::~LoggingHttp2FrameDecoderListener() = default; bool LoggingHttp2FrameDecoderListener::OnFrameHeader( const Http2FrameHeader& header) { diff --git a/chromium/net/http2/decoder/http2_frame_decoder_test.cc b/chromium/net/http2/decoder/http2_frame_decoder_test.cc index a1d848326b9..d81c7ac98ec 100644 --- a/chromium/net/http2/decoder/http2_frame_decoder_test.cc +++ b/chromium/net/http2/decoder/http2_frame_decoder_test.cc @@ -196,7 +196,7 @@ class Http2FrameDecoderTest : public RandomDecoderTest { template <size_t N> AssertionResult DecodePayloadExpectingFrameSizeError(const char (&buf)[N], FrameParts expected) { - expected.has_frame_size_error = true; + expected.SetHasFrameSizeError(true); VERIFY_AND_RETURN_SUCCESS(DecodePayloadExpectingError(buf, expected)); } @@ -260,7 +260,7 @@ TEST_F(Http2FrameDecoderTest, Priority) { }; Http2FrameHeader header(5, Http2FrameType::PRIORITY, 0, 2); FrameParts expected(header); - expected.opt_priority = Http2PriorityFields(1, 17, true); + expected.SetOptPriority(Http2PriorityFields(1, 17, true)); EXPECT_TRUE(DecodePayloadAndValidateSeveralWays(kFrameData, expected)); } @@ -274,7 +274,7 @@ TEST_F(Http2FrameDecoderTest, RstStream) { }; Http2FrameHeader header(4, Http2FrameType::RST_STREAM, 0, 1); FrameParts expected(header); - expected.opt_rst_stream_error_code = Http2ErrorCode::PROTOCOL_ERROR; + expected.SetOptRstStreamErrorCode(Http2ErrorCode::PROTOCOL_ERROR); EXPECT_TRUE(DecodePayloadAndValidateSeveralWays(kFrameData, expected)); } @@ -312,7 +312,7 @@ TEST_F(Http2FrameDecoderTest, PushPromiseMinimal) { Http2FrameHeader header(4, Http2FrameType::PUSH_PROMISE, Http2FrameFlag::END_HEADERS, 2); FrameParts expected(header, ""); - expected.opt_push_promise = Http2PushPromiseFields{1}; + expected.SetOptPushPromise(Http2PushPromiseFields{1}); EXPECT_TRUE(DecodePayloadAndValidateSeveralWays(kFrameData, expected)); } @@ -327,7 +327,8 @@ TEST_F(Http2FrameDecoderTest, Ping) { }; Http2FrameHeader header(8, Http2FrameType::PING, 0, 0); FrameParts expected(header); - expected.opt_ping = Http2PingFields{{'s', 'o', 'm', 'e', 'd', 'a', 't', 'a'}}; + expected.SetOptPing( + Http2PingFields{{'s', 'o', 'm', 'e', 'd', 'a', 't', 'a'}}); EXPECT_TRUE(DecodePayloadAndValidateSeveralWays(kFrameData, expected)); } @@ -342,7 +343,8 @@ TEST_F(Http2FrameDecoderTest, PingAck) { }; Http2FrameHeader header(8, Http2FrameType::PING, Http2FrameFlag::ACK, 0); FrameParts expected(header); - expected.opt_ping = Http2PingFields{{'s', 'o', 'm', 'e', 'd', 'a', 't', 'a'}}; + expected.SetOptPing( + Http2PingFields{{'s', 'o', 'm', 'e', 'd', 'a', 't', 'a'}}); EXPECT_TRUE(DecodePayloadAndValidateSeveralWays(kFrameData, expected)); } @@ -357,8 +359,8 @@ TEST_F(Http2FrameDecoderTest, GoAwayMinimal) { }; Http2FrameHeader header(8, Http2FrameType::GOAWAY, 0, 1); FrameParts expected(header); - expected.opt_goaway = - Http2GoAwayFields(255, Http2ErrorCode::COMPRESSION_ERROR); + expected.SetOptGoaway( + Http2GoAwayFields(255, Http2ErrorCode::COMPRESSION_ERROR)); EXPECT_TRUE(DecodePayloadAndValidateSeveralWays(kFrameData, expected)); } @@ -372,7 +374,7 @@ TEST_F(Http2FrameDecoderTest, WindowUpdate) { }; Http2FrameHeader header(4, Http2FrameType::WINDOW_UPDATE, 0, 1); FrameParts expected(header); - expected.opt_window_update_increment = 1024; + expected.SetOptWindowUpdateIncrement(1024); EXPECT_TRUE(DecodePayloadAndValidateSeveralWays(kFrameData, expected)); } @@ -398,8 +400,8 @@ TEST_F(Http2FrameDecoderTest, AltSvcMinimal) { }; Http2FrameHeader header(2, Http2FrameType::ALTSVC, 0, 0); FrameParts expected(header); - expected.opt_altsvc_origin_length = 0; - expected.opt_altsvc_value_length = 0; + expected.SetOptAltsvcOriginLength(0); + expected.SetOptAltsvcValueLength(0); EXPECT_TRUE(DecodePayloadAndValidateSeveralWays(kFrameData, expected)); } @@ -458,7 +460,7 @@ TEST_F(Http2FrameDecoderTest, HeadersPriority) { Http2FrameHeader header(5, Http2FrameType::HEADERS, Http2FrameFlag::PRIORITY, 2); FrameParts expected(header); - expected.opt_priority = Http2PriorityFields(1, 256, false); + expected.SetOptPriority(Http2PriorityFields(1, 256, false)); EXPECT_TRUE(DecodePayloadAndValidateSeveralWays(kFrameData, expected)); } @@ -475,9 +477,9 @@ TEST_F(Http2FrameDecoderTest, Settings) { }; Http2FrameHeader header(12, Http2FrameType::SETTINGS, 0, 0); FrameParts expected(header); - expected.settings.push_back(Http2SettingFields( + expected.AppendSetting(Http2SettingFields( Http2SettingsParameter::INITIAL_WINDOW_SIZE, 168496141)); - expected.settings.push_back( + expected.AppendSetting( Http2SettingFields(Http2SettingsParameter::ENABLE_PUSH, 3)); EXPECT_TRUE(DecodePayloadAndValidateSeveralWays(kFrameData, expected)); } @@ -494,7 +496,7 @@ TEST_F(Http2FrameDecoderTest, PushPromisePayload) { Http2FrameHeader header(7, Http2FrameType::PUSH_PROMISE, Http2FrameFlag::END_HEADERS, 255); FrameParts expected(header, "abc"); - expected.opt_push_promise = Http2PushPromiseFields{256}; + expected.SetOptPushPromise(Http2PushPromiseFields{256}); EXPECT_TRUE(DecodePayloadAndValidateSeveralWays(kFrameData, expected)); } @@ -510,8 +512,8 @@ TEST_F(Http2FrameDecoderTest, GoAwayOpaqueData) { }; Http2FrameHeader header(14, Http2FrameType::GOAWAY, 0, 0); FrameParts expected(header, "opaque"); - expected.opt_goaway = - Http2GoAwayFields(256, Http2ErrorCode::FLOW_CONTROL_ERROR); + expected.SetOptGoaway( + Http2GoAwayFields(256, Http2ErrorCode::FLOW_CONTROL_ERROR)); EXPECT_TRUE(DecodePayloadAndValidateSeveralWays(kFrameData, expected)); } @@ -615,7 +617,7 @@ TEST_F(Http2FrameDecoderTest, HeadersPayloadPriorityAndPadding) { 2); size_t total_pad_length = 4; // Including the Pad Length field. FrameParts expected(header, "abc", total_pad_length); - expected.opt_priority = Http2PriorityFields(1, 17, true); + expected.SetOptPriority(Http2PriorityFields(1, 17, true)); EXPECT_TRUE(DecodePayloadAndValidateSeveralWays(kFrameData, expected)); } @@ -635,7 +637,7 @@ TEST_F(Http2FrameDecoderTest, PushPromisePayloadAndPadding) { 1); size_t total_pad_length = 4; // Including the Pad Length field. FrameParts expected(header, "abc", total_pad_length); - expected.opt_push_promise = Http2PushPromiseFields{2}; + expected.SetOptPushPromise(Http2PushPromiseFields{2}); EXPECT_TRUE(DecodePayloadAndValidateSeveralWays(kFrameData, expected)); } @@ -651,7 +653,7 @@ TEST_F(Http2FrameDecoderTest, DataMissingPadLengthField) { }; Http2FrameHeader header(0, Http2FrameType::DATA, Http2FrameFlag::PADDED, 1); FrameParts expected(header); - expected.opt_missing_length = 1; + expected.SetOptMissingLength(1); EXPECT_TRUE(DecodePayloadExpectingError(kFrameData, expected)); } @@ -667,7 +669,7 @@ TEST_F(Http2FrameDecoderTest, HeaderPaddingTooLong) { Http2FrameHeader header(2, Http2FrameType::HEADERS, Http2FrameFlag::PADDED, 65536); FrameParts expected(header); - expected.opt_missing_length = 254; + expected.SetOptMissingLength(254); EXPECT_TRUE(DecodePayloadExpectingError(kFrameData, expected)); } @@ -723,7 +725,7 @@ TEST_F(Http2FrameDecoderTest, SettingsWrongSize) { }; Http2FrameHeader header(9, Http2FrameType::SETTINGS, 0, 0); FrameParts expected(header); - expected.settings.push_back( + expected.AppendSetting( Http2SettingFields(Http2SettingsParameter::ENABLE_PUSH, 3)); EXPECT_TRUE(DecodePayloadExpectingFrameSizeError(kFrameData, expected)); } @@ -835,7 +837,7 @@ TEST_F(Http2FrameDecoderTest, BeyondMaximum) { Http2FrameFlag::END_STREAM | Http2FrameFlag::PADDED, 2); FrameParts expected(header); - expected.has_frame_size_error = true; + expected.SetHasFrameSizeError(true); auto validator = [&expected, this](const DecodeBuffer& input, DecodeStatus status) -> AssertionResult { VERIFY_EQ(status, DecodeStatus::kDecodeError); diff --git a/chromium/net/http2/decoder/payload_decoders/goaway_payload_decoder_test.cc b/chromium/net/http2/decoder/payload_decoders/goaway_payload_decoder_test.cc index 74bcd18b1fe..42b359f7d0f 100644 --- a/chromium/net/http2/decoder/payload_decoders/goaway_payload_decoder_test.cc +++ b/chromium/net/http2/decoder/payload_decoders/goaway_payload_decoder_test.cc @@ -98,7 +98,7 @@ TEST_P(GoAwayOpaqueDataLengthTests, ValidLength) { RandStreamId()); set_frame_header(header); FrameParts expected(header, opaque_data); - expected.opt_goaway = goaway; + expected.SetOptGoaway(goaway); ASSERT_TRUE(DecodePayloadAndValidateSeveralWays(fb.buffer(), expected)); } diff --git a/chromium/net/http2/decoder/payload_decoders/headers_payload_decoder_test.cc b/chromium/net/http2/decoder/payload_decoders/headers_payload_decoder_test.cc index 75282d952b2..1889dde2eed 100644 --- a/chromium/net/http2/decoder/payload_decoders/headers_payload_decoder_test.cc +++ b/chromium/net/http2/decoder/payload_decoders/headers_payload_decoder_test.cc @@ -126,7 +126,7 @@ TEST_P(HeadersPayloadDecoderTest, VariousHpackPayloadSizes) { ScrubFlagsOfHeader(&frame_header); FrameParts expected(frame_header, hpack_payload, total_pad_length_); if (has_priority) { - expected.opt_priority = priority; + expected.SetOptPriority(priority); } EXPECT_TRUE(DecodePayloadAndValidateSeveralWays(frame_builder_.buffer(), expected)); diff --git a/chromium/net/http2/decoder/payload_decoders/payload_decoder_base_test_util.h b/chromium/net/http2/decoder/payload_decoders/payload_decoder_base_test_util.h index 43be7b52d37..67033fa779f 100644 --- a/chromium/net/http2/decoder/payload_decoders/payload_decoder_base_test_util.h +++ b/chromium/net/http2/decoder/payload_decoders/payload_decoder_base_test_util.h @@ -232,11 +232,11 @@ class AbstractPayloadDecoderTest : public PayloadDecoderBaseTest { VERIFY_FALSE(listener_.IsInProgress()); VERIFY_EQ(1u, listener_.size()); const FrameParts* frame = listener_.frame(0); - VERIFY_EQ(header, frame->frame_header); - VERIFY_TRUE(frame->has_frame_size_error); + VERIFY_EQ(header, frame->GetFrameHeader()); + VERIFY_TRUE(frame->GetHasFrameSizeError()); // Verify did not get OnPaddingTooLong, as we should only ever produce // one of these two errors for a single frame. - VERIFY_FALSE(frame->opt_missing_length); + VERIFY_FALSE(frame->GetOptMissingLength()); return validator(input, status); }; VERIFY_AND_RETURN_SUCCESS( @@ -403,11 +403,11 @@ class AbstractPaddablePayloadDecoderTest VERIFY_FALSE(listener.IsInProgress()); VERIFY_EQ(1u, listener.size()); const FrameParts* frame = listener.frame(0); - VERIFY_EQ(header, frame->frame_header); - VERIFY_TRUE(frame->opt_missing_length); - VERIFY_EQ(expected_missing_length, frame->opt_missing_length.value()); + VERIFY_EQ(header, frame->GetFrameHeader()); + VERIFY_TRUE(frame->GetOptMissingLength()); + VERIFY_EQ(expected_missing_length, frame->GetOptMissingLength().value()); // Verify did not get OnFrameSizeError. - VERIFY_FALSE(frame->has_frame_size_error); + VERIFY_FALSE(frame->GetHasFrameSizeError()); return ::testing::AssertionSuccess(); }; VERIFY_AND_RETURN_SUCCESS( diff --git a/chromium/net/http2/decoder/payload_decoders/ping_payload_decoder_test.cc b/chromium/net/http2/decoder/payload_decoders/ping_payload_decoder_test.cc index 04e0b445a37..fbe5fef44ad 100644 --- a/chromium/net/http2/decoder/payload_decoders/ping_payload_decoder_test.cc +++ b/chromium/net/http2/decoder/payload_decoders/ping_payload_decoder_test.cc @@ -85,7 +85,7 @@ TEST_F(PingPayloadDecoderTest, Ping) { RandFlags() & ~Http2FrameFlag::ACK, RandStreamId()); set_frame_header(header); FrameParts expected(header); - expected.opt_ping = fields; + expected.SetOptPing(fields); EXPECT_TRUE(DecodePayloadAndValidateSeveralWays(fb.buffer(), expected)); } } @@ -100,7 +100,7 @@ TEST_F(PingPayloadDecoderTest, PingAck) { RandFlags() | Http2FrameFlag::ACK, RandStreamId()); set_frame_header(header); FrameParts expected(header); - expected.opt_ping = fields; + expected.SetOptPing(fields); EXPECT_TRUE(DecodePayloadAndValidateSeveralWays(fb.buffer(), expected)); } } diff --git a/chromium/net/http2/decoder/payload_decoders/priority_payload_decoder_test.cc b/chromium/net/http2/decoder/payload_decoders/priority_payload_decoder_test.cc index 53123631344..b9229ad604a 100644 --- a/chromium/net/http2/decoder/payload_decoders/priority_payload_decoder_test.cc +++ b/chromium/net/http2/decoder/payload_decoders/priority_payload_decoder_test.cc @@ -80,7 +80,7 @@ TEST_F(PriorityPayloadDecoderTest, VariousPayloads) { RandStreamId()); set_frame_header(header); FrameParts expected(header); - expected.opt_priority = fields; + expected.SetOptPriority(fields); EXPECT_TRUE(DecodePayloadAndValidateSeveralWays(fb.buffer(), expected)); } } diff --git a/chromium/net/http2/decoder/payload_decoders/push_promise_payload_decoder_test.cc b/chromium/net/http2/decoder/payload_decoders/push_promise_payload_decoder_test.cc index 92fd183c7a7..537439f668e 100644 --- a/chromium/net/http2/decoder/payload_decoders/push_promise_payload_decoder_test.cc +++ b/chromium/net/http2/decoder/payload_decoders/push_promise_payload_decoder_test.cc @@ -108,7 +108,7 @@ TEST_P(PushPromisePayloadDecoderTest, VariousHpackPayloadSizes) { RandStreamId()); set_frame_header(frame_header); FrameParts expected(frame_header, hpack_payload, total_pad_length_); - expected.opt_push_promise = push_promise; + expected.SetOptPushPromise(push_promise); EXPECT_TRUE( DecodePayloadAndValidateSeveralWays(frame_builder_.buffer(), expected)); } diff --git a/chromium/net/http2/decoder/payload_decoders/rst_stream_payload_decoder_test.cc b/chromium/net/http2/decoder/payload_decoders/rst_stream_payload_decoder_test.cc index 741c444c769..c28decb358a 100644 --- a/chromium/net/http2/decoder/payload_decoders/rst_stream_payload_decoder_test.cc +++ b/chromium/net/http2/decoder/payload_decoders/rst_stream_payload_decoder_test.cc @@ -82,7 +82,7 @@ TEST_F(RstStreamPayloadDecoderTest, AllErrors) { RandStreamId()); set_frame_header(header); FrameParts expected(header); - expected.opt_rst_stream_error_code = error_code; + expected.SetOptRstStreamErrorCode(error_code); EXPECT_TRUE(DecodePayloadAndValidateSeveralWays(fb.buffer(), expected)); } } diff --git a/chromium/net/http2/decoder/payload_decoders/settings_payload_decoder_test.cc b/chromium/net/http2/decoder/payload_decoders/settings_payload_decoder_test.cc index 1764dc2ee19..6f81f8e7a2c 100644 --- a/chromium/net/http2/decoder/payload_decoders/settings_payload_decoder_test.cc +++ b/chromium/net/http2/decoder/payload_decoders/settings_payload_decoder_test.cc @@ -129,7 +129,7 @@ TEST_F(SettingsPayloadDecoderTest, OneRealSetting) { RandStreamId()); set_frame_header(header); FrameParts expected(header); - expected.settings.push_back(fields); + expected.AppendSetting(fields); EXPECT_TRUE(DecodePayloadAndValidateSeveralWays(fb.buffer(), expected)); } } @@ -149,7 +149,7 @@ TEST_F(SettingsPayloadDecoderTest, ManySettings) { Http2SettingFields fields(static_cast<Http2SettingsParameter>(n), Random().Rand32()); fb.Append(fields); - expected.settings.push_back(fields); + expected.AppendSetting(fields); } ASSERT_EQ(size, fb.size()); EXPECT_TRUE(DecodePayloadAndValidateSeveralWays(fb.buffer(), expected)); diff --git a/chromium/net/http2/decoder/payload_decoders/window_update_payload_decoder_test.cc b/chromium/net/http2/decoder/payload_decoders/window_update_payload_decoder_test.cc index e46d55bd711..4626b368e4c 100644 --- a/chromium/net/http2/decoder/payload_decoders/window_update_payload_decoder_test.cc +++ b/chromium/net/http2/decoder/payload_decoders/window_update_payload_decoder_test.cc @@ -86,7 +86,7 @@ TEST_F(WindowUpdatePayloadDecoderTest, VariousPayloads) { RandFlags(), stream_id); set_frame_header(header); FrameParts expected(header); - expected.opt_window_update_increment = fields.window_size_increment; + expected.SetOptWindowUpdateIncrement(fields.window_size_increment); EXPECT_TRUE(DecodePayloadAndValidateSeveralWays(fb.buffer(), expected)); } } diff --git a/chromium/net/http2/hpack/decoder/hpack_block_collector.cc b/chromium/net/http2/hpack/decoder/hpack_block_collector.cc index 4e433e0efda..2bb90b72d0e 100644 --- a/chromium/net/http2/hpack/decoder/hpack_block_collector.cc +++ b/chromium/net/http2/hpack/decoder/hpack_block_collector.cc @@ -17,10 +17,10 @@ using ::testing::AssertionSuccess; namespace net { namespace test { -HpackBlockCollector::HpackBlockCollector() {} +HpackBlockCollector::HpackBlockCollector() = default; HpackBlockCollector::HpackBlockCollector(const HpackBlockCollector& other) : pending_entry_(other.pending_entry_), entries_(other.entries_) {} -HpackBlockCollector::~HpackBlockCollector() {} +HpackBlockCollector::~HpackBlockCollector() = default; void HpackBlockCollector::OnIndexedHeader(size_t index) { pending_entry_.OnIndexedHeader(index); diff --git a/chromium/net/http2/hpack/decoder/hpack_decoder.cc b/chromium/net/http2/hpack/decoder/hpack_decoder.cc index 91a0f03bc35..c3ce24131f8 100644 --- a/chromium/net/http2/hpack/decoder/hpack_decoder.cc +++ b/chromium/net/http2/hpack/decoder/hpack_decoder.cc @@ -17,7 +17,7 @@ HpackDecoder::HpackDecoder(HpackDecoderListener* listener, block_decoder_(&entry_buffer_), error_detected_(false) {} -HpackDecoder::~HpackDecoder() {} +HpackDecoder::~HpackDecoder() = default; void HpackDecoder::set_tables_debug_listener( HpackDecoderTablesDebugListener* debug_listener) { diff --git a/chromium/net/http2/hpack/decoder/hpack_decoder_listener.cc b/chromium/net/http2/hpack/decoder/hpack_decoder_listener.cc index 8f0e0a01511..f85b9033e35 100644 --- a/chromium/net/http2/hpack/decoder/hpack_decoder_listener.cc +++ b/chromium/net/http2/hpack/decoder/hpack_decoder_listener.cc @@ -6,11 +6,11 @@ namespace net { -HpackDecoderListener::HpackDecoderListener() {} -HpackDecoderListener::~HpackDecoderListener() {} +HpackDecoderListener::HpackDecoderListener() = default; +HpackDecoderListener::~HpackDecoderListener() = default; -HpackDecoderNoOpListener::HpackDecoderNoOpListener() {} -HpackDecoderNoOpListener::~HpackDecoderNoOpListener() {} +HpackDecoderNoOpListener::HpackDecoderNoOpListener() = default; +HpackDecoderNoOpListener::~HpackDecoderNoOpListener() = default; void HpackDecoderNoOpListener::OnHeaderListStart() {} void HpackDecoderNoOpListener::OnHeader(HpackEntryType entry_type, diff --git a/chromium/net/http2/hpack/decoder/hpack_decoder_state.cc b/chromium/net/http2/hpack/decoder/hpack_decoder_state.cc index 0e399946a68..60e7207444a 100644 --- a/chromium/net/http2/hpack/decoder/hpack_decoder_state.cc +++ b/chromium/net/http2/hpack/decoder/hpack_decoder_state.cc @@ -33,7 +33,7 @@ HpackDecoderState::HpackDecoderState(HpackDecoderListener* listener) error_detected_(false) { CHECK(listener); } -HpackDecoderState::~HpackDecoderState() {} +HpackDecoderState::~HpackDecoderState() = default; void HpackDecoderState::set_tables_debug_listener( HpackDecoderTablesDebugListener* debug_listener) { diff --git a/chromium/net/http2/hpack/decoder/hpack_decoder_state_test.cc b/chromium/net/http2/hpack/decoder/hpack_decoder_state_test.cc index 3674db03bff..22a8179e848 100644 --- a/chromium/net/http2/hpack/decoder/hpack_decoder_state_test.cc +++ b/chromium/net/http2/hpack/decoder/hpack_decoder_state_test.cc @@ -11,6 +11,7 @@ #include "base/logging.h" #include "net/http2/hpack/hpack_string.h" +#include "net/http2/hpack/http2_hpack_constants.h" #include "net/http2/http2_constants.h" #include "net/http2/platform/api/http2_string.h" #include "net/http2/tools/failure.h" diff --git a/chromium/net/http2/hpack/decoder/hpack_decoder_string_buffer.cc b/chromium/net/http2/hpack/decoder/hpack_decoder_string_buffer.cc index 3e4451c2948..563b7bdac06 100644 --- a/chromium/net/http2/hpack/decoder/hpack_decoder_string_buffer.cc +++ b/chromium/net/http2/hpack/decoder/hpack_decoder_string_buffer.cc @@ -53,7 +53,7 @@ HpackDecoderStringBuffer::HpackDecoderStringBuffer() is_huffman_encoded_(false), state_(State::RESET), backing_(Backing::RESET) {} -HpackDecoderStringBuffer::~HpackDecoderStringBuffer() {} +HpackDecoderStringBuffer::~HpackDecoderStringBuffer() = default; void HpackDecoderStringBuffer::Reset() { DVLOG(3) << "HpackDecoderStringBuffer::Reset"; @@ -168,7 +168,7 @@ void HpackDecoderStringBuffer::BufferStringIfUnbuffered() { if (state_ != State::RESET && backing_ == Backing::UNBUFFERED) { DVLOG(2) << "HpackDecoderStringBuffer buffering string of length " << value_.size(); - value_.CopyToString(&buffer_); + buffer_.assign(value_.data(), value_.size()); if (state_ == State::COMPLETE) { value_ = buffer_; } diff --git a/chromium/net/http2/hpack/decoder/hpack_decoder_tables.cc b/chromium/net/http2/hpack/decoder/hpack_decoder_tables.cc index 61e7970b32b..4ff2b06a5c0 100644 --- a/chromium/net/http2/hpack/decoder/hpack_decoder_tables.cc +++ b/chromium/net/http2/hpack/decoder/hpack_decoder_tables.cc @@ -5,6 +5,7 @@ #include "net/http2/hpack/decoder/hpack_decoder_tables.h" #include "base/logging.h" +#include "net/http2/hpack/http2_hpack_constants.h" namespace net { namespace { @@ -33,8 +34,8 @@ const std::vector<HpackStringPair>* GetStaticTable() { } // namespace -HpackDecoderTablesDebugListener::HpackDecoderTablesDebugListener() {} -HpackDecoderTablesDebugListener::~HpackDecoderTablesDebugListener() {} +HpackDecoderTablesDebugListener::HpackDecoderTablesDebugListener() = default; +HpackDecoderTablesDebugListener::~HpackDecoderTablesDebugListener() = default; HpackDecoderStaticTable::HpackDecoderStaticTable( const std::vector<HpackStringPair>* table) @@ -56,7 +57,7 @@ HpackDecoderDynamicTable::HpackDecoderTableEntry::HpackDecoderTableEntry( HpackDecoderDynamicTable::HpackDecoderDynamicTable() : insert_count_(kFirstDynamicTableIndex - 1), debug_listener_(nullptr) {} -HpackDecoderDynamicTable::~HpackDecoderDynamicTable() {} +HpackDecoderDynamicTable::~HpackDecoderDynamicTable() = default; void HpackDecoderDynamicTable::DynamicTableSizeUpdate(size_t size_limit) { DVLOG(3) << "HpackDecoderDynamicTable::DynamicTableSizeUpdate " << size_limit; @@ -133,8 +134,8 @@ void HpackDecoderDynamicTable::RemoveLastEntry() { } } -HpackDecoderTables::HpackDecoderTables() {} -HpackDecoderTables::~HpackDecoderTables() {} +HpackDecoderTables::HpackDecoderTables() = default; +HpackDecoderTables::~HpackDecoderTables() = default; void HpackDecoderTables::set_debug_listener( HpackDecoderTablesDebugListener* debug_listener) { diff --git a/chromium/net/http2/hpack/decoder/hpack_decoder_tables.h b/chromium/net/http2/hpack/decoder/hpack_decoder_tables.h index 1de28147cf9..35c25057887 100644 --- a/chromium/net/http2/hpack/decoder/hpack_decoder_tables.h +++ b/chromium/net/http2/hpack/decoder/hpack_decoder_tables.h @@ -31,9 +31,6 @@ namespace test { class HpackDecoderTablesPeer; } // namespace test -// TODO(jamessynge): Move to hpack_constants.h -const size_t kFirstDynamicTableIndex = 62; - // HpackDecoderTablesDebugListener supports a QUIC experiment, enabling // the gathering of information about the time-line of use of HPACK // dynamic table entries. diff --git a/chromium/net/http2/hpack/decoder/hpack_decoder_tables_test.cc b/chromium/net/http2/hpack/decoder/hpack_decoder_tables_test.cc index e9e6c545938..8e47aba8307 100644 --- a/chromium/net/http2/hpack/decoder/hpack_decoder_tables_test.cc +++ b/chromium/net/http2/hpack/decoder/hpack_decoder_tables_test.cc @@ -9,6 +9,7 @@ #include <vector> #include "base/logging.h" +#include "net/http2/hpack/http2_hpack_constants.h" #include "net/http2/platform/api/http2_string.h" #include "net/http2/tools/failure.h" #include "net/http2/tools/http2_random.h" @@ -56,7 +57,7 @@ void ShuffleCollection(C* collection, RandomBase* r) { class HpackDecoderStaticTableTest : public ::testing::Test { protected: - HpackDecoderStaticTableTest() {} + HpackDecoderStaticTableTest() = default; std::vector<StaticEntry> shuffled_static_entries() { std::vector<StaticEntry> entries = MakeSpecStaticEntries(); diff --git a/chromium/net/http2/hpack/decoder/hpack_decoder_test.cc b/chromium/net/http2/hpack/decoder/hpack_decoder_test.cc index 61e05ab426f..7a89e82106e 100644 --- a/chromium/net/http2/hpack/decoder/hpack_decoder_test.cc +++ b/chromium/net/http2/hpack/decoder/hpack_decoder_test.cc @@ -83,7 +83,7 @@ class HpackDecoderTest : public ::testing::TestWithParam<bool>, HpackDecoderTest() : decoder_(this, 4096) { fragment_the_hpack_block_ = GetParam(); } - ~HpackDecoderTest() override {} + ~HpackDecoderTest() override = default; void OnHeaderListStart() override { ASSERT_FALSE(saw_start_); diff --git a/chromium/net/http2/hpack/decoder/hpack_entry_collector.cc b/chromium/net/http2/hpack/decoder/hpack_entry_collector.cc index d4d39d4caef..0ea55dcff45 100644 --- a/chromium/net/http2/hpack/decoder/hpack_entry_collector.cc +++ b/chromium/net/http2/hpack/decoder/hpack_entry_collector.cc @@ -60,7 +60,7 @@ HpackEntryCollector::HpackEntryCollector(HpackEntryType type, started_(true), ended_(true) {} -HpackEntryCollector::~HpackEntryCollector() {} +HpackEntryCollector::~HpackEntryCollector() = default; void HpackEntryCollector::OnIndexedHeader(size_t index) { ASSERT_FALSE(started_); diff --git a/chromium/net/http2/hpack/decoder/hpack_whole_entry_buffer.cc b/chromium/net/http2/hpack/decoder/hpack_whole_entry_buffer.cc index 713155153d1..4799a6c8fc7 100644 --- a/chromium/net/http2/hpack/decoder/hpack_whole_entry_buffer.cc +++ b/chromium/net/http2/hpack/decoder/hpack_whole_entry_buffer.cc @@ -15,7 +15,7 @@ HpackWholeEntryBuffer::HpackWholeEntryBuffer(HpackWholeEntryListener* listener, : max_string_size_bytes_(max_string_size_bytes) { set_listener(listener); } -HpackWholeEntryBuffer::~HpackWholeEntryBuffer() {} +HpackWholeEntryBuffer::~HpackWholeEntryBuffer() = default; void HpackWholeEntryBuffer::set_listener(HpackWholeEntryListener* listener) { CHECK(listener); diff --git a/chromium/net/http2/hpack/decoder/hpack_whole_entry_buffer_test.cc b/chromium/net/http2/hpack/decoder/hpack_whole_entry_buffer_test.cc index b7260e296c1..6626bc8c867 100644 --- a/chromium/net/http2/hpack/decoder/hpack_whole_entry_buffer_test.cc +++ b/chromium/net/http2/hpack/decoder/hpack_whole_entry_buffer_test.cc @@ -37,7 +37,7 @@ inline ::testing::PolymorphicMatcher<StringPieceHasSubstrMatcher> HasSubstr( class MockHpackWholeEntryListener : public HpackWholeEntryListener { public: - ~MockHpackWholeEntryListener() override {} + ~MockHpackWholeEntryListener() override = default; MOCK_METHOD1(OnIndexedHeader, void(size_t index)); MOCK_METHOD3(OnNameIndexAndLiteralValue, @@ -55,7 +55,7 @@ class MockHpackWholeEntryListener : public HpackWholeEntryListener { class HpackWholeEntryBufferTest : public ::testing::Test { protected: HpackWholeEntryBufferTest() : entry_buffer_(&listener_, kMaxStringSize) {} - ~HpackWholeEntryBufferTest() override {} + ~HpackWholeEntryBufferTest() override = default; StrictMock<MockHpackWholeEntryListener> listener_; HpackWholeEntryBuffer entry_buffer_; diff --git a/chromium/net/http2/hpack/decoder/hpack_whole_entry_listener.cc b/chromium/net/http2/hpack/decoder/hpack_whole_entry_listener.cc index ed18ff1f179..419c3356e8b 100644 --- a/chromium/net/http2/hpack/decoder/hpack_whole_entry_listener.cc +++ b/chromium/net/http2/hpack/decoder/hpack_whole_entry_listener.cc @@ -6,9 +6,9 @@ namespace net { -HpackWholeEntryListener::~HpackWholeEntryListener() {} +HpackWholeEntryListener::~HpackWholeEntryListener() = default; -HpackWholeEntryNoOpListener::~HpackWholeEntryNoOpListener() {} +HpackWholeEntryNoOpListener::~HpackWholeEntryNoOpListener() = default; void HpackWholeEntryNoOpListener::OnIndexedHeader(size_t index) {} void HpackWholeEntryNoOpListener::OnNameIndexAndLiteralValue( diff --git a/chromium/net/http2/hpack/hpack_string.cc b/chromium/net/http2/hpack/hpack_string.cc index 4db9f48a9fb..570a6cdbd4c 100644 --- a/chromium/net/http2/hpack/hpack_string.cc +++ b/chromium/net/http2/hpack/hpack_string.cc @@ -14,8 +14,8 @@ namespace net { HpackString::HpackString(const char* data) : str_(data) {} HpackString::HpackString(Http2StringPiece str) : str_(str.as_string()) {} HpackString::HpackString(Http2String str) : str_(std::move(str)) {} -HpackString::HpackString(const HpackString& other) : str_(other.str_) {} -HpackString::~HpackString() {} +HpackString::HpackString(const HpackString& other) = default; +HpackString::~HpackString() = default; Http2StringPiece HpackString::ToStringPiece() const { return str_; diff --git a/chromium/net/http2/hpack/http2_hpack_constants.h b/chromium/net/http2/hpack/http2_hpack_constants.h index a2a29e32e2b..38d5812ff94 100644 --- a/chromium/net/http2/hpack/http2_hpack_constants.h +++ b/chromium/net/http2/hpack/http2_hpack_constants.h @@ -17,6 +17,8 @@ namespace net { +const size_t kFirstDynamicTableIndex = 62; + enum class HpackEntryType { // Entry is an index into the static or dynamic table. Decoding it has no // effect on the dynamic table. @@ -55,7 +57,6 @@ HTTP2_EXPORT_PRIVATE Http2String HpackEntryTypeToString(HpackEntryType v); // Inserts the name of the enum member into |out|. HTTP2_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& out, HpackEntryType v); - } // namespace net #endif // NET_HTTP2_HPACK_HTTP2_HPACK_CONSTANTS_H_ diff --git a/chromium/net/http2/hpack/huffman/hpack_huffman_decoder.cc b/chromium/net/http2/hpack/huffman/hpack_huffman_decoder.cc index 3621ca13ca9..68246fd4e07 100644 --- a/chromium/net/http2/hpack/huffman/hpack_huffman_decoder.cc +++ b/chromium/net/http2/hpack/huffman/hpack_huffman_decoder.cc @@ -410,9 +410,9 @@ Http2String HuffmanBitBuffer::DebugString() const { return ss.str(); } -HpackHuffmanDecoder::HpackHuffmanDecoder() {} +HpackHuffmanDecoder::HpackHuffmanDecoder() = default; -HpackHuffmanDecoder::~HpackHuffmanDecoder() {} +HpackHuffmanDecoder::~HpackHuffmanDecoder() = default; bool HpackHuffmanDecoder::Decode(Http2StringPiece input, Http2String* output) { return DecodeShortCodesFirst(input, output); diff --git a/chromium/net/http2/test_tools/frame_parts.cc b/chromium/net/http2/test_tools/frame_parts.cc index db0ee356b42..95b84664ecd 100644 --- a/chromium/net/http2/test_tools/frame_parts.cc +++ b/chromium/net/http2/test_tools/frame_parts.cc @@ -46,15 +46,15 @@ AssertionResult VerifyOptionalEq(const T& opt_a, const T& opt_b) { } // namespace -FrameParts::FrameParts(const Http2FrameHeader& header) : frame_header(header) { - VLOG(1) << "FrameParts, header: " << frame_header; +FrameParts::FrameParts(const Http2FrameHeader& header) : frame_header_(header) { + VLOG(1) << "FrameParts, header: " << frame_header_; } FrameParts::FrameParts(const Http2FrameHeader& header, Http2StringPiece payload) : FrameParts(header) { VLOG(1) << "FrameParts with payload.size() = " << payload.size(); - this->payload.append(payload.data(), payload.size()); - opt_payload_length = payload.size(); + this->payload_.append(payload.data(), payload.size()); + opt_payload_length_ = payload.size(); } FrameParts::FrameParts(const Http2FrameHeader& header, Http2StringPiece payload, @@ -66,31 +66,31 @@ FrameParts::FrameParts(const Http2FrameHeader& header, FrameParts::FrameParts(const FrameParts& header) = default; -FrameParts::~FrameParts() {} +FrameParts::~FrameParts() = default; AssertionResult FrameParts::VerifyEquals(const FrameParts& that) const { #define COMMON_MESSAGE "\n this: " << *this << "\n that: " << that - VERIFY_EQ(frame_header, that.frame_header) << COMMON_MESSAGE; - VERIFY_EQ(payload, that.payload) << COMMON_MESSAGE; - VERIFY_EQ(padding, that.padding) << COMMON_MESSAGE; - VERIFY_EQ(altsvc_origin, that.altsvc_origin) << COMMON_MESSAGE; - VERIFY_EQ(altsvc_value, that.altsvc_value) << COMMON_MESSAGE; - VERIFY_EQ(settings, that.settings) << COMMON_MESSAGE; + VERIFY_EQ(frame_header_, that.frame_header_) << COMMON_MESSAGE; + VERIFY_EQ(payload_, that.payload_) << COMMON_MESSAGE; + VERIFY_EQ(padding_, that.padding_) << COMMON_MESSAGE; + VERIFY_EQ(altsvc_origin_, that.altsvc_origin_) << COMMON_MESSAGE; + VERIFY_EQ(altsvc_value_, that.altsvc_value_) << COMMON_MESSAGE; + VERIFY_EQ(settings_, that.settings_) << COMMON_MESSAGE; #define VERIFY_OPTIONAL_FIELD(field_name) \ VERIFY_SUCCESS(VerifyOptionalEq(field_name, that.field_name)) - VERIFY_OPTIONAL_FIELD(opt_altsvc_origin_length) << COMMON_MESSAGE; - VERIFY_OPTIONAL_FIELD(opt_altsvc_value_length) << COMMON_MESSAGE; - VERIFY_OPTIONAL_FIELD(opt_goaway) << COMMON_MESSAGE; - VERIFY_OPTIONAL_FIELD(opt_missing_length) << COMMON_MESSAGE; - VERIFY_OPTIONAL_FIELD(opt_pad_length) << COMMON_MESSAGE; - VERIFY_OPTIONAL_FIELD(opt_ping) << COMMON_MESSAGE; - VERIFY_OPTIONAL_FIELD(opt_priority) << COMMON_MESSAGE; - VERIFY_OPTIONAL_FIELD(opt_push_promise) << COMMON_MESSAGE; - VERIFY_OPTIONAL_FIELD(opt_rst_stream_error_code) << COMMON_MESSAGE; - VERIFY_OPTIONAL_FIELD(opt_window_update_increment) << COMMON_MESSAGE; + VERIFY_OPTIONAL_FIELD(opt_altsvc_origin_length_) << COMMON_MESSAGE; + VERIFY_OPTIONAL_FIELD(opt_altsvc_value_length_) << COMMON_MESSAGE; + VERIFY_OPTIONAL_FIELD(opt_goaway_) << COMMON_MESSAGE; + VERIFY_OPTIONAL_FIELD(opt_missing_length_) << COMMON_MESSAGE; + VERIFY_OPTIONAL_FIELD(opt_pad_length_) << COMMON_MESSAGE; + VERIFY_OPTIONAL_FIELD(opt_ping_) << COMMON_MESSAGE; + VERIFY_OPTIONAL_FIELD(opt_priority_) << COMMON_MESSAGE; + VERIFY_OPTIONAL_FIELD(opt_push_promise_) << COMMON_MESSAGE; + VERIFY_OPTIONAL_FIELD(opt_rst_stream_error_code_) << COMMON_MESSAGE; + VERIFY_OPTIONAL_FIELD(opt_window_update_increment_) << COMMON_MESSAGE; #undef VERIFY_OPTIONAL_FIELD @@ -98,18 +98,18 @@ AssertionResult FrameParts::VerifyEquals(const FrameParts& that) const { } void FrameParts::SetTotalPadLength(size_t total_pad_length) { - opt_pad_length.reset(); - padding.clear(); + opt_pad_length_.reset(); + padding_.clear(); if (total_pad_length > 0) { ASSERT_LE(total_pad_length, 256u); - ASSERT_TRUE(frame_header.IsPadded()); - opt_pad_length = total_pad_length - 1; + ASSERT_TRUE(frame_header_.IsPadded()); + opt_pad_length_ = total_pad_length - 1; char zero = 0; - padding.append(opt_pad_length.value(), zero); + padding_.append(opt_pad_length_.value(), zero); } - if (opt_pad_length) { - VLOG(1) << "SetTotalPadLength: pad_length=" << opt_pad_length.value(); + if (opt_pad_length_) { + VLOG(1) << "SetTotalPadLength: pad_length=" << opt_pad_length_.value(); } else { VLOG(1) << "SetTotalPadLength: has no pad length"; } @@ -117,10 +117,10 @@ void FrameParts::SetTotalPadLength(size_t total_pad_length) { void FrameParts::SetAltSvcExpected(Http2StringPiece origin, Http2StringPiece value) { - altsvc_origin.append(origin.data(), origin.size()); - altsvc_value.append(value.data(), value.size()); - opt_altsvc_origin_length = origin.size(); - opt_altsvc_value_length = value.size(); + altsvc_origin_.append(origin.data(), origin.size()); + altsvc_value_.append(value.data(), value.size()); + opt_altsvc_origin_length_ = origin.size(); + opt_altsvc_value_length_ = value.size(); } bool FrameParts::OnFrameHeader(const Http2FrameHeader& header) { @@ -131,50 +131,51 @@ bool FrameParts::OnFrameHeader(const Http2FrameHeader& header) { void FrameParts::OnDataStart(const Http2FrameHeader& header) { VLOG(1) << "OnDataStart: " << header; ASSERT_TRUE(StartFrameOfType(header, Http2FrameType::DATA)) << *this; - opt_payload_length = header.payload_length; + opt_payload_length_ = header.payload_length; } void FrameParts::OnDataPayload(const char* data, size_t len) { - VLOG(1) << "OnDataPayload: len=" << len << "; frame_header: " << frame_header; + VLOG(1) << "OnDataPayload: len=" << len + << "; frame_header_: " << frame_header_; ASSERT_TRUE(InFrameOfType(Http2FrameType::DATA)) << *this; - ASSERT_TRUE( - AppendString(Http2StringPiece(data, len), &payload, &opt_payload_length)); + ASSERT_TRUE(AppendString(Http2StringPiece(data, len), &payload_, + &opt_payload_length_)); } void FrameParts::OnDataEnd() { - VLOG(1) << "OnDataEnd; frame_header: " << frame_header; + VLOG(1) << "OnDataEnd; frame_header_: " << frame_header_; ASSERT_TRUE(EndFrameOfType(Http2FrameType::DATA)) << *this; } void FrameParts::OnHeadersStart(const Http2FrameHeader& header) { VLOG(1) << "OnHeadersStart: " << header; ASSERT_TRUE(StartFrameOfType(header, Http2FrameType::HEADERS)) << *this; - opt_payload_length = header.payload_length; + opt_payload_length_ = header.payload_length; } void FrameParts::OnHeadersPriority(const Http2PriorityFields& priority) { VLOG(1) << "OnHeadersPriority: priority: " << priority - << "; frame_header: " << frame_header; + << "; frame_header_: " << frame_header_; ASSERT_TRUE(InFrameOfType(Http2FrameType::HEADERS)) << *this; - ASSERT_FALSE(opt_priority); - opt_priority = priority; - ASSERT_TRUE(opt_payload_length); - opt_payload_length = - opt_payload_length.value() - Http2PriorityFields::EncodedSize(); + ASSERT_FALSE(opt_priority_); + opt_priority_ = priority; + ASSERT_TRUE(opt_payload_length_); + opt_payload_length_ = + opt_payload_length_.value() - Http2PriorityFields::EncodedSize(); } void FrameParts::OnHpackFragment(const char* data, size_t len) { VLOG(1) << "OnHpackFragment: len=" << len - << "; frame_header: " << frame_header; - ASSERT_TRUE(got_start_callback); - ASSERT_FALSE(got_end_callback); - ASSERT_TRUE(FrameCanHaveHpackPayload(frame_header)) << *this; - ASSERT_TRUE( - AppendString(Http2StringPiece(data, len), &payload, &opt_payload_length)); + << "; frame_header_: " << frame_header_; + ASSERT_TRUE(got_start_callback_); + ASSERT_FALSE(got_end_callback_); + ASSERT_TRUE(FrameCanHaveHpackPayload(frame_header_)) << *this; + ASSERT_TRUE(AppendString(Http2StringPiece(data, len), &payload_, + &opt_payload_length_)); } void FrameParts::OnHeadersEnd() { - VLOG(1) << "OnHeadersEnd; frame_header: " << frame_header; + VLOG(1) << "OnHeadersEnd; frame_header_: " << frame_header_; ASSERT_TRUE(EndFrameOfType(Http2FrameType::HEADERS)) << *this; } @@ -182,72 +183,72 @@ void FrameParts::OnPriorityFrame(const Http2FrameHeader& header, const Http2PriorityFields& priority) { VLOG(1) << "OnPriorityFrame: " << header << "; priority: " << priority; ASSERT_TRUE(StartFrameOfType(header, Http2FrameType::PRIORITY)) << *this; - ASSERT_FALSE(opt_priority); - opt_priority = priority; + ASSERT_FALSE(opt_priority_); + opt_priority_ = priority; ASSERT_TRUE(EndFrameOfType(Http2FrameType::PRIORITY)) << *this; } void FrameParts::OnContinuationStart(const Http2FrameHeader& header) { VLOG(1) << "OnContinuationStart: " << header; ASSERT_TRUE(StartFrameOfType(header, Http2FrameType::CONTINUATION)) << *this; - opt_payload_length = header.payload_length; + opt_payload_length_ = header.payload_length; } void FrameParts::OnContinuationEnd() { - VLOG(1) << "OnContinuationEnd; frame_header: " << frame_header; + VLOG(1) << "OnContinuationEnd; frame_header_: " << frame_header_; ASSERT_TRUE(EndFrameOfType(Http2FrameType::CONTINUATION)) << *this; } void FrameParts::OnPadLength(size_t trailing_length) { VLOG(1) << "OnPadLength: trailing_length=" << trailing_length; ASSERT_TRUE(InPaddedFrame()) << *this; - ASSERT_FALSE(opt_pad_length); - ASSERT_TRUE(opt_payload_length); + ASSERT_FALSE(opt_pad_length_); + ASSERT_TRUE(opt_payload_length_); size_t total_padding_length = trailing_length + 1; - ASSERT_GE(opt_payload_length.value(), total_padding_length); - opt_payload_length = opt_payload_length.value() - total_padding_length; - opt_pad_length = trailing_length; + ASSERT_GE(opt_payload_length_.value(), total_padding_length); + opt_payload_length_ = opt_payload_length_.value() - total_padding_length; + opt_pad_length_ = trailing_length; } void FrameParts::OnPadding(const char* pad, size_t skipped_length) { VLOG(1) << "OnPadding: skipped_length=" << skipped_length; ASSERT_TRUE(InPaddedFrame()) << *this; - ASSERT_TRUE(opt_pad_length); - ASSERT_TRUE(AppendString(Http2StringPiece(pad, skipped_length), &padding, - &opt_pad_length)); + ASSERT_TRUE(opt_pad_length_); + ASSERT_TRUE(AppendString(Http2StringPiece(pad, skipped_length), &padding_, + &opt_pad_length_)); } void FrameParts::OnRstStream(const Http2FrameHeader& header, Http2ErrorCode error_code) { VLOG(1) << "OnRstStream: " << header << "; code=" << error_code; ASSERT_TRUE(StartFrameOfType(header, Http2FrameType::RST_STREAM)) << *this; - ASSERT_FALSE(opt_rst_stream_error_code); - opt_rst_stream_error_code = error_code; + ASSERT_FALSE(opt_rst_stream_error_code_); + opt_rst_stream_error_code_ = error_code; ASSERT_TRUE(EndFrameOfType(Http2FrameType::RST_STREAM)) << *this; } void FrameParts::OnSettingsStart(const Http2FrameHeader& header) { VLOG(1) << "OnSettingsStart: " << header; ASSERT_TRUE(StartFrameOfType(header, Http2FrameType::SETTINGS)) << *this; - ASSERT_EQ(0u, settings.size()); + ASSERT_EQ(0u, settings_.size()); ASSERT_FALSE(header.IsAck()) << header; } void FrameParts::OnSetting(const Http2SettingFields& setting_fields) { VLOG(1) << "OnSetting: " << setting_fields; ASSERT_TRUE(InFrameOfType(Http2FrameType::SETTINGS)) << *this; - settings.push_back(setting_fields); + settings_.push_back(setting_fields); } void FrameParts::OnSettingsEnd() { - VLOG(1) << "OnSettingsEnd; frame_header: " << frame_header; + VLOG(1) << "OnSettingsEnd; frame_header_: " << frame_header_; ASSERT_TRUE(EndFrameOfType(Http2FrameType::SETTINGS)) << *this; } void FrameParts::OnSettingsAck(const Http2FrameHeader& header) { VLOG(1) << "OnSettingsAck: " << header; ASSERT_TRUE(StartFrameOfType(header, Http2FrameType::SETTINGS)) << *this; - ASSERT_EQ(0u, settings.size()); + ASSERT_EQ(0u, settings_.size()); ASSERT_TRUE(header.IsAck()); ASSERT_TRUE(EndFrameOfType(Http2FrameType::SETTINGS)) << *this; } @@ -259,12 +260,12 @@ void FrameParts::OnPushPromiseStart(const Http2FrameHeader& header, << "; total_padding_length: " << total_padding_length; ASSERT_TRUE(StartFrameOfType(header, Http2FrameType::PUSH_PROMISE)) << *this; ASSERT_GE(header.payload_length, Http2PushPromiseFields::EncodedSize()); - opt_payload_length = + opt_payload_length_ = header.payload_length - Http2PushPromiseFields::EncodedSize(); - ASSERT_FALSE(opt_push_promise); - opt_push_promise = promise; + ASSERT_FALSE(opt_push_promise_); + opt_push_promise_ = promise; if (total_padding_length > 0) { - ASSERT_GE(opt_payload_length.value(), total_padding_length); + ASSERT_GE(opt_payload_length_.value(), total_padding_length); OnPadLength(total_padding_length - 1); } else { ASSERT_FALSE(header.IsPadded()); @@ -272,7 +273,7 @@ void FrameParts::OnPushPromiseStart(const Http2FrameHeader& header, } void FrameParts::OnPushPromiseEnd() { - VLOG(1) << "OnPushPromiseEnd; frame_header: " << frame_header; + VLOG(1) << "OnPushPromiseEnd; frame_header_: " << frame_header_; ASSERT_TRUE(EndFrameOfType(Http2FrameType::PUSH_PROMISE)) << *this; } @@ -281,8 +282,8 @@ void FrameParts::OnPing(const Http2FrameHeader& header, VLOG(1) << "OnPing header: " << header << " ping: " << ping; ASSERT_TRUE(StartFrameOfType(header, Http2FrameType::PING)) << *this; ASSERT_FALSE(header.IsAck()); - ASSERT_FALSE(opt_ping); - opt_ping = ping; + ASSERT_FALSE(opt_ping_); + opt_ping_ = ping; ASSERT_TRUE(EndFrameOfType(Http2FrameType::PING)) << *this; } @@ -291,8 +292,8 @@ void FrameParts::OnPingAck(const Http2FrameHeader& header, VLOG(1) << "OnPingAck header: " << header << " ping: " << ping; ASSERT_TRUE(StartFrameOfType(header, Http2FrameType::PING)) << *this; ASSERT_TRUE(header.IsAck()); - ASSERT_FALSE(opt_ping); - opt_ping = ping; + ASSERT_FALSE(opt_ping_); + opt_ping_ = ping; ASSERT_TRUE(EndFrameOfType(Http2FrameType::PING)) << *this; } @@ -300,20 +301,21 @@ void FrameParts::OnGoAwayStart(const Http2FrameHeader& header, const Http2GoAwayFields& goaway) { VLOG(1) << "OnGoAwayStart: " << goaway; ASSERT_TRUE(StartFrameOfType(header, Http2FrameType::GOAWAY)) << *this; - ASSERT_FALSE(opt_goaway); - opt_goaway = goaway; - opt_payload_length = header.payload_length - Http2GoAwayFields::EncodedSize(); + ASSERT_FALSE(opt_goaway_); + opt_goaway_ = goaway; + opt_payload_length_ = + header.payload_length - Http2GoAwayFields::EncodedSize(); } void FrameParts::OnGoAwayOpaqueData(const char* data, size_t len) { VLOG(1) << "OnGoAwayOpaqueData: len=" << len; ASSERT_TRUE(InFrameOfType(Http2FrameType::GOAWAY)) << *this; - ASSERT_TRUE( - AppendString(Http2StringPiece(data, len), &payload, &opt_payload_length)); + ASSERT_TRUE(AppendString(Http2StringPiece(data, len), &payload_, + &opt_payload_length_)); } void FrameParts::OnGoAwayEnd() { - VLOG(1) << "OnGoAwayEnd; frame_header: " << frame_header; + VLOG(1) << "OnGoAwayEnd; frame_header_: " << frame_header_; ASSERT_TRUE(EndFrameOfType(Http2FrameType::GOAWAY)) << *this; } @@ -322,8 +324,8 @@ void FrameParts::OnWindowUpdate(const Http2FrameHeader& header, VLOG(1) << "OnWindowUpdate header: " << header << " increment=" << increment; ASSERT_TRUE(StartFrameOfType(header, Http2FrameType::WINDOW_UPDATE)) << *this; - ASSERT_FALSE(opt_window_update_increment); - opt_window_update_increment = increment; + ASSERT_FALSE(opt_window_update_increment_); + opt_window_update_increment_ = increment; ASSERT_TRUE(EndFrameOfType(Http2FrameType::WINDOW_UPDATE)) << *this; } @@ -334,140 +336,140 @@ void FrameParts::OnAltSvcStart(const Http2FrameHeader& header, << " origin_length: " << origin_length << " value_length: " << value_length; ASSERT_TRUE(StartFrameOfType(header, Http2FrameType::ALTSVC)) << *this; - ASSERT_FALSE(opt_altsvc_origin_length); - opt_altsvc_origin_length = origin_length; - ASSERT_FALSE(opt_altsvc_value_length); - opt_altsvc_value_length = value_length; + ASSERT_FALSE(opt_altsvc_origin_length_); + opt_altsvc_origin_length_ = origin_length; + ASSERT_FALSE(opt_altsvc_value_length_); + opt_altsvc_value_length_ = value_length; } void FrameParts::OnAltSvcOriginData(const char* data, size_t len) { VLOG(1) << "OnAltSvcOriginData: len=" << len; ASSERT_TRUE(InFrameOfType(Http2FrameType::ALTSVC)) << *this; - ASSERT_TRUE(AppendString(Http2StringPiece(data, len), &altsvc_origin, - &opt_altsvc_origin_length)); + ASSERT_TRUE(AppendString(Http2StringPiece(data, len), &altsvc_origin_, + &opt_altsvc_origin_length_)); } void FrameParts::OnAltSvcValueData(const char* data, size_t len) { VLOG(1) << "OnAltSvcValueData: len=" << len; ASSERT_TRUE(InFrameOfType(Http2FrameType::ALTSVC)) << *this; - ASSERT_TRUE(AppendString(Http2StringPiece(data, len), &altsvc_value, - &opt_altsvc_value_length)); + ASSERT_TRUE(AppendString(Http2StringPiece(data, len), &altsvc_value_, + &opt_altsvc_value_length_)); } void FrameParts::OnAltSvcEnd() { - VLOG(1) << "OnAltSvcEnd; frame_header: " << frame_header; + VLOG(1) << "OnAltSvcEnd; frame_header_: " << frame_header_; ASSERT_TRUE(EndFrameOfType(Http2FrameType::ALTSVC)) << *this; } void FrameParts::OnUnknownStart(const Http2FrameHeader& header) { VLOG(1) << "OnUnknownStart: " << header; ASSERT_FALSE(IsSupportedHttp2FrameType(header.type)) << header; - ASSERT_FALSE(got_start_callback); - ASSERT_EQ(frame_header, header); - got_start_callback = true; - opt_payload_length = header.payload_length; + ASSERT_FALSE(got_start_callback_); + ASSERT_EQ(frame_header_, header); + got_start_callback_ = true; + opt_payload_length_ = header.payload_length; } void FrameParts::OnUnknownPayload(const char* data, size_t len) { VLOG(1) << "OnUnknownPayload: len=" << len; - ASSERT_FALSE(IsSupportedHttp2FrameType(frame_header.type)) << *this; - ASSERT_TRUE(got_start_callback); - ASSERT_FALSE(got_end_callback); - ASSERT_TRUE( - AppendString(Http2StringPiece(data, len), &payload, &opt_payload_length)); + ASSERT_FALSE(IsSupportedHttp2FrameType(frame_header_.type)) << *this; + ASSERT_TRUE(got_start_callback_); + ASSERT_FALSE(got_end_callback_); + ASSERT_TRUE(AppendString(Http2StringPiece(data, len), &payload_, + &opt_payload_length_)); } void FrameParts::OnUnknownEnd() { - VLOG(1) << "OnUnknownEnd; frame_header: " << frame_header; - ASSERT_FALSE(IsSupportedHttp2FrameType(frame_header.type)) << *this; - ASSERT_TRUE(got_start_callback); - ASSERT_FALSE(got_end_callback); - got_end_callback = true; + VLOG(1) << "OnUnknownEnd; frame_header_: " << frame_header_; + ASSERT_FALSE(IsSupportedHttp2FrameType(frame_header_.type)) << *this; + ASSERT_TRUE(got_start_callback_); + ASSERT_FALSE(got_end_callback_); + got_end_callback_ = true; } void FrameParts::OnPaddingTooLong(const Http2FrameHeader& header, size_t missing_length) { VLOG(1) << "OnPaddingTooLong: " << header << "; missing_length: " << missing_length; - ASSERT_EQ(frame_header, header); - ASSERT_FALSE(got_end_callback); + ASSERT_EQ(frame_header_, header); + ASSERT_FALSE(got_end_callback_); ASSERT_TRUE(FrameIsPadded(header)); - ASSERT_FALSE(opt_pad_length); - ASSERT_FALSE(opt_missing_length); - opt_missing_length = missing_length; - got_start_callback = true; - got_end_callback = true; + ASSERT_FALSE(opt_pad_length_); + ASSERT_FALSE(opt_missing_length_); + opt_missing_length_ = missing_length; + got_start_callback_ = true; + got_end_callback_ = true; } void FrameParts::OnFrameSizeError(const Http2FrameHeader& header) { VLOG(1) << "OnFrameSizeError: " << header; - ASSERT_EQ(frame_header, header); - ASSERT_FALSE(got_end_callback); - ASSERT_FALSE(has_frame_size_error); - has_frame_size_error = true; - got_end_callback = true; + ASSERT_EQ(frame_header_, header); + ASSERT_FALSE(got_end_callback_); + ASSERT_FALSE(has_frame_size_error_); + has_frame_size_error_ = true; + got_end_callback_ = true; } void FrameParts::OutputTo(std::ostream& out) const { - out << "FrameParts{\n frame_header: " << frame_header << "\n"; - if (!payload.empty()) { - out << " payload=\"" << EscapeQueryParamValue(payload, false) << "\"\n"; + out << "FrameParts{\n frame_header_: " << frame_header_ << "\n"; + if (!payload_.empty()) { + out << " payload_=\"" << EscapeQueryParamValue(payload_, false) << "\"\n"; } - if (!padding.empty()) { - out << " padding=\"" << EscapeQueryParamValue(padding, false) << "\"\n"; + if (!padding_.empty()) { + out << " padding_=\"" << EscapeQueryParamValue(padding_, false) << "\"\n"; } - if (!altsvc_origin.empty()) { - out << " altsvc_origin=\"" << EscapeQueryParamValue(altsvc_origin, false) + if (!altsvc_origin_.empty()) { + out << " altsvc_origin_=\"" << EscapeQueryParamValue(altsvc_origin_, false) << "\"\n"; } - if (!altsvc_value.empty()) { - out << " altsvc_value=\"" << EscapeQueryParamValue(altsvc_value, false) + if (!altsvc_value_.empty()) { + out << " altsvc_value_=\"" << EscapeQueryParamValue(altsvc_value_, false) << "\"\n"; } - if (opt_priority) { - out << " priority=" << opt_priority.value() << "\n"; + if (opt_priority_) { + out << " priority=" << opt_priority_.value() << "\n"; } - if (opt_rst_stream_error_code) { - out << " rst_stream=" << opt_rst_stream_error_code.value() << "\n"; + if (opt_rst_stream_error_code_) { + out << " rst_stream=" << opt_rst_stream_error_code_.value() << "\n"; } - if (opt_push_promise) { - out << " push_promise=" << opt_push_promise.value() << "\n"; + if (opt_push_promise_) { + out << " push_promise=" << opt_push_promise_.value() << "\n"; } - if (opt_ping) { - out << " ping=" << opt_ping.value() << "\n"; + if (opt_ping_) { + out << " ping=" << opt_ping_.value() << "\n"; } - if (opt_goaway) { - out << " goaway=" << opt_goaway.value() << "\n"; + if (opt_goaway_) { + out << " goaway=" << opt_goaway_.value() << "\n"; } - if (opt_window_update_increment) { - out << " window_update=" << opt_window_update_increment.value() << "\n"; + if (opt_window_update_increment_) { + out << " window_update=" << opt_window_update_increment_.value() << "\n"; } - if (opt_payload_length) { - out << " payload_length=" << opt_payload_length.value() << "\n"; + if (opt_payload_length_) { + out << " payload_length=" << opt_payload_length_.value() << "\n"; } - if (opt_pad_length) { - out << " pad_length=" << opt_pad_length.value() << "\n"; + if (opt_pad_length_) { + out << " pad_length=" << opt_pad_length_.value() << "\n"; } - if (opt_missing_length) { - out << " missing_length=" << opt_missing_length.value() << "\n"; + if (opt_missing_length_) { + out << " missing_length=" << opt_missing_length_.value() << "\n"; } - if (opt_altsvc_origin_length) { - out << " origin_length=" << opt_altsvc_origin_length.value() << "\n"; + if (opt_altsvc_origin_length_) { + out << " origin_length=" << opt_altsvc_origin_length_.value() << "\n"; } - if (opt_altsvc_value_length) { - out << " value_length=" << opt_altsvc_value_length.value() << "\n"; + if (opt_altsvc_value_length_) { + out << " value_length=" << opt_altsvc_value_length_.value() << "\n"; } - if (has_frame_size_error) { + if (has_frame_size_error_) { out << " has_frame_size_error\n"; } - if (got_start_callback) { + if (got_start_callback_) { out << " got_start_callback\n"; } - if (got_end_callback) { + if (got_end_callback_) { out << " got_end_callback\n"; } - for (size_t ndx = 0; ndx < settings.size(); ++ndx) { - out << " setting[" << ndx << "]=" << settings[ndx]; + for (size_t ndx = 0; ndx < settings_.size(); ++ndx) { + out << " setting[" << ndx << "]=" << settings_[ndx]; } out << "}"; } @@ -476,30 +478,30 @@ AssertionResult FrameParts::StartFrameOfType( const Http2FrameHeader& header, Http2FrameType expected_frame_type) { VERIFY_EQ(header.type, expected_frame_type); - VERIFY_FALSE(got_start_callback); - VERIFY_FALSE(got_end_callback); - VERIFY_EQ(frame_header, header); - got_start_callback = true; + VERIFY_FALSE(got_start_callback_); + VERIFY_FALSE(got_end_callback_); + VERIFY_EQ(frame_header_, header); + got_start_callback_ = true; return AssertionSuccess(); } AssertionResult FrameParts::InFrameOfType(Http2FrameType expected_frame_type) { - VERIFY_TRUE(got_start_callback); - VERIFY_FALSE(got_end_callback); - VERIFY_EQ(frame_header.type, expected_frame_type); + VERIFY_TRUE(got_start_callback_); + VERIFY_FALSE(got_end_callback_); + VERIFY_EQ(frame_header_.type, expected_frame_type); return AssertionSuccess(); } AssertionResult FrameParts::EndFrameOfType(Http2FrameType expected_frame_type) { VERIFY_SUCCESS(InFrameOfType(expected_frame_type)); - got_end_callback = true; + got_end_callback_ = true; return AssertionSuccess(); } AssertionResult FrameParts::InPaddedFrame() { - VERIFY_TRUE(got_start_callback); - VERIFY_FALSE(got_end_callback); - VERIFY_TRUE(FrameIsPadded(frame_header)); + VERIFY_TRUE(got_start_callback_); + VERIFY_FALSE(got_end_callback_); + VERIFY_TRUE(FrameIsPadded(frame_header_)); return AssertionSuccess(); } @@ -509,7 +511,7 @@ AssertionResult FrameParts::AppendString(Http2StringPiece source, target->append(source.data(), source.size()); if (opt_length != nullptr) { VERIFY_TRUE(*opt_length) << "Length is not set yet\n" << *this; - VERIFY_LE(target->size(), static_cast<size_t>(opt_length->value())) + VERIFY_LE(target->size(), opt_length->value()) << "String too large; source.size() = " << source.size() << "\n" << *this; } diff --git a/chromium/net/http2/test_tools/frame_parts.h b/chromium/net/http2/test_tools/frame_parts.h index 1846929b952..7ef392f7d11 100644 --- a/chromium/net/http2/test_tools/frame_parts.h +++ b/chromium/net/http2/test_tools/frame_parts.h @@ -10,9 +10,6 @@ // info that a test expects to be recorded during the decoding of a frame // with the actual recorded value (i.e. by providing a comparator). -// TODO(jamessynge): Convert FrameParts to a class, hide the members, add -// getters/setters. - #include <stddef.h> #include <vector> @@ -29,11 +26,8 @@ namespace net { namespace test { -// Forward declarations. -struct FrameParts; -std::ostream& operator<<(std::ostream& out, const FrameParts& v); - -struct FrameParts : public Http2FrameDecoderListener { +class FrameParts : public Http2FrameDecoderListener { + public: // The first callback for every type of frame includes the frame header; this // is the only constructor used during decoding of a frame. explicit FrameParts(const Http2FrameHeader& header); @@ -113,36 +107,82 @@ struct FrameParts : public Http2FrameDecoderListener { size_t missing_length) override; void OnFrameSizeError(const Http2FrameHeader& header) override; - // The fields are public for access by tests. - - const Http2FrameHeader frame_header; - - Http2String payload; - Http2String padding; - Http2String altsvc_origin; - Http2String altsvc_value; - - base::Optional<Http2PriorityFields> opt_priority; - base::Optional<Http2ErrorCode> opt_rst_stream_error_code; - base::Optional<Http2PushPromiseFields> opt_push_promise; - base::Optional<Http2PingFields> opt_ping; - base::Optional<Http2GoAwayFields> opt_goaway; - - base::Optional<size_t> opt_pad_length; - base::Optional<size_t> opt_payload_length; - base::Optional<size_t> opt_missing_length; - base::Optional<size_t> opt_altsvc_origin_length; - base::Optional<size_t> opt_altsvc_value_length; - - base::Optional<size_t> opt_window_update_increment; - - bool has_frame_size_error = false; - - std::vector<Http2SettingFields> settings; - - // These booleans are not checked by CompareCollectedFrames. - bool got_start_callback = false; - bool got_end_callback = false; + void AppendSetting(const Http2SettingFields& setting_fields) { + settings_.push_back(setting_fields); + } + + const Http2FrameHeader& GetFrameHeader() const { return frame_header_; } + + base::Optional<Http2PriorityFields> GetOptPriority() const { + return opt_priority_; + } + base::Optional<Http2ErrorCode> GetOptRstStreamErrorCode() const { + return opt_rst_stream_error_code_; + } + base::Optional<Http2PushPromiseFields> GetOptPushPromise() const { + return opt_push_promise_; + } + base::Optional<Http2PingFields> GetOptPing() const { return opt_ping_; } + base::Optional<Http2GoAwayFields> GetOptGoaway() const { return opt_goaway_; } + base::Optional<size_t> GetOptPadLength() const { return opt_pad_length_; } + base::Optional<size_t> GetOptPayloadLength() const { + return opt_payload_length_; + } + base::Optional<size_t> GetOptMissingLength() const { + return opt_missing_length_; + } + base::Optional<size_t> GetOptAltsvcOriginLength() const { + return opt_altsvc_origin_length_; + } + base::Optional<size_t> GetOptAltsvcValueLength() const { + return opt_altsvc_value_length_; + } + base::Optional<size_t> GetOptWindowUpdateIncrement() const { + return opt_window_update_increment_; + } + bool GetHasFrameSizeError() const { return has_frame_size_error_; } + + void SetOptPriority(base::Optional<Http2PriorityFields> opt_priority) { + opt_priority_ = opt_priority; + } + void SetOptRstStreamErrorCode( + base::Optional<Http2ErrorCode> opt_rst_stream_error_code) { + opt_rst_stream_error_code_ = opt_rst_stream_error_code; + } + void SetOptPushPromise( + base::Optional<Http2PushPromiseFields> opt_push_promise) { + opt_push_promise_ = opt_push_promise; + } + void SetOptPing(base::Optional<Http2PingFields> opt_ping) { + opt_ping_ = opt_ping; + } + void SetOptGoaway(base::Optional<Http2GoAwayFields> opt_goaway) { + opt_goaway_ = opt_goaway; + } + void SetOptPadLength(base::Optional<size_t> opt_pad_length) { + opt_pad_length_ = opt_pad_length; + } + void SetOptPayloadLength(base::Optional<size_t> opt_payload_length) { + opt_payload_length_ = opt_payload_length; + } + void SetOptMissingLength(base::Optional<size_t> opt_missing_length) { + opt_missing_length_ = opt_missing_length; + } + void SetOptAltsvcOriginLength( + base::Optional<size_t> opt_altsvc_origin_length) { + opt_altsvc_origin_length_ = opt_altsvc_origin_length; + } + void SetOptAltsvcValueLength(base::Optional<size_t> opt_altsvc_value_length) { + opt_altsvc_value_length_ = opt_altsvc_value_length; + } + void SetOptWindowUpdateIncrement( + base::Optional<size_t> opt_window_update_increment) { + opt_window_update_increment_ = opt_window_update_increment; + } + + void SetHasFrameSizeError(bool has_frame_size_error) { + has_frame_size_error_ = has_frame_size_error; + } private: // ASSERT during an On* method that we're handling a frame of type @@ -169,8 +209,39 @@ struct FrameParts : public Http2FrameDecoderListener { ::testing::AssertionResult AppendString(Http2StringPiece source, Http2String* target, base::Optional<size_t>* opt_length); + + const Http2FrameHeader frame_header_; + + Http2String payload_; + Http2String padding_; + Http2String altsvc_origin_; + Http2String altsvc_value_; + + base::Optional<Http2PriorityFields> opt_priority_; + base::Optional<Http2ErrorCode> opt_rst_stream_error_code_; + base::Optional<Http2PushPromiseFields> opt_push_promise_; + base::Optional<Http2PingFields> opt_ping_; + base::Optional<Http2GoAwayFields> opt_goaway_; + + base::Optional<size_t> opt_pad_length_; + base::Optional<size_t> opt_payload_length_; + base::Optional<size_t> opt_missing_length_; + base::Optional<size_t> opt_altsvc_origin_length_; + base::Optional<size_t> opt_altsvc_value_length_; + + base::Optional<size_t> opt_window_update_increment_; + + bool has_frame_size_error_ = false; + + std::vector<Http2SettingFields> settings_; + + // These booleans are not checked by CompareCollectedFrames. + bool got_start_callback_ = false; + bool got_end_callback_ = false; }; +std::ostream& operator<<(std::ostream& out, const FrameParts& v); + } // namespace test } // namespace net diff --git a/chromium/net/http2/test_tools/frame_parts_collector.cc b/chromium/net/http2/test_tools/frame_parts_collector.cc index 18978d74132..9a727d433e5 100644 --- a/chromium/net/http2/test_tools/frame_parts_collector.cc +++ b/chromium/net/http2/test_tools/frame_parts_collector.cc @@ -13,8 +13,8 @@ namespace net { namespace test { -FramePartsCollector::FramePartsCollector() {} -FramePartsCollector::~FramePartsCollector() {} +FramePartsCollector::FramePartsCollector() = default; +FramePartsCollector::~FramePartsCollector() = default; void FramePartsCollector::Reset() { current_frame_.reset(); @@ -101,7 +101,7 @@ Http2FrameDecoderListener* FramePartsCollector::FrameError( // frame before detecting the error; for example, the DATA payload decoder // calls OnDataStart before it can detect padding errors, hence before it // can call OnPaddingTooLong. - EXPECT_EQ(header, current_frame_->frame_header); + EXPECT_EQ(header, current_frame_->GetFrameHeader()); } Http2FrameDecoderListener* result = current_frame(); collected_frames_.push_back(std::move(current_frame_)); diff --git a/chromium/net/http2/tools/random_decoder_test.cc b/chromium/net/http2/tools/random_decoder_test.cc index 47769fc3d3b..be5aaa1b2d9 100644 --- a/chromium/net/http2/tools/random_decoder_test.cc +++ b/chromium/net/http2/tools/random_decoder_test.cc @@ -28,7 +28,7 @@ using ::testing::AssertionSuccess; namespace net { namespace test { -RandomDecoderTest::RandomDecoderTest() {} +RandomDecoderTest::RandomDecoderTest() = default; bool RandomDecoderTest::StopDecodeOnDone() { return stop_decode_on_done_; diff --git a/chromium/net/interfaces/BUILD.gn b/chromium/net/interfaces/BUILD.gn index cbccdbca978..e4b2dccdbf5 100644 --- a/chromium/net/interfaces/BUILD.gn +++ b/chromium/net/interfaces/BUILD.gn @@ -6,6 +6,7 @@ import("//mojo/public/tools/bindings/mojom.gni") mojom("interfaces") { sources = [ + "address_family.mojom", "host_resolver_service.mojom", "ip_address.mojom", "ip_endpoint.mojom", @@ -13,7 +14,4 @@ mojom("interfaces") { public_deps = [ "//url/mojo:url_mojom_gurl", ] - - # TODO(crbug.com/699569): Convert to use the new JS bindings. - use_new_js_bindings = false } diff --git a/chromium/net/interfaces/address_family.mojom b/chromium/net/interfaces/address_family.mojom new file mode 100644 index 00000000000..ec011f18716 --- /dev/null +++ b/chromium/net/interfaces/address_family.mojom @@ -0,0 +1,12 @@ +// Copyright 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. + +module net.interfaces; + +// Mirror of net::AddressFamily. +enum AddressFamily { + UNSPECIFIED, + IPV4, + IPV6, +}; diff --git a/chromium/net/interfaces/address_family.typemap b/chromium/net/interfaces/address_family.typemap new file mode 100644 index 00000000000..89e9459f560 --- /dev/null +++ b/chromium/net/interfaces/address_family.typemap @@ -0,0 +1,14 @@ +# Copyright 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. + +mojom = "//net/interfaces/address_family.mojom" +public_headers = [ "//net/base/address_family.h" ] +traits_headers = [ "//net/interfaces/address_family_traits.h" ] +sources = [ + "//net/interfaces/address_family_traits.cc", +] +type_mappings = [ "net.interfaces.AddressFamily=net::AddressFamily" ] +public_deps = [ + "//net", +] diff --git a/chromium/net/interfaces/address_family_traits.cc b/chromium/net/interfaces/address_family_traits.cc new file mode 100644 index 00000000000..efb947dcf60 --- /dev/null +++ b/chromium/net/interfaces/address_family_traits.cc @@ -0,0 +1,45 @@ +// Copyright 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/interfaces/address_family_traits.h" + +namespace mojo { + +// static +bool EnumTraits<net::interfaces::AddressFamily, net::AddressFamily>::FromMojom( + net::interfaces::AddressFamily address_family, + net::AddressFamily* out) { + using net::interfaces::AddressFamily; + switch (address_family) { + case AddressFamily::UNSPECIFIED: + *out = net::ADDRESS_FAMILY_UNSPECIFIED; + return true; + case AddressFamily::IPV4: + *out = net::ADDRESS_FAMILY_IPV4; + return true; + case AddressFamily::IPV6: + *out = net::ADDRESS_FAMILY_IPV6; + return true; + } + return false; +} + +// static +net::interfaces::AddressFamily +EnumTraits<net::interfaces::AddressFamily, net::AddressFamily>::ToMojom( + net::AddressFamily address_family) { + using net::interfaces::AddressFamily; + switch (address_family) { + case net::ADDRESS_FAMILY_UNSPECIFIED: + return AddressFamily::UNSPECIFIED; + case net::ADDRESS_FAMILY_IPV4: + return AddressFamily::IPV4; + case net::ADDRESS_FAMILY_IPV6: + return AddressFamily::IPV6; + } + NOTREACHED(); + return AddressFamily::UNSPECIFIED; +} + +} // namespace mojo diff --git a/chromium/net/interfaces/address_family_traits.h b/chromium/net/interfaces/address_family_traits.h new file mode 100644 index 00000000000..875b7795aae --- /dev/null +++ b/chromium/net/interfaces/address_family_traits.h @@ -0,0 +1,23 @@ +// Copyright 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 NET_INTERFACES_ADDRESS_FAMILY_TRAITS_H_ +#define NET_INTERFACES_ADDRESS_FAMILY_TRAITS_H_ + +#include "mojo/public/cpp/bindings/enum_traits.h" +#include "net/interfaces/address_family.mojom.h" + +namespace mojo { + +template <> +struct EnumTraits<net::interfaces::AddressFamily, net::AddressFamily> { + static net::interfaces::AddressFamily ToMojom( + net::AddressFamily address_family); + static bool FromMojom(net::interfaces::AddressFamily address_family, + net::AddressFamily* out); +}; + +} // namespace mojo + +#endif // NET_INTERFACES_ADDRESS_FAMILY_TRAITS_H_ diff --git a/chromium/net/interfaces/host_resolver.typemap b/chromium/net/interfaces/host_resolver.typemap index 25d0121dd3d..c0f559ceb56 100644 --- a/chromium/net/interfaces/host_resolver.typemap +++ b/chromium/net/interfaces/host_resolver.typemap @@ -11,7 +11,6 @@ sources = [ type_mappings = [ "net.interfaces.HostResolverRequestInfo=std::unique_ptr<net::HostResolver::RequestInfo>[move_only]", "net.interfaces.AddressList=net::AddressList", - "net.interfaces.AddressFamily=net::AddressFamily", ] public_deps = [ "//net", diff --git a/chromium/net/interfaces/host_resolver_service.mojom b/chromium/net/interfaces/host_resolver_service.mojom index 1c36489a498..4a5e030cd9f 100644 --- a/chromium/net/interfaces/host_resolver_service.mojom +++ b/chromium/net/interfaces/host_resolver_service.mojom @@ -13,13 +13,7 @@ module net.interfaces; import "net/interfaces/ip_endpoint.mojom"; - -// Mirror of net::AddressFamily. -enum AddressFamily { - UNSPECIFIED, - IPV4, - IPV6, -}; +import "net/interfaces/address_family.mojom"; // Mirror of net::HostResolver::RequestInfo. struct HostResolverRequestInfo { diff --git a/chromium/net/interfaces/typemaps.gni b/chromium/net/interfaces/typemaps.gni index 4932e7116cb..b36db71043c 100644 --- a/chromium/net/interfaces/typemaps.gni +++ b/chromium/net/interfaces/typemaps.gni @@ -3,6 +3,7 @@ # found in the LICENSE file. typemaps = [ + "//net/interfaces/address_family.typemap", "//net/interfaces/host_resolver.typemap", "//net/interfaces/ip_address.typemap", "//net/interfaces/ip_endpoint.typemap", diff --git a/chromium/net/log/file_net_log_observer.cc b/chromium/net/log/file_net_log_observer.cc index 3feaa971287..57787866e0a 100644 --- a/chromium/net/log/file_net_log_observer.cc +++ b/chromium/net/log/file_net_log_observer.cc @@ -462,7 +462,7 @@ void FileNetLogObserver::WriteQueue::SwapQueue(EventQueue* local_queue) { memory_ = 0; } -FileNetLogObserver::WriteQueue::~WriteQueue() {} +FileNetLogObserver::WriteQueue::~WriteQueue() = default; FileNetLogObserver::FileWriter::FileWriter( const base::FilePath& log_path, @@ -476,7 +476,7 @@ FileNetLogObserver::FileWriter::FileWriter( wrote_event_bytes_(false), task_runner_(std::move(task_runner)) {} -FileNetLogObserver::FileWriter::~FileWriter() {} +FileNetLogObserver::FileWriter::~FileWriter() = default; void FileNetLogObserver::FileWriter::Initialize( std::unique_ptr<base::Value> constants_value) { diff --git a/chromium/net/log/net_log.cc b/chromium/net/log/net_log.cc index bff7a67d1db..3f2ecc927d0 100644 --- a/chromium/net/log/net_log.cc +++ b/chromium/net/log/net_log.cc @@ -108,8 +108,7 @@ void NetLog::ThreadSafeObserver::OnAddEntryData( NetLog::NetLog() : last_id_(0), is_capturing_(0) { } -NetLog::~NetLog() { -} +NetLog::~NetLog() = default; void NetLog::AddGlobalEntry(NetLogEventType type) { AddEntry(type, NetLogSource(NetLogSourceType::NONE, NextID()), diff --git a/chromium/net/log/net_log_entry.cc b/chromium/net/log/net_log_entry.cc index 1258139f748..3cdfc4528cc 100644 --- a/chromium/net/log/net_log_entry.cc +++ b/chromium/net/log/net_log_entry.cc @@ -58,12 +58,12 @@ NetLogEntryData::NetLogEntryData( time(time), parameters_callback(parameters_callback) {} -NetLogEntryData::~NetLogEntryData() {} +NetLogEntryData::~NetLogEntryData() = default; NetLogEntry::NetLogEntry(const NetLogEntryData* data, NetLogCaptureMode capture_mode) : data_(data), capture_mode_(capture_mode) {} -NetLogEntry::~NetLogEntry() {} +NetLogEntry::~NetLogEntry() = default; } // namespace net diff --git a/chromium/net/log/net_log_event_type_list.h b/chromium/net/log/net_log_event_type_list.h index 551953165f9..8e942348ddd 100644 --- a/chromium/net/log/net_log_event_type_list.h +++ b/chromium/net/log/net_log_event_type_list.h @@ -2005,7 +2005,11 @@ EVENT_TYPE(QUIC_CHROMIUM_CLIENT_STREAM_READ_RESPONSE_TRAILERS) // ------------------------------------------------------------------------ // QuicConnectionMigration // ------------------------------------------------------------------------ - +// Records the QUIC connection migration mode. +// { +// "connection_migration_mode": <The connection migration mode> +// } +EVENT_TYPE(QUIC_CONNECTION_MIGRATION_MODE) // Records that QUIC connection migration has been triggered. // { // "trigger": <The reason for the migration attempt> @@ -2091,6 +2095,12 @@ EVENT_TYPE(QUIC_CONNECTION_MIGRATION_ON_PATH_DEGRADING) // Records that a QUIC connection migration attempt due to efforts to // migrate back to the default network. EVENT_TYPE(QUIC_CONNECTION_MIGRATION_ON_MIGRATE_BACK) + +// Records a QUIC connection migration failure after probing. +EVENT_TYPE(QUIC_CONNECTION_MIGRATION_FAILURE_AFTER_PROBING) + +// Records a QUIC connection migration success after probing. +EVENT_TYPE(QUIC_CONNECTION_MIGRATION_SUCCESS_AFTER_PROBING) // ------------------------------------------------------------------------ // HttpStreamParser // ------------------------------------------------------------------------ diff --git a/chromium/net/log/net_log_unittest.cc b/chromium/net/log/net_log_unittest.cc index e0e8b6695d9..b6dce8b3843 100644 --- a/chromium/net/log/net_log_unittest.cc +++ b/chromium/net/log/net_log_unittest.cc @@ -126,7 +126,7 @@ class CountingObserver : public NetLog::ThreadSafeObserver { class LoggingObserver : public NetLog::ThreadSafeObserver { public: - LoggingObserver() {} + LoggingObserver() = default; ~LoggingObserver() override { if (net_log()) @@ -191,8 +191,8 @@ class NetLogTestThread : public base::SimpleThread { // A thread that adds a bunch of events to the NetLog. class AddEventsTestThread : public NetLogTestThread { public: - AddEventsTestThread() {} - ~AddEventsTestThread() override {} + AddEventsTestThread() = default; + ~AddEventsTestThread() override = default; private: void RunTestThread() override { @@ -206,7 +206,7 @@ class AddEventsTestThread : public NetLogTestThread { // A thread that adds and removes an observer from the NetLog repeatedly. class AddRemoveObserverTestThread : public NetLogTestThread { public: - AddRemoveObserverTestThread() {} + AddRemoveObserverTestThread() = default; ~AddRemoveObserverTestThread() override { EXPECT_TRUE(!observer_.net_log()); } diff --git a/chromium/net/log/net_log_util.cc b/chromium/net/log/net_log_util.cc index efe45716a2c..e133b7b7151 100644 --- a/chromium/net/log/net_log_util.cc +++ b/chromium/net/log/net_log_util.cc @@ -460,7 +460,7 @@ NET_EXPORT void CreateNetLogEntriesForActiveObjects( context->AssertCalledOnValidThread(); // Contexts should all be using the same NetLog. DCHECK_EQ((*contexts.begin())->net_log(), context->net_log()); - for (auto* request : context->url_requests()) { + for (auto* request : *context->url_requests()) { requests.push_back(request); } } diff --git a/chromium/net/log/test_net_log.cc b/chromium/net/log/test_net_log.cc index 8cdcceabd01..36ef00dd4d5 100644 --- a/chromium/net/log/test_net_log.cc +++ b/chromium/net/log/test_net_log.cc @@ -18,8 +18,8 @@ namespace net { // that saves messages to a buffer. class TestNetLog::Observer : public NetLog::ThreadSafeObserver { public: - Observer() {} - ~Observer() override {} + Observer() = default; + ~Observer() override = default; // Returns the list of all entries in the log. void GetEntries(TestNetLogEntry::List* entry_list) const { @@ -110,8 +110,7 @@ BoundTestNetLog::BoundTestNetLog() : net_log_(NetLogWithSource::Make(&test_net_log_, NetLogSourceType::NONE)) { } -BoundTestNetLog::~BoundTestNetLog() { -} +BoundTestNetLog::~BoundTestNetLog() = default; void BoundTestNetLog::GetEntries(TestNetLogEntry::List* entry_list) const { test_net_log_.GetEntries(entry_list); diff --git a/chromium/net/log/test_net_log_entry.cc b/chromium/net/log/test_net_log_entry.cc index e8beb757c31..1936ef3e336 100644 --- a/chromium/net/log/test_net_log_entry.cc +++ b/chromium/net/log/test_net_log_entry.cc @@ -30,8 +30,7 @@ TestNetLogEntry::TestNetLogEntry(const TestNetLogEntry& entry) { *this = entry; } -TestNetLogEntry::~TestNetLogEntry() { -} +TestNetLogEntry::~TestNetLogEntry() = default; TestNetLogEntry& TestNetLogEntry::operator=(const TestNetLogEntry& entry) { type = entry.type; diff --git a/chromium/net/log/trace_net_log_observer.cc b/chromium/net/log/trace_net_log_observer.cc index 4349c3c714a..ed3286fd35b 100644 --- a/chromium/net/log/trace_net_log_observer.cc +++ b/chromium/net/log/trace_net_log_observer.cc @@ -30,7 +30,7 @@ class TracedValue : public base::trace_event::ConvertableToTraceFormat { : value_(std::move(value)) {} private: - ~TracedValue() override {} + ~TracedValue() override = default; void AppendAsTraceFormat(std::string* out) const override { if (value_) { diff --git a/chromium/net/network_error_logging/network_error_logging_end_to_end_test.cc b/chromium/net/network_error_logging/network_error_logging_end_to_end_test.cc new file mode 100644 index 00000000000..3da56ed6ad3 --- /dev/null +++ b/chromium/net/network_error_logging/network_error_logging_end_to_end_test.cc @@ -0,0 +1,232 @@ +// Copyright 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 "base/macros.h" +#include "base/run_loop.h" +#include "base/strings/stringprintf.h" +#include "base/test/scoped_feature_list.h" +#include "base/test/values_test_util.h" +#include "base/time/time.h" +#include "base/values.h" +#include "build/build_config.h" +#include "net/base/net_errors.h" +#include "net/network_error_logging/network_error_logging_service.h" +#include "net/reporting/reporting_feature.h" +#include "net/reporting/reporting_policy.h" +#include "net/test/embedded_test_server/embedded_test_server.h" +#include "net/test/embedded_test_server/http_request.h" +#include "net/test/embedded_test_server/http_response.h" +#include "net/traffic_annotation/network_traffic_annotation_test_helper.h" +#include "net/url_request/url_request.h" +#include "net/url_request/url_request_context.h" +#include "net/url_request/url_request_context_builder.h" +#include "net/url_request/url_request_status.h" +#include "net/url_request/url_request_test_util.h" +#include "testing/gtest/include/gtest/gtest.h" + +#if defined(OS_LINUX) || defined(OS_ANDROID) +#include "net/proxy/proxy_config.h" +#include "net/proxy/proxy_config_service_fixed.h" +#endif // defined(OS_LINUX) || defined(OS_ANDROID) + +namespace net { +namespace { + +const char kGroup[] = "network-errors"; +const int kMaxAgeSec = 86400; + +const char kConfigurePath[] = "/configure"; +const char kFailPath[] = "/fail"; +const char kReportPath[] = "/report"; + +class HungHttpResponse : public test_server::HttpResponse { + public: + HungHttpResponse() = default; + + void SendResponse(const test_server::SendBytesCallback& send, + const test_server::SendCompleteCallback& done) override {} + + private: + DISALLOW_COPY_AND_ASSIGN(HungHttpResponse); +}; + +class NetworkErrorLoggingEndToEndTest : public ::testing::Test { + protected: + NetworkErrorLoggingEndToEndTest() + : test_server_(test_server::EmbeddedTestServer::TYPE_HTTPS), + upload_should_hang_(false), + upload_received_(false) { + scoped_feature_list_.InitWithFeatures( + {features::kReporting, features::kNetworkErrorLogging}, {}); + + // Make report delivery happen instantly. + auto policy = std::make_unique<ReportingPolicy>(); + policy->delivery_interval = base::TimeDelta::FromSeconds(0); + + URLRequestContextBuilder builder; +#if defined(OS_LINUX) || defined(OS_ANDROID) + builder.set_proxy_config_service( + std::make_unique<ProxyConfigServiceFixed>(ProxyConfig::CreateDirect())); +#endif // defined(OS_LINUX) || defined(OS_ANDROID) + builder.set_reporting_policy(std::move(policy)); + builder.set_network_error_logging_enabled(true); + url_request_context_ = builder.Build(); + + EXPECT_TRUE(url_request_context_->reporting_service()); + EXPECT_TRUE(url_request_context_->network_error_logging_delegate()); + + test_server_.RegisterRequestHandler(base::BindRepeating( + &NetworkErrorLoggingEndToEndTest::HandleConfigureRequest, + base::Unretained(this))); + test_server_.RegisterRequestHandler( + base::BindRepeating(&NetworkErrorLoggingEndToEndTest::HandleFailRequest, + base::Unretained(this))); + test_server_.RegisterRequestHandler(base::BindRepeating( + &NetworkErrorLoggingEndToEndTest::HandleReportRequest, + base::Unretained(this))); + EXPECT_TRUE(test_server_.Start()); + } + + GURL GetConfigureURL() { return test_server_.GetURL(kConfigurePath); } + + GURL GetFailURL() { return test_server_.GetURL(kFailPath); } + + GURL GetReportURL() { return test_server_.GetURL(kReportPath); } + + std::unique_ptr<test_server::HttpResponse> HandleConfigureRequest( + const test_server::HttpRequest& request) { + if (request.relative_url != kConfigurePath) + return nullptr; + + GURL endpoint_url = GetReportURL(); + + auto response = std::make_unique<test_server::BasicHttpResponse>(); + response->AddCustomHeader( + "Report-To", + base::StringPrintf("{\"url\":\"%s\",\"group\":\"%s\",\"max-age\":%d}", + endpoint_url.spec().c_str(), kGroup, kMaxAgeSec)); + response->AddCustomHeader( + "NEL", base::StringPrintf("{\"report-to\":\"%s\",\"max-age\":%d}", + kGroup, kMaxAgeSec)); + response->set_content_type("text/plain"); + response->set_content(""); + return std::move(response); + } + + std::unique_ptr<test_server::HttpResponse> HandleFailRequest( + const test_server::HttpRequest& request) { + if (request.relative_url != kFailPath) + return nullptr; + + return std::make_unique<test_server::RawHttpResponse>("", ""); + } + + std::unique_ptr<test_server::HttpResponse> HandleReportRequest( + const test_server::HttpRequest& request) { + if (request.relative_url != kReportPath) + return nullptr; + + EXPECT_FALSE(upload_received_); + upload_received_ = true; + + EXPECT_TRUE(request.has_content); + upload_content_ = request.content; + + if (!upload_closure_.is_null()) + std::move(upload_closure_).Run(); + + if (upload_should_hang_) + return std::make_unique<HungHttpResponse>(); + + auto response = std::make_unique<test_server::BasicHttpResponse>(); + response->set_content_type("text/plain"); + response->set_content(""); + return std::move(response); + } + + base::test::ScopedFeatureList scoped_feature_list_; + std::unique_ptr<URLRequestContext> url_request_context_; + test_server::EmbeddedTestServer test_server_; + + bool upload_should_hang_; + bool upload_received_; + std::string upload_content_; + base::OnceClosure upload_closure_; + + private: + DISALLOW_COPY_AND_ASSIGN(NetworkErrorLoggingEndToEndTest); +}; + +TEST_F(NetworkErrorLoggingEndToEndTest, ReportNetworkError) { + TestDelegate configure_delegate; + auto configure_request = url_request_context_->CreateRequest( + GetConfigureURL(), DEFAULT_PRIORITY, &configure_delegate, + TRAFFIC_ANNOTATION_FOR_TESTS); + configure_request->set_method("GET"); + configure_request->Start(); + base::RunLoop().Run(); + EXPECT_TRUE(configure_request->status().is_success()); + + TestDelegate fail_delegate; + auto fail_request = url_request_context_->CreateRequest( + GetFailURL(), DEFAULT_PRIORITY, &fail_delegate, + TRAFFIC_ANNOTATION_FOR_TESTS); + fail_request->set_method("GET"); + fail_request->Start(); + base::RunLoop().Run(); + EXPECT_EQ(URLRequestStatus::FAILED, fail_request->status().status()); + EXPECT_EQ(ERR_EMPTY_RESPONSE, fail_request->status().error()); + + if (!upload_received_) { + base::RunLoop run_loop; + upload_closure_ = run_loop.QuitClosure(); + run_loop.Run(); + } + + auto reports = base::test::ParseJson(upload_content_); + + base::ListValue* reports_list; + ASSERT_TRUE(reports->GetAsList(&reports_list)); + ASSERT_EQ(1u, reports_list->GetSize()); + base::DictionaryValue* report_dict; + ASSERT_TRUE(reports_list->GetDictionary(0u, &report_dict)); + + ExpectDictStringValue("network-error", *report_dict, "type"); + ExpectDictStringValue(GetFailURL().spec(), *report_dict, "url"); + base::DictionaryValue* body_dict; + ASSERT_TRUE(report_dict->GetDictionary("report", &body_dict)); + + ExpectDictStringValue("http.response.empty", *body_dict, "type"); + ExpectDictIntegerValue(0, *body_dict, "status-code"); + ExpectDictStringValue(GetFailURL().spec(), *body_dict, "uri"); +} + +// Make sure an upload that is in progress at shutdown does not crash. +// This verifies that https://crbug.com/792978 is fixed. +TEST_F(NetworkErrorLoggingEndToEndTest, UploadAtShutdown) { + upload_should_hang_ = true; + + TestDelegate configure_delegate; + auto configure_request = url_request_context_->CreateRequest( + GetConfigureURL(), DEFAULT_PRIORITY, &configure_delegate, + TRAFFIC_ANNOTATION_FOR_TESTS); + configure_request->set_method("GET"); + configure_request->Start(); + base::RunLoop().Run(); + EXPECT_TRUE(configure_request->status().is_success()); + + TestDelegate fail_delegate; + auto fail_request = url_request_context_->CreateRequest( + GetFailURL(), DEFAULT_PRIORITY, &fail_delegate, + TRAFFIC_ANNOTATION_FOR_TESTS); + fail_request->set_method("GET"); + fail_request->Start(); + base::RunLoop().RunUntilIdle(); + + // Let Reporting and NEL shut down with the upload still pending to see if + // they crash. +} + +} // namespace +} // namespace net 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 b1773129d8d..e9d6f7bdf53 100644 --- a/chromium/net/network_error_logging/network_error_logging_service.cc +++ b/chromium/net/network_error_logging/network_error_logging_service.cc @@ -92,6 +92,7 @@ const struct { // http.protocol.error? {ERR_INVALID_HTTP_RESPONSE, "http.response.invalid"}, {ERR_TOO_MANY_REDIRECTS, "http.response.redirect_loop"}, + {ERR_EMPTY_RESPONSE, "http.response.empty"}, // http.failed? {ERR_ABORTED, "abandoned"}, @@ -170,16 +171,21 @@ void NetworkErrorLoggingService::OnNetworkError(const ErrorDetails& details) { if (!reporting_service_) return; - url::Origin origin = url::Origin::Create(details.uri); + // It is expected for Reporting uploads to terminate with ERR_ABORTED, since + // the ReportingUploader cancels them after receiving the response code and + // headers. + if (details.is_reporting_upload && details.type == ERR_ABORTED) + return; // NEL is only available to secure origins, so ignore network errors from // insecure origins. (The check in OnHeader prevents insecure origins from // setting policies, but this check is needed to ensure that insecure origins // can't match wildcard policies from secure origins.) - if (!origin.GetURL().SchemeIsCryptographic()) + if (!details.uri.SchemeIsCryptographic()) return; - const OriginPolicy* policy = FindPolicyForOrigin(origin); + const OriginPolicy* policy = + FindPolicyForOrigin(url::Origin::Create(details.uri)); if (!policy) return; @@ -191,14 +197,36 @@ void NetworkErrorLoggingService::OnNetworkError(const ErrorDetails& details) { CreateReportBody(type_string, details)); } +void NetworkErrorLoggingService::RemoveBrowsingData( + const base::RepeatingCallback<bool(const GURL&)>& origin_filter) { + if (origin_filter.is_null()) { + wildcard_policies_.clear(); + policies_.clear(); + return; + } + + std::vector<url::Origin> origins_to_remove; + + for (auto it = policies_.begin(); it != policies_.end(); ++it) { + if (origin_filter.Run(it->first.GetURL())) + origins_to_remove.push_back(it->first); + } + + for (auto it = origins_to_remove.begin(); it != origins_to_remove.end(); + ++it) { + MaybeRemoveWildcardPolicy(*it, &policies_[*it]); + policies_.erase(*it); + } +} + void NetworkErrorLoggingService::SetTickClockForTesting( - std::unique_ptr<base::TickClock> tick_clock) { + base::TickClock* tick_clock) { DCHECK(tick_clock); - tick_clock_ = std::move(tick_clock); + tick_clock_ = tick_clock; } NetworkErrorLoggingService::NetworkErrorLoggingService() - : tick_clock_(base::MakeUnique<base::DefaultTickClock>()), + : tick_clock_(base::DefaultTickClock::GetInstance()), reporting_service_(nullptr) {} bool NetworkErrorLoggingService::ParseHeader(const std::string& json_value, 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 759bb458bc4..5cefaddd831 100644 --- a/chromium/net/network_error_logging/network_error_logging_service.h +++ b/chromium/net/network_error_logging/network_error_logging_service.h @@ -67,7 +67,10 @@ class NET_EXPORT NetworkErrorLoggingService void OnNetworkError(const ErrorDetails& details) override; - void SetTickClockForTesting(std::unique_ptr<base::TickClock> tick_clock); + void RemoveBrowsingData( + const base::RepeatingCallback<bool(const GURL&)>& origin_filter) override; + + void SetTickClockForTesting(base::TickClock* tick_clock); private: // NEL Policy set by an origin. @@ -113,7 +116,7 @@ class NET_EXPORT NetworkErrorLoggingService const std::string& type, const ErrorDetails& details) const; - std::unique_ptr<base::TickClock> tick_clock_; + base::TickClock* tick_clock_; // Unowned. ReportingService* reporting_service_; diff --git a/chromium/net/network_error_logging/network_error_logging_service_unittest.cc b/chromium/net/network_error_logging/network_error_logging_service_unittest.cc index e7192e0f724..e04a2f25af4 100644 --- a/chromium/net/network_error_logging/network_error_logging_service_unittest.cc +++ b/chromium/net/network_error_logging/network_error_logging_service_unittest.cc @@ -74,12 +74,17 @@ class TestReportingService : public ReportingService { NOTREACHED(); } - void RemoveBrowsingData( - int data_type_mask, - base::Callback<bool(const GURL&)> origin_filter) override { + void RemoveBrowsingData(int data_type_mask, + const base::RepeatingCallback<bool(const GURL&)>& + origin_filter) override { NOTREACHED(); } + bool RequestIsUpload(const URLRequest& request) override { + NOTREACHED(); + return true; + } + private: std::vector<Report> reports_; @@ -119,6 +124,7 @@ class NetworkErrorLoggingServiceTest : public ::testing::Test { details.status_code = 0; details.elapsed_time = base::TimeDelta::FromSeconds(1); details.type = error_type; + details.is_reporting_upload = false; return details; } @@ -131,11 +137,14 @@ class NetworkErrorLoggingServiceTest : public ::testing::Test { const GURL kUrl_ = GURL("https://example.com/path"); const GURL kUrlDifferentPort_ = GURL("https://example.com:4433/path"); const GURL kUrlSubdomain_ = GURL("https://subdomain.example.com/path"); + const GURL kUrlDifferentHost_ = GURL("https://example2.com/path"); const url::Origin kOrigin_ = url::Origin::Create(kUrl_); const url::Origin kOriginDifferentPort_ = url::Origin::Create(kUrlDifferentPort_); const url::Origin kOriginSubdomain_ = url::Origin::Create(kUrlSubdomain_); + const url::Origin kOriginDifferentHost_ = + url::Origin::Create(kUrlDifferentHost_); const std::string kHeader_ = "{\"report-to\":\"group\",\"max-age\":86400}"; const std::string kHeaderIncludeSubdomains_ = @@ -280,5 +289,34 @@ TEST_F(NetworkErrorLoggingServiceTest, EXPECT_TRUE(reports().empty()); } +TEST_F(NetworkErrorLoggingServiceTest, RemoveAllBrowsingData) { + service()->OnHeader(kOrigin_, kHeader_); + + service()->RemoveBrowsingData(base::RepeatingCallback<bool(const GURL&)>()); + + service()->OnNetworkError(MakeErrorDetails(kUrl_, ERR_CONNECTION_REFUSED)); + + EXPECT_TRUE(reports().empty()); +} + +TEST_F(NetworkErrorLoggingServiceTest, RemoveSomeBrowsingData) { + service()->OnHeader(kOrigin_, kHeader_); + service()->OnHeader(kOriginDifferentHost_, kHeader_); + + service()->RemoveBrowsingData( + base::BindRepeating([](const GURL& origin) -> bool { + return origin.host() == "example.com"; + })); + + service()->OnNetworkError(MakeErrorDetails(kUrl_, ERR_CONNECTION_REFUSED)); + + EXPECT_TRUE(reports().empty()); + + service()->OnNetworkError( + MakeErrorDetails(kUrlDifferentHost_, ERR_CONNECTION_REFUSED)); + + EXPECT_EQ(1u, reports().size()); +} + } // namespace } // namespace net diff --git a/chromium/net/nqe/OWNERS b/chromium/net/nqe/OWNERS index fa91285a8fa..30f461a85f9 100644 --- a/chromium/net/nqe/OWNERS +++ b/chromium/net/nqe/OWNERS @@ -1,6 +1,9 @@ -bengr@chromium.org +# Primary tbansal@chromium.org ryansturm@chromium.org +# Secondary +bengr@chromium.org + # TEAM: net-dev@chromium.org # COMPONENT: Internals>Network>NetworkQuality
\ No newline at end of file diff --git a/chromium/net/nqe/cached_network_quality.h b/chromium/net/nqe/cached_network_quality.h index 9f437da93ca..22f60299516 100644 --- a/chromium/net/nqe/cached_network_quality.h +++ b/chromium/net/nqe/cached_network_quality.h @@ -41,8 +41,6 @@ class NET_EXPORT_PRIVATE CachedNetworkQuality { base::TimeTicks last_update_time() { return last_update_time_; } - const NetworkQuality& network_quality() { return network_quality_; } - EffectiveConnectionType effective_connection_type() const { return effective_connection_type_; } diff --git a/chromium/net/nqe/network_id.cc b/chromium/net/nqe/network_id.cc index 3e5fbe5e6cb..be8d350bbdb 100644 --- a/chromium/net/nqe/network_id.cc +++ b/chromium/net/nqe/network_id.cc @@ -17,28 +17,39 @@ namespace internal { // static NetworkID NetworkID::FromString(const std::string& network_id) { std::string base64_decoded; - if (!base::Base64Decode(network_id, &base64_decoded)) - return NetworkID(NetworkChangeNotifier::CONNECTION_UNKNOWN, std::string()); + if (!base::Base64Decode(network_id, &base64_decoded)) { + return NetworkID(NetworkChangeNotifier::CONNECTION_UNKNOWN, std::string(), + INT32_MIN); + } NetworkIDProto network_id_proto; - if (!network_id_proto.ParseFromString(base64_decoded)) - return NetworkID(NetworkChangeNotifier::CONNECTION_UNKNOWN, std::string()); + if (!network_id_proto.ParseFromString(base64_decoded)) { + return NetworkID(NetworkChangeNotifier::CONNECTION_UNKNOWN, std::string(), + INT32_MIN); + } return NetworkID(static_cast<NetworkChangeNotifier::ConnectionType>( network_id_proto.connection_type()), - network_id_proto.id()); + network_id_proto.id(), network_id_proto.signal_strength()); } NetworkID::NetworkID(NetworkChangeNotifier::ConnectionType type, - const std::string& id) - : type(type), id(id) {} + const std::string& id, + int32_t signal_strength) + : type(type), id(id), signal_strength(signal_strength) { + // A valid value of |signal_strength| must be between 0 and 4 (both + // inclusive). + DCHECK((0 <= signal_strength && 4 >= signal_strength) || + (INT32_MIN == signal_strength)); +} NetworkID::NetworkID(const NetworkID& other) = default; NetworkID::~NetworkID() = default; bool NetworkID::operator==(const NetworkID& other) const { - return type == other.type && id == other.id; + return type == other.type && id == other.id && + signal_strength == other.signal_strength; } bool NetworkID::operator!=(const NetworkID& other) const { @@ -49,13 +60,15 @@ NetworkID& NetworkID::operator=(const NetworkID& other) = default; // Overloaded to support ordered collections. bool NetworkID::operator<(const NetworkID& other) const { - return std::tie(type, id) < std::tie(other.type, other.id); + return std::tie(type, id, signal_strength) < + std::tie(other.type, other.id, other.signal_strength); } std::string NetworkID::ToString() const { NetworkIDProto network_id_proto; network_id_proto.set_connection_type(static_cast<int>(type)); network_id_proto.set_id(id); + network_id_proto.set_signal_strength(signal_strength); std::string serialized_network_id; if (!network_id_proto.SerializeToString(&serialized_network_id)) diff --git a/chromium/net/nqe/network_id.h b/chromium/net/nqe/network_id.h index 65f52d198db..618210c87f5 100644 --- a/chromium/net/nqe/network_id.h +++ b/chromium/net/nqe/network_id.h @@ -23,7 +23,9 @@ namespace internal { struct NET_EXPORT_PRIVATE NetworkID { static NetworkID FromString(const std::string& network_id); - NetworkID(NetworkChangeNotifier::ConnectionType type, const std::string& id); + NetworkID(NetworkChangeNotifier::ConnectionType type, + const std::string& id, + int32_t signal_strength); NetworkID(const NetworkID& other); ~NetworkID(); @@ -50,6 +52,14 @@ struct NET_EXPORT_PRIVATE NetworkID { // - An empty string in all other cases or if the network name is not // exposed by platform APIs. std::string id; + + // Signal strength of the network. Set to INT32_MIN when the value is + // unavailable. Otherwise, must be between 0 and 4 (both inclusive). This may + // take into account many different radio technology inputs. 0 represents very + // poor signal strength while 4 represents a very strong signal strength. The + // range is capped between 0 and 4 to ensure that a change in the value + // indicates a non-negligible change in the signal quality. + int32_t signal_strength; }; } // namespace internal diff --git a/chromium/net/nqe/network_id_unittest.cc b/chromium/net/nqe/network_id_unittest.cc index 3ee6998da8f..68e5d01a4ff 100644 --- a/chromium/net/nqe/network_id_unittest.cc +++ b/chromium/net/nqe/network_id_unittest.cc @@ -5,6 +5,7 @@ #include "net/nqe/network_id.h" #include <string> + #include "base/strings/string_number_conversions.h" #include "net/base/network_change_notifier.h" #include "testing/gtest/include/gtest/gtest.h" @@ -17,7 +18,7 @@ namespace { TEST(NetworkIDTest, TestSerialize) { nqe::internal::NetworkID network_id(NetworkChangeNotifier::CONNECTION_2G, - "test1"); + "test1", 2); std::string serialized = network_id.ToString(); EXPECT_EQ(network_id, NetworkID::FromString(serialized)); } diff --git a/chromium/net/nqe/network_qualities_prefs_manager.cc b/chromium/net/nqe/network_qualities_prefs_manager.cc index 7d860f0283b..be3901575f4 100644 --- a/chromium/net/nqe/network_qualities_prefs_manager.cc +++ b/chromium/net/nqe/network_qualities_prefs_manager.cc @@ -14,6 +14,7 @@ #include "base/threading/thread_checker.h" #include "base/threading/thread_task_runner_handle.h" #include "net/nqe/network_quality_estimator.h" +#include "net/nqe/network_quality_estimator_params.h" namespace net { @@ -27,7 +28,7 @@ namespace { // (ii) Connection type of the network as reported by network // change notifier (an enum). // (iii) Effective connection type of the network (an enum). -constexpr size_t kMaxCacheSize = 10u; +constexpr size_t kMaxCacheSize = 20u; // Parses |value| into a map of NetworkIDs and CachedNetworkQualities, // and returns the map. @@ -133,6 +134,19 @@ void NetworkQualitiesPrefsManager::OnChangeInCachedNetworkQualityOnPrefSequence( if (network_id_string.find('.') != std::string::npos) return; + if (cached_network_quality.effective_connection_type() == + network_quality_estimator_->params()->GetDefaultECT(network_id.type)) { + // No need to cache the network quality since the default network quality + // (synthesized using the platform APIs) matches the observed network + // quality. + if (!prefs_->RemoveKey(network_id_string)) { + // Return early since the prefs was unchanged. + return; + } + pref_delegate_->SetDictionaryValue(*prefs_); + return; + } + prefs_->SetString(network_id_string, GetNameForEffectiveConnectionType( cached_network_quality.effective_connection_type())); diff --git a/chromium/net/nqe/network_qualities_prefs_manager_unittest.cc b/chromium/net/nqe/network_qualities_prefs_manager_unittest.cc index 29db509e295..44b228ca58a 100644 --- a/chromium/net/nqe/network_qualities_prefs_manager_unittest.cc +++ b/chromium/net/nqe/network_qualities_prefs_manager_unittest.cc @@ -16,6 +16,7 @@ #include "base/values.h" #include "net/base/network_change_notifier.h" #include "net/nqe/effective_connection_type.h" +#include "net/nqe/network_id.h" #include "net/nqe/network_quality_estimator_test_util.h" #include "net/nqe/network_quality_store.h" #include "testing/gtest/include/gtest/gtest.h" @@ -74,7 +75,12 @@ class TestPrefDelegate : public NetworkQualitiesPrefsManager::PrefDelegate { }; TEST(NetworkQualitiesPrefManager, Write) { - TestNetworkQualityEstimator estimator; + // Force set the ECT to Slow 2G so that the ECT does not match the default + // ECT for the current connection type. This forces the prefs to be written + // for the current connection. + std::map<std::string, std::string> variation_params; + variation_params["force_effective_connection_type"] = "Slow-2G"; + TestNetworkQualityEstimator estimator(variation_params); std::unique_ptr<TestPrefDelegate> prefs_delegate(new TestPrefDelegate()); TestPrefDelegate* prefs_delegate_ptr = prefs_delegate.get(); @@ -88,34 +94,104 @@ TEST(NetworkQualitiesPrefManager, Write) { estimator.SimulateNetworkChange( NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN, "test"); - EXPECT_EQ(0u, prefs_delegate_ptr->write_count()); + EXPECT_EQ(1u, prefs_delegate_ptr->write_count()); // Network quality generated from the default observation must be written. base::RunLoop().RunUntilIdle(); - EXPECT_EQ(1u, prefs_delegate_ptr->write_count()); + EXPECT_EQ(3u, prefs_delegate_ptr->write_count()); estimator.set_recent_effective_connection_type(EFFECTIVE_CONNECTION_TYPE_2G); // Run a request so that effective connection type is recomputed, and // observers are notified of change in the network quality. estimator.RunOneRequest(); base::RunLoop().RunUntilIdle(); - EXPECT_EQ(2u, prefs_delegate_ptr->write_count()); + EXPECT_EQ(4u, prefs_delegate_ptr->write_count()); estimator.set_recent_effective_connection_type(EFFECTIVE_CONNECTION_TYPE_3G); // Run a request so that effective connection type is recomputed, and // observers are notified of change in the network quality.. estimator.RunOneRequest(); base::RunLoop().RunUntilIdle(); + EXPECT_EQ(5u, prefs_delegate_ptr->write_count()); + + // Prefs should not be read again. + EXPECT_EQ(1u, prefs_delegate_ptr->read_count()); + + manager.ShutdownOnPrefSequence(); +} + +TEST(NetworkQualitiesPrefManager, WriteWhenMatchingExpectedECT) { + // Force set the ECT to Slow 2G so that the ECT does not match the default + // ECT for the current connection type. This forces the prefs to be written + // for the current connection. + std::map<std::string, std::string> variation_params; + variation_params["force_effective_connection_type"] = "Slow-2G"; + TestNetworkQualityEstimator estimator(variation_params); + + std::unique_ptr<TestPrefDelegate> prefs_delegate(new TestPrefDelegate()); + TestPrefDelegate* prefs_delegate_ptr = prefs_delegate.get(); + + NetworkQualitiesPrefsManager manager(std::move(prefs_delegate)); + manager.InitializeOnNetworkThread(&estimator); + base::RunLoop().RunUntilIdle(); + + // Prefs must be read at when NetworkQualitiesPrefsManager is constructed. + EXPECT_EQ(1u, prefs_delegate_ptr->read_count()); + + const nqe::internal::NetworkID network_id( + NetworkChangeNotifier::ConnectionType::CONNECTION_4G, "test", INT32_MIN); + + estimator.SimulateNetworkChange(network_id.type, network_id.id); + EXPECT_EQ(1u, prefs_delegate_ptr->write_count()); + // Network quality generated from the default observation must be written. + base::RunLoop().RunUntilIdle(); EXPECT_EQ(3u, prefs_delegate_ptr->write_count()); + estimator.set_recent_effective_connection_type(EFFECTIVE_CONNECTION_TYPE_2G); + // Run a request so that effective connection type is recomputed, and + // observers are notified of change in the network quality. + estimator.RunOneRequest(); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(4u, prefs_delegate_ptr->write_count()); + + estimator.set_recent_effective_connection_type(EFFECTIVE_CONNECTION_TYPE_3G); + // Run a request so that effective connection type is recomputed, and + // observers are notified of change in the network quality.. + estimator.RunOneRequest(); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(5u, prefs_delegate_ptr->write_count()); + // Prefs should not be read again. EXPECT_EQ(1u, prefs_delegate_ptr->read_count()); + EXPECT_EQ(2u, manager.ForceReadPrefsForTesting().size()); + EXPECT_EQ(EFFECTIVE_CONNECTION_TYPE_3G, + manager.ForceReadPrefsForTesting() + .find(network_id) + ->second.effective_connection_type()); + + estimator.set_recent_effective_connection_type(EFFECTIVE_CONNECTION_TYPE_4G); + estimator.RunOneRequest(); + base::RunLoop().RunUntilIdle(); + + // Cached network quality for |network_id| should be deleted from the prefs + // since the expected network quality for |network_id| matches the observed + // network quality. + EXPECT_EQ(1u, manager.ForceReadPrefsForTesting().size()); + EXPECT_EQ(0u, manager.ForceReadPrefsForTesting().count(network_id)); + EXPECT_EQ(6u, prefs_delegate_ptr->write_count()); + manager.ShutdownOnPrefSequence(); } TEST(NetworkQualitiesPrefManager, WriteAndReadWithMultipleNetworkIDs) { - static const size_t kMaxCacheSize = 10u; - TestNetworkQualityEstimator estimator; + static const size_t kMaxCacheSize = 20u; + + // Force set the ECT to Slow 2G so that the ECT does not match the default + // ECT for the current connection type. This forces the prefs to be written + // for the current connection. + std::map<std::string, std::string> variation_params; + variation_params["force_effective_connection_type"] = "Slow-2G"; + TestNetworkQualityEstimator estimator(variation_params); std::unique_ptr<TestPrefDelegate> prefs_delegate(new TestPrefDelegate()); @@ -126,7 +202,7 @@ TEST(NetworkQualitiesPrefManager, WriteAndReadWithMultipleNetworkIDs) { estimator.SimulateNetworkChange( NetworkChangeNotifier::ConnectionType::CONNECTION_2G, "test"); - EXPECT_EQ(0u, manager.ForceReadPrefsForTesting().size()); + EXPECT_EQ(1u, manager.ForceReadPrefsForTesting().size()); estimator.set_recent_effective_connection_type( EFFECTIVE_CONNECTION_TYPE_SLOW_2G); @@ -136,7 +212,7 @@ TEST(NetworkQualitiesPrefManager, WriteAndReadWithMultipleNetworkIDs) { base::RunLoop().RunUntilIdle(); // Verify that the observer was notified, and the updated network quality was // written to the prefs. - EXPECT_EQ(1u, manager.ForceReadPrefsForTesting().size()); + EXPECT_EQ(2u, manager.ForceReadPrefsForTesting().size()); // Change the network ID. for (size_t i = 0; i < kMaxCacheSize; ++i) { @@ -147,7 +223,7 @@ TEST(NetworkQualitiesPrefManager, WriteAndReadWithMultipleNetworkIDs) { estimator.RunOneRequest(); base::RunLoop().RunUntilIdle(); - EXPECT_EQ(std::min(i + 2, kMaxCacheSize), + EXPECT_EQ(std::min(i + 3, kMaxCacheSize), manager.ForceReadPrefsForTesting().size()); } @@ -155,17 +231,27 @@ TEST(NetworkQualitiesPrefManager, WriteAndReadWithMultipleNetworkIDs) { read_prefs = manager.ForceReadPrefsForTesting(); // Verify the contents of the prefs. + size_t count_2g_entries = 0; for (std::map<nqe::internal::NetworkID, nqe::internal::CachedNetworkQuality>::const_iterator it = read_prefs.begin(); it != read_prefs.end(); ++it) { + if (it->first.type == + NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN) { + continue; + } EXPECT_EQ(0u, it->first.id.find("test", 0u)); EXPECT_EQ(NetworkChangeNotifier::ConnectionType::CONNECTION_2G, it->first.type); EXPECT_EQ(EFFECTIVE_CONNECTION_TYPE_SLOW_2G, it->second.effective_connection_type()); + ++count_2g_entries; } + // At most one entry should be for the network with connection type + // NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN. + EXPECT_LE(kMaxCacheSize - 1, count_2g_entries); + base::HistogramTester histogram_tester; estimator.OnPrefsRead(read_prefs); histogram_tester.ExpectUniqueSample("NQE.Prefs.ReadSize", kMaxCacheSize, 1); @@ -175,7 +261,12 @@ TEST(NetworkQualitiesPrefManager, WriteAndReadWithMultipleNetworkIDs) { // Verifies that the prefs are cleared correctly. TEST(NetworkQualitiesPrefManager, ClearPrefs) { - TestNetworkQualityEstimator estimator; + // Force set the ECT to Slow 2G so that the ECT does not match the default + // ECT for the current connection type. This forces the prefs to be written + // for the current connection. + std::map<std::string, std::string> variation_params; + variation_params["force_effective_connection_type"] = "Slow-2G"; + TestNetworkQualityEstimator estimator(variation_params); std::unique_ptr<TestPrefDelegate> prefs_delegate(new TestPrefDelegate()); @@ -186,7 +277,7 @@ TEST(NetworkQualitiesPrefManager, ClearPrefs) { estimator.SimulateNetworkChange( NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN, "test"); - EXPECT_EQ(0u, manager.ForceReadPrefsForTesting().size()); + EXPECT_EQ(1u, manager.ForceReadPrefsForTesting().size()); estimator.set_recent_effective_connection_type( EFFECTIVE_CONNECTION_TYPE_SLOW_2G); @@ -196,7 +287,7 @@ TEST(NetworkQualitiesPrefManager, ClearPrefs) { base::RunLoop().RunUntilIdle(); // Verify that the observer was notified, and the updated network quality was // written to the prefs. - EXPECT_EQ(1u, manager.ForceReadPrefsForTesting().size()); + EXPECT_EQ(2u, manager.ForceReadPrefsForTesting().size()); // Prefs must be completely cleared. manager.ClearPrefs(); diff --git a/chromium/net/nqe/network_quality.cc b/chromium/net/nqe/network_quality.cc index cff98ab81a3..d9f23182702 100644 --- a/chromium/net/nqe/network_quality.cc +++ b/chromium/net/nqe/network_quality.cc @@ -13,7 +13,10 @@ base::TimeDelta InvalidRTT() { } NetworkQuality::NetworkQuality() - : NetworkQuality(InvalidRTT(), InvalidRTT(), INVALID_RTT_THROUGHPUT) {} + : NetworkQuality(InvalidRTT(), InvalidRTT(), INVALID_RTT_THROUGHPUT) { + VerifyValueCorrectness(); + DETACH_FROM_SEQUENCE(sequence_checker_); +} NetworkQuality::NetworkQuality(const base::TimeDelta& http_rtt, const base::TimeDelta& transport_rtt, @@ -21,13 +24,17 @@ NetworkQuality::NetworkQuality(const base::TimeDelta& http_rtt, : http_rtt_(http_rtt), transport_rtt_(transport_rtt), downstream_throughput_kbps_(downstream_throughput_kbps) { - DCHECK_GE(downstream_throughput_kbps_, INVALID_RTT_THROUGHPUT); + VerifyValueCorrectness(); + DETACH_FROM_SEQUENCE(sequence_checker_); } NetworkQuality::NetworkQuality(const NetworkQuality& other) : NetworkQuality(other.http_rtt_, other.transport_rtt_, - other.downstream_throughput_kbps_) {} + other.downstream_throughput_kbps_) { + VerifyValueCorrectness(); + DETACH_FROM_SEQUENCE(sequence_checker_); +} NetworkQuality::~NetworkQuality() = default; @@ -35,16 +42,20 @@ NetworkQuality& NetworkQuality::operator=(const NetworkQuality& other) { http_rtt_ = other.http_rtt_; transport_rtt_ = other.transport_rtt_; downstream_throughput_kbps_ = other.downstream_throughput_kbps_; + VerifyValueCorrectness(); + DETACH_FROM_SEQUENCE(sequence_checker_); return *this; } bool NetworkQuality::operator==(const NetworkQuality& other) const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); return http_rtt_ == other.http_rtt_ && transport_rtt_ == other.transport_rtt_ && downstream_throughput_kbps_ == other.downstream_throughput_kbps_; } bool NetworkQuality::IsFaster(const NetworkQuality& other) const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); return (http_rtt() == InvalidRTT() || other.http_rtt() == InvalidRTT() || http_rtt() <= other.http_rtt()) && (transport_rtt() == InvalidRTT() || @@ -55,6 +66,13 @@ bool NetworkQuality::IsFaster(const NetworkQuality& other) const { downstream_throughput_kbps() >= other.downstream_throughput_kbps()); } +void NetworkQuality::VerifyValueCorrectness() const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK_LE(INVALID_RTT_THROUGHPUT, http_rtt_.InMilliseconds()); + DCHECK_LE(INVALID_RTT_THROUGHPUT, transport_rtt_.InMilliseconds()); + DCHECK_LE(INVALID_RTT_THROUGHPUT, downstream_throughput_kbps_); +} + } // namespace internal } // namespace nqe } // namespace net diff --git a/chromium/net/nqe/network_quality.h b/chromium/net/nqe/network_quality.h index 73afb69fd63..de9d275b81d 100644 --- a/chromium/net/nqe/network_quality.h +++ b/chromium/net/nqe/network_quality.h @@ -9,6 +9,7 @@ #include "base/gtest_prod_util.h" #include "base/macros.h" +#include "base/sequence_checker.h" #include "base/time/time.h" #include "net/base/net_export.h" @@ -53,28 +54,46 @@ class NET_EXPORT_PRIVATE NetworkQuality { bool IsFaster(const NetworkQuality& other) const; // Returns the estimate of the round trip time at the HTTP layer. - const base::TimeDelta& http_rtt() const { return http_rtt_; } + const base::TimeDelta& http_rtt() const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + return http_rtt_; + } - void set_http_rtt(const base::TimeDelta& http_rtt) { http_rtt_ = http_rtt; } + void set_http_rtt(base::TimeDelta http_rtt) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + http_rtt_ = http_rtt; + DCHECK_LE(INVALID_RTT_THROUGHPUT, http_rtt_.InMilliseconds()); + } // Returns the estimate of the round trip time at the transport layer. - const base::TimeDelta& transport_rtt() const { return transport_rtt_; } + const base::TimeDelta& transport_rtt() const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + return transport_rtt_; + } - void set_transport_rtt(const base::TimeDelta& transport_rtt) { + void set_transport_rtt(base::TimeDelta transport_rtt) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); transport_rtt_ = transport_rtt; + DCHECK_LE(INVALID_RTT_THROUGHPUT, transport_rtt_.InMilliseconds()); } // Returns the estimate of the downstream throughput in Kbps (Kilobits per // second). int32_t downstream_throughput_kbps() const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); return downstream_throughput_kbps_; } void set_downstream_throughput_kbps(int32_t downstream_throughput_kbps) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); downstream_throughput_kbps_ = downstream_throughput_kbps; + DCHECK_LE(INVALID_RTT_THROUGHPUT, downstream_throughput_kbps_); } private: + // Verifies that the value of network quality is within the expected range. + void VerifyValueCorrectness() const; + // Estimated round trip time at the HTTP layer. base::TimeDelta http_rtt_; @@ -83,6 +102,8 @@ class NET_EXPORT_PRIVATE NetworkQuality { // Estimated downstream throughput in kilobits per second. int32_t downstream_throughput_kbps_; + + SEQUENCE_CHECKER(sequence_checker_); }; } // namespace internal diff --git a/chromium/net/nqe/network_quality_estimator.cc b/chromium/net/nqe/network_quality_estimator.cc index 096398863a5..ff218942cf1 100644 --- a/chromium/net/nqe/network_quality_estimator.cc +++ b/chromium/net/nqe/network_quality_estimator.cc @@ -14,9 +14,8 @@ #include "base/logging.h" #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/sparse_histogram.h" -#include "base/rand_util.h" #include "base/single_thread_task_runner.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_piece.h" @@ -52,22 +51,6 @@ class HostResolver; namespace { -// Returns the histogram that should be used to record the given statistic. -// |max_limit| is the maximum value that can be stored in the histogram. -base::HistogramBase* GetHistogram(const std::string& statistic_name, - NetworkChangeNotifier::ConnectionType type, - int32_t max_limit) { - const base::LinearHistogram::Sample kLowerLimit = 1; - DCHECK_GT(max_limit, kLowerLimit); - const size_t kBucketCount = 50; - - return base::Histogram::FactoryGet( - "NQE." + statistic_name + - NetworkQualityEstimatorParams::GetNameForConnectionType(type), - kLowerLimit, max_limit, kBucketCount, - base::HistogramBase::kUmaTargetedHistogramFlag); -} - NetworkQualityObservationSource ProtocolSourceToObservationSource( SocketPerformanceWatcherFactory::Protocol protocol) { switch (protocol) { @@ -124,40 +107,6 @@ const char* GetHistogramSuffixObservedThroughput( return kSuffixes[arraysize(kSuffixes) - 1]; } -// The least significant kTrimBits of the metric will be discarded. If the -// trimmed metric value is greater than what can be fit in kBitsPerMetric bits, -// then the largest value that can be represented in kBitsPerMetric bits is -// returned. -const int32_t kTrimBits = 5; - -// Maximum number of bits in which one metric should fit. Restricting the amount -// of space allocated to a single metric makes it possile to fit multiple -// metrics in a single histogram sample, and ensures that all those metrics -// are recorded together as a single tuple. -const int32_t kBitsPerMetric = 7; - -static_assert(32 >= kBitsPerMetric * 4, - "Four metrics would not fit in a 32-bit int"); - -// Trims the |metric| by removing the last kTrimBits, and then rounding down -// the |metric| such that the |metric| fits in kBitsPerMetric. -int32_t FitInKBitsPerMetricBits(int32_t metric) { - // Remove the last kTrimBits. This will allow the metric to fit within - // kBitsPerMetric while losing only the least significant bits. - DCHECK_LE(0, metric); - metric = metric >> kTrimBits; - - // kLargestValuePossible is the largest value that can be recorded using - // kBitsPerMetric. - static const int32_t kLargestValuePossible = (1 << kBitsPerMetric) - 1; - if (metric > kLargestValuePossible) { - // Fit |metric| in kBitsPerMetric by clamping it down. - metric = kLargestValuePossible; - } - DCHECK_EQ(0, metric >> kBitsPerMetric) << metric; - return metric; -} - void RecordRTTAccuracy(base::StringPiece prefix, int32_t metric, base::TimeDelta measuring_duration, @@ -218,24 +167,25 @@ NetworkQualityEstimator::NetworkQualityEstimator( : params_(std::move(params)), use_localhost_requests_(false), disable_offline_check_(false), - tick_clock_(new base::DefaultTickClock()), + tick_clock_(base::DefaultTickClock::GetInstance()), last_connection_change_(tick_clock_->NowTicks()), current_network_id_(nqe::internal::NetworkID( NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN, - std::string())), + std::string(), + INT32_MIN)), http_downstream_throughput_kbps_observations_( params_.get(), - tick_clock_.get(), + tick_clock_, params_->weight_multiplier_per_second(), params_->weight_multiplier_per_signal_strength_level()), http_rtt_ms_observations_( params_.get(), - tick_clock_.get(), + tick_clock_, params_->weight_multiplier_per_second(), params_->weight_multiplier_per_signal_strength_level()), transport_rtt_ms_observations_( params_.get(), - tick_clock_.get(), + tick_clock_, params_->weight_multiplier_per_second(), params_->weight_multiplier_per_signal_strength_level()), effective_connection_type_at_last_main_frame_( @@ -271,7 +221,7 @@ NetworkQualityEstimator::NetworkQualityEstimator( this, params_.get(), base::ThreadTaskRunnerHandle::Get(), base::Bind(&NetworkQualityEstimator::OnNewThroughputObservationAvailable, base::Unretained(this)), - tick_clock_.get(), net_log_)); + tick_clock_, net_log_)); watcher_factory_.reset(new nqe::internal::SocketWatcherFactory( base::ThreadTaskRunnerHandle::Get(), @@ -280,7 +230,7 @@ NetworkQualityEstimator::NetworkQualityEstimator( base::Unretained(this)), base::Bind(&NetworkQualityEstimator::ShouldSocketWatcherNotifyRTT, base::Unretained(this)), - tick_clock_.get())); + tick_clock_)); // Record accuracy after a 15 second interval. The values used here must // remain in sync with the suffixes specified in @@ -378,6 +328,45 @@ void NetworkQualityEstimator::NotifyStartTransaction( throughput_analyzer_->NotifyStartTransaction(request); } +bool NetworkQualityEstimator::IsHangingRequest( + base::TimeDelta observed_http_rtt) const { + DCHECK(thread_checker_.CalledOnValidThread()); + + if (transport_rtt_observation_count_last_ect_computation_ >= + params_->http_rtt_transport_rtt_min_count() && + (params_->hanging_request_http_rtt_upper_bound_transport_rtt_multiplier() <= + 0 || + observed_http_rtt < + params_->hanging_request_http_rtt_upper_bound_transport_rtt_multiplier() * + GetTransportRTT().value_or(base::TimeDelta::FromSeconds(10)))) { + // If there are sufficient number of transport RTT samples available, use + // the transport RTT estimate to determine if the request is hanging. + UMA_HISTOGRAM_TIMES("NQE.RTT.NotAHangingRequest.TransportRTT", + observed_http_rtt); + return false; + } + + if (params_->hanging_request_http_rtt_upper_bound_http_rtt_multiplier() <= + 0 || + observed_http_rtt < + params_->hanging_request_http_rtt_upper_bound_http_rtt_multiplier() * + GetHttpRTT().value_or(base::TimeDelta::FromSeconds(10))) { + // Use the HTTP RTT estimate to determine if the request is hanging. + UMA_HISTOGRAM_TIMES("NQE.RTT.NotAHangingRequest.HttpRTT", + observed_http_rtt); + return false; + } + + if (observed_http_rtt <= + params_->hanging_request_upper_bound_min_http_rtt()) { + UMA_HISTOGRAM_TIMES("NQE.RTT.NotAHangingRequest.MinHttpBound", + observed_http_rtt); + return false; + } + UMA_HISTOGRAM_TIMES("NQE.RTT.HangingRequest", observed_http_rtt); + return true; +} + void NetworkQualityEstimator::NotifyHeadersReceived(const URLRequest& request) { TRACE_EVENT0(kNetTracingCategory, "NetworkQualityEstimator::NotifyHeadersReceived"); @@ -412,8 +401,13 @@ void NetworkQualityEstimator::NotifyHeadersReceived(const URLRequest& request) { if (observed_http_rtt <= base::TimeDelta()) return; DCHECK_GE(observed_http_rtt, base::TimeDelta()); + + if (IsHangingRequest(observed_http_rtt)) + return; + Observation http_rtt_observation(observed_http_rtt.InMilliseconds(), - tick_clock_->NowTicks(), signal_strength_, + tick_clock_->NowTicks(), + current_network_id_.signal_strength, NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP); AddAndNotifyObserversOfRTT(http_rtt_observation); throughput_analyzer_->NotifyBytesRead(request); @@ -532,107 +526,6 @@ void NetworkQualityEstimator::NotifyRequestCompleted(const URLRequest& request, return; throughput_analyzer_->NotifyRequestCompleted(request); - RecordCorrelationMetric(request, net_error); -} - -void NetworkQualityEstimator::RecordCorrelationMetric(const URLRequest& request, - int net_error) const { - DCHECK(thread_checker_.CalledOnValidThread()); - - // The histogram is recorded randomly to reduce overhead involved with sparse - // histograms. Furthermore, recording the correlation on each request is - // unnecessary. - if (RandDouble() >= params_->correlation_uma_logging_probability()) - return; - - if (request.response_info().was_cached || - !request.response_info().network_accessed) { - return; - } - - LoadTimingInfo load_timing_info; - request.GetLoadTimingInfo(&load_timing_info); - // If the load timing info is unavailable, it probably means that the request - // did not go over the network. - if (load_timing_info.send_start.is_null() || - load_timing_info.receive_headers_end.is_null()) { - return; - } - - // Record UMA only for successful requests that have completed. - if (net_error != OK) - return; - if (!request.response_info().headers.get() || - request.response_info().headers->response_code() != HTTP_OK) { - return; - } - if (load_timing_info.receive_headers_end < last_main_frame_request_) - return; - - // Use the system clock instead of |tick_clock_| to compare the current - // timestamp with the |load_timing_info| timestamp since the latter is set by - // the system clock, and may be different from |tick_clock_| in tests. - const base::TimeTicks now = base::TimeTicks::Now(); - // Record UMA only for requests that started recently. - if (now - last_main_frame_request_ > base::TimeDelta::FromSeconds(15)) - return; - - if (last_connection_change_ >= last_main_frame_request_) - return; - - DCHECK_GE(now, load_timing_info.send_start); - - int32_t rtt = 0; - - if (estimated_quality_at_last_main_frame_.downstream_throughput_kbps() == - nqe::internal::INVALID_RTT_THROUGHPUT) { - return; - } - - if (UseTransportRTT()) { - if (estimated_quality_at_last_main_frame_.transport_rtt() == - nqe::internal::InvalidRTT()) { - return; - } - rtt = FitInKBitsPerMetricBits( - estimated_quality_at_last_main_frame_.transport_rtt().InMilliseconds()); - } else { - if (estimated_quality_at_last_main_frame_.http_rtt() == - nqe::internal::InvalidRTT()) { - return; - } - rtt = FitInKBitsPerMetricBits( - estimated_quality_at_last_main_frame_.http_rtt().InMilliseconds()); - } - - const int32_t downstream_throughput = FitInKBitsPerMetricBits( - estimated_quality_at_last_main_frame_.downstream_throughput_kbps()); - - const int32_t resource_load_time = FitInKBitsPerMetricBits( - (now - load_timing_info.send_start).InMilliseconds()); - - int64_t resource_size = (request.GetTotalReceivedBytes() * 8) / 1024; - if (resource_size >= (1 << kBitsPerMetric)) { - // Too large resource size (at least 128 Kb). - return; - } - - DCHECK_EQ( - 0, (rtt | downstream_throughput | resource_load_time | resource_size) >> - kBitsPerMetric); - - // First 32 - (4* kBitsPerMetric) of the sample are unset. Next - // kBitsPerMetric of the sample contain |rtt|. Next - // kBitsPerMetric contain |downstream_throughput|. Next kBitsPerMetric - // contain |resource_load_time|. And, the last kBitsPerMetric - // contain |resource_size|. - int32_t sample = rtt; - sample = (sample << kBitsPerMetric) | downstream_throughput; - sample = (sample << kBitsPerMetric) | resource_load_time; - sample = (sample << kBitsPerMetric) | resource_size; - - UMA_HISTOGRAM_SPARSE_SLOWLY("NQE.Correlation.ResourceLoadTime.0Kb_128Kb", - sample); } void NetworkQualityEstimator::NotifyURLRequestDestroyed( @@ -693,7 +586,6 @@ void NetworkQualityEstimator::DisableOfflineCheckForTesting( bool disable_offline_check) { DCHECK(thread_checker_.CalledOnValidThread()); disable_offline_check_ = disable_offline_check; - network_quality_store_->DisableOfflineCheckForTesting(disable_offline_check_); } void NetworkQualityEstimator::ReportEffectiveConnectionTypeForTesting( @@ -751,8 +643,6 @@ void NetworkQualityEstimator::OnConnectionTypeChanged( NetworkChangeNotifier::ConnectionType type) { DCHECK(thread_checker_.CalledOnValidThread()); - RecordMetricsOnConnectionTypeChanged(); - // Write the estimates of the previous network to the cache. network_quality_store_->Add( current_network_id_, nqe::internal::CachedNetworkQuality( @@ -785,7 +675,7 @@ void NetworkQualityEstimator::OnConnectionTypeChanged( } } #endif // OS_ANDROID - signal_strength_.reset(); + current_network_id_.signal_strength = INT32_MIN; min_signal_strength_since_connection_change_.reset(); max_signal_strength_since_connection_change_.reset(); network_quality_ = nqe::internal::NetworkQuality(); @@ -811,12 +701,15 @@ void NetworkQualityEstimator::GatherEstimatesForNextConnectionType() { current_network_id_ = GetCurrentNetworkID(); RecordNetworkIDAvailability(); - MaybeQueryExternalEstimateProvider(); - // Read any cached estimates for the new network. If cached estimates are // unavailable, add the default estimates. if (!ReadCachedNetworkQualityEstimate()) AddDefaultEstimates(); + + // Query external estimate later since cached estimate has a higher priority, + // and if a cached estimate was available, there is no need to query the + // external estimate provider. + MaybeQueryExternalEstimateProvider(); ComputeEffectiveConnectionType(); } @@ -841,74 +734,52 @@ void NetworkQualityEstimator::MaybeQueryExternalEstimateProvider() const { external_estimate_provider_->Update(); } -void NetworkQualityEstimator::UpdateSignalStrength() { +int32_t NetworkQualityEstimator::GetCurrentSignalStrength() const { DCHECK(thread_checker_.CalledOnValidThread()); - signal_strength_.reset(); #if defined(OS_ANDROID) if (params_->weight_multiplier_per_signal_strength_level() >= 1.0) - return; + return INT32_MIN; if (!NetworkChangeNotifier::IsConnectionCellular(current_network_id_.type)) - return; + return INT32_MIN; + return android::cellular_signal_strength::GetSignalStrengthLevel().value_or( + INT32_MIN); +#endif // OS_ANDROID + + return INT32_MIN; +} + +void NetworkQualityEstimator::UpdateSignalStrength() { + DCHECK(thread_checker_.CalledOnValidThread()); - signal_strength_ = - android::cellular_signal_strength::GetSignalStrengthLevel(); + int32_t past_signal_strength = current_network_id_.signal_strength; + int32_t new_signal_strength = GetCurrentSignalStrength(); - if (!signal_strength_) + // Check if there is no change in the signal strength. + if (past_signal_strength == new_signal_strength) return; + // Check if the signal strength is unavailable. + if (new_signal_strength == INT32_MIN) + return; + + // Record the network quality we experienced for the previous signal strength + // (for when we return to that signal strength). + network_quality_store_->Add(current_network_id_, + nqe::internal::CachedNetworkQuality( + tick_clock_->NowTicks(), network_quality_, + effective_connection_type_)); + + current_network_id_.signal_strength = new_signal_strength; + // Update network quality from cached value for new signal strength. + ReadCachedNetworkQualityEstimate(); + min_signal_strength_since_connection_change_ = std::min(min_signal_strength_since_connection_change_.value_or(INT32_MAX), - signal_strength_.value()); + current_network_id_.signal_strength); max_signal_strength_since_connection_change_ = std::max(max_signal_strength_since_connection_change_.value_or(INT32_MIN), - signal_strength_.value()); -#endif // OS_ANDROID -} - -void NetworkQualityEstimator::RecordMetricsOnConnectionTypeChanged() const { - DCHECK(thread_checker_.CalledOnValidThread()); - base::TimeDelta rtt; - if (GetRecentHttpRTT(base::TimeTicks(), &rtt)) { - // Add the 50th percentile value. - base::HistogramBase* rtt_percentile = - GetHistogram("RTT.Percentile50.", current_network_id_.type, 10 * 1000); - rtt_percentile->Add(rtt.InMilliseconds()); - - // Add the remaining percentile values. - static const int kPercentiles[] = {0, 10, 90, 100}; - for (size_t i = 0; i < arraysize(kPercentiles); ++i) { - rtt = GetRTTEstimateInternal( - base::TimeTicks(), base::Optional<Statistic>(), - nqe::internal::ObservationCategory::kHttp, kPercentiles[i], nullptr); - - rtt_percentile = GetHistogram( - "RTT.Percentile" + base::IntToString(kPercentiles[i]) + ".", - current_network_id_.type, 10 * 1000); // 10 seconds - rtt_percentile->Add(rtt.InMilliseconds()); - } - } - - if (GetRecentTransportRTT(base::TimeTicks(), &rtt, nullptr)) { - // Add the 50th percentile value. - base::HistogramBase* transport_rtt_percentile = GetHistogram( - "TransportRTT.Percentile50.", current_network_id_.type, 10 * 1000); - transport_rtt_percentile->Add(rtt.InMilliseconds()); - - // Add the remaining percentile values. - static const int kPercentiles[] = {0, 10, 90, 100}; - for (size_t i = 0; i < arraysize(kPercentiles); ++i) { - rtt = - GetRTTEstimateInternal(base::TimeTicks(), base::Optional<Statistic>(), - nqe::internal::ObservationCategory::kTransport, - kPercentiles[i], nullptr); - - transport_rtt_percentile = GetHistogram( - "TransportRTT.Percentile" + base::IntToString(kPercentiles[i]) + ".", - current_network_id_.type, 10 * 1000); // 10 seconds - transport_rtt_percentile->Add(rtt.InMilliseconds()); - } - } + current_network_id_.signal_strength); } void NetworkQualityEstimator::RecordNetworkIDAvailability() const { @@ -1264,22 +1135,16 @@ NetworkQualityEstimator::GetRecentEffectiveConnectionTypeUsingMetrics( *transport_rtt = nqe::internal::InvalidRTT(); *downstream_throughput_kbps = nqe::internal::INVALID_RTT_THROUGHPUT; - if (params_->forced_effective_connection_type()) { - *http_rtt = params_ - ->TypicalNetworkQuality( - params_->forced_effective_connection_type().value()) - .http_rtt(); + auto forced_ect = + params_->GetForcedEffectiveConnectionType(current_network_id_.type); + if (forced_ect) { + *http_rtt = params_->TypicalNetworkQuality(forced_ect.value()).http_rtt(); *transport_rtt = - params_ - ->TypicalNetworkQuality( - params_->forced_effective_connection_type().value()) - .transport_rtt(); + params_->TypicalNetworkQuality(forced_ect.value()).transport_rtt(); *downstream_throughput_kbps = - params_ - ->TypicalNetworkQuality( - params_->forced_effective_connection_type().value()) + params_->TypicalNetworkQuality(forced_ect.value()) .downstream_throughput_kbps(); - return params_->forced_effective_connection_type().value(); + return forced_ect.value(); } // If the device is currently offline, then return @@ -1301,7 +1166,8 @@ NetworkQualityEstimator::GetRecentEffectiveConnectionTypeUsingMetrics( *transport_rtt != nqe::internal::InvalidRTT()) { // Use transport RTT to clamp the HTTP RTT between lower and upper bounds. // To improve accuracy, the transport RTT estimate is used only when the - // transport RTT estimate was computed using at least 5 observations. + // transport RTT estimate was computed using at least + // |params_->http_rtt_transport_rtt_min_count()| observations. if (transport_rtt_observation_count_last_ect_computation_ >= params_->http_rtt_transport_rtt_min_count()) { if (params_->lower_bound_http_rtt_transport_rtt_multiplier() > 0) { @@ -1475,14 +1341,14 @@ base::TimeDelta NetworkQualityEstimator::GetRTTEstimateInternal( case nqe::internal::ObservationCategory::kHttp: return base::TimeDelta::FromMilliseconds( http_rtt_ms_observations_ - .GetPercentile(start_time, signal_strength_, percentile, - observations_count) + .GetPercentile(start_time, current_network_id_.signal_strength, + percentile, observations_count) .value_or(nqe::internal::INVALID_RTT_THROUGHPUT)); case nqe::internal::ObservationCategory::kTransport: return base::TimeDelta::FromMilliseconds( transport_rtt_ms_observations_ - .GetPercentile(start_time, signal_strength_, percentile, - observations_count) + .GetPercentile(start_time, current_network_id_.signal_strength, + percentile, observations_count) .value_or(nqe::internal::INVALID_RTT_THROUGHPUT)); } } @@ -1506,7 +1372,8 @@ int32_t NetworkQualityEstimator::GetDownlinkThroughputKbpsEstimateInternal( // Throughput observations are sorted by kbps from slowest to fastest, // thus a higher percentile throughput will be faster than a lower one. return http_downstream_throughput_kbps_observations_ - .GetPercentile(start_time, signal_strength_, 100 - percentile, nullptr) + .GetPercentile(start_time, current_network_id_.signal_strength, + 100 - percentile, nullptr) .value_or(nqe::internal::INVALID_RTT_THROUGHPUT); } @@ -1524,7 +1391,7 @@ nqe::internal::NetworkID NetworkQualityEstimator::GetCurrentNetworkID() const { // (that are approximate to begin with). while (true) { nqe::internal::NetworkID network_id( - NetworkChangeNotifier::GetConnectionType(), std::string()); + NetworkChangeNotifier::GetConnectionType(), std::string(), INT32_MIN); switch (network_id.type) { case NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN: @@ -1561,56 +1428,79 @@ bool NetworkQualityEstimator::ReadCachedNetworkQualityEstimate() { if (!params_->persistent_cache_reading_enabled()) return false; - if (current_network_id_.type != - NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI && - current_network_id_.type != - NetworkChangeNotifier::ConnectionType::CONNECTION_ETHERNET && - !disable_offline_check_) { - return false; - } - nqe::internal::CachedNetworkQuality cached_network_quality; const bool cached_estimate_available = network_quality_store_->GetById( current_network_id_, &cached_network_quality); - if (network_quality_store_->EligibleForCaching(current_network_id_)) { - UMA_HISTOGRAM_BOOLEAN("NQE.CachedNetworkQualityAvailable", - cached_estimate_available); - } + UMA_HISTOGRAM_BOOLEAN("NQE.CachedNetworkQualityAvailable", + cached_estimate_available); if (!cached_estimate_available) return false; + EffectiveConnectionType effective_connection_type = + cached_network_quality.effective_connection_type(); + + if (effective_connection_type == EFFECTIVE_CONNECTION_TYPE_UNKNOWN || + effective_connection_type == EFFECTIVE_CONNECTION_TYPE_OFFLINE || + effective_connection_type == EFFECTIVE_CONNECTION_TYPE_LAST) { + return false; + } + + nqe::internal::NetworkQuality network_quality = + cached_network_quality.network_quality(); + const base::TimeTicks now = tick_clock_->NowTicks(); - if (cached_network_quality.network_quality().downstream_throughput_kbps() != + bool update_network_quality_store = false; + + // Populate |network_quality| with synthetic RTT and throughput observations + // if they are missing. + if (network_quality.http_rtt().InMilliseconds() == nqe::internal::INVALID_RTT_THROUGHPUT) { - Observation througphput_observation( - cached_network_quality.network_quality().downstream_throughput_kbps(), - now, INT32_MIN, - NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP_CACHED_ESTIMATE); - AddAndNotifyObserversOfThroughput(througphput_observation); + network_quality.set_http_rtt( + params_->TypicalNetworkQuality(effective_connection_type).http_rtt()); + update_network_quality_store = true; } - if (cached_network_quality.network_quality().http_rtt() != - nqe::internal::InvalidRTT()) { - Observation rtt_observation( - cached_network_quality.network_quality().http_rtt().InMilliseconds(), - now, INT32_MIN, - NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP_CACHED_ESTIMATE); - AddAndNotifyObserversOfRTT(rtt_observation); + if (network_quality.transport_rtt().InMilliseconds() == + nqe::internal::INVALID_RTT_THROUGHPUT) { + network_quality.set_transport_rtt( + params_->TypicalNetworkQuality(effective_connection_type) + .transport_rtt()); + update_network_quality_store = true; } - if (cached_network_quality.network_quality().transport_rtt() != - nqe::internal::InvalidRTT()) { - Observation rtt_observation( - cached_network_quality.network_quality() - .transport_rtt() - .InMilliseconds(), - now, INT32_MIN, - NETWORK_QUALITY_OBSERVATION_SOURCE_TRANSPORT_CACHED_ESTIMATE); - AddAndNotifyObserversOfRTT(rtt_observation); + if (network_quality.downstream_throughput_kbps() == + nqe::internal::INVALID_RTT_THROUGHPUT) { + network_quality.set_downstream_throughput_kbps( + params_->TypicalNetworkQuality(effective_connection_type) + .downstream_throughput_kbps()); + update_network_quality_store = true; + } + + if (update_network_quality_store) { + network_quality_store_->Add( + current_network_id_, + nqe::internal::CachedNetworkQuality(now, network_quality, + effective_connection_type)); } + + Observation http_rtt_observation( + network_quality.http_rtt().InMilliseconds(), now, INT32_MIN, + NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP_CACHED_ESTIMATE); + AddAndNotifyObserversOfRTT(http_rtt_observation); + + Observation transport_rtt_observation( + network_quality.transport_rtt().InMilliseconds(), now, INT32_MIN, + NETWORK_QUALITY_OBSERVATION_SOURCE_TRANSPORT_CACHED_ESTIMATE); + AddAndNotifyObserversOfRTT(transport_rtt_observation); + + Observation througphput_observation( + network_quality.downstream_throughput_kbps(), now, INT32_MIN, + NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP_CACHED_ESTIMATE); + AddAndNotifyObserversOfThroughput(througphput_observation); + ComputeEffectiveConnectionType(); return true; } @@ -1631,7 +1521,8 @@ void NetworkQualityEstimator::OnUpdatedEstimateAvailable( EXTERNAL_ESTIMATE_PROVIDER_STATUS_RTT_AVAILABLE); UMA_HISTOGRAM_TIMES("NQE.ExternalEstimateProvider.RTT", rtt); Observation rtt_observation( - rtt.InMilliseconds(), tick_clock_->NowTicks(), signal_strength_, + rtt.InMilliseconds(), tick_clock_->NowTicks(), + current_network_id_.signal_strength, NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP_EXTERNAL_ESTIMATE); external_estimate_provider_quality_.set_http_rtt(rtt); AddAndNotifyObserversOfRTT(rtt_observation); @@ -1643,7 +1534,8 @@ void NetworkQualityEstimator::OnUpdatedEstimateAvailable( UMA_HISTOGRAM_COUNTS_1M("NQE.ExternalEstimateProvider.DownlinkBandwidth", downstream_throughput_kbps); Observation throughput_observation( - downstream_throughput_kbps, tick_clock_->NowTicks(), signal_strength_, + downstream_throughput_kbps, tick_clock_->NowTicks(), + current_network_id_.signal_strength, NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP_EXTERNAL_ESTIMATE); external_estimate_provider_quality_.set_downstream_throughput_kbps( downstream_throughput_kbps); @@ -1652,19 +1544,15 @@ void NetworkQualityEstimator::OnUpdatedEstimateAvailable( } void NetworkQualityEstimator::SetTickClockForTesting( - std::unique_ptr<base::TickClock> tick_clock) { + base::TickClock* tick_clock) { DCHECK(thread_checker_.CalledOnValidThread()); - tick_clock_ = std::move(tick_clock); - http_rtt_ms_observations_.SetTickClockForTesting(tick_clock_.get()); - transport_rtt_ms_observations_.SetTickClockForTesting(tick_clock_.get()); + tick_clock_ = tick_clock; + http_rtt_ms_observations_.SetTickClockForTesting(tick_clock_); + transport_rtt_ms_observations_.SetTickClockForTesting(tick_clock_); http_downstream_throughput_kbps_observations_.SetTickClockForTesting( - tick_clock_.get()); - throughput_analyzer_->SetTickClockForTesting(tick_clock_.get()); - watcher_factory_->SetTickClockForTesting(tick_clock_.get()); -} - -double NetworkQualityEstimator::RandDouble() const { - return base::RandDouble(); + tick_clock_); + throughput_analyzer_->SetTickClockForTesting(tick_clock_); + watcher_factory_->SetTickClockForTesting(tick_clock_); } void NetworkQualityEstimator::OnUpdatedTransportRTTAvailable( @@ -1672,10 +1560,10 @@ void NetworkQualityEstimator::OnUpdatedTransportRTTAvailable( const base::TimeDelta& rtt, const base::Optional<nqe::internal::IPHash>& host) { DCHECK(thread_checker_.CalledOnValidThread()); - DCHECK_NE(nqe::internal::InvalidRTT(), rtt); + DCHECK_LT(nqe::internal::INVALID_RTT_THROUGHPUT, rtt.InMilliseconds()); Observation observation(rtt.InMilliseconds(), tick_clock_->NowTicks(), - signal_strength_, + current_network_id_.signal_strength, ProtocolSourceToObservationSource(protocol), host); AddAndNotifyObserversOfRTT(observation); @@ -1778,7 +1666,7 @@ void NetworkQualityEstimator::OnNewThroughputObservationAvailable( DCHECK_NE(nqe::internal::INVALID_RTT_THROUGHPUT, downstream_kbps); Observation throughput_observation(downstream_kbps, tick_clock_->NowTicks(), - signal_strength_, + current_network_id_.signal_strength, NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP); AddAndNotifyObserversOfThroughput(throughput_observation); } diff --git a/chromium/net/nqe/network_quality_estimator.h b/chromium/net/nqe/network_quality_estimator.h index c00e1638ea2..343f735479b 100644 --- a/chromium/net/nqe/network_quality_estimator.h +++ b/chromium/net/nqe/network_quality_estimator.h @@ -214,6 +214,8 @@ class NET_EXPORT NetworkQualityEstimator const std::map<nqe::internal::NetworkID, nqe::internal::CachedNetworkQuality> read_prefs); + const NetworkQualityEstimatorParams* params() { return params_.get(); } + typedef nqe::internal::Observation Observation; typedef nqe::internal::ObservationBuffer ObservationBuffer; @@ -272,10 +274,7 @@ class NET_EXPORT NetworkQualityEstimator const; // Overrides the tick clock used by |this| for testing. - void SetTickClockForTesting(std::unique_ptr<base::TickClock> tick_clock); - - // Returns a random double in the range [0.0, 1.0). Virtualized for testing. - virtual double RandDouble() const; + void SetTickClockForTesting(base::TickClock* tick_clock); // Returns the effective type of the current connection based on only the // observations received after |start_time|. |http_rtt|, |transport_rtt| and @@ -342,10 +341,28 @@ class NET_EXPORT NetworkQualityEstimator // effective connection type. void AddAndNotifyObserversOfThroughput(const Observation& observation); + // Returns true if the request with observed HTTP of |observed_http_rtt| is + // expected to be a hanging request. The decision is made by comparing + // |observed_http_rtt| with the expected HTTP and transport RTT. + bool IsHangingRequest(base::TimeDelta observed_http_rtt) const; + base::Optional<int32_t> ComputeIncreaseInTransportRTTForTests() { return ComputeIncreaseInTransportRTT(); } + // Returns the current network signal strength by querying the platform APIs. + // Set to INT32_MIN when the value is unavailable. Otherwise, must be between + // 0 and 4 (both inclusive). This may take into account many different radio + // technology inputs. 0 represents very poor signal strength while 4 + // represents a very strong signal strength. The range is capped between 0 and + // 4 to ensure that a change in the value indicates a non-negligible change in + // the signal quality. + virtual int32_t GetCurrentSignalStrength() const; + + // Forces computation of effective connection type, and notifies observers + // if there is a change in its value. + void ComputeEffectiveConnectionType(); + // Observer list for RTT or throughput estimates. Protected for testing. base::ObserverList<RTTAndThroughputEstimatesObserver> rtt_and_throughput_estimates_observer_list_; @@ -408,9 +425,6 @@ class NET_EXPORT NetworkQualityEstimator // quality is available, OnUpdatedEstimateAvailable() is called. void MaybeQueryExternalEstimateProvider() const; - // Records UMA when there is a change in connection type. - void RecordMetricsOnConnectionTypeChanged() const; - // Records UMA on whether the NetworkID was available or not. Called right // after a network change event. void RecordNetworkIDAvailability() const; @@ -500,11 +514,6 @@ class NET_EXPORT NetworkQualityEstimator // Returns true if the cached network quality estimate was successfully read. bool ReadCachedNetworkQualityEstimate(); - // Records a correlation metric that can be used for computing the correlation - // between HTTP-layer RTT, transport-layer RTT, throughput and the time - // taken to complete |request|. - void RecordCorrelationMetric(const URLRequest& request, int net_error) const; - // Returns true if transport RTT should be used for computing the effective // connection type. bool UseTransportRTT() const; @@ -525,10 +534,6 @@ class NET_EXPORT NetworkQualityEstimator // Periodically updates |increase_in_transport_rtt_| by posting delayed tasks. void IncreaseInTransportRTTUpdater(); - // Forces computation of effective connection type, and notifies observers - // if there is a change in its value. - void ComputeEffectiveConnectionType(); - const char* GetNameForStatistic(int i) const; // Gathers metrics for the next connection type. Called when there is a change @@ -558,7 +563,7 @@ class NET_EXPORT NetworkQualityEstimator bool disable_offline_check_; // Tick clock used by the network quality estimator. - std::unique_ptr<base::TickClock> tick_clock_; + base::TickClock* tick_clock_; // Intervals after the main frame request arrives at which accuracy of network // quality prediction is recorded. @@ -651,11 +656,6 @@ class NET_EXPORT NetworkQualityEstimator // |effective_connection_type_recomputation_interval_| ago). EffectiveConnectionType effective_connection_type_; - // Last known value of the wireless signal strength level. If the signal - // strength level is available, the value is set to between 0 and 4, both - // inclusive. If the value is unavailable, |signal_strength_| has null value. - base::Optional<int32_t> signal_strength_; - // Minimum and maximum signal strength level observed since last connection // change. Updated on connection change and main frame requests. base::Optional<int32_t> min_signal_strength_since_connection_change_; diff --git a/chromium/net/nqe/network_quality_estimator_params.cc b/chromium/net/nqe/network_quality_estimator_params.cc index c393f54dd5a..28a9aaa9fb2 100644 --- a/chromium/net/nqe/network_quality_estimator_params.cc +++ b/chromium/net/nqe/network_quality_estimator_params.cc @@ -12,6 +12,15 @@ namespace net { const char kForceEffectiveConnectionType[] = "force_effective_connection_type"; +const char kEffectiveConnectionTypeSlow2GOnCellular[] = "Slow-2G-On-Cellular"; +const base::TimeDelta + kHttpRttEffectiveConnectionTypeThresholds[EFFECTIVE_CONNECTION_TYPE_LAST] = + {base::TimeDelta::FromMilliseconds(0), + base::TimeDelta::FromMilliseconds(0), + base::TimeDelta::FromMilliseconds(2010), + base::TimeDelta::FromMilliseconds(1420), + base::TimeDelta::FromMilliseconds(272), + base::TimeDelta::FromMilliseconds(0)}; namespace { @@ -164,7 +173,7 @@ void ObtainDefaultObservations( 74); default_observations[NetworkChangeNotifier::CONNECTION_3G] = - nqe::internal::NetworkQuality(base::TimeDelta::FromMilliseconds(272), + nqe::internal::NetworkQuality(base::TimeDelta::FromMilliseconds(273), base::TimeDelta::FromMilliseconds(209), 749); @@ -287,24 +296,35 @@ void ObtainConnectionThresholds( nqe::internal::NetworkQuality default_effective_connection_type_thresholds [EffectiveConnectionType::EFFECTIVE_CONNECTION_TYPE_LAST]; + DCHECK_LT(base::TimeDelta(), kHttpRttEffectiveConnectionTypeThresholds + [EFFECTIVE_CONNECTION_TYPE_SLOW_2G]); default_effective_connection_type_thresholds [EFFECTIVE_CONNECTION_TYPE_SLOW_2G] = nqe::internal::NetworkQuality( // Set to the 66th percentile of 2G RTT observations on Android. - base::TimeDelta::FromMilliseconds(2010), + kHttpRttEffectiveConnectionTypeThresholds + [EFFECTIVE_CONNECTION_TYPE_SLOW_2G], base::TimeDelta::FromMilliseconds(1870), nqe::internal::INVALID_RTT_THROUGHPUT); + DCHECK_LT( + base::TimeDelta(), + kHttpRttEffectiveConnectionTypeThresholds[EFFECTIVE_CONNECTION_TYPE_2G]); default_effective_connection_type_thresholds[EFFECTIVE_CONNECTION_TYPE_2G] = nqe::internal::NetworkQuality( // Set to the 50th percentile of RTT observations on Android. - base::TimeDelta::FromMilliseconds(1420), + kHttpRttEffectiveConnectionTypeThresholds + [EFFECTIVE_CONNECTION_TYPE_2G], base::TimeDelta::FromMilliseconds(1280), nqe::internal::INVALID_RTT_THROUGHPUT); + DCHECK_LT( + base::TimeDelta(), + kHttpRttEffectiveConnectionTypeThresholds[EFFECTIVE_CONNECTION_TYPE_3G]); default_effective_connection_type_thresholds[EFFECTIVE_CONNECTION_TYPE_3G] = nqe::internal::NetworkQuality( // Set to the 50th percentile of 3G RTT observations on Android. - base::TimeDelta::FromMilliseconds(273), + kHttpRttEffectiveConnectionTypeThresholds + [EFFECTIVE_CONNECTION_TYPE_3G], base::TimeDelta::FromMilliseconds(204), nqe::internal::INVALID_RTT_THROUGHPUT); @@ -354,10 +374,24 @@ void ObtainConnectionThresholds( } } -base::Optional<EffectiveConnectionType> GetForcedEffectiveConnectionType( +std::string GetForcedEffectiveConnectionTypeString( const std::map<std::string, std::string>& params) { - std::string forced_value = GetStringValueForVariationParamWithDefaultValue( + return GetStringValueForVariationParamWithDefaultValue( params, kForceEffectiveConnectionType, ""); +} + +bool GetForcedEffectiveConnectionTypeOnCellularOnly( + const std::map<std::string, std::string>& params) { + return GetForcedEffectiveConnectionTypeString(params) == + kEffectiveConnectionTypeSlow2GOnCellular; +} + +base::Optional<EffectiveConnectionType> GetInitForcedEffectiveConnectionType( + const std::map<std::string, std::string>& params) { + if (GetForcedEffectiveConnectionTypeOnCellularOnly(params)) { + return base::nullopt; + } + std::string forced_value = GetForcedEffectiveConnectionTypeString(params); base::Optional<EffectiveConnectionType> ect = GetEffectiveConnectionTypeForName(forced_value); DCHECK(forced_value.empty() || ect); @@ -377,19 +411,21 @@ NetworkQualityEstimatorParams::NetworkQualityEstimatorParams( GetValueForVariationParam(params_, "throughput_min_transfer_size_kilobytes", 32)), + throughput_hanging_requests_cwnd_size_multiplier_( + GetDoubleValueForVariationParamWithDefaultValue( + params_, + "throughput_hanging_requests_cwnd_size_multiplier", + -1)), weight_multiplier_per_second_(GetWeightMultiplierPerSecond(params_)), weight_multiplier_per_signal_strength_level_( GetDoubleValueForVariationParamWithDefaultValue( params_, "rssi_weight_per_signal_strength_level", 1.0)), - correlation_uma_logging_probability_( - GetDoubleValueForVariationParamWithDefaultValue( - params_, - "correlation_logging_probability", - 0.01)), forced_effective_connection_type_( - GetForcedEffectiveConnectionType(params_)), + GetInitForcedEffectiveConnectionType(params_)), + forced_effective_connection_type_on_cellular_only_( + GetForcedEffectiveConnectionTypeOnCellularOnly(params_)), persistent_cache_reading_enabled_( GetPersistentCacheReadingEnabled(params_)), min_socket_watcher_notification_interval_( @@ -398,12 +434,27 @@ NetworkQualityEstimatorParams::NetworkQualityEstimatorParams( GetDoubleValueForVariationParamWithDefaultValue( params_, "lower_bound_http_rtt_transport_rtt_multiplier", - -1)), + 1.0)), upper_bound_http_rtt_transport_rtt_multiplier_( GetDoubleValueForVariationParamWithDefaultValue( params_, "upper_bound_http_rtt_transport_rtt_multiplier", -1)), + hanging_request_http_rtt_upper_bound_transport_rtt_multiplier_( + GetValueForVariationParam( + params_, + "hanging_request_http_rtt_upper_bound_transport_rtt_multiplier", + -1)), + hanging_request_http_rtt_upper_bound_http_rtt_multiplier_( + GetValueForVariationParam( + params_, + "hanging_request_http_rtt_upper_bound_http_rtt_multiplier", + -1)), + hanging_request_upper_bound_min_http_rtt_( + base::TimeDelta::FromMilliseconds(GetValueForVariationParam( + params_, + "hanging_request_upper_bound_min_http_rtt_msec", + -1))), http_rtt_transport_rtt_min_count_( GetValueForVariationParam(params_, "http_rtt_transport_rtt_min_count", @@ -443,8 +494,6 @@ NetworkQualityEstimatorParams::NetworkQualityEstimatorParams( "socket_watchers_min_notification_interval_msec", 200))), use_small_responses_(false) { - DCHECK_LE(0.0, correlation_uma_logging_probability_); - DCHECK_GE(1.0, correlation_uma_logging_probability_); DCHECK(lower_bound_http_rtt_transport_rtt_multiplier_ == -1 || lower_bound_http_rtt_transport_rtt_multiplier_ > 0); DCHECK(upper_bound_http_rtt_transport_rtt_multiplier_ == -1 || @@ -454,6 +503,20 @@ NetworkQualityEstimatorParams::NetworkQualityEstimatorParams( lower_bound_http_rtt_transport_rtt_multiplier_ < upper_bound_http_rtt_transport_rtt_multiplier_); + DCHECK(hanging_request_http_rtt_upper_bound_transport_rtt_multiplier_ == -1 || + hanging_request_http_rtt_upper_bound_transport_rtt_multiplier_ > 0); + DCHECK(hanging_request_http_rtt_upper_bound_http_rtt_multiplier_ == -1 || + hanging_request_http_rtt_upper_bound_http_rtt_multiplier_ > 0); + DCHECK(hanging_request_http_rtt_upper_bound_transport_rtt_multiplier_ == -1 || + hanging_request_http_rtt_upper_bound_http_rtt_multiplier_ == -1 || + hanging_request_http_rtt_upper_bound_transport_rtt_multiplier_ >= + hanging_request_http_rtt_upper_bound_http_rtt_multiplier_); + + DCHECK(upper_bound_http_rtt_transport_rtt_multiplier_ == -1 || + hanging_request_http_rtt_upper_bound_transport_rtt_multiplier_ == -1 || + upper_bound_http_rtt_transport_rtt_multiplier_ < + hanging_request_http_rtt_upper_bound_transport_rtt_multiplier_); + const auto algorithm_it = params_.find("effective_connection_type_algorithm"); effective_connection_type_algorithm_ = GetEffectiveConnectionTypeAlgorithmFromString( @@ -481,6 +544,21 @@ bool NetworkQualityEstimatorParams::use_small_responses() const { return use_small_responses_; }; +base::Optional<EffectiveConnectionType> +NetworkQualityEstimatorParams::GetForcedEffectiveConnectionType( + NetworkChangeNotifier::ConnectionType connection_type) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (forced_effective_connection_type_) { + return forced_effective_connection_type_; + } + + if (forced_effective_connection_type_on_cellular_only_ && + net::NetworkChangeNotifier::IsConnectionCellular(connection_type)) { + return EFFECTIVE_CONNECTION_TYPE_SLOW_2G; + } + return base::nullopt; +} + // static NetworkQualityEstimatorParams::EffectiveConnectionTypeAlgorithm NetworkQualityEstimatorParams::GetEffectiveConnectionTypeAlgorithmFromString( @@ -529,12 +607,6 @@ int64_t NetworkQualityEstimatorParams::GetThroughputMinTransferSizeBits() 1000; } -// static -const char* NetworkQualityEstimatorParams::GetNameForConnectionType( - NetworkChangeNotifier::ConnectionType connection_type) { - return GetNameForConnectionTypeInternal(connection_type); -} - const nqe::internal::NetworkQuality& NetworkQualityEstimatorParams::DefaultObservation( NetworkChangeNotifier::ConnectionType type) const { @@ -562,4 +634,23 @@ NetworkQualityEstimatorParams::GetEffectiveConnectionTypeAlgorithm() const { return effective_connection_type_algorithm_; } +EffectiveConnectionType NetworkQualityEstimatorParams::GetDefaultECT( + NetworkChangeNotifier::ConnectionType connection_type) const { + switch (connection_type) { + case NetworkChangeNotifier::CONNECTION_UNKNOWN: + case NetworkChangeNotifier::CONNECTION_ETHERNET: + case NetworkChangeNotifier::CONNECTION_WIFI: + case NetworkChangeNotifier::CONNECTION_4G: + case NetworkChangeNotifier::CONNECTION_NONE: + case NetworkChangeNotifier::CONNECTION_BLUETOOTH: + return EFFECTIVE_CONNECTION_TYPE_4G; + case NetworkChangeNotifier::CONNECTION_2G: + return EFFECTIVE_CONNECTION_TYPE_2G; + case NetworkChangeNotifier::CONNECTION_3G: + return EFFECTIVE_CONNECTION_TYPE_3G; + } + NOTREACHED(); + return EFFECTIVE_CONNECTION_TYPE_4G; +} + } // namespace net diff --git a/chromium/net/nqe/network_quality_estimator_params.h b/chromium/net/nqe/network_quality_estimator_params.h index 3a1b079580c..14078cdce23 100644 --- a/chromium/net/nqe/network_quality_estimator_params.h +++ b/chromium/net/nqe/network_quality_estimator_params.h @@ -21,6 +21,11 @@ namespace net { // Forces NQE to return a specific effective connection type. Set using the // |params| provided to the NetworkQualityEstimatorParams constructor. NET_EXPORT extern const char kForceEffectiveConnectionType[]; +NET_EXPORT extern const char kEffectiveConnectionTypeSlow2GOnCellular[]; + +// HTTP RTT thresholds for different effective connection types. +NET_EXPORT extern const base::TimeDelta + kHttpRttEffectiveConnectionTypeThresholds[EFFECTIVE_CONNECTION_TYPE_LAST]; // NetworkQualityEstimatorParams computes the configuration parameters for // the network quality estimator. @@ -46,10 +51,6 @@ class NET_EXPORT NetworkQualityEstimatorParams { // a default value is used. EffectiveConnectionTypeAlgorithm GetEffectiveConnectionTypeAlgorithm() const; - // Returns a descriptive name corresponding to |connection_type|. - static const char* GetNameForConnectionType( - NetworkChangeNotifier::ConnectionType connection_type); - // Returns the default observation for connection |type|. The default // observations are different for different connection types (e.g., 2G, 3G, // 4G, WiFi). The default observations may be used to determine the network @@ -87,20 +88,13 @@ class NET_EXPORT NetworkQualityEstimatorParams { return weight_multiplier_per_signal_strength_level_; } - // Returns the fraction of URL requests that should record the correlation - // UMA. - double correlation_uma_logging_probability() const { - return correlation_uma_logging_probability_; - } - // Returns an unset value if the effective connection type has not been forced // via the |params| provided to this class. Otherwise, returns a value set to - // the effective connection type that has been forced. - base::Optional<EffectiveConnectionType> forced_effective_connection_type() - const { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - return forced_effective_connection_type_; - } + // the effective connection type that has been forced. Forced ECT can be + // forced based on |connection_type| (e.g. Slow-2G on cellular, and default on + // other connection type). + base::Optional<EffectiveConnectionType> GetForcedEffectiveConnectionType( + NetworkChangeNotifier::ConnectionType connection_type); void SetForcedEffectiveConnectionType( EffectiveConnectionType forced_effective_connection_type) { @@ -139,6 +133,14 @@ class NET_EXPORT NetworkQualityEstimatorParams { effective_connection_type_algorithm_ = algorithm; } + // Number of bytes received during a throughput observation window of duration + // 1 HTTP RTT should be at least the value returned by this method times + // the typical size of a congestion window. If not, the throughput observation + // window is heuristically determined as hanging. + double throughput_hanging_requests_cwnd_size_multiplier() const { + return throughput_hanging_requests_cwnd_size_multiplier_; + } + // Returns the multiplier by which the transport RTT should be multipled when // computing the HTTP RTT. The multiplied value of the transport RTT serves // as a lower bound to the HTTP RTT estimate. e.g., if the multiplied @@ -157,6 +159,24 @@ class NET_EXPORT NetworkQualityEstimatorParams { return upper_bound_http_rtt_transport_rtt_multiplier_; } + // For the purpose of estimating the HTTP RTT, a request is marked as hanging + // only if its RTT is at least this times the transport RTT estimate. + int hanging_request_http_rtt_upper_bound_transport_rtt_multiplier() const { + return hanging_request_http_rtt_upper_bound_transport_rtt_multiplier_; + } + + // For the purpose of estimating the HTTP RTT, a request is marked as hanging + // only if its RTT is at least this times the HTTP RTT estimate. + int hanging_request_http_rtt_upper_bound_http_rtt_multiplier() const { + return hanging_request_http_rtt_upper_bound_http_rtt_multiplier_; + } + + // For the purpose of estimating the HTTP RTT, a request is marked as hanging + // only if its RTT is at least as much the value returned by this method. + base::TimeDelta hanging_request_upper_bound_min_http_rtt() const { + return hanging_request_upper_bound_min_http_rtt_; + } + // Returns the number of transport RTT observations that should be available // before the transport RTT estimate can be used to clamp the HTTP RTT // estimate. Set to 5 by default which ensures that when the transport RTT @@ -229,6 +249,10 @@ class NET_EXPORT NetworkQualityEstimatorParams { return socket_watchers_min_notification_interval_; } + // Returns the default effective connection type for a given connection type. + EffectiveConnectionType GetDefaultECT( + NetworkChangeNotifier::ConnectionType connection_type) const; + private: // Map containing all field trial parameters related to // NetworkQualityEstimator field trial. @@ -236,14 +260,18 @@ class NET_EXPORT NetworkQualityEstimatorParams { const size_t throughput_min_requests_in_flight_; const int throughput_min_transfer_size_kilobytes_; + const double throughput_hanging_requests_cwnd_size_multiplier_; const double weight_multiplier_per_second_; const double weight_multiplier_per_signal_strength_level_; - const double correlation_uma_logging_probability_; base::Optional<EffectiveConnectionType> forced_effective_connection_type_; + const bool forced_effective_connection_type_on_cellular_only_; bool persistent_cache_reading_enabled_; const base::TimeDelta min_socket_watcher_notification_interval_; const double lower_bound_http_rtt_transport_rtt_multiplier_; const double upper_bound_http_rtt_transport_rtt_multiplier_; + const int hanging_request_http_rtt_upper_bound_transport_rtt_multiplier_; + const int hanging_request_http_rtt_upper_bound_http_rtt_multiplier_; + const base::TimeDelta hanging_request_upper_bound_min_http_rtt_; const size_t http_rtt_transport_rtt_min_count_; const base::TimeDelta increase_in_transport_rtt_logging_interval_; const base::TimeDelta recent_time_threshold_; diff --git a/chromium/net/nqe/network_quality_estimator_params_unittest.cc b/chromium/net/nqe/network_quality_estimator_params_unittest.cc index 3626f192b55..f10db3e4ca6 100644 --- a/chromium/net/nqe/network_quality_estimator_params_unittest.cc +++ b/chromium/net/nqe/network_quality_estimator_params_unittest.cc @@ -7,6 +7,7 @@ #include <map> #include <string> +#include "net/base/network_change_notifier.h" #include "testing/gtest/include/gtest/gtest.h" namespace net { @@ -139,6 +140,88 @@ TEST(NetworkQualityEstimatorParamsTest, ObtainAlgorithmToUseFromParams) { } } +// Verify that for a given connection type, the default network quality values +// lie in the same range of ECT as the value returned by GetDefaultECT(). +TEST(NetworkQualityEstimatorParamsTest, GetDefaultECT) { + std::map<std::string, std::string> variation_params; + NetworkQualityEstimatorParams params(variation_params); + + for (size_t i = 0; i < NetworkChangeNotifier::ConnectionType::CONNECTION_LAST; + ++i) { + NetworkChangeNotifier::ConnectionType connection_type = + static_cast<NetworkChangeNotifier::ConnectionType>(i); + EffectiveConnectionType ect = params.GetDefaultECT(connection_type); + EXPECT_LE(EFFECTIVE_CONNECTION_TYPE_2G, ect); + + const nqe::internal::NetworkQuality& default_nq = + params.DefaultObservation(connection_type); + + // Now verify that |default_nq| corresponds to |ect|. + if (ect == EFFECTIVE_CONNECTION_TYPE_4G) { + // If the expected effective connection type is 4G, then RTT values in + // |default_nq| should be lower than the threshold for ECT of 3G. + const nqe::internal::NetworkQuality& threshold_3g = + params.ConnectionThreshold(EFFECTIVE_CONNECTION_TYPE_3G); + + EXPECT_LT(default_nq.http_rtt(), threshold_3g.http_rtt()); + EXPECT_LT(default_nq.transport_rtt(), threshold_3g.transport_rtt()); + EXPECT_TRUE(default_nq.downstream_throughput_kbps() > + threshold_3g.downstream_throughput_kbps() || + threshold_3g.downstream_throughput_kbps() < 0); + } else { + // If the expected effective connection type is |ect|, then RTT values in + // |default_nq| should be (i) higher than the threshold for ECT of |ect| + // (ii) Lower than the threshold for |slower_ect|. + const nqe::internal::NetworkQuality& threshold_ect = + params.ConnectionThreshold(ect); + EffectiveConnectionType slower_ect = + static_cast<EffectiveConnectionType>(static_cast<int>(ect) - 1); + const nqe::internal::NetworkQuality& threshold_slower_ect = + params.ConnectionThreshold(slower_ect); + + EXPECT_GT(default_nq.http_rtt(), threshold_ect.http_rtt()); + EXPECT_GT(default_nq.transport_rtt(), threshold_ect.transport_rtt()); + EXPECT_TRUE(default_nq.downstream_throughput_kbps() < + threshold_ect.downstream_throughput_kbps() || + threshold_ect.downstream_throughput_kbps() < 0); + + EXPECT_LT(default_nq.http_rtt(), threshold_slower_ect.http_rtt()); + EXPECT_LT(default_nq.transport_rtt(), + threshold_slower_ect.transport_rtt()); + EXPECT_TRUE(default_nq.downstream_throughput_kbps() > + threshold_slower_ect.downstream_throughput_kbps() || + threshold_slower_ect.downstream_throughput_kbps() < 0); + } + } +} + +// Verify ECT when forced ECT is Slow-2G-On-Cellular. +TEST(NetworkQualityEstimatorParamsTest, GetForcedECTCellularOnly) { + std::map<std::string, std::string> variation_params; + // Set force-effective-connection-type to Slow-2G-On-Cellular. + variation_params[kForceEffectiveConnectionType] = + kEffectiveConnectionTypeSlow2GOnCellular; + + NetworkQualityEstimatorParams params(variation_params); + + for (size_t i = 0; i < NetworkChangeNotifier::ConnectionType::CONNECTION_LAST; + ++i) { + NetworkChangeNotifier::ConnectionType connection_type = + static_cast<NetworkChangeNotifier::ConnectionType>(i); + base::Optional<EffectiveConnectionType> ect = + params.GetForcedEffectiveConnectionType(connection_type); + + if (net::NetworkChangeNotifier::IsConnectionCellular(connection_type)) { + // Test for cellular connection types. Make sure that ECT is Slow-2G. + EXPECT_EQ(EFFECTIVE_CONNECTION_TYPE_SLOW_2G, ect); + } else { + // Test for non-cellular connection types. Make sure that there is no + // forced ect. + EXPECT_EQ(base::nullopt, ect); + } + } +} + } // namespace } // namespace internal diff --git a/chromium/net/nqe/network_quality_estimator_test_util.cc b/chromium/net/nqe/network_quality_estimator_test_util.cc index d9d21f77cd4..3e82cbfc4ac 100644 --- a/chromium/net/nqe/network_quality_estimator_test_util.cc +++ b/chromium/net/nqe/network_quality_estimator_test_util.cc @@ -66,12 +66,11 @@ TestNetworkQualityEstimator::TestNetworkQualityEstimator( std::move(external_estimate_provider), std::make_unique<NetworkQualityEstimatorParams>(variation_params), net_log->bound().net_log()), + net_log_(std::move(net_log)), current_network_type_(NetworkChangeNotifier::CONNECTION_UNKNOWN), accuracy_recording_intervals_set_(false), - rand_double_(0.0), embedded_test_server_(base::FilePath(kTestFilePath)), - suppress_notifications_for_testing_(suppress_notifications_for_testing), - net_log_(std::move(net_log)) { + suppress_notifications_for_testing_(suppress_notifications_for_testing) { SetUseLocalHostRequestsForTesting(allow_local_host_requests_for_tests); SetUseSmallResponsesForTesting(allow_smaller_responses_for_tests); @@ -90,12 +89,11 @@ TestNetworkQualityEstimator::TestNetworkQualityEstimator( : NetworkQualityEstimator(std::unique_ptr<ExternalEstimateProvider>(), std::move(params), net_log->bound().net_log()), + net_log_(std::move(net_log)), current_network_type_(NetworkChangeNotifier::CONNECTION_UNKNOWN), accuracy_recording_intervals_set_(false), - rand_double_(0.0), embedded_test_server_(base::FilePath(kTestFilePath)), - suppress_notifications_for_testing_(false), - net_log_(std::move(net_log)) { + suppress_notifications_for_testing_(false) { // Set up the embedded test server. EXPECT_TRUE(embedded_test_server_.Start()); } @@ -262,10 +260,6 @@ TestNetworkQualityEstimator::GetAccuracyRecordingIntervals() const { return NetworkQualityEstimator::GetAccuracyRecordingIntervals(); } -double TestNetworkQualityEstimator::RandDouble() const { - return rand_double_; -} - base::Optional<int32_t> TestNetworkQualityEstimator::GetBandwidthDelayProductKbits() const { if (bandwidth_delay_product_kbits_.has_value()) @@ -340,7 +334,8 @@ const NetworkQualityEstimatorParams* TestNetworkQualityEstimator::params() nqe::internal::NetworkID TestNetworkQualityEstimator::GetCurrentNetworkID() const { - return nqe::internal::NetworkID(current_network_type_, current_network_id_); + return nqe::internal::NetworkID(current_network_type_, current_network_id_, + INT32_MIN); } TestNetworkQualityEstimator::LocalHttpTestServer::LocalHttpTestServer( @@ -366,4 +361,24 @@ void TestNetworkQualityEstimator:: observer); } +void TestNetworkQualityEstimator::SetStartTimeNullHttpRtt( + const base::TimeDelta http_rtt) { + start_time_null_http_rtt_ = http_rtt; + // Force compute effective connection type so that the new RTT value is + // immediately picked up. This ensures that the next call to + // GetEffectiveConnectionType() returns the effective connnection type + // that was computed based on |http_rtt|. + ComputeEffectiveConnectionType(); +} + +void TestNetworkQualityEstimator::SetStartTimeNullTransportRtt( + const base::TimeDelta transport_rtt) { + start_time_null_transport_rtt_ = transport_rtt; + // Force compute effective connection type so that the new RTT value is + // immediately picked up. This ensures that the next call to + // GetEffectiveConnectionType() returns the effective connnection type + // that was computed based on |transport_rtt|. + ComputeEffectiveConnectionType(); +} + } // namespace net diff --git a/chromium/net/nqe/network_quality_estimator_test_util.h b/chromium/net/nqe/network_quality_estimator_test_util.h index 3e245575636..3b188677657 100644 --- a/chromium/net/nqe/network_quality_estimator_test_util.h +++ b/chromium/net/nqe/network_quality_estimator_test_util.h @@ -122,9 +122,8 @@ class TestNetworkQualityEstimator : public NetworkQualityEstimator { void NotifyRTTAndThroughputEstimatesObserverIfPresent( RTTAndThroughputEstimatesObserver* observer) const override; - void set_start_time_null_http_rtt(const base::TimeDelta& http_rtt) { - start_time_null_http_rtt_ = http_rtt; - } + // Force set the HTTP RTT estimate. + void SetStartTimeNullHttpRtt(const base::TimeDelta http_rtt); void set_recent_http_rtt(const base::TimeDelta& recent_http_rtt) { // Callers should not set effective connection type along with the @@ -138,9 +137,8 @@ class TestNetworkQualityEstimator : public NetworkQualityEstimator { bool GetRecentHttpRTT(const base::TimeTicks& start_time, base::TimeDelta* rtt) const override; - void set_start_time_null_transport_rtt(const base::TimeDelta& transport_rtt) { - start_time_null_transport_rtt_ = transport_rtt; - } + // Force set the transport RTT estimate. + void SetStartTimeNullTransportRtt(const base::TimeDelta transport_rtt); void set_recent_transport_rtt(const base::TimeDelta& recent_transport_rtt) { // Callers should not set effective connection type along with the @@ -196,10 +194,6 @@ class TestNetworkQualityEstimator : public NetworkQualityEstimator { const std::vector<base::TimeDelta>& GetAccuracyRecordingIntervals() const override; - void set_rand_double(double rand_double) { rand_double_ = rand_double; } - - double RandDouble() const override; - void set_bandwidth_delay_product_kbits(int32_t value) { bandwidth_delay_product_kbits_ = value; } @@ -237,6 +231,7 @@ class TestNetworkQualityEstimator : public NetworkQualityEstimator { using NetworkQualityEstimator::OnUpdatedTransportRTTAvailable; using NetworkQualityEstimator::AddAndNotifyObserversOfRTT; using NetworkQualityEstimator::AddAndNotifyObserversOfThroughput; + using NetworkQualityEstimator::IsHangingRequest; private: class LocalHttpTestServer : public EmbeddedTestServer { @@ -253,6 +248,9 @@ class TestNetworkQualityEstimator : public NetworkQualityEstimator { // id (instead of invoking platform APIs). nqe::internal::NetworkID GetCurrentNetworkID() const override; + // Net log provided to network quality estimator. + std::unique_ptr<net::BoundTestNetLog> net_log_; + // If set, GetEffectiveConnectionType() and GetRecentEffectiveConnectionType() // would return the set values, respectively. base::Optional<EffectiveConnectionType> effective_connection_type_; @@ -286,8 +284,6 @@ class TestNetworkQualityEstimator : public NetworkQualityEstimator { // If set, GetRTTEstimateInternal() would return the set value. base::Optional<base::TimeDelta> rtt_estimate_internal_; - double rand_double_; - // If set, GetBandwidthDelayProductKbits() would return its set value. // Otherwise, the base implementation is called. base::Optional<int32_t> bandwidth_delay_product_kbits_; @@ -299,9 +295,6 @@ class TestNetworkQualityEstimator : public NetworkQualityEstimator { base::Optional<size_t> transport_rtt_observation_count_last_ect_computation_; - // Net log provided to network quality estimator. - std::unique_ptr<net::BoundTestNetLog> net_log_; - DISALLOW_COPY_AND_ASSIGN(TestNetworkQualityEstimator); }; diff --git a/chromium/net/nqe/network_quality_estimator_unittest.cc b/chromium/net/nqe/network_quality_estimator_unittest.cc index b8854e3dc76..45a1b31b9f3 100644 --- a/chromium/net/nqe/network_quality_estimator_unittest.cc +++ b/chromium/net/nqe/network_quality_estimator_unittest.cc @@ -199,7 +199,8 @@ TEST(NetworkQualityEstimatorTest, TestKbpsRTTUpdates) { estimator.SimulateNetworkChange( NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN, "test"); - histogram_tester.ExpectTotalCount("NQE.CachedNetworkQualityAvailable", 0); + histogram_tester.ExpectUniqueSample("NQE.CachedNetworkQualityAvailable", + false, 2); base::TimeDelta rtt; int32_t kbps; @@ -282,17 +283,9 @@ TEST(NetworkQualityEstimatorTest, TestKbpsRTTUpdates) { estimator.SimulateNetworkChange( NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI, "test-1"); histogram_tester.ExpectUniqueSample("NQE.CachedNetworkQualityAvailable", - false, 1); + false, 3); histogram_tester.ExpectTotalCount("NQE.RatioMedianRTT.WiFi", 0); - histogram_tester.ExpectTotalCount("NQE.RTT.Percentile0.Unknown", 1); - histogram_tester.ExpectTotalCount("NQE.RTT.Percentile10.Unknown", 1); - histogram_tester.ExpectTotalCount("NQE.RTT.Percentile50.Unknown", 1); - histogram_tester.ExpectTotalCount("NQE.RTT.Percentile90.Unknown", 1); - histogram_tester.ExpectTotalCount("NQE.RTT.Percentile100.Unknown", 1); - - histogram_tester.ExpectTotalCount("NQE.TransportRTT.Percentile50.Unknown", 0); - EXPECT_FALSE(estimator.GetRecentHttpRTT(base::TimeTicks(), &rtt)); EXPECT_FALSE( estimator.GetRecentDownlinkThroughputKbps(base::TimeTicks(), &kbps)); @@ -306,7 +299,7 @@ TEST(NetworkQualityEstimatorTest, TestKbpsRTTUpdates) { estimator.SimulateNetworkChange( NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI, std::string()); histogram_tester.ExpectUniqueSample("NQE.CachedNetworkQualityAvailable", - false, 1); + false, 4); EXPECT_FALSE(estimator.GetRecentHttpRTT(base::TimeTicks(), &rtt)); EXPECT_FALSE( @@ -336,7 +329,7 @@ TEST(NetworkQualityEstimatorTest, TestKbpsRTTUpdates) { estimator.SimulateNetworkChange( NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN, "test"); histogram_tester.ExpectBucketCount("NQE.CachedNetworkQualityAvailable", false, - 1); + 4); } // Tests that the network quality estimator writes and reads network quality @@ -359,7 +352,7 @@ TEST(NetworkQualityEstimatorTest, Caching) { estimator.SimulateNetworkChange(connection_type, connection_id); histogram_tester.ExpectUniqueSample("NQE.CachedNetworkQualityAvailable", - false, 1); + false, 2); base::TimeDelta rtt; int32_t kbps; @@ -383,6 +376,9 @@ TEST(NetworkQualityEstimatorTest, Caching) { request->Start(); base::RunLoop().Run(); } + histogram_tester.ExpectUniqueSample("NQE.RTT.ObservationSource", + NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP, + 2); base::RunLoop().RunUntilIdle(); @@ -399,7 +395,7 @@ TEST(NetworkQualityEstimatorTest, Caching) { EXPECT_FALSE(estimator.GetTransportRTT()); histogram_tester.ExpectBucketCount("NQE.CachedNetworkQualityAvailable", - false, 1); + false, 2); // Add the observers before changing the network type. TestEffectiveConnectionTypeObserver observer; @@ -422,6 +418,11 @@ TEST(NetworkQualityEstimatorTest, Caching) { "NQE.RTT.ObservationSource", NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP_CACHED_ESTIMATE, 1); histogram_tester.ExpectBucketCount( + "NQE.RTT.ObservationSource", + NETWORK_QUALITY_OBSERVATION_SOURCE_TRANSPORT_CACHED_ESTIMATE, 1); + histogram_tester.ExpectTotalCount("NQE.RTT.ObservationSource", 4); + + histogram_tester.ExpectBucketCount( "NQE.Kbps.ObservationSource", NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP_CACHED_ESTIMATE, 1); histogram_tester.ExpectTotalCount( @@ -433,7 +434,7 @@ TEST(NetworkQualityEstimatorTest, Caching) { num_net_log_entries); EXPECT_NE(-1, estimator.GetNetLogLastIntegerValue( NetLogEventType::NETWORK_QUALITY_CHANGED, "http_rtt_ms")); - EXPECT_EQ( + EXPECT_NE( -1, estimator.GetNetLogLastIntegerValue( NetLogEventType::NETWORK_QUALITY_CHANGED, "transport_rtt_ms")); EXPECT_NE(-1, estimator.GetNetLogLastIntegerValue( @@ -447,7 +448,7 @@ TEST(NetworkQualityEstimatorTest, Caching) { histogram_tester.ExpectBucketCount("NQE.CachedNetworkQualityAvailable", true, 1); - histogram_tester.ExpectTotalCount("NQE.CachedNetworkQualityAvailable", 2); + histogram_tester.ExpectTotalCount("NQE.CachedNetworkQualityAvailable", 3); base::RunLoop().RunUntilIdle(); // Verify that the cached network quality was read, and observers were @@ -456,7 +457,7 @@ TEST(NetworkQualityEstimatorTest, Caching) { EXPECT_LE(2U, observer.effective_connection_types().size()); EXPECT_EQ(estimator.GetEffectiveConnectionType(), observer.effective_connection_types().back()); - EXPECT_EQ(1U, rtt_observer.observations().size()); + EXPECT_EQ(2U, rtt_observer.observations().size()); EXPECT_EQ(1U, throughput_observer.observations().size()); } } @@ -729,7 +730,7 @@ TEST(NetworkQualityEstimatorTest, DefaultObservations) { NetworkChangeNotifier::ConnectionType::CONNECTION_3G, "test-3"); EXPECT_TRUE(estimator.GetRecentHttpRTT(base::TimeTicks(), &rtt)); // Taken from network_quality_estimator_params.cc. - EXPECT_EQ(base::TimeDelta::FromMilliseconds(272), rtt); + EXPECT_EQ(base::TimeDelta::FromMilliseconds(273), rtt); EXPECT_EQ(rtt, estimator.GetHttpRTT().value()); EXPECT_TRUE( estimator.GetRecentTransportRTT(base::TimeTicks(), &rtt, nullptr)); @@ -759,7 +760,7 @@ TEST(NetworkQualityEstimatorTest, DefaultObservations) { "effective_connection_type")); EXPECT_EQ(4, rtt_throughput_estimates_observer.notifications_received()); - EXPECT_EQ(base::TimeDelta::FromMilliseconds(272), + EXPECT_EQ(base::TimeDelta::FromMilliseconds(273), rtt_throughput_estimates_observer.http_rtt()); EXPECT_EQ(base::TimeDelta::FromMilliseconds(209), rtt_throughput_estimates_observer.transport_rtt()); @@ -767,7 +768,7 @@ TEST(NetworkQualityEstimatorTest, DefaultObservations) { rtt_throughput_estimates_observer.downstream_throughput_kbps()); EXPECT_EQ(2U, rtt_observer.observations().size()); - EXPECT_EQ(272, rtt_observer.observations().at(0).rtt_ms); + EXPECT_EQ(273, rtt_observer.observations().at(0).rtt_ms); EXPECT_EQ(NETWORK_QUALITY_OBSERVATION_SOURCE_DEFAULT_HTTP_FROM_PLATFORM, rtt_observer.observations().at(0).source); EXPECT_EQ(209, rtt_observer.observations().at(1).rtt_ms); @@ -856,7 +857,7 @@ TEST(NetworkQualityEstimatorTest, DefaultObservationsOverridden) { estimator.SimulateNetworkChange( NetworkChangeNotifier::ConnectionType::CONNECTION_3G, "test-3"); EXPECT_TRUE(estimator.GetRecentHttpRTT(base::TimeTicks(), &rtt)); - EXPECT_EQ(base::TimeDelta::FromMilliseconds(272), rtt); + EXPECT_EQ(base::TimeDelta::FromMilliseconds(273), rtt); EXPECT_EQ(rtt, estimator.GetHttpRTT().value()); EXPECT_TRUE( estimator.GetRecentTransportRTT(base::TimeTicks(), &rtt, nullptr)); @@ -929,15 +930,12 @@ TEST(NetworkQualityEstimatorTest, ObtainThresholdsOnlyRTT) { }; for (const auto& test : tests) { - estimator.set_start_time_null_http_rtt( - base::TimeDelta::FromMilliseconds(test.rtt_msec)); estimator.set_recent_http_rtt( base::TimeDelta::FromMilliseconds(test.rtt_msec)); estimator.set_start_time_null_downlink_throughput_kbps(INT32_MAX); estimator.set_recent_downlink_throughput_kbps(INT32_MAX); - // Run one main frame request to force recomputation of effective connection - // type. - estimator.RunOneRequest(); + estimator.SetStartTimeNullHttpRtt( + base::TimeDelta::FromMilliseconds(test.rtt_msec)); EXPECT_EQ(test.expected_conn_type, estimator.GetEffectiveConnectionType()); } } @@ -987,7 +985,7 @@ TEST(NetworkQualityEstimatorTest, DefaultTransportRTTBasedThresholds) { estimator.SimulateNetworkChange(NetworkChangeNotifier::CONNECTION_WIFI, "test"); - estimator.set_start_time_null_transport_rtt( + estimator.SetStartTimeNullTransportRtt( base::TimeDelta::FromMilliseconds(test.transport_rtt_msec)); estimator.set_recent_transport_rtt( base::TimeDelta::FromMilliseconds(test.transport_rtt_msec)); @@ -1043,15 +1041,12 @@ TEST(NetworkQualityEstimatorTest, DefaultHttpRTTBasedThresholds) { estimator.SimulateNetworkChange(NetworkChangeNotifier::CONNECTION_WIFI, "test"); - estimator.set_start_time_null_http_rtt( + estimator.SetStartTimeNullHttpRtt( base::TimeDelta::FromMilliseconds(test.http_rtt_msec)); estimator.set_recent_http_rtt( base::TimeDelta::FromMilliseconds(test.http_rtt_msec)); estimator.set_start_time_null_downlink_throughput_kbps(INT32_MAX); estimator.set_recent_downlink_throughput_kbps(INT32_MAX); - // Run one main frame request to force recomputation of effective connection - // type. - estimator.RunOneRequest(); EXPECT_EQ(test.expected_conn_type, estimator.GetEffectiveConnectionType()); } } @@ -1102,15 +1097,12 @@ TEST(NetworkQualityEstimatorTest, MAYBE_ObtainThresholdsOnlyTransportRTT) { }; for (const auto& test : tests) { - estimator.set_start_time_null_transport_rtt( - base::TimeDelta::FromMilliseconds(test.transport_rtt_msec)); estimator.set_recent_transport_rtt( base::TimeDelta::FromMilliseconds(test.transport_rtt_msec)); estimator.set_start_time_null_downlink_throughput_kbps(INT32_MAX); estimator.set_recent_downlink_throughput_kbps(INT32_MAX); - // Run one main frame request to force recomputation of effective connection - // type. - estimator.RunOneRequest(); + estimator.SetStartTimeNullTransportRtt( + base::TimeDelta::FromMilliseconds(test.transport_rtt_msec)); EXPECT_EQ(test.expected_conn_type, estimator.GetEffectiveConnectionType()); } } @@ -1163,7 +1155,7 @@ TEST(NetworkQualityEstimatorTest, ObtainThresholdsHttpRTTandThroughput) { }; for (const auto& test : tests) { - estimator.set_start_time_null_http_rtt( + estimator.SetStartTimeNullHttpRtt( base::TimeDelta::FromMilliseconds(test.rtt_msec)); estimator.set_recent_http_rtt( base::TimeDelta::FromMilliseconds(test.rtt_msec)); @@ -1228,17 +1220,14 @@ TEST(NetworkQualityEstimatorTest, ObtainThresholdsTransportRTTandThroughput) { }; for (const auto& test : tests) { - estimator.set_start_time_null_transport_rtt( - base::TimeDelta::FromMilliseconds(test.transport_rtt_msec)); estimator.set_recent_transport_rtt( base::TimeDelta::FromMilliseconds(test.transport_rtt_msec)); estimator.set_start_time_null_downlink_throughput_kbps( test.downlink_throughput_kbps); estimator.set_recent_downlink_throughput_kbps( test.downlink_throughput_kbps); - // Run one main frame request to force recomputation of effective connection - // type. - estimator.RunOneRequest(); + estimator.SetStartTimeNullTransportRtt( + base::TimeDelta::FromMilliseconds(test.transport_rtt_msec)); EXPECT_EQ(test.expected_conn_type, estimator.GetEffectiveConnectionType()); } } @@ -1563,6 +1552,7 @@ TEST(NetworkQualityEstimatorTest, TestExternalEstimateProviderMergeEstimates) { std::map<std::string, std::string> variation_params; variation_params["throughput_min_requests_in_flight"] = "1"; + variation_params["add_default_platform_observations"] = "false"; TestNetworkQualityEstimator estimator(variation_params, std::move(external_estimate_provider)); estimator.SimulateNetworkChange(net::NetworkChangeNotifier::CONNECTION_WIFI, @@ -1668,9 +1658,7 @@ TEST(NetworkQualityEstimatorTest, TestThroughputNoRequestOverlap) { // interval, and that the observers are notified of any change. TEST(NetworkQualityEstimatorTest, MAYBE_TestEffectiveConnectionTypeObserver) { base::HistogramTester histogram_tester; - std::unique_ptr<base::SimpleTestTickClock> tick_clock( - new base::SimpleTestTickClock()); - base::SimpleTestTickClock* tick_clock_ptr = tick_clock.get(); + base::SimpleTestTickClock tick_clock; TestEffectiveConnectionTypeObserver observer; std::map<std::string, std::string> variation_params; @@ -1680,7 +1668,7 @@ TEST(NetworkQualityEstimatorTest, MAYBE_TestEffectiveConnectionTypeObserver) { // |observer| may be notified as soon as it is added. Run the loop to so that // the notification to |observer| is finished. base::RunLoop().RunUntilIdle(); - estimator.SetTickClockForTesting(std::move(tick_clock)); + estimator.SetTickClockForTesting(&tick_clock); TestDelegate test_delegate; TestURLRequestContext context(true); @@ -1689,11 +1677,10 @@ TEST(NetworkQualityEstimatorTest, MAYBE_TestEffectiveConnectionTypeObserver) { EXPECT_EQ(0U, observer.effective_connection_types().size()); - estimator.set_start_time_null_http_rtt( - base::TimeDelta::FromMilliseconds(1500)); + estimator.SetStartTimeNullHttpRtt(base::TimeDelta::FromMilliseconds(1500)); estimator.set_start_time_null_downlink_throughput_kbps(100000); - tick_clock_ptr->Advance(base::TimeDelta::FromMinutes(60)); + tick_clock.Advance(base::TimeDelta::FromMinutes(60)); std::unique_ptr<URLRequest> request( context.CreateRequest(estimator.GetEchoURL(), DEFAULT_PRIORITY, @@ -1733,18 +1720,16 @@ TEST(NetworkQualityEstimatorTest, MAYBE_TestEffectiveConnectionTypeObserver) { EXPECT_EQ(1U, observer.effective_connection_types().size()); // Change in connection type should send out notification to the observers. - estimator.set_start_time_null_http_rtt( - base::TimeDelta::FromMilliseconds(500)); + estimator.SetStartTimeNullHttpRtt(base::TimeDelta::FromMilliseconds(500)); estimator.SimulateNetworkChange(NetworkChangeNotifier::CONNECTION_WIFI, "test"); - EXPECT_EQ(2U, observer.effective_connection_types().size()); + EXPECT_EQ(3U, observer.effective_connection_types().size()); // A change in effective connection type does not trigger notification to the // observers, since it is not accompanied by any new observation or a network // change event. - estimator.set_start_time_null_http_rtt( - base::TimeDelta::FromMilliseconds(100)); - EXPECT_EQ(2U, observer.effective_connection_types().size()); + estimator.SetStartTimeNullHttpRtt(base::TimeDelta::FromMilliseconds(100)); + EXPECT_EQ(4U, observer.effective_connection_types().size()); TestEffectiveConnectionTypeObserver observer_2; estimator.AddEffectiveConnectionTypeObserver(&observer_2); @@ -1776,7 +1761,7 @@ TEST(NetworkQualityEstimatorTest, TestTransportRttUsedForHttpRttComputation) { { base::TimeDelta::FromMilliseconds(100), base::TimeDelta::FromMilliseconds(200), "", "", - base::TimeDelta::FromMilliseconds(100), EFFECTIVE_CONNECTION_TYPE_4G, + base::TimeDelta::FromMilliseconds(200), EFFECTIVE_CONNECTION_TYPE_4G, }, { base::TimeDelta::FromMilliseconds(100), @@ -1826,12 +1811,13 @@ TEST(NetworkQualityEstimatorTest, TestTransportRttUsedForHttpRttComputation) { { base::TimeDelta::FromMilliseconds(100), base::TimeDelta::FromMilliseconds(200), "foobar", "", - base::TimeDelta::FromMilliseconds(100), EFFECTIVE_CONNECTION_TYPE_4G, + base::TimeDelta::FromMilliseconds(200), EFFECTIVE_CONNECTION_TYPE_4G, }, { base::TimeDelta::FromMilliseconds(100), base::TimeDelta::FromMilliseconds(4000), "", "", - base::TimeDelta::FromMilliseconds(100), EFFECTIVE_CONNECTION_TYPE_4G, + base::TimeDelta::FromMilliseconds(4000), + EFFECTIVE_CONNECTION_TYPE_SLOW_2G, }, { base::TimeDelta::FromMilliseconds(100), @@ -1871,14 +1857,12 @@ TEST(NetworkQualityEstimatorTest, TestTransportRttUsedForHttpRttComputation) { variation_params["add_default_platform_observations"] = "false"; TestNetworkQualityEstimator estimator(variation_params); - std::unique_ptr<base::SimpleTestTickClock> tick_clock( - new base::SimpleTestTickClock()); - tick_clock->Advance(base::TimeDelta::FromSeconds(1)); - base::SimpleTestTickClock* tick_clock_ptr = tick_clock.get(); - estimator.SetTickClockForTesting(std::move(tick_clock)); + base::SimpleTestTickClock tick_clock; + tick_clock.Advance(base::TimeDelta::FromSeconds(1)); + estimator.SetTickClockForTesting(&tick_clock); - estimator.set_start_time_null_http_rtt(test.http_rtt); - estimator.set_start_time_null_transport_rtt(test.transport_rtt); + estimator.SetStartTimeNullHttpRtt(test.http_rtt); + estimator.SetStartTimeNullTransportRtt(test.transport_rtt); // Minimum number of transport RTT samples that should be present before // transport RTT estimate can be used to clamp the HTTP RTT. @@ -1887,10 +1871,9 @@ TEST(NetworkQualityEstimatorTest, TestTransportRttUsedForHttpRttComputation) { // Add one observation to ensure ECT is not computed for each request. estimator.AddAndNotifyObserversOfRTT(NetworkQualityEstimator::Observation( - test.http_rtt.InMilliseconds(), tick_clock_ptr->NowTicks(), INT32_MIN, + test.http_rtt.InMilliseconds(), tick_clock.NowTicks(), INT32_MIN, NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP)); - estimator.RunOneRequest(); EXPECT_EQ(test.expected_http_rtt, estimator.GetHttpRTT()); EXPECT_EQ(test.transport_rtt, estimator.GetTransportRTT()); EXPECT_EQ(test.expected_type, estimator.GetEffectiveConnectionType()) @@ -1902,16 +1885,14 @@ TEST(NetworkQualityEstimatorTest, TestTransportRttUsedForHttpRttComputation) { // that the network quality observers are notified of any change. TEST(NetworkQualityEstimatorTest, TestRTTAndThroughputEstimatesObserver) { base::HistogramTester histogram_tester; - std::unique_ptr<base::SimpleTestTickClock> tick_clock( - new base::SimpleTestTickClock()); - base::SimpleTestTickClock* tick_clock_ptr = tick_clock.get(); + base::SimpleTestTickClock tick_clock; TestRTTAndThroughputEstimatesObserver observer; std::map<std::string, std::string> variation_params; variation_params["add_default_platform_observations"] = "false"; TestNetworkQualityEstimator estimator(variation_params); estimator.AddRTTAndThroughputEstimatesObserver(&observer); - estimator.SetTickClockForTesting(std::move(tick_clock)); + estimator.SetTickClockForTesting(&tick_clock); TestDelegate test_delegate; TestURLRequestContext context(true); @@ -1928,11 +1909,11 @@ TEST(NetworkQualityEstimatorTest, TestRTTAndThroughputEstimatesObserver) { base::TimeDelta http_rtt(base::TimeDelta::FromMilliseconds(100)); base::TimeDelta transport_rtt(base::TimeDelta::FromMilliseconds(200)); int32_t downstream_throughput_kbps(300); - estimator.set_start_time_null_http_rtt(http_rtt); - estimator.set_start_time_null_transport_rtt(transport_rtt); + estimator.SetStartTimeNullHttpRtt(http_rtt); + estimator.SetStartTimeNullTransportRtt(transport_rtt); estimator.set_start_time_null_downlink_throughput_kbps( downstream_throughput_kbps); - tick_clock_ptr->Advance(base::TimeDelta::FromMinutes(60)); + tick_clock.Advance(base::TimeDelta::FromMinutes(60)); std::unique_ptr<URLRequest> request( context.CreateRequest(estimator.GetEchoURL(), DEFAULT_PRIORITY, @@ -1968,10 +1949,9 @@ TEST(NetworkQualityEstimatorTest, TestRTTAndThroughputEstimatesObserver) { // A change in effective connection type does not trigger notification to the // observers, since it is not accompanied by any new observation or a network // change event. - estimator.set_start_time_null_http_rtt( - base::TimeDelta::FromMilliseconds(10000)); - estimator.set_start_time_null_http_rtt(base::TimeDelta::FromMilliseconds(1)); - EXPECT_EQ(0, observer.notifications_received() - notifications_received); + estimator.SetStartTimeNullHttpRtt(base::TimeDelta::FromMilliseconds(10000)); + estimator.SetStartTimeNullHttpRtt(base::TimeDelta::FromMilliseconds(1)); + EXPECT_EQ(2, observer.notifications_received() - notifications_received); TestRTTAndThroughputEstimatesObserver observer_2; estimator.AddRTTAndThroughputEstimatesObserver(&observer_2); @@ -2004,17 +1984,15 @@ TEST(NetworkQualityEstimatorTest, TestRTTAndThroughputEstimatesObserver) { // Tests that the effective connection type is computed on every RTT // observation if the last computed effective connection type was unknown. TEST(NetworkQualityEstimatorTest, UnknownEffectiveConnectionType) { - std::unique_ptr<base::SimpleTestTickClock> tick_clock( - new base::SimpleTestTickClock()); - base::SimpleTestTickClock* tick_clock_ptr = tick_clock.get(); + base::SimpleTestTickClock tick_clock; TestEffectiveConnectionTypeObserver observer; std::map<std::string, std::string> variation_params; variation_params["add_default_platform_observations"] = "false"; TestNetworkQualityEstimator estimator(variation_params); - estimator.SetTickClockForTesting(std::move(tick_clock)); + estimator.SetTickClockForTesting(&tick_clock); estimator.AddEffectiveConnectionTypeObserver(&observer); - tick_clock_ptr->Advance(base::TimeDelta::FromMinutes(60)); + tick_clock.Advance(base::TimeDelta::FromMinutes(60)); size_t expected_effective_connection_type_notifications = 0; estimator.set_recent_effective_connection_type( @@ -2026,7 +2004,7 @@ TEST(NetworkQualityEstimatorTest, UnknownEffectiveConnectionType) { "test"); NetworkQualityEstimator::Observation rtt_observation( - 5000, tick_clock_ptr->NowTicks(), INT32_MIN, + 5000, tick_clock.NowTicks(), INT32_MIN, NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP); for (size_t i = 0; i < 10; ++i) { @@ -2040,7 +2018,7 @@ TEST(NetworkQualityEstimatorTest, UnknownEffectiveConnectionType) { // more RTT sample should trigger recomputation of the effective connection // type since the last computed effective connection type was unknown. estimator.AddAndNotifyObserversOfRTT(NetworkQualityEstimator::Observation( - 5000, tick_clock_ptr->NowTicks(), INT32_MIN, + 5000, tick_clock.NowTicks(), INT32_MIN, NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP)); ++expected_effective_connection_type_notifications; EXPECT_EQ(expected_effective_connection_type_notifications, @@ -2052,15 +2030,13 @@ TEST(NetworkQualityEstimatorTest, UnknownEffectiveConnectionType) { TEST(NetworkQualityEstimatorTest, AdaptiveRecomputationEffectiveConnectionType) { base::HistogramTester histogram_tester; - std::unique_ptr<base::SimpleTestTickClock> tick_clock( - new base::SimpleTestTickClock()); - base::SimpleTestTickClock* tick_clock_ptr = tick_clock.get(); + base::SimpleTestTickClock tick_clock; TestEffectiveConnectionTypeObserver observer; std::map<std::string, std::string> variation_params; variation_params["add_default_platform_observations"] = "false"; TestNetworkQualityEstimator estimator(variation_params); - estimator.SetTickClockForTesting(std::move(tick_clock)); + estimator.SetTickClockForTesting(&tick_clock); estimator.SimulateNetworkChange(NetworkChangeNotifier::CONNECTION_WIFI, "test"); estimator.AddEffectiveConnectionTypeObserver(&observer); @@ -2076,7 +2052,7 @@ TEST(NetworkQualityEstimatorTest, EXPECT_EQ(0U, observer.effective_connection_types().size()); estimator.set_recent_effective_connection_type(EFFECTIVE_CONNECTION_TYPE_2G); - tick_clock_ptr->Advance(base::TimeDelta::FromMinutes(60)); + tick_clock.Advance(base::TimeDelta::FromMinutes(60)); std::unique_ptr<URLRequest> request( context.CreateRequest(estimator.GetEchoURL(), DEFAULT_PRIORITY, @@ -2128,7 +2104,7 @@ TEST(NetworkQualityEstimatorTest, // effective connection type. for (size_t i = 0; i < rtt_observations_count + 1; ++i) { estimator.AddAndNotifyObserversOfRTT(NetworkQualityEstimator::Observation( - 5000, tick_clock_ptr->NowTicks(), INT32_MIN, + 5000, tick_clock.NowTicks(), INT32_MIN, NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP)); if (i == rtt_observations_count) { @@ -2244,15 +2220,13 @@ TEST(NetworkQualityEstimatorTest, TestRttThroughputObservers) { } TEST(NetworkQualityEstimatorTest, TestGlobalSocketWatcherThrottle) { - std::unique_ptr<base::SimpleTestTickClock> tick_clock( - new base::SimpleTestTickClock()); - base::SimpleTestTickClock* tick_clock_ptr = tick_clock.get(); - tick_clock_ptr->Advance(base::TimeDelta::FromSeconds(1)); + base::SimpleTestTickClock tick_clock; + tick_clock.Advance(base::TimeDelta::FromSeconds(1)); std::map<std::string, std::string> variation_params; variation_params["add_default_platform_observations"] = "false"; TestNetworkQualityEstimator estimator(variation_params); - estimator.SetTickClockForTesting(std::move(tick_clock)); + estimator.SetTickClockForTesting(&tick_clock); TestRTTObserver rtt_observer; estimator.AddRTTObserver(&rtt_observer); @@ -2293,7 +2267,7 @@ TEST(NetworkQualityEstimatorTest, TestGlobalSocketWatcherThrottle) { EXPECT_EQ(2U, rtt_observer.observations().size()); // Advancing the clock should make it possible to notify new RTT // notifications. - tick_clock_ptr->Advance( + tick_clock.Advance( estimator.params()->socket_watchers_min_notification_interval()); EXPECT_TRUE(tcp_watcher->ShouldNotifyUpdatedRTT()); @@ -2305,7 +2279,7 @@ TEST(NetworkQualityEstimatorTest, TestGlobalSocketWatcherThrottle) { // TestTCPSocketRTT requires kernel support for tcp_info struct, and so it is // enabled only on certain platforms. -#if defined(TCP_INFO) || defined(OS_LINUX) +#if defined(TCP_INFO) || defined(OS_LINUX) || defined(OS_ANDROID) #define MAYBE_TestTCPSocketRTT TestTCPSocketRTT #else #define MAYBE_TestTCPSocketRTT DISABLED_TestTCPSocketRTT @@ -2313,10 +2287,8 @@ TEST(NetworkQualityEstimatorTest, TestGlobalSocketWatcherThrottle) { // Tests that the TCP socket notifies the Network Quality Estimator of TCP RTTs, // which in turn notifies registered RTT observers. TEST(NetworkQualityEstimatorTest, MAYBE_TestTCPSocketRTT) { - std::unique_ptr<base::SimpleTestTickClock> tick_clock( - new base::SimpleTestTickClock()); - base::SimpleTestTickClock* tick_clock_ptr = tick_clock.get(); - tick_clock_ptr->Advance(base::TimeDelta::FromSeconds(1)); + base::SimpleTestTickClock tick_clock; + tick_clock.Advance(base::TimeDelta::FromSeconds(1)); base::HistogramTester histogram_tester; TestRTTObserver rtt_observer; @@ -2327,7 +2299,7 @@ TEST(NetworkQualityEstimatorTest, MAYBE_TestTCPSocketRTT) { TestNetworkQualityEstimator estimator( nullptr, variation_params, true, true, std::make_unique<BoundTestNetLog>()); - estimator.SetTickClockForTesting(std::move(tick_clock)); + estimator.SetTickClockForTesting(&tick_clock); estimator.SimulateNetworkChange( NetworkChangeNotifier::ConnectionType::CONNECTION_2G, "test"); @@ -2371,7 +2343,7 @@ TEST(NetworkQualityEstimatorTest, MAYBE_TestTCPSocketRTT) { &test_delegate, TRAFFIC_ANNOTATION_FOR_TESTS)); request->SetLoadFlags(request->load_flags() | LOAD_MAIN_FRAME_DEPRECATED); request->Start(); - tick_clock_ptr->Advance( + tick_clock.Advance( estimator.params()->socket_watchers_min_notification_interval()); base::RunLoop().Run(); @@ -2395,13 +2367,6 @@ TEST(NetworkQualityEstimatorTest, MAYBE_TestTCPSocketRTT) { estimator.SimulateNetworkChange( NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI, "test-1"); - histogram_tester.ExpectTotalCount("NQE.TransportRTT.Percentile50.2G", 1); - histogram_tester.ExpectBucketCount("NQE.TransportRTT.Percentile50.2G", - rtt.InMilliseconds(), 1); - histogram_tester.ExpectTotalCount("NQE.TransportRTT.Percentile10.2G", 1); - histogram_tester.ExpectTotalCount("NQE.TransportRTT.Percentile50.2G", 1); - histogram_tester.ExpectTotalCount("NQE.TransportRTT.Percentile90.2G", 1); - histogram_tester.ExpectTotalCount("NQE.TransportRTT.Percentile100.2G", 1); // Verify that metrics are logged correctly on main-frame requests. histogram_tester.ExpectTotalCount("NQE.MainFrame.TransportRTT.Percentile50", @@ -2439,13 +2404,13 @@ TEST(NetworkQualityEstimatorTest, MAYBE_TestTCPSocketRTT) { NetworkChangeNotifier::ConnectionType::CONNECTION_2G, "test"); histogram_tester.ExpectBucketCount( "NQE.RTT.ObservationSource", - NETWORK_QUALITY_OBSERVATION_SOURCE_TRANSPORT_CACHED_ESTIMATE, 0); + NETWORK_QUALITY_OBSERVATION_SOURCE_TRANSPORT_CACHED_ESTIMATE, 1); estimator.SimulateNetworkChange( NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI, "test-1"); histogram_tester.ExpectBucketCount( "NQE.RTT.ObservationSource", - NETWORK_QUALITY_OBSERVATION_SOURCE_TRANSPORT_CACHED_ESTIMATE, 1); + NETWORK_QUALITY_OBSERVATION_SOURCE_TRANSPORT_CACHED_ESTIMATE, 2); } #if defined(OS_IOS) @@ -2493,10 +2458,8 @@ TEST(NetworkQualityEstimatorTest, MAYBE_RecordAccuracy) { for (const auto& accuracy_recording_delay : accuracy_recording_delays) { for (const auto& test : tests) { - std::unique_ptr<base::SimpleTestTickClock> tick_clock( - new base::SimpleTestTickClock()); - base::SimpleTestTickClock* tick_clock_ptr = tick_clock.get(); - tick_clock_ptr->Advance(base::TimeDelta::FromSeconds(1)); + base::SimpleTestTickClock tick_clock; + tick_clock.Advance(base::TimeDelta::FromSeconds(1)); std::unique_ptr<ExternalEstimateProvider> external_estimate_provider( new TestExternalEstimateProvider(test.rtt, 0)); @@ -2505,10 +2468,10 @@ TEST(NetworkQualityEstimatorTest, MAYBE_RecordAccuracy) { TestNetworkQualityEstimator estimator( variation_params, std::move(external_estimate_provider)); - estimator.SetTickClockForTesting(std::move(tick_clock)); + estimator.SetTickClockForTesting(&tick_clock); estimator.SimulateNetworkChange( NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI, "test-1"); - tick_clock_ptr->Advance(base::TimeDelta::FromSeconds(1)); + tick_clock.Advance(base::TimeDelta::FromSeconds(1)); std::vector<base::TimeDelta> accuracy_recording_intervals; accuracy_recording_intervals.push_back(accuracy_recording_delay); @@ -2516,10 +2479,10 @@ TEST(NetworkQualityEstimatorTest, MAYBE_RecordAccuracy) { // RTT is higher than threshold. Network is slow. // Network was predicted to be slow and actually was slow. - estimator.set_start_time_null_http_rtt(test.rtt); + estimator.SetStartTimeNullHttpRtt(test.rtt); estimator.set_recent_http_rtt(test.recent_rtt); estimator.set_rtt_estimate_internal(test.recent_rtt); - estimator.set_start_time_null_transport_rtt(test.rtt); + estimator.SetStartTimeNullTransportRtt(test.rtt); estimator.set_recent_transport_rtt(test.recent_rtt); estimator.set_start_time_null_downlink_throughput_kbps( test.downstream_throughput_kbps); @@ -2543,7 +2506,7 @@ TEST(NetworkQualityEstimatorTest, MAYBE_RecordAccuracy) { base::RunLoop().Run(); if (accuracy_recording_delay != base::TimeDelta()) { - tick_clock_ptr->Advance(accuracy_recording_delay); + tick_clock.Advance(accuracy_recording_delay); // Sleep for some time to ensure that the delayed task is posted. base::PlatformThread::Sleep(accuracy_recording_delay * 2); @@ -2675,202 +2638,13 @@ TEST(NetworkQualityEstimatorTest, TestRecordNetworkIDAvailability) { histogram_tester.ExpectTotalCount("NQE.NetworkIdAvailable", 4); } -// Tests that the correlation histogram is recorded correctly based on -// correlation logging probability set in the variation params. -TEST(NetworkQualityEstimatorTest, CorrelationHistogram) { - // Match the values set in network_quality_estimator.cc. - static const int32_t kTrimBits = 5; - static const int32_t kBitsPerMetric = 7; - - const struct { - bool use_transport_rtt; - double rand_double; - double correlation_logging_probability; - base::TimeDelta transport_rtt; - int32_t expected_transport_rtt_milliseconds; - base::TimeDelta http_rtt; - int32_t expected_http_rtt_milliseconds; - int32_t downstream_throughput_kbps; - int32_t expected_downstream_throughput_kbps; - - } tests[] = { - { - // Verify that the metric is not recorded if the logging probability - // is set to 0.0. - false, 0.5, 0.0, base::TimeDelta::FromSeconds(1), 1000 >> kTrimBits, - base::TimeDelta::FromSeconds(2), 2000 >> kTrimBits, 3000, - 3000 >> kTrimBits, - }, - { - // Verify that the metric is not recorded if the logging probability - // is lower than the value returned by the random number generator. - false, 0.3, 0.1, base::TimeDelta::FromSeconds(1), 1000 >> kTrimBits, - base::TimeDelta::FromSeconds(2), 2000 >> kTrimBits, 3000, - 3000 >> kTrimBits, - }, - { - // Verify that the metric is recorded if the logging probability is - // higher than the value returned by the random number generator. - false, 0.3, 0.4, base::TimeDelta::FromSeconds(1), 1000 >> kTrimBits, - base::TimeDelta::FromSeconds(2), 2000 >> kTrimBits, 3000, - 3000 >> kTrimBits, - }, - { - // Verify that the metric is not recorded if the HTTP RTT is - // unavailable. - false, 0.3, 0.4, base::TimeDelta::FromSeconds(1), 1000 >> kTrimBits, - nqe::internal::InvalidRTT(), 2000 >> kTrimBits, 3000, - 3000 >> kTrimBits, - }, - { - // Verify that the metric is not recorded if the transport RTT is - // unavailable. - true, 0.3, 0.4, nqe::internal::InvalidRTT(), 1000 >> kTrimBits, - base::TimeDelta::FromSeconds(2), 2000 >> kTrimBits, 3000, - 3000 >> kTrimBits, - }, - { - // Verify that the metric is not recorded if the throughput is - // unavailable. - false, 0.3, 0.4, base::TimeDelta::FromSeconds(1), 1000 >> kTrimBits, - base::TimeDelta::FromSeconds(2), 2000 >> kTrimBits, - nqe::internal::INVALID_RTT_THROUGHPUT, 3000 >> kTrimBits, - }, - { - // Verify that the metric is recorded if the logging probability is - // set to 1.0. - false, 0.5, 1.0, base::TimeDelta::FromSeconds(1), 1000 >> kTrimBits, - base::TimeDelta::FromSeconds(2), 2000 >> kTrimBits, 3000, - 3000 >> kTrimBits, - }, - { - // Verify that the metric is recorded if the logging probability is - // set to 1.0. - true, 0.5, 1.0, base::TimeDelta::FromSeconds(1), 1000 >> kTrimBits, - base::TimeDelta::FromSeconds(2), 2000 >> kTrimBits, 3000, - 3000 >> kTrimBits, - }, - { - // Verify that if the metric is larger than - // 2^(kBitsPerMetric + kTrimBits), it is rounded down to - // (2^(kBitsPerMetric + kTrimBits) - 1) >> kTrimBits. - false, 0.5, 1.0, base::TimeDelta::FromSeconds(10), 4095 >> kTrimBits, - base::TimeDelta::FromSeconds(20), 4095 >> kTrimBits, 30000, - 4095 >> kTrimBits, - }, - }; - - for (const auto& test : tests) { - base::HistogramTester histogram_tester; - - std::map<std::string, std::string> variation_params; - variation_params["correlation_logging_probability"] = - base::NumberToString(test.correlation_logging_probability); - if (test.use_transport_rtt) { - variation_params["effective_connection_type_algorithm"] = - "TransportRTTOrDownstreamThroughput"; - } - TestNetworkQualityEstimator estimator(variation_params); - - estimator.set_start_time_null_transport_rtt(test.transport_rtt); - estimator.set_recent_transport_rtt(test.transport_rtt); - estimator.set_start_time_null_http_rtt(test.http_rtt); - estimator.set_recent_http_rtt(test.http_rtt); - estimator.set_start_time_null_downlink_throughput_kbps( - test.downstream_throughput_kbps); - estimator.set_rand_double(test.rand_double); - - TestDelegate test_delegate; - TestURLRequestContext context(true); - context.set_network_quality_estimator(&estimator); - context.Init(); - - histogram_tester.ExpectTotalCount( - "NQE.Correlation.ResourceLoadTime.0Kb_128Kb", 0); - - // Start a main-frame request that should cause network quality estimator to - // record the network quality at the last main frame request. - std::unique_ptr<URLRequest> request_1( - context.CreateRequest(estimator.GetEchoURL(), DEFAULT_PRIORITY, - &test_delegate, TRAFFIC_ANNOTATION_FOR_TESTS)); - request_1->SetLoadFlags(request_1->load_flags() | - LOAD_MAIN_FRAME_DEPRECATED); - request_1->Start(); - base::RunLoop().Run(); - - if (test.rand_double >= test.correlation_logging_probability) { - histogram_tester.ExpectTotalCount( - "NQE.Correlation.ResourceLoadTime.0Kb_128Kb", 0); - continue; - } - if (!test.use_transport_rtt && - test.http_rtt == nqe::internal::InvalidRTT()) { - histogram_tester.ExpectTotalCount( - "NQE.Correlation.ResourceLoadTime.0Kb_128Kb", 0); - continue; - } - if (test.use_transport_rtt && - test.transport_rtt == nqe::internal::InvalidRTT()) { - histogram_tester.ExpectTotalCount( - "NQE.Correlation.ResourceLoadTime.0Kb_128Kb", 0); - continue; - } - if (test.downstream_throughput_kbps == - nqe::internal::INVALID_RTT_THROUGHPUT) { - histogram_tester.ExpectTotalCount( - "NQE.Correlation.ResourceLoadTime.0Kb_128Kb", 0); - continue; - } - - histogram_tester.ExpectTotalCount( - "NQE.Correlation.ResourceLoadTime.0Kb_128Kb", 1); - std::vector<base::Bucket> buckets = histogram_tester.GetAllSamples( - "NQE.Correlation.ResourceLoadTime.0Kb_128Kb"); - // Get the bits at index 0-10 which contain the RTT. - // 128 is 2^kBitsPerMetric. - if (test.use_transport_rtt) { - EXPECT_EQ(test.expected_transport_rtt_milliseconds, - buckets.at(0).min >> kBitsPerMetric >> kBitsPerMetric >> - kBitsPerMetric); - } else { - EXPECT_EQ(test.expected_http_rtt_milliseconds, - buckets.at(0).min >> kBitsPerMetric >> kBitsPerMetric >> - kBitsPerMetric); - } - - // Get the bits at index 11-17 which contain the downstream throughput. - EXPECT_EQ(test.expected_downstream_throughput_kbps, - (buckets.at(0).min >> kBitsPerMetric >> kBitsPerMetric) % 128); - - // Get the bits at index 18-24 which contain the resource fetch time. - EXPECT_LE(0, (buckets.at(0).min >> kBitsPerMetric) % 128); - - // Get the bits at index 25-31 which contain the resource load size. - EXPECT_LE(0, (buckets.at(0).min) % 128); - - // Start another main-frame request which is redirected to an HTTPS URL. - // Redirection should not cause any crashes. - std::unique_ptr<URLRequest> request_3( - context.CreateRequest(estimator.GetRedirectURL(), DEFAULT_PRIORITY, - &test_delegate, TRAFFIC_ANNOTATION_FOR_TESTS)); - request_3->Start(); - base::RunLoop().Run(); - EXPECT_FALSE(request_3->original_url().SchemeIsCryptographic()); - EXPECT_TRUE(request_3->url().SchemeIsCryptographic()); - EXPECT_TRUE(!request_3->response_info().headers.get() || - request_3->response_info().headers->response_code() != HTTP_OK); - // Correlation metric should not be logged for redirected requests. - histogram_tester.ExpectTotalCount( - "NQE.Correlation.ResourceLoadTime.0Kb_128Kb", 1); - } -} - class TestNetworkQualitiesCacheObserver : public nqe::internal::NetworkQualityStore::NetworkQualitiesCacheObserver { public: TestNetworkQualitiesCacheObserver() : network_id_(net::NetworkChangeNotifier::CONNECTION_UNKNOWN, - std::string()), + std::string(), + INT32_MIN), notification_received_(0) {} ~TestNetworkQualitiesCacheObserver() override = default; @@ -2907,7 +2681,7 @@ TEST(NetworkQualityEstimatorTest, CacheObserver) { estimator.SimulateNetworkChange( NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN, "test3g"); estimator.RunOneRequest(); - EXPECT_EQ(2u, observer.get_notification_received_and_reset()); + EXPECT_EQ(4u, observer.get_notification_received_and_reset()); EXPECT_EQ("test3g", observer.network_id().id); estimator.set_recent_effective_connection_type(EFFECTIVE_CONNECTION_TYPE_2G); @@ -3045,29 +2819,20 @@ TEST(NetworkQualityEstimatorTest, TypicalNetworkQualities) { // Set the RTT and throughput values to the typical values for // |effective_connection_type|. The effective connection type should be // computed as |effective_connection_type|. - estimator.set_start_time_null_http_rtt( + estimator.SetStartTimeNullHttpRtt( estimator.params_ ->TypicalNetworkQuality(static_cast<EffectiveConnectionType>( effective_connection_type)) .http_rtt()); - estimator.set_start_time_null_transport_rtt( + estimator.set_start_time_null_downlink_throughput_kbps(INT32_MAX); + estimator.SetStartTimeNullTransportRtt( estimator.params_ ->TypicalNetworkQuality(static_cast<EffectiveConnectionType>( effective_connection_type)) .transport_rtt()); - estimator.set_start_time_null_downlink_throughput_kbps(INT32_MAX); - - // Force recomputation of effective connection type by starting a main - // frame request. - std::unique_ptr<URLRequest> request( - context.CreateRequest(estimator.GetEchoURL(), DEFAULT_PRIORITY, - &test_delegate, TRAFFIC_ANNOTATION_FOR_TESTS)); - request->SetLoadFlags(request->load_flags() | LOAD_MAIN_FRAME_DEPRECATED); - request->Start(); - base::RunLoop().Run(); EXPECT_EQ(effective_connection_type, - estimator.GetEffectiveConnectionType()); + static_cast<size_t>(estimator.GetEffectiveConnectionType())); } } } @@ -3080,13 +2845,13 @@ TEST(NetworkQualityEstimatorTest, OnPrefsRead) { std::map<nqe::internal::NetworkID, nqe::internal::CachedNetworkQuality> read_prefs; read_prefs[nqe::internal::NetworkID(NetworkChangeNotifier::CONNECTION_WIFI, - "test_ect_2g")] = + "test_ect_2g", INT32_MIN)] = nqe::internal::CachedNetworkQuality(EFFECTIVE_CONNECTION_TYPE_2G); read_prefs[nqe::internal::NetworkID(NetworkChangeNotifier::CONNECTION_WIFI, - "test_ect_slow_2g")] = + "test_ect_slow_2g", INT32_MIN)] = nqe::internal::CachedNetworkQuality(EFFECTIVE_CONNECTION_TYPE_SLOW_2G); read_prefs[nqe::internal::NetworkID(NetworkChangeNotifier::CONNECTION_4G, - "test_ect_4g")] = + "test_ect_4g", INT32_MIN)] = nqe::internal::CachedNetworkQuality(EFFECTIVE_CONNECTION_TYPE_4G); std::map<std::string, std::string> variation_params; @@ -3143,7 +2908,8 @@ TEST(NetworkQualityEstimatorTest, OnPrefsRead) { // Compare the ECT stored in prefs with the observer's last entry. EXPECT_EQ( read_prefs[nqe::internal::NetworkID( - NetworkChangeNotifier::CONNECTION_WIFI, network_name)] + NetworkChangeNotifier::CONNECTION_WIFI, network_name, + INT32_MIN)] .effective_connection_type(), effective_connection_type_observer.effective_connection_types().back()); @@ -3170,7 +2936,8 @@ TEST(NetworkQualityEstimatorTest, OnPrefsRead) { // Compare with the last entry. EXPECT_EQ( read_prefs[nqe::internal::NetworkID( - NetworkChangeNotifier::CONNECTION_WIFI, network_name)] + NetworkChangeNotifier::CONNECTION_WIFI, network_name, + INT32_MIN)] .effective_connection_type(), effective_connection_type_observer.effective_connection_types().back()); @@ -3191,13 +2958,13 @@ TEST(NetworkQualityEstimatorTest, OnPrefsReadWithReadingDisabled) { std::map<nqe::internal::NetworkID, nqe::internal::CachedNetworkQuality> read_prefs; read_prefs[nqe::internal::NetworkID(NetworkChangeNotifier::CONNECTION_WIFI, - "test_ect_2g")] = + "test_ect_2g", INT32_MIN)] = nqe::internal::CachedNetworkQuality(EFFECTIVE_CONNECTION_TYPE_2G); read_prefs[nqe::internal::NetworkID(NetworkChangeNotifier::CONNECTION_WIFI, - "test_ect_slow_2g")] = + "test_ect_slow_2g", INT32_MIN)] = nqe::internal::CachedNetworkQuality(EFFECTIVE_CONNECTION_TYPE_SLOW_2G); read_prefs[nqe::internal::NetworkID(NetworkChangeNotifier::CONNECTION_4G, - "test_ect_4g")] = + "test_ect_4g", INT32_MIN)] = nqe::internal::CachedNetworkQuality(EFFECTIVE_CONNECTION_TYPE_4G); std::map<std::string, std::string> variation_params; @@ -3241,7 +3008,7 @@ TEST(NetworkQualityEstimatorTest, OnPrefsReadWithReadingDisabled) { nqe::internal::CachedNetworkQuality cached_network_quality; EXPECT_TRUE(estimator.network_quality_store_->GetById( nqe::internal::NetworkID(NetworkChangeNotifier::CONNECTION_WIFI, - "test_ect_2g"), + "test_ect_2g", INT32_MIN), &cached_network_quality)); EXPECT_EQ(EFFECTIVE_CONNECTION_TYPE_2G, cached_network_quality.effective_connection_type()); @@ -3317,17 +3084,15 @@ TEST(NetworkQualityEstimatorTest, TestBDPComputation) { TEST(NetworkQualityEstimatorTest, TestComputeIncreaseInTransportRTTFullHostsOverlap) { - std::unique_ptr<base::SimpleTestTickClock> tick_clock( - new base::SimpleTestTickClock()); - base::SimpleTestTickClock* tick_clock_ptr = tick_clock.get(); - tick_clock_ptr->Advance(base::TimeDelta::FromMinutes(1)); + base::SimpleTestTickClock tick_clock; + tick_clock.Advance(base::TimeDelta::FromMinutes(1)); std::map<std::string, std::string> variation_params; variation_params["add_default_platform_observations"] = "false"; TestNetworkQualityEstimator estimator(variation_params); - estimator.SetTickClockForTesting(std::move(tick_clock)); + estimator.SetTickClockForTesting(&tick_clock); - base::TimeTicks now = tick_clock_ptr->NowTicks(); + base::TimeTicks now = tick_clock.NowTicks(); base::TimeTicks recent = now - base::TimeDelta::FromMilliseconds(2500); base::TimeTicks historical = now - base::TimeDelta::FromSeconds(20); @@ -3359,17 +3124,15 @@ TEST(NetworkQualityEstimatorTest, TEST(NetworkQualityEstimatorTest, TestComputeIncreaseInTransportRTTPartialHostsOverlap) { - std::unique_ptr<base::SimpleTestTickClock> tick_clock( - new base::SimpleTestTickClock()); - base::SimpleTestTickClock* tick_clock_ptr = tick_clock.get(); - tick_clock_ptr->Advance(base::TimeDelta::FromMinutes(1)); + base::SimpleTestTickClock tick_clock; + tick_clock.Advance(base::TimeDelta::FromMinutes(1)); std::map<std::string, std::string> variation_params; variation_params["add_default_platform_observations"] = "false"; TestNetworkQualityEstimator estimator(variation_params); - estimator.SetTickClockForTesting(std::move(tick_clock)); + estimator.SetTickClockForTesting(&tick_clock); - base::TimeTicks now = tick_clock_ptr->NowTicks(); + base::TimeTicks now = tick_clock.NowTicks(); base::TimeTicks recent = now - base::TimeDelta::FromMilliseconds(2500); base::TimeTicks historical = now - base::TimeDelta::FromSeconds(20); @@ -3409,7 +3172,7 @@ TEST(NetworkQualityEstimatorTest, std::map<nqe::internal::NetworkID, nqe::internal::CachedNetworkQuality> read_prefs; read_prefs[nqe::internal::NetworkID(NetworkChangeNotifier::CONNECTION_WIFI, - "test_2g")] = + "test_2g", INT32_MIN)] = nqe::internal::CachedNetworkQuality(EFFECTIVE_CONNECTION_TYPE_2G); std::map<std::string, std::string> variation_params; @@ -3514,20 +3277,18 @@ TEST(NetworkQualityEstimatorTest, // Tests that the ECT is computed when more than N RTT samples have been // received. TEST(NetworkQualityEstimatorTest, MaybeComputeECTAfterNSamples) { - std::unique_ptr<base::SimpleTestTickClock> tick_clock( - new base::SimpleTestTickClock()); - base::SimpleTestTickClock* tick_clock_ptr = tick_clock.get(); - tick_clock_ptr->Advance(base::TimeDelta::FromMinutes(1)); + base::SimpleTestTickClock tick_clock; + tick_clock.Advance(base::TimeDelta::FromMinutes(1)); std::map<std::string, std::string> variation_params; variation_params["add_default_platform_observations"] = "false"; TestNetworkQualityEstimator estimator(variation_params); estimator.DisableOfflineCheckForTesting(true); base::RunLoop().RunUntilIdle(); - estimator.SetTickClockForTesting(std::move(tick_clock)); + estimator.SetTickClockForTesting(&tick_clock); estimator.SimulateNetworkChange( NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN, "test"); - tick_clock_ptr->Advance(base::TimeDelta::FromMinutes(1)); + tick_clock.Advance(base::TimeDelta::FromMinutes(1)); const base::TimeDelta rtt = base::TimeDelta::FromSeconds(1); uint64_t host = 1u; @@ -3536,21 +3297,143 @@ TEST(NetworkQualityEstimatorTest, MaybeComputeECTAfterNSamples) { // to observation buffer's size increasing to 1.5x. for (size_t i = 0; i < estimator.params()->observation_buffer_size(); ++i) { estimator.AddAndNotifyObserversOfRTT(NetworkQualityEstimator::Observation( - rtt.InMilliseconds(), tick_clock_ptr->NowTicks(), INT32_MIN, + rtt.InMilliseconds(), tick_clock.NowTicks(), INT32_MIN, NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP, host)); } EXPECT_EQ(rtt, estimator.GetHttpRTT().value()); - tick_clock_ptr->Advance(base::TimeDelta::FromMinutes(60)); + tick_clock.Advance(base::TimeDelta::FromMinutes(60)); const base::TimeDelta rtt_new = base::TimeDelta::FromSeconds(3); for (size_t i = 0; i < estimator.params()->count_new_observations_received_compute_ect(); ++i) { estimator.AddAndNotifyObserversOfRTT(NetworkQualityEstimator::Observation( - rtt_new.InMilliseconds(), tick_clock_ptr->NowTicks(), INT32_MIN, + rtt_new.InMilliseconds(), tick_clock.NowTicks(), INT32_MIN, NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP, host)); } EXPECT_EQ(rtt_new, estimator.GetHttpRTT().value()); } +// Tests that the hanging request is correctly detected. +TEST(NetworkQualityEstimatorTest, HangingRequestUsingHttpOnly) { + base::HistogramTester histogram_tester; + + std::map<std::string, std::string> variation_params; + variation_params["add_default_platform_observations"] = "false"; + variation_params["hanging_request_http_rtt_upper_bound_http_rtt_multiplier"] = + "6"; + variation_params["hanging_request_upper_bound_min_http_rtt_msec"] = "500"; + + TestNetworkQualityEstimator estimator(variation_params); + + // 500 msec. + const int32_t hanging_request_threshold = + estimator.params() + ->hanging_request_upper_bound_min_http_rtt() + .InMilliseconds(); + + estimator.SetStartTimeNullHttpRtt(base::TimeDelta::FromMilliseconds(5)); + base::RunLoop().RunUntilIdle(); + estimator.SimulateNetworkChange( + NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN, "test"); + + const struct { + base::TimeDelta observed_http_rtt; + std::string histogram_name; + } tests[] = { + {base::TimeDelta::FromMilliseconds(10), + "NQE.RTT.NotAHangingRequest.HttpRTT"}, + {base::TimeDelta::FromMilliseconds(100), + "NQE.RTT.NotAHangingRequest.MinHttpBound"}, + {base::TimeDelta::FromMilliseconds(hanging_request_threshold - 1), + "NQE.RTT.NotAHangingRequest.MinHttpBound"}, + {base::TimeDelta::FromMilliseconds(hanging_request_threshold + 1), + "NQE.RTT.HangingRequest"}, + {base::TimeDelta::FromMilliseconds(1000), "NQE.RTT.HangingRequest"}, + }; + + for (const auto& test : tests) { + EXPECT_EQ( + test.observed_http_rtt.InMilliseconds() >= hanging_request_threshold, + estimator.IsHangingRequest(test.observed_http_rtt)); + histogram_tester.ExpectBucketCount( + test.histogram_name, test.observed_http_rtt.InMilliseconds(), 1); + } + + // Verify total sample count in all histograms. + histogram_tester.ExpectTotalCount("NQE.RTT.NotAHangingRequest.TransportRTT", + 0); + histogram_tester.ExpectTotalCount("NQE.RTT.NotAHangingRequest.HttpRTT", 1); + histogram_tester.ExpectTotalCount("NQE.RTT.NotAHangingRequest.MinHttpBound", + 2); + histogram_tester.ExpectTotalCount("NQE.RTT.HangingRequest", 2); +} + +TEST(NetworkQualityEstimatorTest, HangingRequestUsingTransportAndHttpOnly) { + base::HistogramTester histogram_tester; + + std::map<std::string, std::string> variation_params; + variation_params["add_default_platform_observations"] = "false"; + variation_params + ["hanging_request_http_rtt_upper_bound_transport_rtt_multiplier"] = "8"; + variation_params["hanging_request_http_rtt_upper_bound_http_rtt_multiplier"] = + "6"; + variation_params["hanging_request_upper_bound_min_http_rtt_msec"] = "500"; + + const base::TimeDelta transport_rtt = base::TimeDelta::FromMilliseconds(100); + + TestNetworkQualityEstimator estimator(variation_params); + + // 800 msec. + const int32_t hanging_request_threshold = + transport_rtt.InMilliseconds() * + estimator.params() + ->hanging_request_http_rtt_upper_bound_transport_rtt_multiplier(); + + estimator.DisableOfflineCheckForTesting(true); + estimator.SetStartTimeNullHttpRtt(base::TimeDelta::FromMilliseconds(5)); + + for (size_t i = 0; i < 100; ++i) { + // Throw enough transport RTT samples so that transport RTT estimate is + // recomputed. + estimator.AddAndNotifyObserversOfRTT(NetworkQualityEstimator::Observation( + transport_rtt.InMilliseconds(), base::TimeTicks::Now(), INT32_MIN, + NETWORK_QUALITY_OBSERVATION_SOURCE_TCP, 0)); + } + + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(transport_rtt, estimator.GetTransportRTT()); + + const struct { + base::TimeDelta observed_http_rtt; + std::string histogram_name; + } tests[] = { + {base::TimeDelta::FromMilliseconds(100), + "NQE.RTT.NotAHangingRequest.TransportRTT"}, + {base::TimeDelta::FromMilliseconds(500), + "NQE.RTT.NotAHangingRequest.TransportRTT"}, + {base::TimeDelta::FromMilliseconds(hanging_request_threshold - 1), + "NQE.RTT.NotAHangingRequest.TransportRTT"}, + {base::TimeDelta::FromMilliseconds(hanging_request_threshold + 1), + "NQE.RTT.HangingRequest"}, + {base::TimeDelta::FromMilliseconds(1000), "NQE.RTT.HangingRequest"}, + }; + + for (const auto& test : tests) { + EXPECT_EQ( + test.observed_http_rtt.InMilliseconds() >= hanging_request_threshold, + estimator.IsHangingRequest(test.observed_http_rtt)); + histogram_tester.ExpectBucketCount( + test.histogram_name, test.observed_http_rtt.InMilliseconds(), 1); + } + + // Verify total sample count in all histograms. + histogram_tester.ExpectTotalCount("NQE.RTT.NotAHangingRequest.TransportRTT", + 3); + histogram_tester.ExpectTotalCount("NQE.RTT.NotAHangingRequest.HttpRTT", 0); + histogram_tester.ExpectTotalCount("NQE.RTT.NotAHangingRequest.MinHttpBound", + 0); + histogram_tester.ExpectTotalCount("NQE.RTT.HangingRequest", 2); +} + } // namespace net diff --git a/chromium/net/nqe/network_quality_store.cc b/chromium/net/nqe/network_quality_store.cc index 490f0703d03..6d856225b54 100644 --- a/chromium/net/nqe/network_quality_store.cc +++ b/chromium/net/nqe/network_quality_store.cc @@ -14,14 +14,13 @@ namespace nqe { namespace internal { -NetworkQualityStore::NetworkQualityStore() - : disable_offline_check_(false), weak_ptr_factory_(this) { +NetworkQualityStore::NetworkQualityStore() : weak_ptr_factory_(this) { static_assert(kMaximumNetworkQualityCacheSize > 0, "Size of the network quality cache must be > 0"); // This limit should not be increased unless the logic for removing the // oldest cache entry is rewritten to use a doubly-linked-list LRU queue. - static_assert(kMaximumNetworkQualityCacheSize <= 10, - "Size of the network quality cache must <= 10"); + static_assert(kMaximumNetworkQualityCacheSize <= 20, + "Size of the network quality cache must <= 20"); } NetworkQualityStore::~NetworkQualityStore() { @@ -40,9 +39,6 @@ void NetworkQualityStore::Add( return; } - if (!EligibleForCaching(network_id)) - return; - // Remove the entry from the map, if it is already present. cached_network_qualities_.erase(network_id); @@ -71,16 +67,50 @@ void NetworkQualityStore::Add( bool NetworkQualityStore::GetById( const nqe::internal::NetworkID& network_id, - nqe::internal::CachedNetworkQuality* cached_network_quality) { + nqe::internal::CachedNetworkQuality* cached_network_quality) const { DCHECK(thread_checker_.CalledOnValidThread()); - CachedNetworkQualities::const_iterator it = - cached_network_qualities_.find(network_id); + // |matching_it| points to the entry that has the same connection type and + // id as |network_id|, and has the signal strength closest to the signal + // stength of |network_id|. + CachedNetworkQualities::const_iterator matching_it = + cached_network_qualities_.end(); + int matching_it_diff_signal_strength = INT32_MAX; + + for (CachedNetworkQualities::const_iterator it = + cached_network_qualities_.begin(); + it != cached_network_qualities_.end(); ++it) { + if (network_id.type != it->first.type || network_id.id != it->first.id) { + // The |type| and |id| must match. + continue; + } + + if (network_id.signal_strength == INT32_MIN) { + // Current network does not have a valid signal strength value. Return the + // entry without searching for the entry with the closest signal strength. + matching_it = it; + break; + } + + // Determine if the signal strength of |network_id| is closer to the + // signal strength of the network at |it| then that of the network at + // |matching_it|. + int diff_signal_strength = + std::abs(network_id.signal_strength - it->first.signal_strength); + if (it->first.signal_strength == INT32_MIN) + diff_signal_strength = INT32_MAX; + + if (matching_it == cached_network_qualities_.end() || + diff_signal_strength < matching_it_diff_signal_strength) { + matching_it = it; + matching_it_diff_signal_strength = diff_signal_strength; + } + } - if (it == cached_network_qualities_.end()) + if (matching_it == cached_network_qualities_.end()) return false; - *cached_network_quality = it->second; + *cached_network_quality = matching_it->second; return true; } @@ -102,24 +132,6 @@ void NetworkQualityStore::RemoveNetworkQualitiesCacheObserver( network_qualities_cache_observer_list_.RemoveObserver(observer); } -bool NetworkQualityStore::EligibleForCaching( - const NetworkID& network_id) const { - DCHECK(thread_checker_.CalledOnValidThread()); - - // |disable_offline_check_| forces caching of the network quality even if - // the network is set to offline. - return network_id.type == NetworkChangeNotifier::CONNECTION_ETHERNET || - !network_id.id.empty() || - (network_id.type == NetworkChangeNotifier::CONNECTION_NONE && - disable_offline_check_); -} - -void NetworkQualityStore::DisableOfflineCheckForTesting( - bool disable_offline_check) { - DCHECK(thread_checker_.CalledOnValidThread()); - disable_offline_check_ = disable_offline_check; -} - void NetworkQualityStore::NotifyCacheObserverIfPresent( NetworkQualitiesCacheObserver* observer) const { DCHECK(thread_checker_.CalledOnValidThread()); diff --git a/chromium/net/nqe/network_quality_store.h b/chromium/net/nqe/network_quality_store.h index 6213da79e86..77b7e384c27 100644 --- a/chromium/net/nqe/network_quality_store.h +++ b/chromium/net/nqe/network_quality_store.h @@ -56,8 +56,9 @@ class NET_EXPORT_PRIVATE NetworkQualityStore { // Returns true if the network quality estimate was successfully read // for a network with ID |network_id|, and sets |cached_network_quality| to // the estimate read. - bool GetById(const nqe::internal::NetworkID& network_id, - nqe::internal::CachedNetworkQuality* cached_network_quality); + bool GetById( + const nqe::internal::NetworkID& network_id, + nqe::internal::CachedNetworkQuality* cached_network_quality) const; // Adds and removes |observer| from the list of cache observers. The // observers are notified on the same thread on which it was added. Addition @@ -67,9 +68,6 @@ class NET_EXPORT_PRIVATE NetworkQualityStore { void RemoveNetworkQualitiesCacheObserver( NetworkQualitiesCacheObserver* observer); - // Returns true if network quality for |network_id| can be cached. - bool EligibleForCaching(const NetworkID& network_id) const; - // If |disable_offline_check| is set to true, the offline check is disabled // when storing the network quality. void DisableOfflineCheckForTesting(bool disable_offline_check); @@ -78,7 +76,7 @@ class NET_EXPORT_PRIVATE NetworkQualityStore { // Maximum size of the store that holds network quality estimates. // A smaller size may reduce the cache hit rate due to frequent evictions. // A larger size may affect performance. - static const size_t kMaximumNetworkQualityCacheSize = 10; + static const size_t kMaximumNetworkQualityCacheSize = 20; // Notifies |observer| of the current effective connection type if |observer| // is still registered as an observer. @@ -99,10 +97,6 @@ class NET_EXPORT_PRIVATE NetworkQualityStore { base::ObserverList<NetworkQualitiesCacheObserver> network_qualities_cache_observer_list_; - // When set to true, disables the offline check when storing the network - // quality. - bool disable_offline_check_; - base::ThreadChecker thread_checker_; base::WeakPtrFactory<NetworkQualityStore> weak_ptr_factory_; diff --git a/chromium/net/nqe/network_quality_store_unittest.cc b/chromium/net/nqe/network_quality_store_unittest.cc index 40ab2f4e12a..12928c507ff 100644 --- a/chromium/net/nqe/network_quality_store_unittest.cc +++ b/chromium/net/nqe/network_quality_store_unittest.cc @@ -38,7 +38,7 @@ TEST(NetworkQualityStoreTest, TestCaching) { // Entry should not be added. nqe::internal::NetworkID network_id(NetworkChangeNotifier::CONNECTION_2G, - "test1"); + "test1", 0); nqe::internal::CachedNetworkQuality read_network_quality; network_quality_store.Add(network_id, cached_network_quality_unknown); EXPECT_FALSE( @@ -48,7 +48,7 @@ TEST(NetworkQualityStoreTest, TestCaching) { { // Entry will be added for (2G, "test1"). nqe::internal::NetworkID network_id(NetworkChangeNotifier::CONNECTION_2G, - "test1"); + "test1", 0); nqe::internal::CachedNetworkQuality read_network_quality; network_quality_store.Add(network_id, cached_network_quality_2g_test1); EXPECT_TRUE( @@ -60,7 +60,7 @@ TEST(NetworkQualityStoreTest, TestCaching) { { // Entry will be added for (2G, "test2"). nqe::internal::NetworkID network_id(NetworkChangeNotifier::CONNECTION_2G, - "test2"); + "test2", 0); nqe::internal::CachedNetworkQuality read_network_quality; nqe::internal::CachedNetworkQuality cached_network_quality( tick_clock.NowTicks(), @@ -77,7 +77,7 @@ TEST(NetworkQualityStoreTest, TestCaching) { { // Entry will be added for (3G, "test3"). nqe::internal::NetworkID network_id(NetworkChangeNotifier::CONNECTION_3G, - "test3"); + "test3", 0); nqe::internal::CachedNetworkQuality read_network_quality; nqe::internal::CachedNetworkQuality cached_network_quality( tick_clock.NowTicks(), @@ -92,9 +92,9 @@ TEST(NetworkQualityStoreTest, TestCaching) { } { - // Entry will not be added for (Unknown, ""). + // Entry will be added for (Unknown, ""). nqe::internal::NetworkID network_id( - NetworkChangeNotifier::CONNECTION_UNKNOWN, ""); + NetworkChangeNotifier::CONNECTION_UNKNOWN, "", 0); nqe::internal::CachedNetworkQuality read_network_quality; nqe::internal::CachedNetworkQuality set_network_quality( tick_clock.NowTicks(), @@ -102,14 +102,14 @@ TEST(NetworkQualityStoreTest, TestCaching) { base::TimeDelta::FromSeconds(4), 4), EFFECTIVE_CONNECTION_TYPE_4G); network_quality_store.Add(network_id, set_network_quality); - EXPECT_FALSE( + EXPECT_TRUE( network_quality_store.GetById(network_id, &read_network_quality)); } { // Existing entry will be read for (2G, "test1"). nqe::internal::NetworkID network_id(NetworkChangeNotifier::CONNECTION_2G, - "test1"); + "test1", 0); nqe::internal::CachedNetworkQuality read_network_quality; EXPECT_TRUE( network_quality_store.GetById(network_id, &read_network_quality)); @@ -120,7 +120,7 @@ TEST(NetworkQualityStoreTest, TestCaching) { { // Existing entry will be overwritten for (2G, "test1"). nqe::internal::NetworkID network_id(NetworkChangeNotifier::CONNECTION_2G, - "test1"); + "test1", 0); nqe::internal::CachedNetworkQuality read_network_quality; const nqe::internal::CachedNetworkQuality cached_network_quality( tick_clock.NowTicks(), @@ -137,13 +137,96 @@ TEST(NetworkQualityStoreTest, TestCaching) { { // No entry should exist for (2G, "test4"). nqe::internal::NetworkID network_id(NetworkChangeNotifier::CONNECTION_2G, - "test4"); + "test4", 0); nqe::internal::CachedNetworkQuality read_network_quality; EXPECT_FALSE( network_quality_store.GetById(network_id, &read_network_quality)); } } +TEST(NetworkQualityStoreTest, TestCachingClosestSignalStrength) { + nqe::internal::NetworkQualityStore network_quality_store; + base::SimpleTestTickClock tick_clock; + + // Cached network quality for network with NetworkID (2G, "test1"). + const nqe::internal::CachedNetworkQuality cached_network_quality_strength_1( + tick_clock.NowTicks(), + nqe::internal::NetworkQuality(base::TimeDelta::FromSeconds(1), + base::TimeDelta::FromSeconds(1), 1), + EFFECTIVE_CONNECTION_TYPE_2G); + + const nqe::internal::CachedNetworkQuality cached_network_quality_strength_3( + tick_clock.NowTicks(), + nqe::internal::NetworkQuality(base::TimeDelta::FromSeconds(3), + base::TimeDelta::FromSeconds(3), 3), + EFFECTIVE_CONNECTION_TYPE_2G); + + { + // Entry will be added for (2G, "test1") with signal strength value of 1. + nqe::internal::NetworkID network_id(NetworkChangeNotifier::CONNECTION_2G, + "test1", 1); + nqe::internal::CachedNetworkQuality read_network_quality; + network_quality_store.Add(network_id, cached_network_quality_strength_1); + EXPECT_TRUE( + network_quality_store.GetById(network_id, &read_network_quality)); + EXPECT_EQ(cached_network_quality_strength_1.network_quality(), + read_network_quality.network_quality()); + } + + { + // Entry will be added for (2G, "test1") with signal strength value of 3. + nqe::internal::NetworkID network_id(NetworkChangeNotifier::CONNECTION_2G, + "test1", 3); + nqe::internal::CachedNetworkQuality read_network_quality; + network_quality_store.Add(network_id, cached_network_quality_strength_3); + EXPECT_TRUE( + network_quality_store.GetById(network_id, &read_network_quality)); + EXPECT_EQ(cached_network_quality_strength_3.network_quality(), + read_network_quality.network_quality()); + } + + { + // Now with cached entries for signal strengths 1 and 3, verify across the + // range of strength values that the closest value match will be returned + // when looking up (2G, "test1", signal_strength). + for (int32_t signal_strength = 0; signal_strength <= 4; ++signal_strength) { + nqe::internal::CachedNetworkQuality expected_cached_network_quality = + signal_strength <= 2 ? cached_network_quality_strength_1 + : cached_network_quality_strength_3; + nqe::internal::NetworkID network_id(NetworkChangeNotifier::CONNECTION_2G, + "test1", signal_strength); + nqe::internal::CachedNetworkQuality read_network_quality; + EXPECT_TRUE( + network_quality_store.GetById(network_id, &read_network_quality)); + EXPECT_EQ(expected_cached_network_quality.network_quality(), + read_network_quality.network_quality()); + } + } + + { + // Existing entry will be read for (2G, "test1", INT32_MIN). + // The first entry in the store matching (2G, "test1", *) would be returned. + int32_t signal_strength = INT32_MIN; + nqe::internal::NetworkID network_id(NetworkChangeNotifier::CONNECTION_2G, + "test1", signal_strength); + nqe::internal::CachedNetworkQuality read_network_quality; + EXPECT_TRUE( + network_quality_store.GetById(network_id, &read_network_quality)); + EXPECT_TRUE((cached_network_quality_strength_1.network_quality() == + read_network_quality.network_quality()) || + (cached_network_quality_strength_3.network_quality() == + read_network_quality.network_quality())); + } + + { + // No entry should exist for (2G, "test4"). + nqe::internal::NetworkID network_id(NetworkChangeNotifier::CONNECTION_2G, + "test4", 0); + nqe::internal::CachedNetworkQuality read_network_quality; + EXPECT_FALSE( + network_quality_store.GetById(network_id, &read_network_quality)); + } +} // Tests if the cache size remains bounded. Also, ensure that the cache is // LRU. TEST(NetworkQualityStoreTest, TestLRUCacheMaximumSize) { @@ -151,7 +234,7 @@ TEST(NetworkQualityStoreTest, TestLRUCacheMaximumSize) { base::SimpleTestTickClock tick_clock; // Add more networks than the maximum size of the cache. - const size_t network_count = 11; + const size_t network_count = 21; nqe::internal::CachedNetworkQuality read_network_quality( tick_clock.NowTicks(), @@ -161,7 +244,7 @@ TEST(NetworkQualityStoreTest, TestLRUCacheMaximumSize) { for (size_t i = 0; i < network_count; ++i) { nqe::internal::NetworkID network_id(NetworkChangeNotifier::CONNECTION_2G, - "test" + base::IntToString(i)); + "test" + base::IntToString(i), 0); const nqe::internal::CachedNetworkQuality network_quality( tick_clock.NowTicks(), @@ -176,7 +259,7 @@ TEST(NetworkQualityStoreTest, TestLRUCacheMaximumSize) { size_t cache_match_count = 0; for (size_t i = 0; i < network_count; ++i) { nqe::internal::NetworkID network_id(NetworkChangeNotifier::CONNECTION_2G, - "test" + base::IntToString(i)); + "test" + base::IntToString(i), 0); nqe::internal::CachedNetworkQuality read_network_quality( tick_clock.NowTicks(), diff --git a/chromium/net/nqe/observation_buffer_unittest.cc b/chromium/net/nqe/observation_buffer_unittest.cc index 1f15b79f2db..187e1c5c9fe 100644 --- a/chromium/net/nqe/observation_buffer_unittest.cc +++ b/chromium/net/nqe/observation_buffer_unittest.cc @@ -45,10 +45,6 @@ TEST(NetworkQualityObservationBufferTest, BoundedBuffer) { } } -// Test disabled on OS_WIN to avoid linking errors when calling -// SetTickClockForTesting. -// TODO(tbansal): crbug.com/651963. Pass the clock through NQE's constructor. -#if !defined(OS_WIN) // Verify that the percentiles are monotonically non-decreasing when a weight is // applied. TEST(NetworkQualityObservationBufferTest, GetPercentileWithWeights) { @@ -90,7 +86,6 @@ TEST(NetworkQualityObservationBufferTest, GetPercentileWithWeights) { } EXPECT_LT(result_lowest, result_highest); } -#endif // Verifies that the percentiles are correctly computed. All observations have // the same timestamp. diff --git a/chromium/net/nqe/proto/network_id_proto.proto b/chromium/net/nqe/proto/network_id_proto.proto index 28c7fb06e7d..a6d217a8c82 100644 --- a/chromium/net/nqe/proto/network_id_proto.proto +++ b/chromium/net/nqe/proto/network_id_proto.proto @@ -9,7 +9,8 @@ option optimize_for = LITE_RUNTIME; package net.nqe.internal; // NetworkIDProto contains data that can be used to uniquely identify a network -// type. Next id: 3 +// type. +// Next id: 4 message NetworkIDProto { // Connection type of the network mapped from // net::NetworkChangeNotifier::ConnectionType. @@ -17,4 +18,11 @@ message NetworkIDProto { // Name of this network. This is set to WiFi SSID or the MCCMNC of the // network. optional string id = 2; + // Signal strength of the network. Set to INT32_MIN when the value is + // unavailable. Otherwise, must be between 0 and 4 (both inclusive). This may + // take into account many different radio technology inputs. 0 represents very + // poor signal strength while 4 represents a very strong signal strength. + // The range is capped between 0 and 4 to ensure that a change in the value + // indicates a non-negligible change in the signal quality. + optional int32 signal_strength = 3; } diff --git a/chromium/net/nqe/throughput_analyzer.cc b/chromium/net/nqe/throughput_analyzer.cc index e72821cd37a..ac685d118eb 100644 --- a/chromium/net/nqe/throughput_analyzer.cc +++ b/chromium/net/nqe/throughput_analyzer.cc @@ -215,6 +215,46 @@ void ThroughputAnalyzer::NotifyRequestCompleted(const URLRequest& request) { MaybeStartThroughputObservationWindow(); } +bool ThroughputAnalyzer::IsHangingWindow(int64_t bits_received, + base::TimeDelta duration, + double downstream_kbps_double) const { + DCHECK(thread_checker_.CalledOnValidThread()); + + if (params_->throughput_hanging_requests_cwnd_size_multiplier() <= 0) + return false; + + // Initial congestion window size for TCP connections. + static constexpr size_t kCwndSizeKilobytes = 10 * 1.5; + static constexpr size_t kCwndSizeBits = kCwndSizeKilobytes * 1000 * 8; + + // Scale the |duration| to one HTTP RTT, and compute the number of bits that + // would be received over a duration of one HTTP RTT. + size_t bits_received_over_one_http_rtt = + bits_received * (network_quality_provider_->GetHttpRTT() + .value_or(base::TimeDelta::FromSeconds(10)) + .InMillisecondsF() / + duration.InMillisecondsF()); + + // If |is_hanging| is true, it implies that less than + // kCwndSizeKilobytes were received over a period of 1 HTTP RTT. For a network + // that is not under-utilized, it is expected that at least |kCwndSizeBits| + // are received over a duration of 1 HTTP RTT. + bool is_hanging = + bits_received_over_one_http_rtt < + (kCwndSizeBits * + params_->throughput_hanging_requests_cwnd_size_multiplier()); + + // Record kbps as function of |is_hanging|. + if (is_hanging) { + UMA_HISTOGRAM_COUNTS_1M("NQE.ThroughputObservation.Hanging", + downstream_kbps_double); + } else { + UMA_HISTOGRAM_COUNTS_1M("NQE.ThroughputObservation.NotHanging", + downstream_kbps_double); + } + return is_hanging; +} + bool ThroughputAnalyzer::MaybeGetThroughputObservation( int32_t* downstream_kbps) { DCHECK(thread_checker_.CalledOnValidThread()); @@ -248,6 +288,13 @@ bool ThroughputAnalyzer::MaybeGetThroughputObservation( double downstream_kbps_double = (bits_received * 1.0f) / duration.InMillisecondsF(); + + if (IsHangingWindow(bits_received, duration, downstream_kbps_double)) { + requests_.clear(); + EndThroughputObservationWindow(); + return false; + } + // Round-up |downstream_kbps_double|. *downstream_kbps = static_cast<int64_t>(std::ceil(downstream_kbps_double)); DCHECK(IsCurrentlyTrackingThroughput()); diff --git a/chromium/net/nqe/throughput_analyzer.h b/chromium/net/nqe/throughput_analyzer.h index a6cb95c7cf5..77350017b3a 100644 --- a/chromium/net/nqe/throughput_analyzer.h +++ b/chromium/net/nqe/throughput_analyzer.h @@ -113,6 +113,12 @@ class NET_EXPORT_PRIVATE ThroughputAnalyzer { // testing. void EraseHangingRequests(const URLRequest& request); + // Returns true if the current throughput observation window is heuristically + // determined to contain hanging requests. + bool IsHangingWindow(int64_t bits_received, + base::TimeDelta duration, + double downstream_kbps_double) const; + private: friend class TestThroughputAnalyzer; diff --git a/chromium/net/nqe/throughput_analyzer_unittest.cc b/chromium/net/nqe/throughput_analyzer_unittest.cc index 66432232673..629c10379ea 100644 --- a/chromium/net/nqe/throughput_analyzer_unittest.cc +++ b/chromium/net/nqe/throughput_analyzer_unittest.cc @@ -104,6 +104,7 @@ class TestThroughputAnalyzer : public internal::ThroughputAnalyzer { using internal::ThroughputAnalyzer::disable_throughput_measurements; using internal::ThroughputAnalyzer::CountInFlightRequests; using internal::ThroughputAnalyzer::EraseHangingRequests; + using internal::ThroughputAnalyzer::IsHangingWindow; private: int throughput_observations_received_; @@ -126,12 +127,12 @@ TEST(ThroughputAnalyzerTest, MaximumRequests) { }}; for (const auto& test : tests) { - base::DefaultTickClock tick_clock; + base::DefaultTickClock* tick_clock = base::DefaultTickClock::GetInstance(); TestNetworkQualityProvider network_quality_provider; std::map<std::string, std::string> variation_params; NetworkQualityEstimatorParams params(variation_params); TestThroughputAnalyzer throughput_analyzer(&network_quality_provider, - ¶ms, &tick_clock); + ¶ms, tick_clock); TestDelegate test_delegate; TestURLRequestContext context; @@ -168,7 +169,7 @@ TEST(ThroughputAnalyzerTest, MaximumRequests) { // Tests that the throughput observation is taken only if there are sufficient // number of requests in-flight. TEST(ThroughputAnalyzerTest, TestMinRequestsForThroughputSample) { - base::DefaultTickClock tick_clock; + base::DefaultTickClock* tick_clock = base::DefaultTickClock::GetInstance(); TestNetworkQualityProvider network_quality_provider; std::map<std::string, std::string> variation_params; NetworkQualityEstimatorParams params(variation_params); @@ -177,7 +178,7 @@ TEST(ThroughputAnalyzerTest, TestMinRequestsForThroughputSample) { num_requests <= params.throughput_min_requests_in_flight() + 1; ++num_requests) { TestThroughputAnalyzer throughput_analyzer(&network_quality_provider, - ¶ms, &tick_clock); + ¶ms, tick_clock); TestDelegate test_delegate; TestURLRequestContext context; throughput_analyzer.AddIPAddressResolution(&context); @@ -270,7 +271,7 @@ TEST(ThroughputAnalyzerTest, TestHangingRequests) { for (const auto& test : tests) { base::HistogramTester histogram_tester; - base::DefaultTickClock tick_clock; + base::DefaultTickClock* tick_clock = base::DefaultTickClock::GetInstance(); TestNetworkQualityProvider network_quality_provider; if (test.http_rtt >= base::TimeDelta()) network_quality_provider.SetHttpRtt(test.http_rtt); @@ -283,7 +284,7 @@ TEST(ThroughputAnalyzerTest, TestHangingRequests) { const size_t num_requests = params.throughput_min_requests_in_flight(); TestThroughputAnalyzer throughput_analyzer(&network_quality_provider, - ¶ms, &tick_clock); + ¶ms, tick_clock); TestDelegate test_delegate; TestURLRequestContext context; throughput_analyzer.AddIPAddressResolution(&context); @@ -557,13 +558,13 @@ TEST(ThroughputAnalyzerTest, TestThroughputWithMultipleRequestsOverlap) { }; for (const auto& test : tests) { - base::DefaultTickClock tick_clock; + base::DefaultTickClock* tick_clock = base::DefaultTickClock::GetInstance(); TestNetworkQualityProvider network_quality_provider; // Localhost requests are not allowed for estimation purposes. std::map<std::string, std::string> variation_params; NetworkQualityEstimatorParams params(variation_params); TestThroughputAnalyzer throughput_analyzer(&network_quality_provider, - ¶ms, &tick_clock); + ¶ms, tick_clock); TestDelegate test_delegate; TestURLRequestContext context; @@ -658,7 +659,7 @@ TEST(ThroughputAnalyzerTest, TestThroughputWithNetworkRequestsOverlap) { }; for (const auto& test : tests) { - base::DefaultTickClock tick_clock; + base::DefaultTickClock* tick_clock = base::DefaultTickClock::GetInstance(); TestNetworkQualityProvider network_quality_provider; // Localhost requests are not allowed for estimation purposes. std::map<std::string, std::string> variation_params; @@ -666,7 +667,7 @@ TEST(ThroughputAnalyzerTest, TestThroughputWithNetworkRequestsOverlap) { base::IntToString(test.throughput_min_requests_in_flight); NetworkQualityEstimatorParams params(variation_params); TestThroughputAnalyzer throughput_analyzer(&network_quality_provider, - ¶ms, &tick_clock); + ¶ms, tick_clock); TestDelegate test_delegate; TestURLRequestContext context; throughput_analyzer.AddIPAddressResolution(&context); @@ -716,13 +717,13 @@ TEST(ThroughputAnalyzerTest, TestThroughputWithNetworkRequestsOverlap) { // of network requests overlap, and the minimum number of in flight requests // when taking an observation is more than 1. TEST(ThroughputAnalyzerTest, TestThroughputWithMultipleNetworkRequests) { - base::DefaultTickClock tick_clock; + base::DefaultTickClock* tick_clock = base::DefaultTickClock::GetInstance(); TestNetworkQualityProvider network_quality_provider; std::map<std::string, std::string> variation_params; variation_params["throughput_min_requests_in_flight"] = "3"; NetworkQualityEstimatorParams params(variation_params); TestThroughputAnalyzer throughput_analyzer(&network_quality_provider, ¶ms, - &tick_clock); + tick_clock); TestDelegate test_delegate; TestURLRequestContext context; throughput_analyzer.AddIPAddressResolution(&context); @@ -783,6 +784,63 @@ TEST(ThroughputAnalyzerTest, TestThroughputWithMultipleNetworkRequests) { EXPECT_EQ(1, throughput_analyzer.throughput_observations_received()); } +TEST(ThroughputAnalyzerTest, TestHangingWindow) { + static constexpr size_t kCwndSizeKilobytes = 10 * 1.5; + static constexpr size_t kCwndSizeBits = kCwndSizeKilobytes * 1000 * 8; + + base::SimpleTestTickClock tick_clock; + + TestNetworkQualityProvider network_quality_provider; + int64_t http_rtt_msec = 1000; + network_quality_provider.SetHttpRtt( + base::TimeDelta::FromMilliseconds(http_rtt_msec)); + std::map<std::string, std::string> variation_params; + variation_params["throughput_hanging_requests_cwnd_size_multiplier"] = "1"; + NetworkQualityEstimatorParams params(variation_params); + + TestThroughputAnalyzer throughput_analyzer(&network_quality_provider, ¶ms, + &tick_clock); + + const struct { + size_t bits_received; + base::TimeDelta window_duration; + bool expected_hanging; + } tests[] = { + {100, base::TimeDelta::FromMilliseconds(http_rtt_msec), true}, + {kCwndSizeBits - 1, base::TimeDelta::FromMilliseconds(http_rtt_msec), + true}, + {kCwndSizeBits + 1, base::TimeDelta::FromMilliseconds(http_rtt_msec), + false}, + {2 * (kCwndSizeBits - 1), + base::TimeDelta::FromMilliseconds(http_rtt_msec * 2), true}, + {2 * (kCwndSizeBits + 1), + base::TimeDelta::FromMilliseconds(http_rtt_msec * 2), false}, + {kCwndSizeBits / 2 - 1, + base::TimeDelta::FromMilliseconds(http_rtt_msec / 2), true}, + {kCwndSizeBits / 2 + 1, + base::TimeDelta::FromMilliseconds(http_rtt_msec / 2), false}, + }; + + for (const auto& test : tests) { + base::HistogramTester histogram_tester; + double kbps = test.bits_received / test.window_duration.InMillisecondsF(); + EXPECT_EQ(test.expected_hanging, + throughput_analyzer.IsHangingWindow(test.bits_received, + test.window_duration, kbps)); + + if (test.expected_hanging) { + histogram_tester.ExpectUniqueSample("NQE.ThroughputObservation.Hanging", + kbps, 1); + histogram_tester.ExpectTotalCount("NQE.ThroughputObservation.NotHanging", + 0); + } else { + histogram_tester.ExpectTotalCount("NQE.ThroughputObservation.Hanging", 0); + histogram_tester.ExpectUniqueSample( + "NQE.ThroughputObservation.NotHanging", kbps, 1); + } + } +} + } // namespace } // namespace nqe diff --git a/chromium/net/ntlm/ntlm_buffer_reader.cc b/chromium/net/ntlm/ntlm_buffer_reader.cc index b23e38b851c..8bba339a998 100644 --- a/chromium/net/ntlm/ntlm_buffer_reader.cc +++ b/chromium/net/ntlm/ntlm_buffer_reader.cc @@ -25,7 +25,7 @@ NtlmBufferReader::NtlmBufferReader(const uint8_t* ptr, size_t len) : NtlmBufferReader( base::StringPiece(reinterpret_cast<const char*>(ptr), len)) {} -NtlmBufferReader::~NtlmBufferReader() {} +NtlmBufferReader::~NtlmBufferReader() = default; bool NtlmBufferReader::CanRead(size_t len) const { return CanReadFrom(GetCursor(), len); diff --git a/chromium/net/ntlm/ntlm_buffer_writer.cc b/chromium/net/ntlm/ntlm_buffer_writer.cc index da6bc773cc7..300812b4c4d 100644 --- a/chromium/net/ntlm/ntlm_buffer_writer.cc +++ b/chromium/net/ntlm/ntlm_buffer_writer.cc @@ -18,7 +18,7 @@ namespace ntlm { NtlmBufferWriter::NtlmBufferWriter(size_t buffer_len) : buffer_(buffer_len, 0), cursor_(0) {} -NtlmBufferWriter::~NtlmBufferWriter() {} +NtlmBufferWriter::~NtlmBufferWriter() = default; bool NtlmBufferWriter::CanWrite(size_t len) const { if (!GetBufferPtr()) diff --git a/chromium/net/ntlm/ntlm_client.cc b/chromium/net/ntlm/ntlm_client.cc index a034fd37fbd..f8e12f5fdec 100644 --- a/chromium/net/ntlm/ntlm_client.cc +++ b/chromium/net/ntlm/ntlm_client.cc @@ -144,7 +144,7 @@ NtlmClient::NtlmClient(NtlmFeatures features) GenerateNegotiateMessage(); } -NtlmClient::~NtlmClient() {} +NtlmClient::~NtlmClient() = default; Buffer NtlmClient::GetNegotiateMessage() const { return negotiate_message_; diff --git a/chromium/net/proxy/dhcp_proxy_script_fetcher.cc b/chromium/net/proxy/dhcp_proxy_script_fetcher.cc index 839c59bbd31..71a32c213b8 100644 --- a/chromium/net/proxy/dhcp_proxy_script_fetcher.cc +++ b/chromium/net/proxy/dhcp_proxy_script_fetcher.cc @@ -12,13 +12,13 @@ std::string DhcpProxyScriptFetcher::GetFetcherName() const { return std::string(); } -DhcpProxyScriptFetcher::DhcpProxyScriptFetcher() {} +DhcpProxyScriptFetcher::DhcpProxyScriptFetcher() = default; -DhcpProxyScriptFetcher::~DhcpProxyScriptFetcher() {} +DhcpProxyScriptFetcher::~DhcpProxyScriptFetcher() = default; -DoNothingDhcpProxyScriptFetcher::DoNothingDhcpProxyScriptFetcher() {} +DoNothingDhcpProxyScriptFetcher::DoNothingDhcpProxyScriptFetcher() = default; -DoNothingDhcpProxyScriptFetcher::~DoNothingDhcpProxyScriptFetcher() {} +DoNothingDhcpProxyScriptFetcher::~DoNothingDhcpProxyScriptFetcher() = default; int DoNothingDhcpProxyScriptFetcher::Fetch( base::string16* utf16_text, const CompletionCallback& callback) { diff --git a/chromium/net/proxy/dhcp_proxy_script_fetcher_factory.cc b/chromium/net/proxy/dhcp_proxy_script_fetcher_factory.cc index 0590690344b..b0188eaf020 100644 --- a/chromium/net/proxy/dhcp_proxy_script_fetcher_factory.cc +++ b/chromium/net/proxy/dhcp_proxy_script_fetcher_factory.cc @@ -13,9 +13,9 @@ namespace net { -DhcpProxyScriptFetcherFactory::DhcpProxyScriptFetcherFactory() {} +DhcpProxyScriptFetcherFactory::DhcpProxyScriptFetcherFactory() = default; -DhcpProxyScriptFetcherFactory::~DhcpProxyScriptFetcherFactory() {} +DhcpProxyScriptFetcherFactory::~DhcpProxyScriptFetcherFactory() = default; std::unique_ptr<DhcpProxyScriptFetcher> DhcpProxyScriptFetcherFactory::Create( URLRequestContext* context) { diff --git a/chromium/net/proxy/dhcp_proxy_script_fetcher_win_unittest.cc b/chromium/net/proxy/dhcp_proxy_script_fetcher_win_unittest.cc index 03ed2c9d118..b7e407c9b32 100644 --- a/chromium/net/proxy/dhcp_proxy_script_fetcher_win_unittest.cc +++ b/chromium/net/proxy/dhcp_proxy_script_fetcher_win_unittest.cc @@ -674,7 +674,7 @@ TEST(DhcpProxyScriptFetcherWin, OnShutdown) { client.ResetTestState(); EXPECT_THAT(client.RunTestThatMayFailSync(), IsError(ERR_CONTEXT_SHUT_DOWN)); - EXPECT_EQ(0u, context.url_requests().size()); + EXPECT_EQ(0u, context.url_requests()->size()); } } // namespace diff --git a/chromium/net/proxy/dhcpcsvc_init_win.cc b/chromium/net/proxy/dhcpcsvc_init_win.cc index d243f1859aa..d9079606782 100644 --- a/chromium/net/proxy/dhcpcsvc_init_win.cc +++ b/chromium/net/proxy/dhcpcsvc_init_win.cc @@ -7,6 +7,8 @@ #include "base/lazy_instance.h" #include "base/logging.h" +#include <windows.h> // Must be in front of other Windows header files. + #include <dhcpcsdk.h> #include <dhcpv6csdk.h> diff --git a/chromium/net/proxy/mock_proxy_resolver.cc b/chromium/net/proxy/mock_proxy_resolver.cc index 2d6889d05bd..0daea49ccdc 100644 --- a/chromium/net/proxy/mock_proxy_resolver.cc +++ b/chromium/net/proxy/mock_proxy_resolver.cc @@ -31,7 +31,7 @@ MockAsyncProxyResolver::Job::Job(MockAsyncProxyResolver* resolver, const CompletionCallback& callback) : resolver_(resolver), url_(url), results_(results), callback_(callback) {} -MockAsyncProxyResolver::Job::~Job() {} +MockAsyncProxyResolver::Job::~Job() = default; void MockAsyncProxyResolver::Job::CompleteNow(int rv) { CompletionCallback callback = callback_; @@ -41,7 +41,7 @@ void MockAsyncProxyResolver::Job::CompleteNow(int rv) { callback.Run(rv); } -MockAsyncProxyResolver::~MockAsyncProxyResolver() {} +MockAsyncProxyResolver::~MockAsyncProxyResolver() = default; int MockAsyncProxyResolver::GetProxyForURL( const GURL& url, @@ -77,8 +77,7 @@ void MockAsyncProxyResolver::RemovePendingJob(Job* job) { pending_jobs_.erase(it); } -MockAsyncProxyResolver::MockAsyncProxyResolver() { -} +MockAsyncProxyResolver::MockAsyncProxyResolver() = default; MockAsyncProxyResolverFactory::Request::Request( MockAsyncProxyResolverFactory* factory, @@ -90,8 +89,7 @@ MockAsyncProxyResolverFactory::Request::Request( resolver_(resolver), callback_(callback) {} -MockAsyncProxyResolverFactory::Request::~Request() { -} +MockAsyncProxyResolverFactory::Request::~Request() = default; void MockAsyncProxyResolverFactory::Request::CompleteNow( int rv, diff --git a/chromium/net/proxy/mock_proxy_script_fetcher.cc b/chromium/net/proxy/mock_proxy_script_fetcher.cc index e07bde57a8b..8e0d3dd39c7 100644 --- a/chromium/net/proxy/mock_proxy_script_fetcher.cc +++ b/chromium/net/proxy/mock_proxy_script_fetcher.cc @@ -18,7 +18,7 @@ MockProxyScriptFetcher::MockProxyScriptFetcher() waiting_for_fetch_(false), is_shutdown_(false) {} -MockProxyScriptFetcher::~MockProxyScriptFetcher() {} +MockProxyScriptFetcher::~MockProxyScriptFetcher() = default; // ProxyScriptFetcher implementation. int MockProxyScriptFetcher::Fetch(const GURL& url, base::string16* text, diff --git a/chromium/net/proxy/multi_threaded_proxy_resolver.cc b/chromium/net/proxy/multi_threaded_proxy_resolver.cc index 4edab19ff6d..a50b3f946ba 100644 --- a/chromium/net/proxy/multi_threaded_proxy_resolver.cc +++ b/chromium/net/proxy/multi_threaded_proxy_resolver.cc @@ -224,7 +224,7 @@ class Job : public base::RefCountedThreadSafe<Job> { friend class base::RefCountedThreadSafe<Job>; - virtual ~Job() {} + virtual ~Job() = default; private: const Type type_; @@ -270,7 +270,7 @@ class CreateResolverJob : public Job { } protected: - ~CreateResolverJob() override {} + ~CreateResolverJob() override = default; private: // Runs the completion callback on the origin thread. @@ -338,7 +338,7 @@ class MultiThreadedProxyResolver::GetProxyForURLJob : public Job { } protected: - ~GetProxyForURLJob() override {} + ~GetProxyForURLJob() override = default; private: // Runs the completion callback on the origin thread. diff --git a/chromium/net/proxy/multi_threaded_proxy_resolver_unittest.cc b/chromium/net/proxy/multi_threaded_proxy_resolver_unittest.cc index 59524eb717b..8cc5bb6306c 100644 --- a/chromium/net/proxy/multi_threaded_proxy_resolver_unittest.cc +++ b/chromium/net/proxy/multi_threaded_proxy_resolver_unittest.cc @@ -142,7 +142,7 @@ class BlockableProxyResolverFactory : public ProxyResolverFactory { public: BlockableProxyResolverFactory() : ProxyResolverFactory(false) {} - ~BlockableProxyResolverFactory() override {} + ~BlockableProxyResolverFactory() override = default; int CreateProxyResolver( const scoped_refptr<ProxyResolverScriptData>& script_data, diff --git a/chromium/net/proxy/network_delegate_error_observer.cc b/chromium/net/proxy/network_delegate_error_observer.cc index e51b39994f2..6fe0aaace05 100644 --- a/chromium/net/proxy/network_delegate_error_observer.cc +++ b/chromium/net/proxy/network_delegate_error_observer.cc @@ -43,8 +43,7 @@ NetworkDelegateErrorObserver::Core::Core( DCHECK(origin_runner); } -NetworkDelegateErrorObserver::Core::~Core() {} - +NetworkDelegateErrorObserver::Core::~Core() = default; void NetworkDelegateErrorObserver::Core::NotifyPACScriptError( int line_number, diff --git a/chromium/net/proxy/network_delegate_error_observer_unittest.cc b/chromium/net/proxy/network_delegate_error_observer_unittest.cc index 3055340fbc9..8a6fe3c027b 100644 --- a/chromium/net/proxy/network_delegate_error_observer_unittest.cc +++ b/chromium/net/proxy/network_delegate_error_observer_unittest.cc @@ -22,7 +22,7 @@ namespace { class TestNetworkDelegate : public NetworkDelegateImpl { public: TestNetworkDelegate() : got_pac_error_(false) {} - ~TestNetworkDelegate() override {} + ~TestNetworkDelegate() override = default; bool got_pac_error() const { return got_pac_error_; } diff --git a/chromium/net/proxy/pac_js_library.h b/chromium/net/proxy/pac_js_library.h new file mode 100644 index 00000000000..a26ea80a7e6 --- /dev/null +++ b/chromium/net/proxy/pac_js_library.h @@ -0,0 +1,282 @@ +// Copyright (c) 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_PROXY_PAC_JS_LIBRARY_H_ +#define NET_PROXY_PAC_JS_LIBRARY_H_ + +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Akhil Arora <akhil.arora@sun.com> + * Tomi Leppikangas <Tomi.Leppikangas@oulu.fi> + * Darin Fisher <darin@meer.net> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +// The following code was formatted from: +// 'mozilla/netwerk/base/src/nsProxyAutoConfig.js' (1.55) +// +// Using the command: +// $ cat nsProxyAutoConfig.js | +// awk '/var pacUtils/,/EOF/' | +// sed -e 's/^\s*$/""/g' | +// sed -e 's/"\s*[+]\s*$/"/g' | +// sed -e 's/"$/" \\/g' | +// sed -e 's/\/(ipaddr);/\/.exec(ipaddr);/g' | +// grep -v '^var pacUtils =' +// +// isPlainHost() was removed. +#define PAC_JS_LIBRARY \ + "function dnsDomainIs(host, domain) {\n" \ + " return (host.length >= domain.length &&\n" \ + " host.substring(host.length - domain.length) == domain);\n" \ + "}\n" \ + "" \ + "function dnsDomainLevels(host) {\n" \ + " return host.split('.').length-1;\n" \ + "}\n" \ + "" \ + "function convert_addr(ipchars) {\n" \ + " var bytes = ipchars.split('.');\n" \ + " var result = ((bytes[0] & 0xff) << 24) |\n" \ + " ((bytes[1] & 0xff) << 16) |\n" \ + " ((bytes[2] & 0xff) << 8) |\n" \ + " (bytes[3] & 0xff);\n" \ + " return result;\n" \ + "}\n" \ + "" \ + "function isInNet(ipaddr, pattern, maskstr) {\n" \ + " var test = " \ + "/^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$/.exec(ipaddr);\n" \ + " if (test == null) {\n" \ + " ipaddr = dnsResolve(ipaddr);\n" \ + " if (ipaddr == null)\n" \ + " return false;\n" \ + " } else if (test[1] > 255 || test[2] > 255 || \n" \ + " test[3] > 255 || test[4] > 255) {\n" \ + " return false; // not an IP address\n" \ + " }\n" \ + " var host = convert_addr(ipaddr);\n" \ + " var pat = convert_addr(pattern);\n" \ + " var mask = convert_addr(maskstr);\n" \ + " return ((host & mask) == (pat & mask));\n" \ + " \n" \ + "}\n" \ + "" \ + "function isResolvable(host) {\n" \ + " var ip = dnsResolve(host);\n" \ + " return (ip != null);\n" \ + "}\n" \ + "" \ + "function localHostOrDomainIs(host, hostdom) {\n" \ + " return (host == hostdom) ||\n" \ + " (hostdom.lastIndexOf(host + '.', 0) == 0);\n" \ + "}\n" \ + "" \ + "function shExpMatch(url, pattern) {\n" \ + " pattern = pattern.replace(/\\./g, '\\\\.');\n" \ + " pattern = pattern.replace(/\\*/g, '.*');\n" \ + " pattern = pattern.replace(/\\?/g, '.');\n" \ + " var newRe = new RegExp('^'+pattern+'$');\n" \ + " return newRe.test(url);\n" \ + "}\n" \ + "" \ + "var wdays = {SUN: 0, MON: 1, TUE: 2, WED: 3, THU: 4, FRI: 5, SAT: 6};\n" \ + "" \ + "var months = {JAN: 0, FEB: 1, MAR: 2, APR: 3, MAY: 4, JUN: 5, JUL: 6, " \ + "AUG: 7, SEP: 8, OCT: 9, NOV: 10, DEC: 11};\n" \ + "" \ + "function weekdayRange() {\n" \ + " function getDay(weekday) {\n" \ + " if (weekday in wdays) {\n" \ + " return wdays[weekday];\n" \ + " }\n" \ + " return -1;\n" \ + " }\n" \ + " var date = new Date();\n" \ + " var argc = arguments.length;\n" \ + " var wday;\n" \ + " if (argc < 1)\n" \ + " return false;\n" \ + " if (arguments[argc - 1] == 'GMT') {\n" \ + " argc--;\n" \ + " wday = date.getUTCDay();\n" \ + " } else {\n" \ + " wday = date.getDay();\n" \ + " }\n" \ + " var wd1 = getDay(arguments[0]);\n" \ + " var wd2 = (argc == 2) ? getDay(arguments[1]) : wd1;\n" \ + " return (wd1 == -1 || wd2 == -1) ? false\n" \ + " : (wd1 <= wday && wday <= wd2);\n" \ + "}\n" \ + "" \ + "function dateRange() {\n" \ + " function getMonth(name) {\n" \ + " if (name in months) {\n" \ + " return months[name];\n" \ + " }\n" \ + " return -1;\n" \ + " }\n" \ + " var date = new Date();\n" \ + " var argc = arguments.length;\n" \ + " if (argc < 1) {\n" \ + " return false;\n" \ + " }\n" \ + " var isGMT = (arguments[argc - 1] == 'GMT');\n" \ + "\n" \ + " if (isGMT) {\n" \ + " argc--;\n" \ + " }\n" \ + " // function will work even without explict handling of this case\n" \ + " if (argc == 1) {\n" \ + " var tmp = parseInt(arguments[0]);\n" \ + " if (isNaN(tmp)) {\n" \ + " return ((isGMT ? date.getUTCMonth() : date.getMonth()) ==\n" \ + "getMonth(arguments[0]));\n" \ + " } else if (tmp < 32) {\n" \ + " return ((isGMT ? date.getUTCDate() : date.getDate()) == " \ + "tmp);\n" \ + " } else { \n" \ + " return ((isGMT ? date.getUTCFullYear() : date.getFullYear()) " \ + "==\n" \ + "tmp);\n" \ + " }\n" \ + " }\n" \ + " var year = date.getFullYear();\n" \ + " var date1, date2;\n" \ + " date1 = new Date(year, 0, 1, 0, 0, 0);\n" \ + " date2 = new Date(year, 11, 31, 23, 59, 59);\n" \ + " var adjustMonth = false;\n" \ + " for (var i = 0; i < (argc >> 1); i++) {\n" \ + " var tmp = parseInt(arguments[i]);\n" \ + " if (isNaN(tmp)) {\n" \ + " var mon = getMonth(arguments[i]);\n" \ + " date1.setMonth(mon);\n" \ + " } else if (tmp < 32) {\n" \ + " adjustMonth = (argc <= 2);\n" \ + " date1.setDate(tmp);\n" \ + " } else {\n" \ + " date1.setFullYear(tmp);\n" \ + " }\n" \ + " }\n" \ + " for (var i = (argc >> 1); i < argc; i++) {\n" \ + " var tmp = parseInt(arguments[i]);\n" \ + " if (isNaN(tmp)) {\n" \ + " var mon = getMonth(arguments[i]);\n" \ + " date2.setMonth(mon);\n" \ + " } else if (tmp < 32) {\n" \ + " date2.setDate(tmp);\n" \ + " } else {\n" \ + " date2.setFullYear(tmp);\n" \ + " }\n" \ + " }\n" \ + " if (adjustMonth) {\n" \ + " date1.setMonth(date.getMonth());\n" \ + " date2.setMonth(date.getMonth());\n" \ + " }\n" \ + " if (isGMT) {\n" \ + " var tmp = date;\n" \ + " tmp.setFullYear(date.getUTCFullYear());\n" \ + " tmp.setMonth(date.getUTCMonth());\n" \ + " tmp.setDate(date.getUTCDate());\n" \ + " tmp.setHours(date.getUTCHours());\n" \ + " tmp.setMinutes(date.getUTCMinutes());\n" \ + " tmp.setSeconds(date.getUTCSeconds());\n" \ + " date = tmp;\n" \ + " }\n" \ + " return ((date1 <= date) && (date <= date2));\n" \ + "}\n" \ + "" \ + "function timeRange() {\n" \ + " var argc = arguments.length;\n" \ + " var date = new Date();\n" \ + " var isGMT= false;\n" \ + "\n" \ + " if (argc < 1) {\n" \ + " return false;\n" \ + " }\n" \ + " if (arguments[argc - 1] == 'GMT') {\n" \ + " isGMT = true;\n" \ + " argc--;\n" \ + " }\n" \ + "\n" \ + " var hour = isGMT ? date.getUTCHours() : date.getHours();\n" \ + " var date1, date2;\n" \ + " date1 = new Date();\n" \ + " date2 = new Date();\n" \ + "\n" \ + " if (argc == 1) {\n" \ + " return (hour == arguments[0]);\n" \ + " } else if (argc == 2) {\n" \ + " return ((arguments[0] <= hour) && (hour <= arguments[1]));\n" \ + " } else {\n" \ + " switch (argc) {\n" \ + " case 6:\n" \ + " date1.setSeconds(arguments[2]);\n" \ + " date2.setSeconds(arguments[5]);\n" \ + " case 4:\n" \ + " var middle = argc >> 1;\n" \ + " date1.setHours(arguments[0]);\n" \ + " date1.setMinutes(arguments[1]);\n" \ + " date2.setHours(arguments[middle]);\n" \ + " date2.setMinutes(arguments[middle + 1]);\n" \ + " if (middle == 2) {\n" \ + " date2.setSeconds(59);\n" \ + " }\n" \ + " break;\n" \ + " default:\n" \ + " throw 'timeRange: bad number of arguments'\n" \ + " }\n" \ + " }\n" \ + "\n" \ + " if (isGMT) {\n" \ + " date.setFullYear(date.getUTCFullYear());\n" \ + " date.setMonth(date.getUTCMonth());\n" \ + " date.setDate(date.getUTCDate());\n" \ + " date.setHours(date.getUTCHours());\n" \ + " date.setMinutes(date.getUTCMinutes());\n" \ + " date.setSeconds(date.getUTCSeconds());\n" \ + " }\n" \ + " return ((date1 <= date) && (date <= date2));\n" \ + "}\n" + +// This is a Microsoft extension to PAC for IPv6, see: +// http://blogs.msdn.com/b/wndp/archive/2006/07/13/ipv6-pac-extensions-v0-9.aspx +#define PAC_JS_LIBRARY_EX \ + "function isResolvableEx(host) {\n" \ + " var ipList = dnsResolveEx(host);\n" \ + " return (ipList != '');\n" \ + "}\n" + +#endif // NET_PROXY_PAC_JS_LIBRARY_H_ diff --git a/chromium/net/proxy/polling_proxy_config_service.cc b/chromium/net/proxy/polling_proxy_config_service.cc index 0208979c5b1..7a78400ad08 100644 --- a/chromium/net/proxy/polling_proxy_config_service.cc +++ b/chromium/net/proxy/polling_proxy_config_service.cc @@ -98,7 +98,7 @@ class PollingProxyConfigService::Core private: friend class base::RefCountedThreadSafe<Core>; - ~Core() {} + ~Core() = default; void PollAsync(GetConfigFunction func) { ProxyConfig config; diff --git a/chromium/net/proxy/proxy_bypass_rules.cc b/chromium/net/proxy/proxy_bypass_rules.cc index 2d22ae909c7..dddfe43548a 100644 --- a/chromium/net/proxy/proxy_bypass_rules.cc +++ b/chromium/net/proxy/proxy_bypass_rules.cc @@ -136,18 +136,15 @@ bool IsIPAddress(const std::string& domain) { } // namespace -ProxyBypassRules::Rule::Rule() { -} +ProxyBypassRules::Rule::Rule() = default; -ProxyBypassRules::Rule::~Rule() { -} +ProxyBypassRules::Rule::~Rule() = default; bool ProxyBypassRules::Rule::Equals(const Rule& rule) const { return ToString() == rule.ToString(); } -ProxyBypassRules::ProxyBypassRules() { -} +ProxyBypassRules::ProxyBypassRules() = default; ProxyBypassRules::ProxyBypassRules(const ProxyBypassRules& rhs) { AssignFrom(rhs); diff --git a/chromium/net/proxy/proxy_config.cc b/chromium/net/proxy/proxy_config.cc index 87e17d8eb48..1f4ae8b1d16 100644 --- a/chromium/net/proxy/proxy_config.cc +++ b/chromium/net/proxy/proxy_config.cc @@ -45,8 +45,7 @@ ProxyConfig::ProxyRules::ProxyRules() ProxyConfig::ProxyRules::ProxyRules(const ProxyRules& other) = default; -ProxyConfig::ProxyRules::~ProxyRules() { -} +ProxyConfig::ProxyRules::~ProxyRules() = default; void ProxyConfig::ProxyRules::Apply(const GURL& url, ProxyInfo* result) const { if (empty()) { @@ -198,8 +197,7 @@ ProxyConfig::ProxyConfig() ProxyConfig::ProxyConfig(const ProxyConfig& config) = default; -ProxyConfig::~ProxyConfig() { -} +ProxyConfig::~ProxyConfig() = default; ProxyConfig& ProxyConfig::operator=(const ProxyConfig& config) = default; diff --git a/chromium/net/proxy/proxy_config_service_fixed.cc b/chromium/net/proxy/proxy_config_service_fixed.cc index 3081ea5afa1..ebcdbd382f7 100644 --- a/chromium/net/proxy/proxy_config_service_fixed.cc +++ b/chromium/net/proxy/proxy_config_service_fixed.cc @@ -10,7 +10,7 @@ ProxyConfigServiceFixed::ProxyConfigServiceFixed(const ProxyConfig& pc) : pc_(pc) { } -ProxyConfigServiceFixed::~ProxyConfigServiceFixed() {} +ProxyConfigServiceFixed::~ProxyConfigServiceFixed() = default; ProxyConfigService::ConfigAvailability ProxyConfigServiceFixed::GetLatestProxyConfig(ProxyConfig* config) { diff --git a/chromium/net/proxy/proxy_config_service_linux.cc b/chromium/net/proxy/proxy_config_service_linux.cc index a28ed5b4e19..bd7bce55741 100644 --- a/chromium/net/proxy/proxy_config_service_linux.cc +++ b/chromium/net/proxy/proxy_config_service_linux.cc @@ -5,12 +5,7 @@ #include "net/proxy/proxy_config_service_linux.h" #include <errno.h> -#if defined(USE_GCONF) -#include <gconf/gconf-client.h> -#endif // defined(USE_GCONF) #include <limits.h> -#include <stdio.h> -#include <stdlib.h> #include <sys/inotify.h> #include <unistd.h> @@ -18,8 +13,6 @@ #include <utility> #include "base/bind.h" -#include "base/compiler_specific.h" -#include "base/debug/leak_annotations.h" #include "base/files/file_descriptor_watcher_posix.h" #include "base/files/file_path.h" #include "base/files/file_util.h" @@ -36,14 +29,11 @@ #include "base/task_scheduler/task_traits.h" #include "base/threading/thread_restrictions.h" #include "base/timer/timer.h" -#include "net/base/net_errors.h" -#include "net/http/http_util.h" #include "net/proxy/proxy_config.h" #include "net/proxy/proxy_server.h" -#include "url/url_canon.h" #if defined(USE_GIO) -#include "library_loaders/libgio.h" // nogncheck +#include <gio/gio.h> #endif // defined(USE_GIO) namespace net { @@ -94,8 +84,7 @@ std::string FixupProxyHostScheme(ProxyServer::Scheme scheme, } // namespace -ProxyConfigServiceLinux::Delegate::~Delegate() { -} +ProxyConfigServiceLinux::Delegate::~Delegate() = default; bool ProxyConfigServiceLinux::Delegate::GetProxyFromEnvVarForScheme( base::StringPiece variable, @@ -204,324 +193,8 @@ namespace { const int kDebounceTimeoutMilliseconds = 250; -#if defined(USE_GCONF) -// This setting getter uses gconf, as used in GNOME 2 and some GNOME 3 desktops. -class SettingGetterImplGConf : public ProxyConfigServiceLinux::SettingGetter { - public: - SettingGetterImplGConf() - : client_(nullptr), - system_proxy_id_(0), - system_http_proxy_id_(0), - notify_delegate_(nullptr), - debounce_timer_(new base::OneShotTimer()) {} - - ~SettingGetterImplGConf() override { - // client_ should have been released before now, from - // Delegate::OnDestroy(), while running on the UI thread. However - // on exiting the process, it may happen that Delegate::OnDestroy() - // task is left pending on the glib loop after the loop was quit, - // and pending tasks may then be deleted without being run. - if (client_) { - // gconf client was not cleaned up. - if (task_runner_->RunsTasksInCurrentSequence()) { - // We are on the UI thread so we can clean it safely. This is - // the case at least for ui_tests running under Valgrind in - // bug 16076. - VLOG(1) << "~SettingGetterImplGConf: releasing gconf client"; - ShutDown(); - } else { - // This is very bad! We are deleting the setting getter but we're not on - // the UI thread. This is not supposed to happen: the setting getter is - // owned by the proxy config service's delegate, which is supposed to be - // destroyed on the UI thread only. We will get change notifications to - // a deleted object if we continue here, so fail now. - LOG(FATAL) << "~SettingGetterImplGConf: deleting on wrong thread!"; - } - } - DCHECK(!client_); - } - - bool Init(const scoped_refptr<base::SingleThreadTaskRunner>& glib_task_runner) - override { - DCHECK(glib_task_runner->RunsTasksInCurrentSequence()); - DCHECK(!client_); - DCHECK(!task_runner_.get()); - task_runner_ = glib_task_runner; - - client_ = gconf_client_get_default(); - if (!client_) { - // It's not clear whether/when this can return NULL. - LOG(ERROR) << "Unable to create a gconf client"; - task_runner_ = nullptr; - return false; - } - GError* error = nullptr; - bool added_system_proxy = false; - // We need to add the directories for which we'll be asking - // for notifications, and we might as well ask to preload them. - // These need to be removed again in ShutDown(); we are careful - // here to only leave client_ non-NULL if both have been added. - gconf_client_add_dir(client_, "/system/proxy", - GCONF_CLIENT_PRELOAD_ONELEVEL, &error); - if (!error) { - added_system_proxy = true; - gconf_client_add_dir(client_, "/system/http_proxy", - GCONF_CLIENT_PRELOAD_ONELEVEL, &error); - } - if (!error) - return true; - - LOG(ERROR) << "Error requesting gconf directory: " << error->message; - g_error_free(error); - if (added_system_proxy) - gconf_client_remove_dir(client_, "/system/proxy", nullptr); - g_object_unref(client_); - client_ = nullptr; - task_runner_ = nullptr; - return false; - } - - void ShutDown() override { - if (client_) { - DCHECK(task_runner_->RunsTasksInCurrentSequence()); - // We must explicitly disable gconf notifications here, because the gconf - // client will be shared between all setting getters, and they do not all - // have the same lifetimes. (For instance, incognito sessions get their - // own, which is destroyed when the session ends.) - gconf_client_notify_remove(client_, system_http_proxy_id_); - gconf_client_notify_remove(client_, system_proxy_id_); - gconf_client_remove_dir(client_, "/system/http_proxy", nullptr); - gconf_client_remove_dir(client_, "/system/proxy", nullptr); - g_object_unref(client_); - client_ = nullptr; - task_runner_ = nullptr; - } - debounce_timer_.reset(); - } - - bool SetUpNotifications( - ProxyConfigServiceLinux::Delegate* delegate) override { - DCHECK(client_); - DCHECK(task_runner_->RunsTasksInCurrentSequence()); - GError* error = nullptr; - notify_delegate_ = delegate; - // We have to keep track of the IDs returned by gconf_client_notify_add() so - // that we can remove them in ShutDown(). (Otherwise, notifications will be - // delivered to this object after it is deleted, which is bad, m'kay?) - system_proxy_id_ = gconf_client_notify_add(client_, "/system/proxy", - OnGConfChangeNotification, this, - nullptr, &error); - if (!error) { - system_http_proxy_id_ = gconf_client_notify_add( - client_, "/system/http_proxy", OnGConfChangeNotification, this, - nullptr, &error); - } - if (!error) { - // Simulate a change to avoid possibly losing updates before this point. - OnChangeNotification(); - return true; - } - - LOG(ERROR) << "Error requesting gconf notifications: " << error->message; - g_error_free(error); - ShutDown(); - return false; - } - - const scoped_refptr<base::SequencedTaskRunner>& GetNotificationTaskRunner() - override { - return task_runner_; - } - - ProxyConfigSource GetConfigSource() override { - return PROXY_CONFIG_SOURCE_GCONF; - } - - bool GetString(StringSetting key, std::string* result) override { - switch (key) { - case PROXY_MODE: - return GetStringByPath("/system/proxy/mode", result); - case PROXY_AUTOCONF_URL: - return GetStringByPath("/system/proxy/autoconfig_url", result); - case PROXY_HTTP_HOST: - return GetStringByPath("/system/http_proxy/host", result); - case PROXY_HTTPS_HOST: - return GetStringByPath("/system/proxy/secure_host", result); - case PROXY_FTP_HOST: - return GetStringByPath("/system/proxy/ftp_host", result); - case PROXY_SOCKS_HOST: - return GetStringByPath("/system/proxy/socks_host", result); - } - return false; // Placate compiler. - } - bool GetBool(BoolSetting key, bool* result) override { - switch (key) { - case PROXY_USE_HTTP_PROXY: - return GetBoolByPath("/system/http_proxy/use_http_proxy", result); - case PROXY_USE_SAME_PROXY: - return GetBoolByPath("/system/http_proxy/use_same_proxy", result); - case PROXY_USE_AUTHENTICATION: - return GetBoolByPath("/system/http_proxy/use_authentication", result); - } - return false; // Placate compiler. - } - bool GetInt(IntSetting key, int* result) override { - switch (key) { - case PROXY_HTTP_PORT: - return GetIntByPath("/system/http_proxy/port", result); - case PROXY_HTTPS_PORT: - return GetIntByPath("/system/proxy/secure_port", result); - case PROXY_FTP_PORT: - return GetIntByPath("/system/proxy/ftp_port", result); - case PROXY_SOCKS_PORT: - return GetIntByPath("/system/proxy/socks_port", result); - } - return false; // Placate compiler. - } - bool GetStringList(StringListSetting key, - std::vector<std::string>* result) override { - switch (key) { - case PROXY_IGNORE_HOSTS: - return GetStringListByPath("/system/http_proxy/ignore_hosts", result); - } - return false; // Placate compiler. - } - - bool BypassListIsReversed() override { - // This is a KDE-specific setting. - return false; - } - - bool MatchHostsUsingSuffixMatching() override { return false; } - - private: - bool GetStringByPath(base::StringPiece key, std::string* result) { - DCHECK(client_); - DCHECK(task_runner_->RunsTasksInCurrentSequence()); - GError* error = nullptr; - gchar* value = gconf_client_get_string(client_, key.data(), &error); - if (HandleGError(error, key.data())) - return false; - if (!value) - return false; - *result = value; - g_free(value); - return true; - } - bool GetBoolByPath(base::StringPiece key, bool* result) { - DCHECK(client_); - DCHECK(task_runner_->RunsTasksInCurrentSequence()); - GError* error = nullptr; - // We want to distinguish unset values from values defaulting to - // false. For that we need to use the type-generic - // gconf_client_get() rather than gconf_client_get_bool(). - GConfValue* gconf_value = gconf_client_get(client_, key.data(), &error); - if (HandleGError(error, key.data())) - return false; - if (!gconf_value) { - // Unset. - return false; - } - if (gconf_value->type != GCONF_VALUE_BOOL) { - gconf_value_free(gconf_value); - return false; - } - gboolean bool_value = gconf_value_get_bool(gconf_value); - *result = static_cast<bool>(bool_value); - gconf_value_free(gconf_value); - return true; - } - bool GetIntByPath(base::StringPiece key, int* result) { - DCHECK(client_); - DCHECK(task_runner_->RunsTasksInCurrentSequence()); - GError* error = nullptr; - int value = gconf_client_get_int(client_, key.data(), &error); - if (HandleGError(error, key.data())) - return false; - // We don't bother to distinguish an unset value because callers - // don't care. 0 is returned if unset. - *result = value; - return true; - } - bool GetStringListByPath(base::StringPiece key, - std::vector<std::string>* result) { - DCHECK(client_); - DCHECK(task_runner_->RunsTasksInCurrentSequence()); - GError* error = nullptr; - GSList* list = - gconf_client_get_list(client_, key.data(), GCONF_VALUE_STRING, &error); - if (HandleGError(error, key.data())) - return false; - if (!list) - return false; - for (GSList *it = list; it; it = it->next) { - result->push_back(static_cast<char*>(it->data)); - g_free(it->data); - } - g_slist_free(list); - return true; - } - - // Logs and frees a glib error. Returns false if there was no error - // (error is NULL). - bool HandleGError(GError* error, base::StringPiece key) { - if (!error) - return false; - - LOG(ERROR) << "Error getting gconf value for " << key << ": " - << error->message; - g_error_free(error); - return true; - } - - // This is the callback from the debounce timer. - void OnDebouncedNotification() { - DCHECK(task_runner_->RunsTasksInCurrentSequence()); - CHECK(notify_delegate_); - // Forward to a method on the proxy config service delegate object. - notify_delegate_->OnCheckProxyConfigSettings(); - } - - void OnChangeNotification() { - // We don't use Reset() because the timer may not yet be running. - // (In that case Stop() is a no-op.) - debounce_timer_->Stop(); - debounce_timer_->Start(FROM_HERE, - base::TimeDelta::FromMilliseconds(kDebounceTimeoutMilliseconds), - this, &SettingGetterImplGConf::OnDebouncedNotification); - } - - // gconf notification callback, dispatched on the default glib main loop. - static void OnGConfChangeNotification(GConfClient* client, guint cnxn_id, - GConfEntry* entry, gpointer user_data) { - VLOG(1) << "gconf change notification for key " - << gconf_entry_get_key(entry); - // We don't track which key has changed, just that something did change. - SettingGetterImplGConf* setting_getter = - reinterpret_cast<SettingGetterImplGConf*>(user_data); - setting_getter->OnChangeNotification(); - } - - GConfClient* client_; - // These ids are the values returned from gconf_client_notify_add(), which we - // will need in order to later call gconf_client_notify_remove(). - guint system_proxy_id_; - guint system_http_proxy_id_; - - ProxyConfigServiceLinux::Delegate* notify_delegate_; - std::unique_ptr<base::OneShotTimer> debounce_timer_; - - // Task runner for the thread that we make gconf calls on. It should - // be the UI thread and all our methods should be called on this - // thread. Only for assertions. - scoped_refptr<base::SequencedTaskRunner> task_runner_; - - DISALLOW_COPY_AND_ASSIGN(SettingGetterImplGConf); -}; -#endif // defined(USE_GCONF) - #if defined(USE_GIO) -const char kProxyGConfSchema[] = "org.gnome.system.proxy"; +const char kProxyGSettingsSchema[] = "org.gnome.system.proxy"; // This setting getter uses gsettings, as used in most GNOME 3 desktops. class SettingGetterImplGSettings @@ -544,7 +217,7 @@ class SettingGetterImplGSettings // after the loop was quit, and pending tasks may then be deleted // without being run. if (client_) { - // gconf client was not cleaned up. + // gsettings client was not cleaned up. if (task_runner_->RunsTasksInCurrentSequence()) { // We are on the UI thread so we can clean it safely. This is // the case at least for ui_tests running under Valgrind in @@ -559,18 +232,8 @@ class SettingGetterImplGSettings DCHECK(!client_); } - bool SchemaExists(base::StringPiece schema_name) { - const gchar* const* schemas = libgio_loader_.g_settings_list_schemas(); - while (*schemas) { - if (!strcmp(schema_name.data(), static_cast<const char*>(*schemas))) - return true; - schemas++; - } - return false; - } - - // LoadAndCheckVersion() must be called *before* Init()! - bool LoadAndCheckVersion(base::Environment* env); + // CheckVersion() must be called *before* Init()! + bool CheckVersion(base::Environment* env); bool Init(const scoped_refptr<base::SingleThreadTaskRunner>& glib_task_runner) override { @@ -578,18 +241,19 @@ class SettingGetterImplGSettings DCHECK(!client_); DCHECK(!task_runner_.get()); - if (!SchemaExists(kProxyGConfSchema) || - !(client_ = libgio_loader_.g_settings_new(kProxyGConfSchema))) { + if (!g_settings_schema_source_lookup(g_settings_schema_source_get_default(), + kProxyGSettingsSchema, FALSE) || + !(client_ = g_settings_new(kProxyGSettingsSchema))) { // It's not clear whether/when this can return NULL. LOG(ERROR) << "Unable to create a gsettings client"; return false; } task_runner_ = glib_task_runner; // We assume these all work if the above call worked. - http_client_ = libgio_loader_.g_settings_get_child(client_, "http"); - https_client_ = libgio_loader_.g_settings_get_child(client_, "https"); - ftp_client_ = libgio_loader_.g_settings_get_child(client_, "ftp"); - socks_client_ = libgio_loader_.g_settings_get_child(client_, "socks"); + http_client_ = g_settings_get_child(client_, "http"); + https_client_ = g_settings_get_child(client_, "https"); + ftp_client_ = g_settings_get_child(client_, "ftp"); + socks_client_ = g_settings_get_child(client_, "socks"); DCHECK(http_client_ && https_client_ && ftp_client_ && socks_client_); return true; } @@ -714,7 +378,7 @@ class SettingGetterImplGSettings base::StringPiece key, std::string* result) { DCHECK(task_runner_->RunsTasksInCurrentSequence()); - gchar* value = libgio_loader_.g_settings_get_string(client, key.data()); + gchar* value = g_settings_get_string(client, key.data()); if (!value) return false; *result = value; @@ -723,20 +387,19 @@ class SettingGetterImplGSettings } bool GetBoolByPath(GSettings* client, base::StringPiece key, bool* result) { DCHECK(task_runner_->RunsTasksInCurrentSequence()); - *result = static_cast<bool>( - libgio_loader_.g_settings_get_boolean(client, key.data())); + *result = static_cast<bool>(g_settings_get_boolean(client, key.data())); return true; } bool GetIntByPath(GSettings* client, base::StringPiece key, int* result) { DCHECK(task_runner_->RunsTasksInCurrentSequence()); - *result = libgio_loader_.g_settings_get_int(client, key.data()); + *result = g_settings_get_int(client, key.data()); return true; } bool GetStringListByPath(GSettings* client, base::StringPiece key, std::vector<std::string>* result) { DCHECK(task_runner_->RunsTasksInCurrentSequence()); - gchar** list = libgio_loader_.g_settings_get_strv(client, key.data()); + gchar** list = g_settings_get_strv(client, key.data()); if (!list) return false; for (size_t i = 0; list[i]; ++i) { @@ -787,70 +450,25 @@ class SettingGetterImplGSettings // thread. Only for assertions. scoped_refptr<base::SequencedTaskRunner> task_runner_; - LibGioLoader libgio_loader_; - DISALLOW_COPY_AND_ASSIGN(SettingGetterImplGSettings); }; -bool SettingGetterImplGSettings::LoadAndCheckVersion( +bool SettingGetterImplGSettings::CheckVersion( base::Environment* env) { - // LoadAndCheckVersion() must be called *before* Init()! + // CheckVersion() must be called *before* Init()! DCHECK(!client_); - // The APIs to query gsettings were introduced after the minimum glib - // version we target, so we can't link directly against them. We load them - // dynamically at runtime, and if they don't exist, return false here. (We - // support linking directly via gyp flags though.) Additionally, even when - // they are present, we do two additional checks to make sure we should use - // them and not gconf. First, we attempt to load the schema for proxy - // settings. Second, we check for the program that was used in older - // versions of GNOME to configure proxy settings, and return false if it - // exists. Some distributions (e.g. Ubuntu 11.04) have the API and schema - // but don't use gsettings for proxy settings, but they do have the old - // binary, so we detect these systems that way. - - { - // TODO(phajdan.jr): Redesign the code to load library on different thread. - base::ThreadRestrictions::ScopedAllowIO allow_io; - - // Try also without .0 at the end; on some systems this may be required. - if (!libgio_loader_.Load("libgio-2.0.so.0") && - !libgio_loader_.Load("libgio-2.0.so")) { - VLOG(1) << "Cannot load gio library. Will fall back to gconf."; - return false; - } - - // g_type_init will be deprecated in 2.36. 2.35 is the development - // version for 2.36, hence do not call g_type_init starting 2.35. - // http://developer.gnome.org/gobject/unstable/gobject-Type-Information.html#g-type-init - if (libgio_loader_.glib_check_version(2, 35, 0)) { - libgio_loader_.g_type_init(); - } - } - GSettings* client = nullptr; - if (SchemaExists(kProxyGConfSchema)) { - ANNOTATE_SCOPED_MEMORY_LEAK; // http://crbug.com/380782 - client = libgio_loader_.g_settings_new(kProxyGConfSchema); + if (g_settings_schema_source_lookup(g_settings_schema_source_get_default(), + kProxyGSettingsSchema, FALSE)) { + client = g_settings_new(kProxyGSettingsSchema); } if (!client) { - VLOG(1) << "Cannot create gsettings client. Will fall back to gconf."; + VLOG(1) << "Cannot create gsettings client."; return false; } g_object_unref(client); - // Yes, we're on the UI thread. Yes, we're accessing the file system. - // Sadly, we don't have much choice. We need the proxy settings and we - // need them now, and to figure out where to get them, we have to check - // for this binary. See http://crbug.com/69057 for additional details. - { - base::ThreadRestrictions::ScopedAllowIO allow_io; - if (base::ExecutableExistsInPath(env, "gnome-network-properties")) { - VLOG(1) << "Found gnome-network-properties. Will fall back to gconf."; - return false; - } - } - VLOG(1) << "All gsettings tests OK. Will get proxy config from gsettings."; return true; } @@ -865,7 +483,7 @@ int StringToIntOrDefault(base::StringPiece value, int default_value) { return default_value; } -// This is the KDE version that reads kioslaverc and simulates gconf. +// This is the KDE version that reads kioslaverc and simulates gsettings. // Doing this allows the main Delegate code, as well as the unit tests // for it, to stay the same - and the settings map fairly well besides. class SettingGetterImplKDE : public ProxyConfigServiceLinux::SettingGetter { @@ -906,10 +524,10 @@ class SettingGetterImplKDE : public ProxyConfigServiceLinux::SettingGetter { // back as well. So if there is a .kde4 directory, check the timestamps // of the config directories within and use the newest one. // Note that we should currently be running in the UI thread, because in - // the gconf version, that is the only thread that can access the proxy - // settings (a gconf restriction). As noted below, the initial read of - // the proxy settings will be done in this thread anyway, so we check - // for .kde4 here in this thread as well. + // the gsettings version, that is the only thread that can access the + // proxy settings (a gsettings restriction). As noted below, the initial + // read of the proxy settings will be done in this thread anyway, so we + // check for .kde4 here in this thread as well. base::FilePath kde3_path = base::FilePath(home).Append(".kde"); base::FilePath kde3_config = KDEHomeToConfigPath(kde3_path); base::FilePath kde4_path = base::FilePath(home).Append(".kde4"); @@ -1379,7 +997,7 @@ bool ProxyConfigServiceLinux::Delegate::GetProxyFromSettings( host += ":" + base::IntToString(port); } - // gconf settings do not appear to distinguish between SOCKS version. We + // gsettings settings do not appear to distinguish between SOCKS version. We // default to version 5. For more information on this policy decision, see: // http://code.google.com/p/chromium/issues/detail?id=55912#c2 ProxyServer::Scheme scheme = (host_key == SettingGetter::PROXY_SOCKS_HOST) ? @@ -1398,9 +1016,8 @@ bool ProxyConfigServiceLinux::Delegate::GetConfigFromSettings( ProxyConfig* config) { std::string mode; if (!setting_getter_->GetString(SettingGetter::PROXY_MODE, &mode)) { - // We expect this to always be set, so if we don't see it then we - // probably have a gconf/gsettings problem, and so we don't have a valid - // proxy config. + // We expect this to always be set, so if we don't see it then we probably + // have a gsettings problem, and so we don't have a valid proxy config. return false; } if (mode == "none") { @@ -1538,6 +1155,7 @@ ProxyConfigServiceLinux::Delegate::Delegate( : env_var_getter_(std::move(env_var_getter)) { // Figure out which SettingGetterImpl to use, if any. switch (base::nix::GetDesktopEnvironment(env_var_getter_.get())) { + case base::nix::DESKTOP_ENVIRONMENT_CINNAMON: case base::nix::DESKTOP_ENVIRONMENT_GNOME: case base::nix::DESKTOP_ENVIRONMENT_PANTHEON: case base::nix::DESKTOP_ENVIRONMENT_UNITY: @@ -1546,16 +1164,11 @@ ProxyConfigServiceLinux::Delegate::Delegate( std::unique_ptr<SettingGetterImplGSettings> gs_getter( new SettingGetterImplGSettings()); // We have to load symbols and check the GNOME version in use to decide - // if we should use the gsettings getter. See LoadAndCheckVersion(). - if (gs_getter->LoadAndCheckVersion(env_var_getter_.get())) + // if we should use the gsettings getter. See CheckVersion(). + if (gs_getter->CheckVersion(env_var_getter_.get())) setting_getter_ = std::move(gs_getter); } #endif -#if defined(USE_GCONF) - // Fall back on gconf if gsettings is unavailable or incorrect. - if (!setting_getter_) - setting_getter_.reset(new SettingGetterImplGConf()); -#endif break; case base::nix::DESKTOP_ENVIRONMENT_KDE3: case base::nix::DESKTOP_ENVIRONMENT_KDE4: @@ -1578,7 +1191,7 @@ void ProxyConfigServiceLinux::Delegate::SetUpAndFetchInitialConfig( const scoped_refptr<base::SingleThreadTaskRunner>& glib_task_runner, const scoped_refptr<base::SequencedTaskRunner>& main_task_runner) { // We should be running on the default glib main loop thread right - // now. gconf can only be accessed from this thread. + // now. gsettings can only be accessed from this thread. DCHECK(glib_task_runner->RunsTasksInCurrentSequence()); glib_task_runner_ = glib_task_runner; main_task_runner_ = main_task_runner; @@ -1596,7 +1209,7 @@ void ProxyConfigServiceLinux::Delegate::SetUpAndFetchInitialConfig( // the ProxyService. // Note: It would be nice to prioritize environment variables - // and only fall back to gconf if env vars were unset. But + // and only fall back to gsettings if env vars were unset. But // gnome-terminal "helpfully" sets http_proxy and no_proxy, and it // does so even if the proxy mode is set to auto, which would // mislead us. @@ -1609,7 +1222,7 @@ void ProxyConfigServiceLinux::Delegate::SetUpAndFetchInitialConfig( VLOG(1) << "Obtained proxy settings from " << ProxyConfigSourceToString(cached_config_.source()); - // If gconf proxy mode is "none", meaning direct, then we take + // If gsettings proxy mode is "none", meaning direct, then we take // that to be a valid config and will not check environment // variables. The alternative would have been to look for a proxy // whereever we can find one. @@ -1656,7 +1269,7 @@ void ProxyConfigServiceLinux::Delegate::SetUpAndFetchInitialConfig( } // Depending on the SettingGetter in use, this method will be called -// on either the UI thread (GConf) or the file thread (KDE). +// on either the UI thread (GSettings) or the file thread (KDE). void ProxyConfigServiceLinux::Delegate::SetUpNotifications() { scoped_refptr<base::SequencedTaskRunner> required_loop = setting_getter_->GetNotificationTaskRunner(); @@ -1698,7 +1311,7 @@ ProxyConfigService::ConfigAvailability } // Depending on the SettingGetter in use, this method will be called -// on either the UI thread (GConf) or the file thread (KDE). +// on either the UI thread (GSettings) or the file thread (KDE). void ProxyConfigServiceLinux::Delegate::OnCheckProxyConfigSettings() { scoped_refptr<base::SequencedTaskRunner> required_loop = setting_getter_->GetNotificationTaskRunner(); diff --git a/chromium/net/proxy/proxy_config_service_linux_unittest.cc b/chromium/net/proxy/proxy_config_service_linux_unittest.cc index 795b2665f75..11584acb1b3 100644 --- a/chromium/net/proxy/proxy_config_service_linux_unittest.cc +++ b/chromium/net/proxy/proxy_config_service_linux_unittest.cc @@ -58,12 +58,12 @@ struct EnvVarValues { #undef TRUE #undef FALSE -// So as to distinguish between an unset gconf boolean variable and +// So as to distinguish between an unset boolean variable and // one that is false. enum BoolSettingValue { UNSET = 0, TRUE, FALSE }; -// Set of values for all gconf settings that we might query. -struct GConfValues { +// Set of values for all gsettings settings that we might query. +struct GSettingsValues { // strings const char* mode; const char* autoconfig_url; @@ -85,7 +85,7 @@ struct GConfValues { }; // Mapping from a setting name to the location of the corresponding -// value (inside a EnvVarValues or GConfValues struct). +// value (inside a EnvVarValues or GSettingsValues struct). template <typename key_type, typename value_type> struct SettingsTable { typedef std::map<key_type, value_type*> map_type; @@ -192,7 +192,7 @@ class MockSettingGetter : public ProxyConfigServiceLinux::SettingGetter { // Zeros all environment values. void Reset() { - GConfValues zero_values = {0}; + GSettingsValues zero_values = {0}; values = zero_values; } @@ -259,7 +259,7 @@ class MockSettingGetter : public ProxyConfigServiceLinux::SettingGetter { bool MatchHostsUsingSuffixMatching() override { return false; } // Intentionally public, for convenience when setting up a test. - GConfValues values; + GSettingsValues values; private: scoped_refptr<base::SequencedTaskRunner> task_runner_; @@ -302,7 +302,7 @@ class SyncConfigGetter : public ProxyConfigService::Observer { Wait(); } - // Does gconf setup and initial fetch of the proxy config, + // Does gsettings setup and initial fetch of the proxy config, // all on the calling thread (meant to be the thread with the // default glib main loop, which is the glib thread). void SetupAndInitialFetch() { @@ -449,7 +449,7 @@ class ProxyConfigServiceLinuxTest : public PlatformTest { // Builds an identifier for each test in an array. #define TEST_DESC(desc) base::StringPrintf("at line %d <%s>", __LINE__, desc) -TEST_F(ProxyConfigServiceLinuxTest, BasicGConfTest) { +TEST_F(ProxyConfigServiceLinuxTest, BasicGSettingsTest) { std::vector<std::string> empty_ignores; std::vector<std::string> google_ignores; @@ -462,7 +462,7 @@ TEST_F(ProxyConfigServiceLinuxTest, BasicGConfTest) { std::string description; // Input. - GConfValues values; + GSettingsValues values; // Expected outputs (availability and fields of ProxyConfig). ProxyConfigService::ConfigAvailability availability; @@ -1099,7 +1099,7 @@ TEST_F(ProxyConfigServiceLinuxTest, BasicEnvTest) { } } -TEST_F(ProxyConfigServiceLinuxTest, GconfNotification) { +TEST_F(ProxyConfigServiceLinuxTest, GSettingsNotification) { std::unique_ptr<MockEnvironment> env(new MockEnvironment); MockSettingGetter* setting_getter = new MockSettingGetter; ProxyConfigServiceLinux* service = diff --git a/chromium/net/proxy/proxy_config_source.cc b/chromium/net/proxy/proxy_config_source.cc index 6dd6071a653..7ab9ce1330c 100644 --- a/chromium/net/proxy/proxy_config_source.cc +++ b/chromium/net/proxy/proxy_config_source.cc @@ -14,7 +14,6 @@ const char* const kSourceNames[] = { "UNKNOWN", "SYSTEM", "SYSTEM FAILED", - "GCONF", "GSETTINGS", "KDE", "ENV", diff --git a/chromium/net/proxy/proxy_config_source.h b/chromium/net/proxy/proxy_config_source.h index a7e375ab749..ea69e17b7c5 100644 --- a/chromium/net/proxy/proxy_config_source.h +++ b/chromium/net/proxy/proxy_config_source.h @@ -17,7 +17,6 @@ enum ProxyConfigSource { PROXY_CONFIG_SOURCE_SYSTEM, // System settings (Win/Mac). PROXY_CONFIG_SOURCE_SYSTEM_FAILED, // Default settings after failure to // determine system settings. - PROXY_CONFIG_SOURCE_GCONF, // GConf (Linux) PROXY_CONFIG_SOURCE_GSETTINGS, // GSettings (Linux). PROXY_CONFIG_SOURCE_KDE, // KDE (Linux). PROXY_CONFIG_SOURCE_ENV, // Environment variables. diff --git a/chromium/net/proxy/proxy_info.cc b/chromium/net/proxy/proxy_info.cc index 642a421f900..01879dfff88 100644 --- a/chromium/net/proxy/proxy_info.cc +++ b/chromium/net/proxy/proxy_info.cc @@ -17,8 +17,7 @@ ProxyInfo::ProxyInfo() ProxyInfo::ProxyInfo(const ProxyInfo& other) = default; -ProxyInfo::~ProxyInfo() { -} +ProxyInfo::~ProxyInfo() = default; void ProxyInfo::Use(const ProxyInfo& other) { proxy_resolve_start_time_ = other.proxy_resolve_start_time_; @@ -65,6 +64,10 @@ void ProxyInfo::OverrideProxyList(const ProxyList& proxy_list) { proxy_list_ = proxy_list; } +void ProxyInfo::SetAlternativeProxy(const ProxyServer& proxy_server) { + alternative_proxy_ = proxy_server; +} + std::string ProxyInfo::ToPacString() const { return proxy_list_.ToPacString(); } @@ -93,4 +96,10 @@ void ProxyInfo::Reset() { did_use_pac_script_ = false; } +const NetworkTrafficAnnotationTag ProxyInfo::traffic_annotation() const { + // TODO(crbug.com/656607): Get appropriate annotation from the origin of + // config_source_. + return NO_TRAFFIC_ANNOTATION_BUG_656607; +} + } // namespace net diff --git a/chromium/net/proxy/proxy_info.h b/chromium/net/proxy/proxy_info.h index eb3f90fe330..fd3c11780a9 100644 --- a/chromium/net/proxy/proxy_info.h +++ b/chromium/net/proxy/proxy_info.h @@ -14,6 +14,7 @@ #include "net/proxy/proxy_list.h" #include "net/proxy/proxy_retry_info.h" #include "net/proxy/proxy_server.h" +#include "net/traffic_annotation/network_traffic_annotation.h" namespace net { @@ -71,6 +72,10 @@ class NET_EXPORT ProxyInfo { // proxy configuration. void OverrideProxyList(const ProxyList& proxy_list); + // Sets the alternative service to try when connecting to the first valid + // proxy server, but does not otherwise reset the proxy configuration. + void SetAlternativeProxy(const ProxyServer& proxy_server); + // Returns true if this proxy info specifies a direct connection. bool is_direct() const { // We don't implicitly fallback to DIRECT unless it was added to the list. @@ -134,6 +139,9 @@ class NET_EXPORT ProxyInfo { // Returns the source for configuration settings used for proxy resolution. ProxyConfigSource config_source() const { return config_source_; } + // Returns traffic annotation tag based on current config source. + const NetworkTrafficAnnotationTag traffic_annotation() const; + // See description in ProxyList::ToPacString(). std::string ToPacString() const; @@ -158,6 +166,9 @@ class NET_EXPORT ProxyInfo { return proxy_list_; } + // Returns the alternative proxy, which may be invalid. + const ProxyServer& alternative_proxy() const { return alternative_proxy_; } + base::TimeTicks proxy_resolve_start_time() const { return proxy_resolve_start_time_; } @@ -181,6 +192,10 @@ class NET_EXPORT ProxyInfo { // try. If proxy_list_ is empty, then there is nothing left to fall back to. ProxyList proxy_list_; + // An alternative to proxy_server() (in the sense of HTTP Alternative + // Services). + ProxyServer alternative_proxy_; + // List of proxies that have been tried already. ProxyRetryInfoMap proxy_retry_info_; diff --git a/chromium/net/proxy/proxy_list.cc b/chromium/net/proxy/proxy_list.cc index 2f65c720419..9eefac0483e 100644 --- a/chromium/net/proxy/proxy_list.cc +++ b/chromium/net/proxy/proxy_list.cc @@ -19,13 +19,11 @@ using base::TimeTicks; namespace net { -ProxyList::ProxyList() { -} +ProxyList::ProxyList() = default; ProxyList::ProxyList(const ProxyList& other) = default; -ProxyList::~ProxyList() { -} +ProxyList::~ProxyList() = default; void ProxyList::Set(const std::string& proxy_uri_list) { proxies_.clear(); diff --git a/chromium/net/proxy/proxy_resolver_factory.cc b/chromium/net/proxy/proxy_resolver_factory.cc index fc7173e96bd..9e88ff4e3c1 100644 --- a/chromium/net/proxy/proxy_resolver_factory.cc +++ b/chromium/net/proxy/proxy_resolver_factory.cc @@ -13,7 +13,6 @@ ProxyResolverFactory::ProxyResolverFactory(bool expects_pac_bytes) : expects_pac_bytes_(expects_pac_bytes) { } -ProxyResolverFactory::~ProxyResolverFactory() { -} +ProxyResolverFactory::~ProxyResolverFactory() = default; } // namespace net diff --git a/chromium/net/proxy/proxy_resolver_script.h b/chromium/net/proxy/proxy_resolver_script.h deleted file mode 100644 index e838bed599f..00000000000 --- a/chromium/net/proxy/proxy_resolver_script.h +++ /dev/null @@ -1,278 +0,0 @@ -// Copyright (c) 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_PROXY_PROXY_RESOLVER_SCRIPT_H_ -#define NET_PROXY_PROXY_RESOLVER_SCRIPT_H_ - -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org code. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1998 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Akhil Arora <akhil.arora@sun.com> - * Tomi Leppikangas <Tomi.Leppikangas@oulu.fi> - * Darin Fisher <darin@meer.net> - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -// The following code was formatted from: -// 'mozilla/netwerk/base/src/nsProxyAutoConfig.js' (1.55) -// -// Using the command: -// $ cat nsProxyAutoConfig.js | -// awk '/var pacUtils/,/EOF/' | -// sed -e 's/^\s*$/""/g' | -// sed -e 's/"\s*[+]\s*$/"/g' | -// sed -e 's/"$/" \\/g' | -// sed -e 's/\/(ipaddr);/\/.exec(ipaddr);/g' | -// grep -v '^var pacUtils =' -// -// isPlainHost() was removed. -#define PROXY_RESOLVER_SCRIPT \ - "function dnsDomainIs(host, domain) {\n" \ - " return (host.length >= domain.length &&\n" \ - " host.substring(host.length - domain.length) == domain);\n" \ - "}\n" \ - "" \ - "function dnsDomainLevels(host) {\n" \ - " return host.split('.').length-1;\n" \ - "}\n" \ - "" \ - "function convert_addr(ipchars) {\n" \ - " var bytes = ipchars.split('.');\n" \ - " var result = ((bytes[0] & 0xff) << 24) |\n" \ - " ((bytes[1] & 0xff) << 16) |\n" \ - " ((bytes[2] & 0xff) << 8) |\n" \ - " (bytes[3] & 0xff);\n" \ - " return result;\n" \ - "}\n" \ - "" \ - "function isInNet(ipaddr, pattern, maskstr) {\n" \ - " var test = /^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$/.exec(ipaddr);\n" \ - " if (test == null) {\n" \ - " ipaddr = dnsResolve(ipaddr);\n" \ - " if (ipaddr == null)\n" \ - " return false;\n" \ - " } else if (test[1] > 255 || test[2] > 255 || \n" \ - " test[3] > 255 || test[4] > 255) {\n" \ - " return false; // not an IP address\n" \ - " }\n" \ - " var host = convert_addr(ipaddr);\n" \ - " var pat = convert_addr(pattern);\n" \ - " var mask = convert_addr(maskstr);\n" \ - " return ((host & mask) == (pat & mask));\n" \ - " \n" \ - "}\n" \ - "" \ - "function isResolvable(host) {\n" \ - " var ip = dnsResolve(host);\n" \ - " return (ip != null);\n" \ - "}\n" \ - "" \ - "function localHostOrDomainIs(host, hostdom) {\n" \ - " return (host == hostdom) ||\n" \ - " (hostdom.lastIndexOf(host + '.', 0) == 0);\n" \ - "}\n" \ - "" \ - "function shExpMatch(url, pattern) {\n" \ - " pattern = pattern.replace(/\\./g, '\\\\.');\n" \ - " pattern = pattern.replace(/\\*/g, '.*');\n" \ - " pattern = pattern.replace(/\\?/g, '.');\n" \ - " var newRe = new RegExp('^'+pattern+'$');\n" \ - " return newRe.test(url);\n" \ - "}\n" \ - "" \ - "var wdays = {SUN: 0, MON: 1, TUE: 2, WED: 3, THU: 4, FRI: 5, SAT: 6};\n" \ - "" \ - "var months = {JAN: 0, FEB: 1, MAR: 2, APR: 3, MAY: 4, JUN: 5, JUL: 6, AUG: 7, SEP: 8, OCT: 9, NOV: 10, DEC: 11};\n" \ - "" \ - "function weekdayRange() {\n" \ - " function getDay(weekday) {\n" \ - " if (weekday in wdays) {\n" \ - " return wdays[weekday];\n" \ - " }\n" \ - " return -1;\n" \ - " }\n" \ - " var date = new Date();\n" \ - " var argc = arguments.length;\n" \ - " var wday;\n" \ - " if (argc < 1)\n" \ - " return false;\n" \ - " if (arguments[argc - 1] == 'GMT') {\n" \ - " argc--;\n" \ - " wday = date.getUTCDay();\n" \ - " } else {\n" \ - " wday = date.getDay();\n" \ - " }\n" \ - " var wd1 = getDay(arguments[0]);\n" \ - " var wd2 = (argc == 2) ? getDay(arguments[1]) : wd1;\n" \ - " return (wd1 == -1 || wd2 == -1) ? false\n" \ - " : (wd1 <= wday && wday <= wd2);\n" \ - "}\n" \ - "" \ - "function dateRange() {\n" \ - " function getMonth(name) {\n" \ - " if (name in months) {\n" \ - " return months[name];\n" \ - " }\n" \ - " return -1;\n" \ - " }\n" \ - " var date = new Date();\n" \ - " var argc = arguments.length;\n" \ - " if (argc < 1) {\n" \ - " return false;\n" \ - " }\n" \ - " var isGMT = (arguments[argc - 1] == 'GMT');\n" \ - "\n" \ - " if (isGMT) {\n" \ - " argc--;\n" \ - " }\n" \ - " // function will work even without explict handling of this case\n" \ - " if (argc == 1) {\n" \ - " var tmp = parseInt(arguments[0]);\n" \ - " if (isNaN(tmp)) {\n" \ - " return ((isGMT ? date.getUTCMonth() : date.getMonth()) ==\n" \ - "getMonth(arguments[0]));\n" \ - " } else if (tmp < 32) {\n" \ - " return ((isGMT ? date.getUTCDate() : date.getDate()) == tmp);\n" \ - " } else { \n" \ - " return ((isGMT ? date.getUTCFullYear() : date.getFullYear()) ==\n" \ - "tmp);\n" \ - " }\n" \ - " }\n" \ - " var year = date.getFullYear();\n" \ - " var date1, date2;\n" \ - " date1 = new Date(year, 0, 1, 0, 0, 0);\n" \ - " date2 = new Date(year, 11, 31, 23, 59, 59);\n" \ - " var adjustMonth = false;\n" \ - " for (var i = 0; i < (argc >> 1); i++) {\n" \ - " var tmp = parseInt(arguments[i]);\n" \ - " if (isNaN(tmp)) {\n" \ - " var mon = getMonth(arguments[i]);\n" \ - " date1.setMonth(mon);\n" \ - " } else if (tmp < 32) {\n" \ - " adjustMonth = (argc <= 2);\n" \ - " date1.setDate(tmp);\n" \ - " } else {\n" \ - " date1.setFullYear(tmp);\n" \ - " }\n" \ - " }\n" \ - " for (var i = (argc >> 1); i < argc; i++) {\n" \ - " var tmp = parseInt(arguments[i]);\n" \ - " if (isNaN(tmp)) {\n" \ - " var mon = getMonth(arguments[i]);\n" \ - " date2.setMonth(mon);\n" \ - " } else if (tmp < 32) {\n" \ - " date2.setDate(tmp);\n" \ - " } else {\n" \ - " date2.setFullYear(tmp);\n" \ - " }\n" \ - " }\n" \ - " if (adjustMonth) {\n" \ - " date1.setMonth(date.getMonth());\n" \ - " date2.setMonth(date.getMonth());\n" \ - " }\n" \ - " if (isGMT) {\n" \ - " var tmp = date;\n" \ - " tmp.setFullYear(date.getUTCFullYear());\n" \ - " tmp.setMonth(date.getUTCMonth());\n" \ - " tmp.setDate(date.getUTCDate());\n" \ - " tmp.setHours(date.getUTCHours());\n" \ - " tmp.setMinutes(date.getUTCMinutes());\n" \ - " tmp.setSeconds(date.getUTCSeconds());\n" \ - " date = tmp;\n" \ - " }\n" \ - " return ((date1 <= date) && (date <= date2));\n" \ - "}\n" \ - "" \ - "function timeRange() {\n" \ - " var argc = arguments.length;\n" \ - " var date = new Date();\n" \ - " var isGMT= false;\n" \ - "\n" \ - " if (argc < 1) {\n" \ - " return false;\n" \ - " }\n" \ - " if (arguments[argc - 1] == 'GMT') {\n" \ - " isGMT = true;\n" \ - " argc--;\n" \ - " }\n" \ - "\n" \ - " var hour = isGMT ? date.getUTCHours() : date.getHours();\n" \ - " var date1, date2;\n" \ - " date1 = new Date();\n" \ - " date2 = new Date();\n" \ - "\n" \ - " if (argc == 1) {\n" \ - " return (hour == arguments[0]);\n" \ - " } else if (argc == 2) {\n" \ - " return ((arguments[0] <= hour) && (hour <= arguments[1]));\n" \ - " } else {\n" \ - " switch (argc) {\n" \ - " case 6:\n" \ - " date1.setSeconds(arguments[2]);\n" \ - " date2.setSeconds(arguments[5]);\n" \ - " case 4:\n" \ - " var middle = argc >> 1;\n" \ - " date1.setHours(arguments[0]);\n" \ - " date1.setMinutes(arguments[1]);\n" \ - " date2.setHours(arguments[middle]);\n" \ - " date2.setMinutes(arguments[middle + 1]);\n" \ - " if (middle == 2) {\n" \ - " date2.setSeconds(59);\n" \ - " }\n" \ - " break;\n" \ - " default:\n" \ - " throw 'timeRange: bad number of arguments'\n" \ - " }\n" \ - " }\n" \ - "\n" \ - " if (isGMT) {\n" \ - " date.setFullYear(date.getUTCFullYear());\n" \ - " date.setMonth(date.getUTCMonth());\n" \ - " date.setDate(date.getUTCDate());\n" \ - " date.setHours(date.getUTCHours());\n" \ - " date.setMinutes(date.getUTCMinutes());\n" \ - " date.setSeconds(date.getUTCSeconds());\n" \ - " }\n" \ - " return ((date1 <= date) && (date <= date2));\n" \ - "}\n" - -// This is a Microsoft extension to PAC for IPv6, see: -// http://blogs.msdn.com/b/wndp/archive/2006/07/13/ipv6-pac-extensions-v0-9.aspx -#define PROXY_RESOLVER_SCRIPT_EX \ - "function isResolvableEx(host) {\n" \ - " var ipList = dnsResolveEx(host);\n" \ - " return (ipList != '');\n" \ - "}\n" - -#endif // NET_PROXY_PROXY_RESOLVER_SCRIPT_H_ diff --git a/chromium/net/proxy/proxy_resolver_script_data.cc b/chromium/net/proxy/proxy_resolver_script_data.cc index 8c4fd3187ae..d62095551c7 100644 --- a/chromium/net/proxy/proxy_resolver_script_data.cc +++ b/chromium/net/proxy/proxy_resolver_script_data.cc @@ -71,6 +71,6 @@ ProxyResolverScriptData::ProxyResolverScriptData(Type type, utf16_(utf16) { } -ProxyResolverScriptData::~ProxyResolverScriptData() {} +ProxyResolverScriptData::~ProxyResolverScriptData() = default; } // namespace net diff --git a/chromium/net/proxy/proxy_resolver_v8.cc b/chromium/net/proxy/proxy_resolver_v8.cc index c26ecff3715..40f3e0314bb 100644 --- a/chromium/net/proxy/proxy_resolver_v8.cc +++ b/chromium/net/proxy/proxy_resolver_v8.cc @@ -24,8 +24,8 @@ #include "gin/v8_initializer.h" #include "net/base/ip_address.h" #include "net/base/net_errors.h" +#include "net/proxy/pac_js_library.h" #include "net/proxy/proxy_info.h" -#include "net/proxy/proxy_resolver_script.h" #include "net/proxy/proxy_resolver_script_data.h" #include "url/gurl.h" #include "url/url_canon.h" @@ -34,8 +34,7 @@ // Notes on the javascript environment: // // For the majority of the PAC utility functions, we use the same code -// as Firefox. See the javascript library that proxy_resolver_scipt.h -// pulls in. +// as Firefox. See the javascript library that pac_js_library.h pulls in. // // In addition, we implement a subset of Microsoft's extensions to PAC. // - myIpAddressEx() @@ -570,10 +569,7 @@ class ProxyResolverV8::Context { // (This script should never fail, as it is a string literal!) // Note that the two string literals are concatenated. int rv = RunScript( - ASCIILiteralToV8String( - isolate_, - PROXY_RESOLVER_SCRIPT - PROXY_RESOLVER_SCRIPT_EX), + ASCIILiteralToV8String(isolate_, PAC_JS_LIBRARY PAC_JS_LIBRARY_EX), kPacUtilityResourceName); if (rv != OK) { NOTREACHED(); @@ -855,7 +851,7 @@ ProxyResolverV8::ProxyResolverV8(std::unique_ptr<Context> context) DCHECK(context_); } -ProxyResolverV8::~ProxyResolverV8() {} +ProxyResolverV8::~ProxyResolverV8() = default; int ProxyResolverV8::GetProxyForURL(const GURL& query_url, ProxyInfo* results, diff --git a/chromium/net/proxy/proxy_resolver_v8_tracing_unittest.cc b/chromium/net/proxy/proxy_resolver_v8_tracing_unittest.cc index 4eaf8327578..ceb921654f3 100644 --- a/chromium/net/proxy/proxy_resolver_v8_tracing_unittest.cc +++ b/chromium/net/proxy/proxy_resolver_v8_tracing_unittest.cc @@ -725,6 +725,21 @@ class BlockableHostResolver : public HostResolver { return ERR_DNS_CACHE_MISS; } + int ResolveStaleFromCache(const RequestInfo& info, + AddressList* addresses, + HostCache::EntryStaleness* stale_info, + const NetLogWithSource& net_log) override { + NOTREACHED(); + return ERR_DNS_CACHE_MISS; + } + + bool HasCached(base::StringPiece hostname, + HostCache::Entry::Source* source_out, + HostCache::EntryStaleness* stale_out) const override { + NOTIMPLEMENTED(); + return false; + } + void IncreaseNumOfCancelledRequests() { num_cancelled_requests_++; } void SetAction(const base::Callback<void(void)>& action) { diff --git a/chromium/net/proxy/proxy_resolver_v8_tracing_wrapper_unittest.cc b/chromium/net/proxy/proxy_resolver_v8_tracing_wrapper_unittest.cc index 4d3ac69bf99..0128610b0b9 100644 --- a/chromium/net/proxy/proxy_resolver_v8_tracing_wrapper_unittest.cc +++ b/chromium/net/proxy/proxy_resolver_v8_tracing_wrapper_unittest.cc @@ -822,6 +822,21 @@ class BlockableHostResolver : public HostResolver { return ERR_DNS_CACHE_MISS; } + int ResolveStaleFromCache(const RequestInfo& info, + AddressList* addresses, + HostCache::EntryStaleness* stale_info, + const NetLogWithSource& net_log) override { + NOTREACHED(); + return ERR_DNS_CACHE_MISS; + } + + bool HasCached(base::StringPiece hostname, + HostCache::Entry::Source* source_out, + HostCache::EntryStaleness* stale_out) const override { + NOTIMPLEMENTED(); + return false; + } + void IncreaseNumOfCancelledRequests() { num_cancelled_requests_++; } void SetAction(const base::Callback<void(void)>& action) { action_ = action; } diff --git a/chromium/net/proxy/proxy_script_decider_unittest.cc b/chromium/net/proxy/proxy_script_decider_unittest.cc index 1a2a368b8ea..15c5d0f319b 100644 --- a/chromium/net/proxy/proxy_script_decider_unittest.cc +++ b/chromium/net/proxy/proxy_script_decider_unittest.cc @@ -162,9 +162,9 @@ class MockDhcpProxyScriptFetcher : public DhcpProxyScriptFetcher { DISALLOW_COPY_AND_ASSIGN(MockDhcpProxyScriptFetcher); }; -MockDhcpProxyScriptFetcher::MockDhcpProxyScriptFetcher() { } +MockDhcpProxyScriptFetcher::MockDhcpProxyScriptFetcher() = default; -MockDhcpProxyScriptFetcher::~MockDhcpProxyScriptFetcher() { } +MockDhcpProxyScriptFetcher::~MockDhcpProxyScriptFetcher() = default; int MockDhcpProxyScriptFetcher::Fetch(base::string16* utf16_text, const CompletionCallback& callback) { @@ -756,8 +756,8 @@ class AsyncFailDhcpFetcher : public DhcpProxyScriptFetcher, public base::SupportsWeakPtr<AsyncFailDhcpFetcher> { public: - AsyncFailDhcpFetcher() {} - ~AsyncFailDhcpFetcher() override {} + AsyncFailDhcpFetcher() = default; + ~AsyncFailDhcpFetcher() override = default; int Fetch(base::string16* utf16_text, const CompletionCallback& callback) override { diff --git a/chromium/net/proxy/proxy_script_fetcher_impl.cc b/chromium/net/proxy/proxy_script_fetcher_impl.cc index c736c590409..fe427e2af08 100644 --- a/chromium/net/proxy/proxy_script_fetcher_impl.cc +++ b/chromium/net/proxy/proxy_script_fetcher_impl.cc @@ -35,7 +35,17 @@ const int kDefaultMaxResponseBytes = 1048576; // 1 megabyte // The maximum duration (in milliseconds) allowed for fetching the PAC script. // Responses exceeding this will fail with ERR_TIMED_OUT. -const int kDefaultMaxDurationMs = 300000; // 5 minutes +// +// This timeout applies to both scripts fetched in the course of WPAD, as well +// as explicitly configured ones. +// +// If the default timeout is too high, auto-detect can stall for a long time, +// and if it is too low then slow loading scripts may be skipped. +// +// 30 seconds is a compromise between those competing goals. This value also +// appears to match Microsoft Edge (based on testing). +constexpr base::TimeDelta kDefaultMaxDuration = + base::TimeDelta::FromSeconds(30); // Returns true if |mime_type| is one of the known PAC mime type. bool IsPacMimeType(const std::string& mime_type) { @@ -82,7 +92,7 @@ ProxyScriptFetcherImpl::ProxyScriptFetcherImpl( result_code_(OK), result_text_(NULL), max_response_bytes_(kDefaultMaxResponseBytes), - max_duration_(base::TimeDelta::FromMilliseconds(kDefaultMaxDurationMs)), + max_duration_(kDefaultMaxDuration), weak_factory_(this) { DCHECK(url_request_context); } @@ -175,7 +185,7 @@ int ProxyScriptFetcherImpl::Fetch( // requests, PAC requests are aren't blocked on them. cur_request_ = url_request_context_->CreateRequest(url, MAXIMUM_PRIORITY, this, traffic_annotation); - cur_request_->set_method("GET"); + cur_request_->set_is_pac_request(true); // Make sure that the PAC script is downloaded using a direct connection, // to avoid circular dependencies (fetching is a part of proxy resolution). diff --git a/chromium/net/proxy/proxy_script_fetcher_impl_unittest.cc b/chromium/net/proxy/proxy_script_fetcher_impl_unittest.cc index c7d1f53da44..5390c549592 100644 --- a/chromium/net/proxy/proxy_script_fetcher_impl_unittest.cc +++ b/chromium/net/proxy/proxy_script_fetcher_impl_unittest.cc @@ -140,8 +140,8 @@ GURL GetTestFileUrl(const std::string& relpath) { class BasicNetworkDelegate : public NetworkDelegateImpl { public: - BasicNetworkDelegate() {} - ~BasicNetworkDelegate() override {} + BasicNetworkDelegate() = default; + ~BasicNetworkDelegate() override = default; private: int OnBeforeURLRequest(URLRequest* request, @@ -551,15 +551,15 @@ TEST_F(ProxyScriptFetcherImplTest, OnShutdown) { int result = pac_fetcher.Fetch(test_server_.GetURL("/hung"), &text, callback.callback()); EXPECT_THAT(result, IsError(ERR_IO_PENDING)); - EXPECT_EQ(1u, context_.url_requests().size()); + EXPECT_EQ(1u, context_.url_requests()->size()); pac_fetcher.OnShutdown(); - EXPECT_EQ(0u, context_.url_requests().size()); + EXPECT_EQ(0u, context_.url_requests()->size()); EXPECT_THAT(callback.WaitForResult(), IsError(ERR_CONTEXT_SHUT_DOWN)); // Make sure there's no asynchronous completion notification. base::RunLoop().RunUntilIdle(); - EXPECT_EQ(0u, context_.url_requests().size()); + EXPECT_EQ(0u, context_.url_requests()->size()); EXPECT_FALSE(callback.have_result()); result = pac_fetcher.Fetch(test_server_.GetURL("/hung"), &text, @@ -578,7 +578,7 @@ TEST_F(ProxyScriptFetcherImplTest, OnShutdownWithNoLiveRequest) { int result = pac_fetcher.Fetch(test_server_.GetURL("/hung"), &text, callback.callback()); EXPECT_THAT(result, IsError(ERR_CONTEXT_SHUT_DOWN)); - EXPECT_EQ(0u, context_.url_requests().size()); + EXPECT_EQ(0u, context_.url_requests()->size()); } } // namespace diff --git a/chromium/net/proxy/proxy_service.cc b/chromium/net/proxy/proxy_service.cc index 0503ae963e7..369a1ca0c22 100644 --- a/chromium/net/proxy/proxy_service.cc +++ b/chromium/net/proxy/proxy_service.cc @@ -125,7 +125,7 @@ const int64_t kDelayAfterNetworkChangesMs = 2000; // TODO(eroman): Figure out what Internet Explorer does. class DefaultPollPolicy : public ProxyService::PacPollPolicy { public: - DefaultPollPolicy() {} + DefaultPollPolicy() = default; Mode GetNextDelay(int initial_error, TimeDelta current_delay, @@ -180,7 +180,7 @@ class ProxyConfigServiceDirect : public ProxyConfigService { // Proxy resolver that fails every time. class ProxyResolverNull : public ProxyResolver { public: - ProxyResolverNull() {} + ProxyResolverNull() = default; // ProxyResolver implementation. int GetProxyForURL(const GURL& url, @@ -322,8 +322,8 @@ std::unique_ptr<base::Value> NetLogFinishedResolvingProxyCallback( #if defined(OS_CHROMEOS) class UnsetProxyConfigService : public ProxyConfigService { public: - UnsetProxyConfigService() {} - ~UnsetProxyConfigService() override {} + UnsetProxyConfigService() = default; + ~UnsetProxyConfigService() override = default; void AddObserver(Observer* observer) override {} void RemoveObserver(Observer* observer) override {} @@ -773,18 +773,17 @@ class ProxyService::ProxyScriptDeciderPoller { const ProxyService::PacPollPolicy* ProxyService::ProxyScriptDeciderPoller::poll_policy_ = NULL; -// ProxyService::PacRequest --------------------------------------------------- +// ProxyService::Request --------------------------------------------------- -class ProxyService::PacRequest - : public base::RefCounted<ProxyService::PacRequest> { +class ProxyService::Request : public base::RefCounted<ProxyService::Request> { public: - PacRequest(ProxyService* service, - const GURL& url, - const std::string& method, - ProxyDelegate* proxy_delegate, - ProxyInfo* results, - const CompletionCallback& user_callback, - const NetLogWithSource& net_log) + Request(ProxyService* service, + const GURL& url, + const std::string& method, + ProxyDelegate* proxy_delegate, + ProxyInfo* results, + const CompletionCallback& user_callback, + const NetLogWithSource& net_log) : service_(service), user_callback_(user_callback), results_(results), @@ -811,7 +810,7 @@ class ProxyService::PacRequest return resolver()->GetProxyForURL( url_, results_, - base::Bind(&PacRequest::QueryComplete, base::Unretained(this)), + base::Bind(&Request::QueryComplete, base::Unretained(this)), &resolve_job_, net_log_); } @@ -892,15 +891,15 @@ class ProxyService::PacRequest } private: - friend class base::RefCounted<ProxyService::PacRequest>; + friend class base::RefCounted<ProxyService::Request>; - ~PacRequest() {} + ~Request() = default; // Callback for when the ProxyResolver request has completed. void QueryComplete(int result_code) { result_code = QueryDidComplete(result_code); - // Remove this completed PacRequest from the service's pending list. + // Remove this completed Request from the service's pending list. /// (which will probably cause deletion of |this|). if (!user_callback_.is_null()) { CompletionCallback callback = user_callback_; @@ -1020,7 +1019,7 @@ int ProxyService::ResolveProxy(const GURL& raw_url, const std::string& method, ProxyInfo* result, const CompletionCallback& callback, - PacRequest** pac_request, + Request** pac_request, ProxyDelegate* proxy_delegate, const NetLogWithSource& net_log) { DCHECK(!callback.is_null()); @@ -1032,7 +1031,7 @@ int ProxyService::ResolveProxyHelper(const GURL& raw_url, const std::string& method, ProxyInfo* result, const CompletionCallback& callback, - PacRequest** pac_request, + Request** pac_request, ProxyDelegate* proxy_delegate, const NetLogWithSource& net_log) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); @@ -1066,8 +1065,8 @@ int ProxyService::ResolveProxyHelper(const GURL& raw_url, if (callback.is_null()) return ERR_IO_PENDING; - scoped_refptr<PacRequest> req(new PacRequest( - this, url, method, proxy_delegate, result, callback, net_log)); + scoped_refptr<Request> req(new Request(this, url, method, proxy_delegate, + result, callback, net_log)); if (current_state_ == STATE_READY) { // Start the resolve request. @@ -1146,7 +1145,7 @@ void ProxyService::SuspendAllPendingRequests() { for (PendingRequests::iterator it = pending_requests_.begin(); it != pending_requests_.end(); ++it) { - PacRequest* req = it->get(); + Request* req = it->get(); if (req->is_started()) { req->CancelResolveJob(); @@ -1161,14 +1160,14 @@ void ProxyService::SetReady() { current_state_ = STATE_READY; // Make a copy in case |this| is deleted during the synchronous completion - // of one of the requests. If |this| is deleted then all of the PacRequest + // of one of the requests. If |this| is deleted then all of the Request // instances will be Cancel()-ed. PendingRequests pending_copy = pending_requests_; for (PendingRequests::iterator it = pending_copy.begin(); it != pending_copy.end(); ++it) { - PacRequest* req = it->get(); + Request* req = it->get(); if (!req->is_started() && !req->was_cancelled()) { req->net_log()->EndEvent( NetLogEventType::PROXY_SERVICE_WAITING_FOR_INIT_PAC); @@ -1256,7 +1255,7 @@ int ProxyService::ReconsiderProxyAfterError(const GURL& url, int net_error, ProxyInfo* result, const CompletionCallback& callback, - PacRequest** pac_request, + Request** pac_request, ProxyDelegate* proxy_delegate, const NetLogWithSource& net_log) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); @@ -1329,25 +1328,25 @@ void ProxyService::ReportSuccess(const ProxyInfo& result, } } -void ProxyService::CancelPacRequest(PacRequest* req) { +void ProxyService::CancelRequest(Request* req) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK(req); req->Cancel(); RemovePendingRequest(req); } -LoadState ProxyService::GetLoadState(const PacRequest* req) const { +LoadState ProxyService::GetLoadState(const Request* req) const { CHECK(req); if (current_state_ == STATE_WAITING_FOR_INIT_PROXY_RESOLVER) return init_proxy_resolver_->GetLoadState(); return req->GetLoadState(); } -bool ProxyService::ContainsPendingRequest(PacRequest* req) { +bool ProxyService::ContainsPendingRequest(Request* req) { return pending_requests_.count(req) == 1; } -void ProxyService::RemovePendingRequest(PacRequest* req) { +void ProxyService::RemovePendingRequest(Request* req) { DCHECK(ContainsPendingRequest(req)); pending_requests_.erase(req); } @@ -1502,7 +1501,7 @@ ProxyService::CreateSystemProxyConfigService( // Assume we got called on the thread that runs the default glib // main loop, so the current thread is where we should be running - // gconf calls from. + // gsettings calls from. scoped_refptr<base::SingleThreadTaskRunner> glib_thread_task_runner = base::ThreadTaskRunnerHandle::Get(); diff --git a/chromium/net/proxy/proxy_service.h b/chromium/net/proxy/proxy_service.h index 687418ed2a1..b615543a987 100644 --- a/chromium/net/proxy/proxy_service.h +++ b/chromium/net/proxy/proxy_service.h @@ -119,9 +119,8 @@ class NET_EXPORT ProxyService : public NetworkChangeNotifier::IPAddressObserver, ~ProxyService() override; - // Used internally to handle PAC queries. - // TODO(eroman): consider naming this simply "Request". - class PacRequest; + // Used to track proxy resolution requests that complete asynchronously. + class Request; // Determines the appropriate proxy for |url| for a |method| request and // stores the result in |results|. If |method| is empty, the caller can expect @@ -133,9 +132,9 @@ class NET_EXPORT ProxyService : public NetworkChangeNotifier::IPAddressObserver, // ResolveProxy. // // The caller is responsible for ensuring that |results| and |callback| - // remain valid until the callback is run or until |pac_request| is cancelled - // via CancelPacRequest. |pac_request| is only valid while the completion - // callback is still pending. NULL can be passed for |pac_request| if + // remain valid until the callback is run or until |request| is cancelled + // via CancelRequest. |request| is only valid while the completion + // callback is still pending. NULL can be passed for |request| if // the caller will not need to cancel the request. // // We use the three possible proxy access types in the following order, @@ -150,7 +149,7 @@ class NET_EXPORT ProxyService : public NetworkChangeNotifier::IPAddressObserver, const std::string& method, ProxyInfo* results, const CompletionCallback& callback, - PacRequest** pac_request, + Request** request, ProxyDelegate* proxy_delegate, const NetLogWithSource& net_log); @@ -170,7 +169,7 @@ class NET_EXPORT ProxyService : public NetworkChangeNotifier::IPAddressObserver, // list of possible values. The semantics of this call are otherwise // similar to ResolveProxy. // - // NULL can be passed for |pac_request| if the caller will not need to + // NULL can be passed for |request| if the caller will not need to // cancel the request. // // Returns ERR_FAILED if there is not another proxy config to try. @@ -181,7 +180,7 @@ class NET_EXPORT ProxyService : public NetworkChangeNotifier::IPAddressObserver, int net_error, ProxyInfo* results, const CompletionCallback& callback, - PacRequest** pac_request, + Request** request, ProxyDelegate* proxy_delegate, const NetLogWithSource& net_log); @@ -208,11 +207,11 @@ class NET_EXPORT ProxyService : public NetworkChangeNotifier::IPAddressObserver, void ReportSuccess(const ProxyInfo& proxy_info, ProxyDelegate* proxy_delegate); - // Call this method with a non-null |pac_request| to cancel the PAC request. - void CancelPacRequest(PacRequest* pac_request); + // Call this method with a non-null |request| to cancel the PAC request. + void CancelRequest(Request* request); - // Returns the LoadState for this |pac_request| which must be non-NULL. - LoadState GetLoadState(const PacRequest* pac_request) const; + // Returns the LoadState for this |request| which must be non-NULL. + LoadState GetLoadState(const Request* request) const; // Sets the ProxyScriptFetcher and DhcpProxyScriptFetcher dependencies. This // is needed if the ProxyResolver is of type ProxyResolverWithoutFetch. @@ -318,11 +317,11 @@ class NET_EXPORT ProxyService : public NetworkChangeNotifier::IPAddressObserver, private: FRIEND_TEST_ALL_PREFIXES(ProxyServiceTest, UpdateConfigAfterFailedAutodetect); FRIEND_TEST_ALL_PREFIXES(ProxyServiceTest, UpdateConfigFromPACToDirect); - friend class PacRequest; + friend class Request; class InitProxyResolver; class ProxyScriptDeciderPoller; - typedef std::set<scoped_refptr<PacRequest>> PendingRequests; + typedef std::set<scoped_refptr<Request>> PendingRequests; enum State { STATE_NONE, @@ -361,7 +360,7 @@ class NET_EXPORT ProxyService : public NetworkChangeNotifier::IPAddressObserver, const std::string& method, ProxyInfo* results, const CompletionCallback& callback, - PacRequest** pac_request, + Request** request, ProxyDelegate* proxy_delegate, const NetLogWithSource& net_log); @@ -374,10 +373,10 @@ class NET_EXPORT ProxyService : public NetworkChangeNotifier::IPAddressObserver, void SetReady(); // Returns true if |pending_requests_| contains |req|. - bool ContainsPendingRequest(PacRequest* req); + bool ContainsPendingRequest(Request* req); // Removes |req| from the list of pending requests. - void RemovePendingRequest(PacRequest* req); + void RemovePendingRequest(Request* req); // Called when proxy resolution has completed (either synchronously or // asynchronously). Handles logging the result, and cleaning out diff --git a/chromium/net/proxy/proxy_service_unittest.cc b/chromium/net/proxy/proxy_service_unittest.cc index 6a423fe6e63..ce48b205253 100644 --- a/chromium/net/proxy/proxy_service_unittest.cc +++ b/chromium/net/proxy/proxy_service_unittest.cc @@ -51,7 +51,7 @@ namespace { // This polling policy will decide to poll every 1 ms. class ImmediatePollPolicy : public ProxyService::PacPollPolicy { public: - ImmediatePollPolicy() {} + ImmediatePollPolicy() = default; Mode GetNextDelay(int error, base::TimeDelta current_delay, @@ -68,7 +68,7 @@ class ImmediatePollPolicy : public ProxyService::PacPollPolicy { // will never trigger a poll class NeverPollPolicy : public ProxyService::PacPollPolicy { public: - NeverPollPolicy() {} + NeverPollPolicy() = default; Mode GetNextDelay(int error, base::TimeDelta current_delay, @@ -84,7 +84,7 @@ class NeverPollPolicy : public ProxyService::PacPollPolicy { // This polling policy starts a poll immediately after network activity. class ImmediateAfterActivityPollPolicy : public ProxyService::PacPollPolicy { public: - ImmediateAfterActivityPollPolicy() {} + ImmediateAfterActivityPollPolicy() = default; Mode GetNextDelay(int error, base::TimeDelta current_delay, @@ -214,23 +214,10 @@ class TestResolveProxyDelegate : public ProxyDelegate { return proxy_retry_info_; } - void OnTunnelConnectCompleted(const HostPortPair& endpoint, - const HostPortPair& proxy_server, - int net_error) override {} void OnFallback(const ProxyServer& bad_proxy, int net_error) override {} - void OnBeforeTunnelRequest(const HostPortPair& proxy_server, - HttpRequestHeaders* extra_headers) override {} - void OnTunnelHeadersReceived( - const HostPortPair& origin, - const HostPortPair& proxy_server, - const HttpResponseHeaders& response_headers) override {} bool IsTrustedSpdyProxy(const net::ProxyServer& proxy_server) override { return true; } - void GetAlternativeProxy( - const GURL& url, - const ProxyServer& resolved_proxy_server, - ProxyServer* alternative_proxy_server) const override {} void OnAlternativeProxyBroken( const ProxyServer& alternative_proxy_server) override {} @@ -253,27 +240,14 @@ class TestProxyFallbackProxyDelegate : public ProxyDelegate { const std::string& method, const ProxyRetryInfoMap& proxy_retry_info, ProxyInfo* result) override {} - void OnTunnelConnectCompleted(const HostPortPair& endpoint, - const HostPortPair& proxy_server, - int net_error) override {} void OnFallback(const ProxyServer& bad_proxy, int net_error) override { proxy_server_ = bad_proxy; proxy_fallback_net_error_ = net_error; on_proxy_fallback_called_ = true; } - void OnBeforeTunnelRequest(const HostPortPair& proxy_server, - HttpRequestHeaders* extra_headers) override {} - void OnTunnelHeadersReceived( - const HostPortPair& origin, - const HostPortPair& proxy_server, - const HttpResponseHeaders& response_headers) override {} bool IsTrustedSpdyProxy(const net::ProxyServer& proxy_server) override { return true; } - void GetAlternativeProxy( - const GURL& url, - const ProxyServer& resolved_proxy_server, - ProxyServer* alternative_proxy_server) const override {} void OnAlternativeProxyBroken( const ProxyServer& alternative_proxy_server) override {} @@ -525,7 +499,7 @@ TEST_F(ProxyServiceTest, PAC) { ProxyInfo info; TestCompletionCallback callback; - ProxyService::PacRequest* request; + ProxyService::Request* request; BoundTestNetLog log; int rv = service.ResolveProxy(url, std::string(), &info, callback.callback(), @@ -1974,7 +1948,7 @@ TEST_F(ProxyServiceTest, CancelInProgressRequest) { ProxyInfo info2; TestCompletionCallback callback2; - ProxyService::PacRequest* request2; + ProxyService::Request* request2; rv = service.ResolveProxy(url2, std::string(), &info2, callback2.callback(), &request2, nullptr, NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); @@ -1989,7 +1963,7 @@ TEST_F(ProxyServiceTest, CancelInProgressRequest) { GetPendingJobsForURLs(resolver, url1, url2, url3); // Cancel the second request - service.CancelPacRequest(request2); + service.CancelRequest(request2); JobMap jobs = GetPendingJobsForURLs(resolver, url1, url3); @@ -2035,7 +2009,7 @@ TEST_F(ProxyServiceTest, InitialPACScriptDownload) { ProxyInfo info1; TestCompletionCallback callback1; - ProxyService::PacRequest* request1; + ProxyService::Request* request1; int rv = service.ResolveProxy(url1, std::string(), &info1, callback1.callback(), &request1, nullptr, NetLogWithSource()); @@ -2047,14 +2021,14 @@ TEST_F(ProxyServiceTest, InitialPACScriptDownload) { ProxyInfo info2; TestCompletionCallback callback2; - ProxyService::PacRequest* request2; + ProxyService::Request* request2; rv = service.ResolveProxy(url2, std::string(), &info2, callback2.callback(), &request2, nullptr, NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); ProxyInfo info3; TestCompletionCallback callback3; - ProxyService::PacRequest* request3; + ProxyService::Request* request3; rv = service.ResolveProxy(url3, std::string(), &info3, callback3.callback(), &request3, nullptr, NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); @@ -2204,7 +2178,7 @@ TEST_F(ProxyServiceTest, CancelWhilePACFetching) { // Start 3 requests. ProxyInfo info1; TestCompletionCallback callback1; - ProxyService::PacRequest* request1; + ProxyService::Request* request1; BoundTestNetLog log1; int rv = service.ResolveProxy(GURL("http://request1"), std::string(), &info1, callback1.callback(), &request1, nullptr, @@ -2217,7 +2191,7 @@ TEST_F(ProxyServiceTest, CancelWhilePACFetching) { ProxyInfo info2; TestCompletionCallback callback2; - ProxyService::PacRequest* request2; + ProxyService::Request* request2; rv = service.ResolveProxy(GURL("http://request2"), std::string(), &info2, callback2.callback(), &request2, nullptr, NetLogWithSource()); @@ -2234,8 +2208,8 @@ TEST_F(ProxyServiceTest, CancelWhilePACFetching) { EXPECT_TRUE(factory->pending_requests().empty()); // Cancel the first 2 jobs. - service.CancelPacRequest(request1); - service.CancelPacRequest(request2); + service.CancelRequest(request1); + service.CancelRequest(request2); // At this point the ProxyService should be waiting for the // ProxyScriptFetcher to invoke its completion callback, notifying it of @@ -2311,7 +2285,7 @@ TEST_F(ProxyServiceTest, FallbackFromAutodetectToCustomPac) { ProxyInfo info2; TestCompletionCallback callback2; - ProxyService::PacRequest* request2; + ProxyService::Request* request2; rv = service.ResolveProxy(url2, std::string(), &info2, callback2.callback(), &request2, nullptr, NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); @@ -2395,7 +2369,7 @@ TEST_F(ProxyServiceTest, FallbackFromAutodetectToCustomPac2) { ProxyInfo info2; TestCompletionCallback callback2; - ProxyService::PacRequest* request2; + ProxyService::Request* request2; rv = service.ResolveProxy(url2, std::string(), &info2, callback2.callback(), &request2, nullptr, NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); @@ -2472,7 +2446,7 @@ TEST_F(ProxyServiceTest, FallbackFromAutodetectToCustomToManual) { ProxyInfo info2; TestCompletionCallback callback2; - ProxyService::PacRequest* request2; + ProxyService::Request* request2; rv = service.ResolveProxy(GURL("http://request2"), std::string(), &info2, callback2.callback(), &request2, nullptr, NetLogWithSource()); @@ -3726,7 +3700,7 @@ TEST_F(ProxyServiceTest, OnShutdownWithLiveRequest) { ProxyInfo info; TestCompletionCallback callback; - ProxyService::PacRequest* request; + ProxyService::Request* request; int rv = service.ResolveProxy(GURL("http://request/"), std::string(), &info, callback.callback(), &request, nullptr, NetLogWithSource()); @@ -3762,7 +3736,7 @@ TEST_F(ProxyServiceTest, OnShutdownFollowedByRequest) { ProxyInfo info; TestCompletionCallback callback; - ProxyService::PacRequest* request; + ProxyService::Request* request; int rv = service.ResolveProxy(GURL("http://request/"), std::string(), &info, callback.callback(), &request, nullptr, NetLogWithSource()); diff --git a/chromium/net/quic/chromium/bidirectional_stream_quic_impl_unittest.cc b/chromium/net/quic/chromium/bidirectional_stream_quic_impl_unittest.cc index 015c910c848..16ad25497e2 100644 --- a/chromium/net/quic/chromium/bidirectional_stream_quic_impl_unittest.cc +++ b/chromium/net/quic/chromium/bidirectional_stream_quic_impl_unittest.cc @@ -35,6 +35,7 @@ #include "net/quic/core/crypto/quic_encrypter.h" #include "net/quic/core/quic_connection.h" #include "net/quic/core/spdy_utils.h" +#include "net/quic/core/tls_client_handshaker.h" #include "net/quic/platform/api/quic_string_piece.h" #include "net/quic/platform/api/quic_text_utils.h" #include "net/quic/test_tools/crypto_test_utils.h" @@ -379,7 +380,7 @@ class DeleteStreamDelegate : public TestDelegateBase { } // namespace class BidirectionalStreamQuicImplTest - : public ::testing::TestWithParam<QuicTransportVersion> { + : public ::testing::TestWithParam<std::tuple<QuicTransportVersion, bool>> { protected: static const bool kFin = true; static const bool kIncludeVersion = true; @@ -397,21 +398,27 @@ class BidirectionalStreamQuicImplTest }; BidirectionalStreamQuicImplTest() - : crypto_config_(crypto_test_utils::ProofVerifierForTesting()), + : version_(std::get<0>(GetParam())), + client_headers_include_h2_stream_dependency_(std::get<1>(GetParam())), + crypto_config_(crypto_test_utils::ProofVerifierForTesting(), + TlsClientHandshaker::CreateSslCtx()), read_buffer_(new IOBufferWithSize(4096)), connection_id_(2), stream_id_(GetNthClientInitiatedStreamId(0)), - client_maker_(GetParam(), + client_maker_(version_, connection_id_, &clock_, kDefaultServerHostName, - Perspective::IS_CLIENT), - server_maker_(GetParam(), + Perspective::IS_CLIENT, + client_headers_include_h2_stream_dependency_), + server_maker_(version_, connection_id_, &clock_, kDefaultServerHostName, - Perspective::IS_SERVER), - random_generator_(0) { + Perspective::IS_SERVER, + false), + random_generator_(0), + destination_(kDefaultServerHostName, kDefaultServerPort) { IPAddress ip(192, 0, 2, 33); peer_addr_ = IPEndPoint(ip, 443); self_addr_ = IPEndPoint(ip, 8435); @@ -475,7 +482,8 @@ class BidirectionalStreamQuicImplTest helper_.get(), alarm_factory_.get(), new QuicChromiumPacketWriter(socket.get(), runner_.get()), true /* owns_writer */, Perspective::IS_CLIENT, - SupportedTransportVersions(GetParam())); + SupportedVersions( + net::ParsedQuicVersion(net::PROTOCOL_QUIC_CRYPTO, version_))); base::TimeTicks dns_end = base::TimeTicks::Now(); base::TimeTicks dns_start = dns_end - base::TimeDelta::FromMilliseconds(1); @@ -490,10 +498,13 @@ class BidirectionalStreamQuicImplTest /*migrate_session_on_network_change*/ false, /*migrate_session_early*/ false, /*migrate_session_on_network_change_v2*/ false, + base::TimeDelta::FromSeconds(kMaxTimeOnNonDefaultNetworkSecs), + kMaxMigrationsToNonDefaultNetworkOnPathDegrading, kQuicYieldAfterPacketsRead, QuicTime::Delta::FromMilliseconds(kQuicYieldAfterDurationMilliseconds), - /*cert_verify_flags=*/0, DefaultQuicConfig(), &crypto_config_, - "CONNECTION_UNKNOWN", dns_start, dns_end, &push_promise_index_, nullptr, + client_headers_include_h2_stream_dependency_, /*cert_verify_flags=*/0, + DefaultQuicConfig(), &crypto_config_, "CONNECTION_UNKNOWN", dns_start, + dns_end, &push_promise_index_, nullptr, base::ThreadTaskRunnerHandle::Get().get(), /*socket_performance_watcher=*/nullptr, net_log().bound().net_log())); session_->Initialize(); @@ -574,12 +585,26 @@ class BidirectionalStreamQuicImplTest RequestPriority request_priority, size_t* spdy_headers_frame_length, QuicStreamOffset* offset) { + return ConstructRequestHeadersPacketInner( + packet_number, stream_id, fin, request_priority, 0, + spdy_headers_frame_length, offset); + } + + std::unique_ptr<QuicReceivedPacket> ConstructRequestHeadersPacketInner( + QuicPacketNumber packet_number, + QuicStreamId stream_id, + bool fin, + RequestPriority request_priority, + QuicStreamId parent_stream_id, + size_t* spdy_headers_frame_length, + QuicStreamOffset* offset) { SpdyPriority priority = ConvertRequestPriorityToQuicPriority(request_priority); std::unique_ptr<QuicReceivedPacket> packet( client_maker_.MakeRequestHeadersPacket( packet_number, stream_id, kIncludeVersion, fin, priority, - std::move(request_headers_), spdy_headers_frame_length, offset)); + std::move(request_headers_), parent_stream_id, + spdy_headers_frame_length, offset)); DVLOG(2) << "packet(" << packet_number << "): " << std::endl << QuicTextUtils::HexDump(packet->AsStringPiece()); return packet; @@ -598,7 +623,7 @@ class BidirectionalStreamQuicImplTest std::unique_ptr<QuicReceivedPacket> packet( client_maker_.MakeRequestHeadersAndMultipleDataFramesPacket( packet_number, stream_id_, kIncludeVersion, fin, priority, - std::move(request_headers_), header_stream_offset, + std::move(request_headers_), 0, header_stream_offset, spdy_headers_frame_length, data)); DVLOG(2) << "packet(" << packet_number << "): " << std::endl << QuicTextUtils::HexDump(packet->AsStringPiece()); @@ -744,10 +769,12 @@ class BidirectionalStreamQuicImplTest QuicChromiumClientSession* session() const { return session_.get(); } QuicStreamId GetNthClientInitiatedStreamId(int n) { - return test::GetNthClientInitiatedStreamId(GetParam(), n); + return test::GetNthClientInitiatedStreamId(version_, n); } protected: + const QuicTransportVersion version_; + const bool client_headers_include_h2_stream_dependency_; BoundTestNetLog net_log_; scoped_refptr<TestTaskRunner> runner_; std::unique_ptr<MockWrite[]> mock_writes_; @@ -773,11 +800,14 @@ class BidirectionalStreamQuicImplTest std::unique_ptr<StaticSocketDataProvider> socket_data_; std::vector<PacketToWrite> writes_; QuicClientPushPromiseIndex push_promise_index_; + HostPortPair destination_; }; -INSTANTIATE_TEST_CASE_P(Version, - BidirectionalStreamQuicImplTest, - ::testing::ValuesIn(AllSupportedTransportVersions())); +INSTANTIATE_TEST_CASE_P( + Version, + BidirectionalStreamQuicImplTest, + ::testing::Combine(::testing::ValuesIn(AllSupportedTransportVersions()), + ::testing::Bool())); TEST_P(BidirectionalStreamQuicImplTest, GetRequest) { SetRequest("GET", "/", DEFAULT_PRIORITY); @@ -801,7 +831,8 @@ TEST_P(BidirectionalStreamQuicImplTest, GetRequest) { std::unique_ptr<TestDelegateBase> delegate( new TestDelegateBase(read_buffer.get(), kReadBufferSize)); delegate->set_trailers_expected(true); - delegate->Start(&request, net_log().bound(), session()->CreateHandle()); + delegate->Start(&request, net_log().bound(), + session()->CreateHandle(destination_)); delegate->WaitUntilNextCallback(kOnStreamReady); ConfirmHandshake(); @@ -886,8 +917,8 @@ TEST_P(BidirectionalStreamQuicImplTest, LoadTimingTwoRequests) { // SetRequest() again for second request as |request_headers_| was moved. SetRequest("GET", "/", DEFAULT_PRIORITY); AddWrite(ConstructRequestHeadersPacketInner( - 2, GetNthClientInitiatedStreamId(1), kFin, DEFAULT_PRIORITY, nullptr, - &offset)); + 2, GetNthClientInitiatedStreamId(1), kFin, DEFAULT_PRIORITY, + GetNthClientInitiatedStreamId(0), nullptr, &offset)); AddWrite(ConstructInitialSettingsPacket(3, &offset)); AddWrite(ConstructClientAckPacket(4, 3, 1, 1)); Initialize(); @@ -902,13 +933,15 @@ TEST_P(BidirectionalStreamQuicImplTest, LoadTimingTwoRequests) { scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize)); std::unique_ptr<TestDelegateBase> delegate( new TestDelegateBase(read_buffer.get(), kReadBufferSize)); - delegate->Start(&request, net_log().bound(), session()->CreateHandle()); + delegate->Start(&request, net_log().bound(), + session()->CreateHandle(destination_)); // Start second request. scoped_refptr<IOBuffer> read_buffer2(new IOBuffer(kReadBufferSize)); std::unique_ptr<TestDelegateBase> delegate2( new TestDelegateBase(read_buffer2.get(), kReadBufferSize)); - delegate2->Start(&request, net_log().bound(), session()->CreateHandle()); + delegate2->Start(&request, net_log().bound(), + session()->CreateHandle(destination_)); delegate->WaitUntilNextCallback(kOnStreamReady); delegate2->WaitUntilNextCallback(kOnStreamReady); @@ -991,7 +1024,8 @@ TEST_P(BidirectionalStreamQuicImplTest, CoalesceDataBuffersNotHeadersFrame) { std::unique_ptr<TestDelegateBase> delegate( new TestDelegateBase(read_buffer.get(), kReadBufferSize)); delegate->DoNotSendRequestHeadersAutomatically(); - delegate->Start(&request, net_log().bound(), session()->CreateHandle()); + delegate->Start(&request, net_log().bound(), + session()->CreateHandle(destination_)); EXPECT_FALSE(delegate->is_ready()); ConfirmHandshake(); delegate->WaitUntilNextCallback(kOnStreamReady); @@ -1098,7 +1132,8 @@ TEST_P(BidirectionalStreamQuicImplTest, std::unique_ptr<TestDelegateBase> delegate( new TestDelegateBase(read_buffer.get(), kReadBufferSize)); delegate->DoNotSendRequestHeadersAutomatically(); - delegate->Start(&request, net_log().bound(), session()->CreateHandle()); + delegate->Start(&request, net_log().bound(), + session()->CreateHandle(destination_)); ConfirmHandshake(); delegate->WaitUntilNextCallback(kOnStreamReady); @@ -1205,7 +1240,8 @@ TEST_P(BidirectionalStreamQuicImplTest, std::unique_ptr<TestDelegateBase> delegate( new TestDelegateBase(read_buffer.get(), kReadBufferSize)); delegate->DoNotSendRequestHeadersAutomatically(); - delegate->Start(&request, net_log().bound(), session()->CreateHandle()); + delegate->Start(&request, net_log().bound(), + session()->CreateHandle(destination_)); ConfirmHandshake(); delegate->WaitUntilNextCallback(kOnStreamReady); @@ -1297,7 +1333,8 @@ TEST_P(BidirectionalStreamQuicImplTest, std::unique_ptr<DeleteStreamDelegate> delegate(new DeleteStreamDelegate( read_buffer.get(), kReadBufferSize, DeleteStreamDelegate::ON_FAILED)); delegate->DoNotSendRequestHeadersAutomatically(); - delegate->Start(&request, net_log().bound(), session()->CreateHandle()); + delegate->Start(&request, net_log().bound(), + session()->CreateHandle(destination_)); ConfirmHandshake(); delegate->WaitUntilNextCallback(kOnStreamReady); @@ -1330,7 +1367,8 @@ TEST_P(BidirectionalStreamQuicImplTest, std::unique_ptr<DeleteStreamDelegate> delegate(new DeleteStreamDelegate( read_buffer.get(), kReadBufferSize, DeleteStreamDelegate::ON_FAILED)); delegate->DoNotSendRequestHeadersAutomatically(); - delegate->Start(&request, net_log().bound(), session()->CreateHandle()); + delegate->Start(&request, net_log().bound(), + session()->CreateHandle(destination_)); ConfirmHandshake(); delegate->WaitUntilNextCallback(kOnStreamReady); @@ -1368,7 +1406,8 @@ TEST_P(BidirectionalStreamQuicImplTest, PostRequest) { scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize)); std::unique_ptr<TestDelegateBase> delegate( new TestDelegateBase(read_buffer.get(), kReadBufferSize)); - delegate->Start(&request, net_log().bound(), session()->CreateHandle()); + delegate->Start(&request, net_log().bound(), + session()->CreateHandle(destination_)); ConfirmHandshake(); delegate->WaitUntilNextCallback(kOnStreamReady); @@ -1446,7 +1485,8 @@ TEST_P(BidirectionalStreamQuicImplTest, PutRequest) { scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize)); std::unique_ptr<TestDelegateBase> delegate( new TestDelegateBase(read_buffer.get(), kReadBufferSize)); - delegate->Start(&request, net_log().bound(), session()->CreateHandle()); + delegate->Start(&request, net_log().bound(), + session()->CreateHandle(destination_)); delegate->WaitUntilNextCallback(kOnStreamReady); // Send a DATA frame. @@ -1527,7 +1567,8 @@ TEST_P(BidirectionalStreamQuicImplTest, InterleaveReadDataAndSendData) { scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize)); std::unique_ptr<TestDelegateBase> delegate( new TestDelegateBase(read_buffer.get(), kReadBufferSize)); - delegate->Start(&request, net_log().bound(), session()->CreateHandle()); + delegate->Start(&request, net_log().bound(), + session()->CreateHandle(destination_)); ConfirmHandshake(); delegate->WaitUntilNextCallback(kOnStreamReady); @@ -1610,7 +1651,8 @@ TEST_P(BidirectionalStreamQuicImplTest, ServerSendsRstAfterHeaders) { scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize)); std::unique_ptr<TestDelegateBase> delegate( new TestDelegateBase(read_buffer.get(), kReadBufferSize)); - delegate->Start(&request, net_log().bound(), session()->CreateHandle()); + delegate->Start(&request, net_log().bound(), + session()->CreateHandle(destination_)); delegate->WaitUntilNextCallback(kOnStreamReady); ConfirmHandshake(); @@ -1655,7 +1697,8 @@ TEST_P(BidirectionalStreamQuicImplTest, ServerSendsRstAfterReadData) { scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize)); std::unique_ptr<TestDelegateBase> delegate( new TestDelegateBase(read_buffer.get(), kReadBufferSize)); - delegate->Start(&request, net_log().bound(), session()->CreateHandle()); + delegate->Start(&request, net_log().bound(), + session()->CreateHandle(destination_)); delegate->WaitUntilNextCallback(kOnStreamReady); ConfirmHandshake(); @@ -1713,7 +1756,8 @@ TEST_P(BidirectionalStreamQuicImplTest, SessionClosedBeforeReadData) { scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize)); std::unique_ptr<TestDelegateBase> delegate( new TestDelegateBase(read_buffer.get(), kReadBufferSize)); - delegate->Start(&request, net_log().bound(), session()->CreateHandle()); + delegate->Start(&request, net_log().bound(), + session()->CreateHandle(destination_)); ConfirmHandshake(); delegate->WaitUntilNextCallback(kOnStreamReady); @@ -1770,7 +1814,8 @@ TEST_P(BidirectionalStreamQuicImplTest, SessionClosedBeforeStartConfirmed) { scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize)); std::unique_ptr<TestDelegateBase> delegate( new TestDelegateBase(read_buffer.get(), kReadBufferSize)); - delegate->Start(&request, net_log().bound(), session()->CreateHandle()); + delegate->Start(&request, net_log().bound(), + session()->CreateHandle(destination_)); delegate->WaitUntilNextCallback(kOnFailed); EXPECT_TRUE(delegate->on_failed_called()); EXPECT_THAT(delegate->error(), IsError(ERR_CONNECTION_CLOSED)); @@ -1792,7 +1837,8 @@ TEST_P(BidirectionalStreamQuicImplTest, SessionClosedBeforeStartNotConfirmed) { scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize)); std::unique_ptr<TestDelegateBase> delegate( new TestDelegateBase(read_buffer.get(), kReadBufferSize)); - delegate->Start(&request, net_log().bound(), session()->CreateHandle()); + delegate->Start(&request, net_log().bound(), + session()->CreateHandle(destination_)); delegate->WaitUntilNextCallback(kOnFailed); EXPECT_TRUE(delegate->on_failed_called()); EXPECT_THAT(delegate->error(), IsError(ERR_QUIC_HANDSHAKE_FAILED)); @@ -1815,7 +1861,8 @@ TEST_P(BidirectionalStreamQuicImplTest, SessionCloseDuringOnStreamReady) { scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize)); std::unique_ptr<DeleteStreamDelegate> delegate(new DeleteStreamDelegate( read_buffer.get(), kReadBufferSize, DeleteStreamDelegate::ON_FAILED)); - delegate->Start(&request, net_log().bound(), session()->CreateHandle()); + delegate->Start(&request, net_log().bound(), + session()->CreateHandle(destination_)); ConfirmHandshake(); delegate->WaitUntilNextCallback(kOnFailed); @@ -1845,7 +1892,8 @@ TEST_P(BidirectionalStreamQuicImplTest, DeleteStreamDuringOnStreamReady) { std::unique_ptr<DeleteStreamDelegate> delegate( new DeleteStreamDelegate(read_buffer.get(), kReadBufferSize, DeleteStreamDelegate::ON_STREAM_READY)); - delegate->Start(&request, net_log().bound(), session()->CreateHandle()); + delegate->Start(&request, net_log().bound(), + session()->CreateHandle(destination_)); ConfirmHandshake(); delegate->WaitUntilNextCallback(kOnStreamReady); @@ -1874,7 +1922,8 @@ TEST_P(BidirectionalStreamQuicImplTest, DeleteStreamAfterReadData) { scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize)); std::unique_ptr<TestDelegateBase> delegate( new TestDelegateBase(read_buffer.get(), kReadBufferSize)); - delegate->Start(&request, net_log().bound(), session()->CreateHandle()); + delegate->Start(&request, net_log().bound(), + session()->CreateHandle(destination_)); ConfirmHandshake(); delegate->WaitUntilNextCallback(kOnStreamReady); @@ -1929,7 +1978,8 @@ TEST_P(BidirectionalStreamQuicImplTest, DeleteStreamDuringOnHeadersReceived) { std::unique_ptr<DeleteStreamDelegate> delegate( new DeleteStreamDelegate(read_buffer.get(), kReadBufferSize, DeleteStreamDelegate::ON_HEADERS_RECEIVED)); - delegate->Start(&request, net_log().bound(), session()->CreateHandle()); + delegate->Start(&request, net_log().bound(), + session()->CreateHandle(destination_)); ConfirmHandshake(); delegate->WaitUntilNextCallback(kOnStreamReady); @@ -1975,7 +2025,8 @@ TEST_P(BidirectionalStreamQuicImplTest, DeleteStreamDuringOnDataRead) { scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize)); std::unique_ptr<DeleteStreamDelegate> delegate(new DeleteStreamDelegate( read_buffer.get(), kReadBufferSize, DeleteStreamDelegate::ON_DATA_READ)); - delegate->Start(&request, net_log().bound(), session()->CreateHandle()); + delegate->Start(&request, net_log().bound(), + session()->CreateHandle(destination_)); ConfirmHandshake(); delegate->WaitUntilNextCallback(kOnStreamReady); @@ -2034,7 +2085,8 @@ TEST_P(BidirectionalStreamQuicImplTest, AsyncFinRead) { std::unique_ptr<TestDelegateBase> delegate( new TestDelegateBase(read_buffer.get(), kReadBufferSize)); - delegate->Start(&request, net_log().bound(), session()->CreateHandle()); + delegate->Start(&request, net_log().bound(), + session()->CreateHandle(destination_)); ConfirmHandshake(); delegate->WaitUntilNextCallback(kOnStreamReady); @@ -2096,7 +2148,8 @@ TEST_P(BidirectionalStreamQuicImplTest, DeleteStreamDuringOnTrailersReceived) { std::unique_ptr<DeleteStreamDelegate> delegate( new DeleteStreamDelegate(read_buffer.get(), kReadBufferSize, DeleteStreamDelegate::ON_TRAILERS_RECEIVED)); - delegate->Start(&request, net_log().bound(), session()->CreateHandle()); + delegate->Start(&request, net_log().bound(), + session()->CreateHandle(destination_)); delegate->WaitUntilNextCallback(kOnStreamReady); // Server acks the request. @@ -2164,7 +2217,8 @@ TEST_P(BidirectionalStreamQuicImplTest, ReleaseStreamFails) { delegate->set_trailers_expected(true); // QuicChromiumClientSession::Handle::RequestStream() returns OK synchronously // because Initialize() has established a Session. - delegate->Start(&request, net_log().bound(), session()->CreateHandle()); + delegate->Start(&request, net_log().bound(), + session()->CreateHandle(destination_)); // Now closes the underlying session. session_->CloseSessionOnError(ERR_ABORTED, QUIC_INTERNAL_ERROR); delegate->WaitUntilNextCallback(kOnFailed); diff --git a/chromium/net/quic/chromium/crypto/proof_source_chromium.cc b/chromium/net/quic/chromium/crypto/proof_source_chromium.cc index fdce1e9b170..6231a159aad 100644 --- a/chromium/net/quic/chromium/crypto/proof_source_chromium.cc +++ b/chromium/net/quic/chromium/crypto/proof_source_chromium.cc @@ -6,6 +6,7 @@ #include "base/strings/string_number_conversions.h" #include "crypto/openssl_util.h" +#include "net/cert/x509_util.h" #include "net/quic/core/crypto/crypto_protocol.h" #include "third_party/boringssl/src/include/openssl/digest.h" #include "third_party/boringssl/src/include/openssl/evp.h" @@ -41,12 +42,8 @@ bool ProofSourceChromium::Initialize(const base::FilePath& cert_path, std::vector<string> certs; for (const scoped_refptr<X509Certificate>& cert : certs_in_file) { - std::string der_encoded_cert; - if (!X509Certificate::GetDEREncoded(cert->os_cert_handle(), - &der_encoded_cert)) { - return false; - } - certs.push_back(der_encoded_cert); + certs.emplace_back( + x509_util::CryptoBufferAsStringPiece(cert->cert_buffer())); } chain_ = new ProofSource::Chain(certs); diff --git a/chromium/net/quic/chromium/crypto/proof_verifier_chromium.cc b/chromium/net/quic/chromium/crypto/proof_verifier_chromium.cc index 5217270b6d4..da638941406 100644 --- a/chromium/net/quic/chromium/crypto/proof_verifier_chromium.cc +++ b/chromium/net/quic/chromium/crypto/proof_verifier_chromium.cc @@ -10,6 +10,7 @@ #include "base/bind_helpers.h" #include "base/callback_helpers.h" #include "base/logging.h" +#include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" #include "base/strings/stringprintf.h" #include "crypto/signature_verifier.h" @@ -32,7 +33,7 @@ using std::string; namespace net { ProofVerifyDetailsChromium::ProofVerifyDetailsChromium() - : pkp_bypassed(false) {} + : pkp_bypassed(false), is_fatal_cert_error(false) {} ProofVerifyDetailsChromium::~ProofVerifyDetailsChromium() {} @@ -226,9 +227,9 @@ QuicAsyncStatus ProofVerifierChromium::Job::VerifyProof( // Note that this is a completely synchronous operation: The CT Log Verifier // gets all the data it needs for SCT verification and does not do any // external communication. - cert_transparency_verifier_->Verify(cert_.get(), std::string(), cert_sct, - &verify_details_->ct_verify_result.scts, - net_log_); + cert_transparency_verifier_->Verify( + hostname, cert_.get(), std::string(), cert_sct, + &verify_details_->ct_verify_result.scts, net_log_); // We call VerifySignature first to avoid copying of server_config and // signature. @@ -378,8 +379,7 @@ int ProofVerifierChromium::Job::DoVerifyCert(int result) { } int ProofVerifierChromium::Job::DoVerifyCertComplete(int result) { - UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.CertVerificationResult", - -result); + base::UmaHistogramSparse("Net.QuicSession.CertVerificationResult", -result); cert_verifier_request_.reset(); const CertVerifyResult& cert_verify_result = @@ -490,6 +490,10 @@ int ProofVerifierChromium::Job::DoVerifyCertComplete(int result) { result = ct_result; } + verify_details_->is_fatal_cert_error = + IsCertStatusError(cert_status) && !IsCertStatusMinorError(cert_status) && + transport_security_state_->ShouldSSLErrorsBeFatal(hostname_); + if (result != OK) { std::string error_string = ErrorToString(result); error_details_ = StringPrintf("Failed to verify certificate chain: %s", @@ -518,7 +522,7 @@ bool ProofVerifierChromium::Job::VerifySignature( size_t size_bits; X509Certificate::PublicKeyType type; - X509Certificate::GetPublicKeyInfo(cert_->os_cert_handle(), &size_bits, &type); + X509Certificate::GetPublicKeyInfo(cert_->cert_buffer(), &size_bits, &type); if (type == X509Certificate::kPublicKeyTypeRSA) { crypto::SignatureVerifier::HashAlgorithm hash_alg = crypto::SignatureVerifier::SHA256; diff --git a/chromium/net/quic/chromium/crypto/proof_verifier_chromium.h b/chromium/net/quic/chromium/crypto/proof_verifier_chromium.h index f5b0db5028d..53ddce4e6eb 100644 --- a/chromium/net/quic/chromium/crypto/proof_verifier_chromium.h +++ b/chromium/net/quic/chromium/crypto/proof_verifier_chromium.h @@ -48,6 +48,10 @@ class NET_EXPORT_PRIVATE ProofVerifyDetailsChromium // True if PKP was bypassed due to a local trust anchor. bool pkp_bypassed; + + // True if there was a certificate error which should be treated as fatal, + // and false otherwise. + bool is_fatal_cert_error; }; // ProofVerifyContextChromium is the implementation-specific information that a diff --git a/chromium/net/quic/chromium/crypto/proof_verifier_chromium_test.cc b/chromium/net/quic/chromium/crypto/proof_verifier_chromium_test.cc index 51956f303ef..696efbbad07 100644 --- a/chromium/net/quic/chromium/crypto/proof_verifier_chromium_test.cc +++ b/chromium/net/quic/chromium/crypto/proof_verifier_chromium_test.cc @@ -15,6 +15,7 @@ #include "net/cert/ct_serialization.h" #include "net/cert/mock_cert_verifier.h" #include "net/cert/multi_log_ct_verifier.h" +#include "net/cert/x509_util.h" #include "net/http/transport_security_state.h" #include "net/quic/chromium/crypto/proof_source_chromium.h" #include "net/quic/core/crypto/proof_verifier.h" @@ -126,7 +127,7 @@ class ProofVerifierChromiumTest : public ::testing::Test { } scoped_refptr<X509Certificate> GetTestServerCertificate() { - static const char kTestCert[] = "quic_test.example.com.crt"; + static const char kTestCert[] = "quic-chain.pem"; return ImportCertFromFile(GetTestCertsDirectory(), kTestCert); } @@ -134,20 +135,17 @@ class ProofVerifierChromiumTest : public ::testing::Test { scoped_refptr<X509Certificate> cert = GetTestServerCertificate(); ASSERT_TRUE(cert); - std::string der_bytes; - ASSERT_TRUE( - X509Certificate::GetDEREncoded(cert->os_cert_handle(), &der_bytes)); - certs->clear(); - certs->push_back(der_bytes); + certs->emplace_back( + x509_util::CryptoBufferAsStringPiece(cert->cert_buffer())); } std::string GetTestSignature() { ProofSourceChromium source; source.Initialize( - GetTestCertsDirectory().AppendASCII("quic_test.example.com.crt"), - GetTestCertsDirectory().AppendASCII("quic_test.example.com.key.pkcs8"), - GetTestCertsDirectory().AppendASCII("quic_test.example.com.key.sct")); + GetTestCertsDirectory().AppendASCII("quic-chain.pem"), + GetTestCertsDirectory().AppendASCII("quic-leaf-cert.key"), + base::FilePath()); std::string signature; source.GetProof(QuicSocketAddress(), kTestHostname, kTestConfig, QUIC_VERSION_35, kTestChloHash, @@ -161,12 +159,9 @@ class ProofVerifierChromiumTest : public ::testing::Test { der_test_cert.data(), der_test_cert.length()); ASSERT_TRUE(test_cert.get()); - std::string der_bytes; - ASSERT_TRUE(X509Certificate::GetDEREncoded(test_cert->os_cert_handle(), - &der_bytes)); - certs->clear(); - certs->push_back(der_bytes); + certs->emplace_back( + x509_util::CryptoBufferAsStringPiece(test_cert->cert_buffer())); } void CheckSCT(bool sct_expected_ok) { @@ -445,6 +440,67 @@ HashValueVector MakeHashValueVector(uint8_t tag) { return hashes; } +TEST_F(ProofVerifierChromiumTest, IsFatalErrorNotSetForNonFatalError) { + scoped_refptr<X509Certificate> test_cert = GetTestServerCertificate(); + ASSERT_TRUE(test_cert); + + CertVerifyResult dummy_result; + dummy_result.cert_status = MapNetErrorToCertStatus(ERR_CERT_DATE_INVALID); + dummy_result.verified_cert = test_cert; + + MockCertVerifier dummy_verifier; + 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()); + + std::unique_ptr<DummyProofVerifierCallback> callback( + new DummyProofVerifierCallback); + QuicAsyncStatus status = proof_verifier.VerifyProof( + kTestHostname, kTestPort, kTestConfig, QUIC_VERSION_35, kTestChloHash, + certs_, kTestEmptySCT, GetTestSignature(), verify_context_.get(), + &error_details_, &details_, std::move(callback)); + ASSERT_EQ(QUIC_FAILURE, status); + + ProofVerifyDetailsChromium* verify_details = + static_cast<ProofVerifyDetailsChromium*>(details_.get()); + EXPECT_FALSE(verify_details->is_fatal_cert_error); +} + +TEST_F(ProofVerifierChromiumTest, IsFatalErrorSetForFatalError) { + scoped_refptr<X509Certificate> test_cert = GetTestServerCertificate(); + ASSERT_TRUE(test_cert); + + CertVerifyResult dummy_result; + dummy_result.cert_status = MapNetErrorToCertStatus(ERR_CERT_DATE_INVALID); + dummy_result.verified_cert = test_cert; + + MockCertVerifier dummy_verifier; + dummy_verifier.AddResultForCert(test_cert.get(), dummy_result, + ERR_CERT_DATE_INVALID); + + const base::Time expiry = + 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()); + + std::unique_ptr<DummyProofVerifierCallback> callback( + new DummyProofVerifierCallback); + QuicAsyncStatus status = proof_verifier.VerifyProof( + kTestHostname, kTestPort, kTestConfig, QUIC_VERSION_35, kTestChloHash, + certs_, kTestEmptySCT, GetTestSignature(), verify_context_.get(), + &error_details_, &details_, std::move(callback)); + ASSERT_EQ(QUIC_FAILURE, status); + ProofVerifyDetailsChromium* verify_details = + static_cast<ProofVerifyDetailsChromium*>(details_.get()); + EXPECT_TRUE(verify_details->is_fatal_cert_error); +} + // Test that PKP is enforced for certificates that chain up to known roots. TEST_F(ProofVerifierChromiumTest, PKPEnforced) { scoped_refptr<X509Certificate> test_cert = GetTestServerCertificate(); diff --git a/chromium/net/quic/chromium/crypto_test_utils_chromium.cc b/chromium/net/quic/chromium/crypto_test_utils_chromium.cc index 238822c89e9..4ced45fa73a 100644 --- a/chromium/net/quic/chromium/crypto_test_utils_chromium.cc +++ b/chromium/net/quic/chromium/crypto_test_utils_chromium.cc @@ -82,9 +82,9 @@ std::unique_ptr<ProofSource> ProofSourceForTesting() { std::unique_ptr<ProofSourceChromium> source(new ProofSourceChromium()); base::FilePath certs_dir = GetTestCertsDirectory(); CHECK(source->Initialize( - certs_dir.AppendASCII("quic_chain.crt"), - certs_dir.AppendASCII("quic_test.example.com.key.pkcs8"), - certs_dir.AppendASCII("quic_test.example.com.key.sct"))); + certs_dir.AppendASCII("quic-chain.pem"), + certs_dir.AppendASCII("quic-leaf-cert.key"), + certs_dir.AppendASCII("quic-leaf-cert.key.sct"))); return std::move(source); } @@ -93,17 +93,13 @@ std::unique_ptr<ProofVerifier> ProofVerifierForTesting() { std::unique_ptr<MockCertVerifier> cert_verifier(new MockCertVerifier()); net::CertVerifyResult verify_result; verify_result.verified_cert = - ImportCertFromFile(GetTestCertsDirectory(), "quic_test.example.com.crt"); - cert_verifier->AddResultForCertAndHost(verify_result.verified_cert.get(), - "test.example.com", verify_result, OK); - verify_result.verified_cert = ImportCertFromFile( - GetTestCertsDirectory(), "quic_test_ecc.example.com.crt"); + ImportCertFromFile(GetTestCertsDirectory(), "quic-chain.pem"); cert_verifier->AddResultForCertAndHost(verify_result.verified_cert.get(), "test.example.com", verify_result, OK); return std::make_unique<TestProofVerifierChromium>( std::move(cert_verifier), std::make_unique<TransportSecurityState>(), std::make_unique<MultiLogCTVerifier>(), - std::make_unique<CTPolicyEnforcer>(), "quic_root.crt"); + std::make_unique<CTPolicyEnforcer>(), "quic-root.pem"); } ProofVerifyContext* ProofVerifyContextForTesting() { diff --git a/chromium/net/quic/chromium/quic_chromium_client_session.cc b/chromium/net/quic/chromium/quic_chromium_client_session.cc index 1d30aba28ac..c578354f612 100644 --- a/chromium/net/quic/chromium/quic_chromium_client_session.cc +++ b/chromium/net/quic/chromium/quic_chromium_client_session.cc @@ -9,6 +9,7 @@ #include "base/callback_helpers.h" #include "base/location.h" #include "base/memory/ptr_util.h" +#include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" #include "base/metrics/sparse_histogram.h" #include "base/single_thread_task_runner.h" @@ -65,9 +66,6 @@ const size_t kTokenBindingSignatureMapSize = 10; // migrating sessions need to wait for a new network to connect. const size_t kWaitTimeForNewNetworkSecs = 10; -// With exponential backoff, altogether we allow using non-default network -// for up to 255 seconds before close the session. -const int kMaxRetryCount = 7; const size_t kMinRetryTimeForDefaultNetworkSecs = 1; // Maximum RTT time for this session when set initial timeout for probing @@ -118,7 +116,7 @@ std::unique_ptr<base::Value> NetLogQuicConnectionMigrationFailureCallback( std::string reason, NetLogCaptureMode capture_mode) { std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); - dict->SetString("connection_id", base::Uint64ToString(connection_id)); + dict->SetString("connection_id", base::NumberToString(connection_id)); dict->SetString("reason", reason); return std::move(dict); } @@ -127,7 +125,7 @@ std::unique_ptr<base::Value> NetLogQuicConnectionMigrationSuccessCallback( QuicConnectionId connection_id, NetLogCaptureMode capture_mode) { std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); - dict->SetString("connection_id", base::Uint64ToString(connection_id)); + dict->SetString("connection_id", base::NumberToString(connection_id)); return std::move(dict); } @@ -247,9 +245,11 @@ class QuicServerPushHelper : public ServerPushDelegate::ServerPushHelper { } // namespace QuicChromiumClientSession::Handle::Handle( - const base::WeakPtr<QuicChromiumClientSession>& session) + const base::WeakPtr<QuicChromiumClientSession>& session, + const HostPortPair& destination) : MultiplexedSessionHandle(session), session_(session), + destination_(destination), net_log_(session_->net_log()), was_handshake_confirmed_(session->IsCryptoHandshakeConfirmed()), net_error_(OK), @@ -660,8 +660,11 @@ QuicChromiumClientSession::QuicChromiumClientSession( bool migrate_sessions_on_network_change, bool migrate_session_early_v2, bool migrate_sessions_on_network_change_v2, + base::TimeDelta max_time_on_non_default_network, + int max_migrations_to_non_default_network_on_path_degrading, int yield_after_packets, QuicTime::Delta yield_after_duration, + bool headers_include_h2_stream_dependency, int cert_verify_flags, const QuicConfig& config, QuicCryptoClientConfig* crypto_config, @@ -681,6 +684,10 @@ QuicChromiumClientSession::QuicChromiumClientSession( migrate_session_early_v2_(migrate_session_early_v2), migrate_session_on_network_change_v2_( migrate_sessions_on_network_change_v2), + max_time_on_non_default_network_(max_time_on_non_default_network), + max_migrations_to_non_default_network_on_path_degrading_( + max_migrations_to_non_default_network_on_path_degrading), + current_migrations_to_non_default_network_on_path_degrading_(0), clock_(clock), yield_after_packets_(yield_after_packets), yield_after_duration_(yield_after_duration), @@ -692,6 +699,7 @@ QuicChromiumClientSession::QuicChromiumClientSession( transport_security_state_(transport_security_state), server_info_(std::move(server_info)), pkp_bypassed_(false), + is_fatal_cert_error_(false), num_total_streams_(0), task_runner_(task_runner), net_log_(NetLogWithSource::Make(net_log, NetLogSourceType::QUIC_SESSION)), @@ -710,6 +718,8 @@ QuicChromiumClientSession::QuicChromiumClientSession( probing_manager_(this, task_runner_), retry_migrate_back_count_(0), migration_pending_(false), + headers_include_h2_stream_dependency_( + headers_include_h2_stream_dependency), weak_factory_(this) { default_network_ = socket->GetBoundNetwork(); sockets_.push_back(std::move(socket)); @@ -815,10 +825,10 @@ QuicChromiumClientSession::~QuicChromiumClientSession() { // The MTU used by QUIC is limited to a fairly small set of predefined values // (initial values and MTU discovery values), but does not fare well when // bucketed. Because of that, a sparse histogram is used here. - UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.ClientSideMtu", - connection()->max_packet_length()); - UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.ServerSideMtu", - stats.max_received_packet_size); + base::UmaHistogramSparse("Net.QuicSession.ClientSideMtu", + connection()->max_packet_length()); + base::UmaHistogramSparse("Net.QuicSession.ServerSideMtu", + stats.max_received_packet_size); UMA_HISTOGRAM_COUNTS_1M("Net.QuicSession.MtuProbesSent", connection()->mtu_probe_count()); @@ -856,6 +866,26 @@ void QuicChromiumClientSession::Initialize() { set_max_uncompressed_header_bytes(kMaxUncompressedHeaderSize); } +size_t QuicChromiumClientSession::WriteHeaders( + QuicStreamId id, + SpdyHeaderBlock headers, + bool fin, + SpdyPriority priority, + QuicReferenceCountedPointer<QuicAckListenerInterface> + ack_notifier_delegate) { + if (headers_include_h2_stream_dependency_) { + SpdyStreamId parent_stream_id = 0; + bool exclusive = false; + priority_dependency_state_.OnStreamCreation(id, priority, &parent_stream_id, + &exclusive); + return QuicSpdySession::WriteHeaders(id, std::move(headers), fin, priority, + parent_stream_id, exclusive, + std::move(ack_notifier_delegate)); + } + return QuicSpdySession::WriteHeaders(id, std::move(headers), fin, priority, + std::move(ack_notifier_delegate)); +} + void QuicChromiumClientSession::OnHeadersHeadOfLineBlocking( QuicTime::Delta delta) { UMA_HISTOGRAM_TIMES( @@ -863,6 +893,29 @@ void QuicChromiumClientSession::OnHeadersHeadOfLineBlocking( base::TimeDelta::FromMicroseconds(delta.ToMicroseconds())); } +void QuicChromiumClientSession::UnregisterStreamPriority(QuicStreamId id) { + if (headers_include_h2_stream_dependency_) { + priority_dependency_state_.OnStreamDestruction(id); + } + QuicSpdySession::UnregisterStreamPriority(id); +} + +void QuicChromiumClientSession::UpdateStreamPriority( + QuicStreamId id, + SpdyPriority new_priority) { + if (headers_include_h2_stream_dependency_) { + auto updates = priority_dependency_state_.OnStreamUpdate(id, new_priority); + for (auto update : updates) { + QuicSpdyStream* stream = GetSpdyDataStream(update.id); + DCHECK(stream); + int weight = Spdy3PriorityToHttp2Weight(stream->priority()); + WritePriority(update.id, update.dependent_stream_id, weight, + update.exclusive); + } + } + QuicSpdySession::UpdateStreamPriority(id, new_priority); +} + void QuicChromiumClientSession::OnStreamFrame(const QuicStreamFrame& frame) { // Record total number of stream frames. UMA_HISTOGRAM_COUNTS_1M("Net.QuicNumStreamFramesInPacket", 1); @@ -891,6 +944,25 @@ void QuicChromiumClientSession::RemoveHandle(Handle* handle) { handles_.erase(handle); } +// TODO(zhongyi): replace migration_session_* booleans with +// ConnectionMigrationMode. +ConnectionMigrationMode QuicChromiumClientSession::connection_migration_mode() + const { + if (migrate_session_early_v2_) + return ConnectionMigrationMode::FULL_MIGRATION_V2; + + if (migrate_session_on_network_change_v2_) + return ConnectionMigrationMode::NO_MIGRATION_ON_PATH_DEGRADING_V2; + + if (migrate_session_early_) + return ConnectionMigrationMode::FULL_MIGRATION_V1; + + if (migrate_session_on_network_change_) + return ConnectionMigrationMode::NO_MIGRATION_ON_PATH_DEGRADING_V1; + + return ConnectionMigrationMode::NO_MIGRATION; +} + int QuicChromiumClientSession::WaitForHandshakeConfirmation( const CompletionCallback& callback) { if (!connection()->connected()) @@ -904,11 +976,6 @@ int QuicChromiumClientSession::WaitForHandshakeConfirmation( } int QuicChromiumClientSession::TryCreateStream(StreamRequest* request) { - if (stream_factory_ && stream_factory_->IsQuicBroken(this)) { - DVLOG(1) << "QUIC broken."; - return ERR_QUIC_PROTOCOL_ERROR; - } - if (goaway_received()) { DVLOG(1) << "Going away."; return ERR_CONNECTION_CLOSED; @@ -1070,6 +1137,7 @@ bool QuicChromiumClientSession::GetSSLInfo(SSLInfo* ssl_info) const { ssl_info->security_bits = security_bits; ssl_info->handshake_type = SSLInfo::HANDSHAKE_FULL; ssl_info->pinning_failure_log = pinning_failure_log_; + ssl_info->is_fatal_cert_error = is_fatal_cert_error_; ssl_info->UpdateCertificateTransparencyInfo(*ct_verify_result_); @@ -1357,7 +1425,7 @@ void QuicChromiumClientSession::OnConnectionClosed( logger_->OnConnectionClosed(error, error_details, source); if (source == ConnectionCloseSource::FROM_PEER) { if (IsCryptoHandshakeConfirmed()) { - UMA_HISTOGRAM_SPARSE_SLOWLY( + base::UmaHistogramSparse( "Net.QuicSession.ConnectionCloseErrorCodeServer.HandshakeConfirmed", error); base::HistogramBase* histogram = base::SparseHistogram::FactoryGet( @@ -1367,11 +1435,11 @@ void QuicChromiumClientSession::OnConnectionClosed( if (num_streams > 0) histogram->AddCount(error, num_streams); } - UMA_HISTOGRAM_SPARSE_SLOWLY( - "Net.QuicSession.ConnectionCloseErrorCodeServer", error); + base::UmaHistogramSparse("Net.QuicSession.ConnectionCloseErrorCodeServer", + error); } else { if (IsCryptoHandshakeConfirmed()) { - UMA_HISTOGRAM_SPARSE_SLOWLY( + base::UmaHistogramSparse( "Net.QuicSession.ConnectionCloseErrorCodeClient.HandshakeConfirmed", error); base::HistogramBase* histogram = base::SparseHistogram::FactoryGet( @@ -1381,8 +1449,8 @@ void QuicChromiumClientSession::OnConnectionClosed( if (num_streams > 0) histogram->AddCount(error, num_streams); } - UMA_HISTOGRAM_SPARSE_SLOWLY( - "Net.QuicSession.ConnectionCloseErrorCodeClient", error); + base::UmaHistogramSparse("Net.QuicSession.ConnectionCloseErrorCodeClient", + error); } if (error == QUIC_NETWORK_IDLE_TIMEOUT) { @@ -1400,7 +1468,7 @@ void QuicChromiumClientSession::OnConnectionClosed( UMA_HISTOGRAM_COUNTS_1M( "Net.QuicSession.TimedOutWithOpenStreams.ConsecutiveTLPCount", connection()->sent_packet_manager().GetConsecutiveTlpCount()); - UMA_HISTOGRAM_SPARSE_SLOWLY( + base::UmaHistogramSparse( "Net.QuicSession.TimedOutWithOpenStreams.LocalPort", connection()->self_address().port()); } @@ -1430,19 +1498,19 @@ void QuicChromiumClientSession::OnConnectionClosed( RecordHandshakeFailureReason(HANDSHAKE_FAILURE_PUBLIC_RESET); } else if (connection()->GetStats().packets_received == 0) { RecordHandshakeFailureReason(HANDSHAKE_FAILURE_BLACK_HOLE); - UMA_HISTOGRAM_SPARSE_SLOWLY( + base::UmaHistogramSparse( "Net.QuicSession.ConnectionClose.HandshakeFailureBlackHole.QuicError", error); } else { RecordHandshakeFailureReason(HANDSHAKE_FAILURE_UNKNOWN); - UMA_HISTOGRAM_SPARSE_SLOWLY( + base::UmaHistogramSparse( "Net.QuicSession.ConnectionClose.HandshakeFailureUnknown.QuicError", error); } } - UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.QuicVersion", - connection()->transport_version()); + base::UmaHistogramSparse("Net.QuicSession.QuicVersion", + connection()->transport_version()); NotifyFactoryOfSessionGoingAway(); QuicSession::OnConnectionClosed(error, error_details, source); @@ -1479,10 +1547,10 @@ void QuicChromiumClientSession::OnConnectivityProbeReceived( int QuicChromiumClientSession::HandleWriteError( int error_code, scoped_refptr<QuicChromiumPacketWriter::ReusableIOBuffer> packet) { - UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.WriteError", -error_code); + base::UmaHistogramSparse("Net.QuicSession.WriteError", -error_code); if (IsCryptoHandshakeConfirmed()) { - UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.WriteError.HandshakeConfirmed", - -error_code); + base::UmaHistogramSparse("Net.QuicSession.WriteError.HandshakeConfirmed", + -error_code); } if (stream_factory_ == nullptr || !stream_factory_->migrate_sessions_on_network_change()) { @@ -1626,19 +1694,26 @@ void QuicChromiumClientSession::OnProbeNetworkSucceeded( // be acquired by connection and used as default on success. if (!MigrateToSocket(std::move(socket), std::move(reader), std::move(writer))) { + net_log_.AddEvent( + NetLogEventType::QUIC_CONNECTION_MIGRATION_FAILURE_AFTER_PROBING); return; } + net_log_.AddEvent( + NetLogEventType::QUIC_CONNECTION_MIGRATION_SUCCESS_AFTER_PROBING); if (network == default_network_) { DVLOG(1) << "Client successfully migrated to default network."; CancelMigrateBackToDefaultNetworkTimer(); - } else if (!migrate_back_to_default_timer_.IsRunning()) { - // We get off the |default_network|, stay on |network| for now but - // try to migrate back to default network after 1 second. + } else { DVLOG(1) << "Client successfully got off default network after " << "successful probing network: " << network << "."; - StartMigrateBackToDefaultNetworkTimer( - base::TimeDelta::FromSeconds(kMinRetryTimeForDefaultNetworkSecs)); + current_migrations_to_non_default_network_on_path_degrading_++; + if (!migrate_back_to_default_timer_.IsRunning()) { + // Session gets off the |default_network|, stay on |network| for now but + // try to migrate back to default network after 1 second. + StartMigrateBackToDefaultNetworkTimer( + base::TimeDelta::FromSeconds(kMinRetryTimeForDefaultNetworkSecs)); + } } } @@ -1734,6 +1809,8 @@ void QuicChromiumClientSession::OnNetworkDisconnectedV2( void QuicChromiumClientSession::OnNetworkMadeDefault( NetworkChangeNotifier::NetworkHandle new_network, const NetLogWithSource& migration_net_log) { + net_log_.AddEvent( + NetLogEventType::QUIC_CONNECTION_MIGRATION_ON_NETWORK_MADE_DEFAULT); LogMetricsOnNetworkMadeDefault(); if (!migrate_session_on_network_change_ && @@ -1748,6 +1825,7 @@ void QuicChromiumClientSession::OnNetworkMadeDefault( migration_net_log); return; } + current_migrations_to_non_default_network_on_path_degrading_ = 0; // Connection migration v2. // If we are already on the new network. @@ -1829,12 +1907,22 @@ void QuicChromiumClientSession::OnPathDegrading() { stream_factory_->FindAlternateNetwork( GetDefaultSocket()->GetBoundNetwork()); if (alternate_network != NetworkChangeNotifier::kInvalidNetworkHandle) { - // Probe alternative network, we will migrate to the probed network - // and decide whether we want to migrate back to the default network - // on success. - StartProbeNetwork(alternate_network, - connection()->peer_address().impl().socket_address(), - migration_net_log); + if (GetDefaultSocket()->GetBoundNetwork() == default_network_ && + current_migrations_to_non_default_network_on_path_degrading_ >= + max_migrations_to_non_default_network_on_path_degrading_) { + HistogramAndLogMigrationFailure( + migration_net_log, MIGRATION_STATUS_ON_PATH_DEGRADING_DISABLED, + connection_id(), + "Exceeds maximum number of migrations on path degrading"); + } else { + // Probe alternative network, session will migrate to the probed + // network and decide whether it wants to migrate back to the default + // network on success. + StartProbeNetwork( + alternate_network, + connection()->peer_address().impl().socket_address(), + migration_net_log); + } } else { HistogramAndLogMigrationFailure( migration_net_log, MIGRATION_STATUS_DISABLED, connection_id(), @@ -1890,6 +1978,7 @@ void QuicChromiumClientSession::OnProofVerifyDetailsAvailable( ct_verify_result_ = std::move(ct_verify_result_copy); logger_->OnCertificateVerified(*cert_verify_result_); pkp_bypassed_ = verify_details_chromium->pkp_bypassed; + is_fatal_cert_error_ = verify_details_chromium->is_fatal_cert_error; } void QuicChromiumClientSession::StartReading() { @@ -1900,8 +1989,7 @@ void QuicChromiumClientSession::StartReading() { void QuicChromiumClientSession::CloseSessionOnError(int net_error, QuicErrorCode quic_error) { - UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.CloseSessionOnError", - -net_error); + base::UmaHistogramSparse("Net.QuicSession.CloseSessionOnError", -net_error); if (!callback_.is_null()) { base::ResetAndReturn(&callback_).Run(net_error); @@ -1922,8 +2010,7 @@ void QuicChromiumClientSession::CloseSessionOnError(int net_error, void QuicChromiumClientSession::CloseSessionOnErrorLater( int net_error, QuicErrorCode quic_error) { - UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.CloseSessionOnError", - -net_error); + base::UmaHistogramSparse("Net.QuicSession.CloseSessionOnError", -net_error); if (!callback_.is_null()) { base::ResetAndReturn(&callback_).Run(net_error); @@ -2114,13 +2201,14 @@ void QuicChromiumClientSession::TryMigrateBackToDefaultNetwork( } void QuicChromiumClientSession::MaybeRetryMigrateBackToDefaultNetwork() { - if (retry_migrate_back_count_ > kMaxRetryCount) { + base::TimeDelta retry_migrate_back_timeout = + base::TimeDelta::FromSeconds(UINT64_C(1) << retry_migrate_back_count_); + if (retry_migrate_back_timeout > max_time_on_non_default_network_) { // Mark session as going away to accept no more streams. stream_factory_->OnSessionGoingAway(this); return; } - TryMigrateBackToDefaultNetwork( - base::TimeDelta::FromSeconds(UINT64_C(1) << retry_migrate_back_count_)); + TryMigrateBackToDefaultNetwork(retry_migrate_back_timeout); } bool QuicChromiumClientSession::ShouldMigrateSession( @@ -2202,9 +2290,8 @@ void QuicChromiumClientSession::LogMetricsOnNetworkDisconnected() { "Net.QuicNetworkGapBetweenWriteErrorAndDisconnection", write_error_to_disconnection_gap, base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10), 100); - UMA_HISTOGRAM_SPARSE_SLOWLY( - "Net.QuicSession.WriteError.NetworkDisconnected", - -most_recent_write_error_); + base::UmaHistogramSparse("Net.QuicSession.WriteError.NetworkDisconnected", + -most_recent_write_error_); most_recent_write_error_ = 0; most_recent_write_error_timestamp_ = base::TimeTicks(); } @@ -2249,7 +2336,7 @@ std::unique_ptr<base::Value> QuicChromiumClientSession::GetInfoAsValue( dict->SetInteger("total_streams", num_total_streams_); dict->SetString("peer_address", peer_address().ToString()); - dict->SetString("connection_id", base::Uint64ToString(connection_id())); + dict->SetString("connection_id", base::NumberToString(connection_id())); dict->SetBoolean("connected", connection()->connected()); const QuicConnectionStats& stats = connection()->GetStats(); dict->SetInteger("packets_sent", stats.packets_sent); @@ -2268,9 +2355,9 @@ std::unique_ptr<base::Value> QuicChromiumClientSession::GetInfoAsValue( } std::unique_ptr<QuicChromiumClientSession::Handle> -QuicChromiumClientSession::CreateHandle() { +QuicChromiumClientSession::CreateHandle(const HostPortPair& destination) { return std::make_unique<QuicChromiumClientSession::Handle>( - weak_factory_.GetWeakPtr()); + weak_factory_.GetWeakPtr(), destination); } void QuicChromiumClientSession::OnReadError( @@ -2283,7 +2370,7 @@ void QuicChromiumClientSession::OnReadError( return; } DVLOG(1) << "Closing session on read error: " << result; - UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.ReadError", -result); + base::UmaHistogramSparse("Net.QuicSession.ReadError", -result); connection()->CloseConnection(QUIC_PACKET_READ_ERROR, ErrorToString(result), ConnectionCloseBehavior::SILENT_CLOSE); } diff --git a/chromium/net/quic/chromium/quic_chromium_client_session.h b/chromium/net/quic/chromium/quic_chromium_client_session.h index 886a9b8ca9a..6cbe4582f4f 100644 --- a/chromium/net/quic/chromium/quic_chromium_client_session.h +++ b/chromium/net/quic/chromium/quic_chromium_client_session.h @@ -40,6 +40,7 @@ #include "net/quic/core/quic_spdy_client_session_base.h" #include "net/quic/core/quic_time.h" #include "net/socket/socket_performance_watcher.h" +#include "net/spdy/chromium/http2_priority_dependencies.h" #include "net/spdy/chromium/multiplexed_session.h" #include "net/spdy/chromium/server_push_delegate.h" @@ -69,6 +70,15 @@ enum class MigrationResult { FAILURE // Migration failed for other reasons. }; +// Mode of connection migration. +enum class ConnectionMigrationMode { + NO_MIGRATION, + NO_MIGRATION_ON_PATH_DEGRADING_V1, + FULL_MIGRATION_V1, + NO_MIGRATION_ON_PATH_DEGRADING_V2, + FULL_MIGRATION_V2 +}; + // Result of a connectivity probing attempt. enum class ProbingResult { PENDING, // Probing started, pending result. @@ -95,7 +105,10 @@ class NET_EXPORT_PRIVATE QuicChromiumClientSession : public MultiplexedSessionHandle, public QuicClientPushPromiseIndex::Delegate { public: - explicit Handle(const base::WeakPtr<QuicChromiumClientSession>& session); + // Constructs a handle to |session| which was created via the alternative + // server |destination|. + Handle(const base::WeakPtr<QuicChromiumClientSession>& session, + const HostPortPair& destination); Handle(const Handle& other) = delete; ~Handle() override; @@ -169,9 +182,17 @@ class NET_EXPORT_PRIVATE QuicChromiumClientSession // Returns the session's server ID. QuicServerId server_id() const { return server_id_; } + // Returns the alternative server used for this session. + HostPortPair destination() const { return destination_; } + // Returns the session's net log. const NetLogWithSource& net_log() const { return net_log_; } + // Returns the session's connection migration mode. + ConnectionMigrationMode connection_migration_mode() const { + return session_->connection_migration_mode(); + } + // QuicClientPushPromiseIndex::Delegate implementation bool CheckVary(const SpdyHeaderBlock& client_request, const SpdyHeaderBlock& promise_request, @@ -212,6 +233,8 @@ class NET_EXPORT_PRIVATE QuicChromiumClientSession // Underlying session which may be destroyed before this handle. base::WeakPtr<QuicChromiumClientSession> session_; + HostPortPair destination_; + // Stream request created by |RequestStream()|. std::unique_ptr<StreamRequest> stream_request_; @@ -318,8 +341,11 @@ class NET_EXPORT_PRIVATE QuicChromiumClientSession bool migrate_session_on_network_change, bool migrate_sesion_early_v2, bool migrate_session_on_network_change_v2, + base::TimeDelta max_time_on_non_default_network, + int max_migrations_to_non_default_network_on_path_degrading, int yield_after_packets, QuicTime::Delta yield_after_duration, + bool headers_include_h2_stream_dependency, int cert_verify_flags, const QuicConfig& config, QuicCryptoClientConfig* crypto_config, @@ -338,6 +364,9 @@ class NET_EXPORT_PRIVATE QuicChromiumClientSession void AddHandle(Handle* handle); void RemoveHandle(Handle* handle); + // Returns the session's connection migration mode. + ConnectionMigrationMode connection_migration_mode() const; + // Waits for the handshake to be confirmed and invokes |callback| when // that happens. If the handshake has already been confirmed, returns OK. // If the connection has already been closed, returns a net error. If the @@ -380,7 +409,16 @@ class NET_EXPORT_PRIVATE QuicChromiumClientSession const QuicSocketAddress& peer_address) override; // QuicSpdySession methods: + size_t WriteHeaders(QuicStreamId id, + SpdyHeaderBlock headers, + bool fin, + SpdyPriority priority, + QuicReferenceCountedPointer<QuicAckListenerInterface> + ack_listener) override; void OnHeadersHeadOfLineBlocking(QuicTime::Delta delta) override; + void UnregisterStreamPriority(QuicStreamId id) override; + void UpdateStreamPriority(QuicStreamId id, + SpdyPriority new_priority) override; // QuicSession methods: void OnStreamFrame(const QuicStreamFrame& frame) override; @@ -451,7 +489,8 @@ class NET_EXPORT_PRIVATE QuicChromiumClientSession const NetLogWithSource& net_log() const { return net_log_; } // Returns a Handle to this session. - std::unique_ptr<QuicChromiumClientSession::Handle> CreateHandle(); + std::unique_ptr<QuicChromiumClientSession::Handle> CreateHandle( + const HostPortPair& destination); // Returns the number of client hello messages that have been sent on the // crypto stream. If the handshake has completed then this is one greater @@ -652,6 +691,11 @@ class NET_EXPORT_PRIVATE QuicChromiumClientSession bool migrate_session_on_network_change_; bool migrate_session_early_v2_; bool migrate_session_on_network_change_v2_; + base::TimeDelta max_time_on_non_default_network_; + // Maximum allowed number of migrations to non-default network triggered by + // path degrading per default network. + int max_migrations_to_non_default_network_on_path_degrading_; + int current_migrations_to_non_default_network_on_path_degrading_; QuicClock* clock_; // Unowned. int yield_after_packets_; QuicTime::Delta yield_after_duration_; @@ -671,6 +715,7 @@ class NET_EXPORT_PRIVATE QuicChromiumClientSession std::unique_ptr<ct::CTVerifyResult> ct_verify_result_; std::string pinning_failure_log_; bool pkp_bypassed_; + bool is_fatal_cert_error_; HandleSet handles_; StreamRequestQueue stream_requests_; std::vector<CompletionCallback> waiting_for_confirmation_callbacks_; @@ -708,6 +753,12 @@ class NET_EXPORT_PRIVATE QuicChromiumClientSession // sockets_.size(). Then in MigrateSessionOnError, check to see if // the current sockets_.size() == the passed in value. bool migration_pending_; // True while migration is underway. + + // If true, client headers will include HTTP/2 stream dependency info derived + // from SpdyPriority. + bool headers_include_h2_stream_dependency_; + Http2PriorityDependencies priority_dependency_state_; + base::WeakPtrFactory<QuicChromiumClientSession> weak_factory_; DISALLOW_COPY_AND_ASSIGN(QuicChromiumClientSession); diff --git a/chromium/net/quic/chromium/quic_chromium_client_session_test.cc b/chromium/net/quic/chromium/quic_chromium_client_session_test.cc index 293479de195..aaa3b2ebe44 100644 --- a/chromium/net/quic/chromium/quic_chromium_client_session_test.cc +++ b/chromium/net/quic/chromium/quic_chromium_client_session_test.cc @@ -34,6 +34,7 @@ #include "net/quic/core/crypto/quic_encrypter.h" #include "net/quic/core/quic_client_promised_info.h" #include "net/quic/core/quic_packet_writer.h" +#include "net/quic/core/tls_client_handshaker.h" #include "net/quic/platform/api/quic_flags.h" #include "net/quic/platform/impl/quic_test_impl.h" #include "net/quic/test_tools/crypto_test_utils.h" @@ -81,26 +82,32 @@ class TestingQuicChromiumClientSession : public QuicChromiumClientSession { }; class QuicChromiumClientSessionTest - : public ::testing::TestWithParam<QuicTransportVersion> { + : public ::testing::TestWithParam<std::tuple<QuicTransportVersion, bool>> { public: QuicChromiumClientSessionTest() - : crypto_config_(crypto_test_utils::ProofVerifierForTesting()), + : version_(std::get<0>(GetParam())), + client_headers_include_h2_stream_dependency_(std::get<1>(GetParam())), + crypto_config_(crypto_test_utils::ProofVerifierForTesting(), + TlsClientHandshaker::CreateSslCtx()), default_read_(new MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)), socket_data_( new SequencedSocketData(default_read_.get(), 1, nullptr, 0)), random_(0), helper_(&clock_, &random_), server_id_(kServerHostname, kServerPort, PRIVACY_MODE_DISABLED), - client_maker_(GetParam(), + destination_(kServerHostname, kServerPort), + client_maker_(version_, 0, &clock_, kServerHostname, - Perspective::IS_CLIENT), - server_maker_(GetParam(), + Perspective::IS_CLIENT, + client_headers_include_h2_stream_dependency_), + server_maker_(version_, 0, &clock_, kServerHostname, - Perspective::IS_SERVER) { + Perspective::IS_SERVER, + false) { // Advance the time, because timers do not like uninitialized times. clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1)); } @@ -126,7 +133,8 @@ class QuicChromiumClientSessionTest QuicConnection* connection = new QuicConnection( 0, QuicSocketAddress(QuicSocketAddressImpl(kIpEndPoint)), &helper_, &alarm_factory_, writer, true, Perspective::IS_CLIENT, - SupportedTransportVersions(GetParam())); + SupportedVersions( + net::ParsedQuicVersion(net::PROTOCOL_QUIC_CRYPTO, version_))); session_.reset(new TestingQuicChromiumClientSession( connection, std::move(socket), /*stream_factory=*/nullptr, &crypto_client_stream_factory_, &clock_, @@ -136,12 +144,14 @@ class QuicChromiumClientSessionTest /*migrate_session_on_network_change*/ false, /*migrate_session_early_v2*/ false, /*migrate_session_on_network_change_v2*/ false, + base::TimeDelta::FromSeconds(kMaxTimeOnNonDefaultNetworkSecs), + kMaxMigrationsToNonDefaultNetworkOnPathDegrading, kQuicYieldAfterPacketsRead, QuicTime::Delta::FromMilliseconds(kQuicYieldAfterDurationMilliseconds), - /*cert_verify_flags=*/0, DefaultQuicConfig(), &crypto_config_, - "CONNECTION_UNKNOWN", base::TimeTicks::Now(), base::TimeTicks::Now(), - &push_promise_index_, &test_push_delegate_, - base::ThreadTaskRunnerHandle::Get().get(), + /*cert_verify_flags=*/0, client_headers_include_h2_stream_dependency_, + DefaultQuicConfig(), &crypto_config_, "CONNECTION_UNKNOWN", + base::TimeTicks::Now(), base::TimeTicks::Now(), &push_promise_index_, + &test_push_delegate_, base::ThreadTaskRunnerHandle::Get().get(), /*socket_performance_watcher=*/nullptr, &net_log_)); scoped_refptr<X509Certificate> cert( @@ -173,13 +183,15 @@ class QuicChromiumClientSessionTest } QuicStreamId GetNthClientInitiatedStreamId(int n) { - return test::GetNthClientInitiatedStreamId(GetParam(), n); + return test::GetNthClientInitiatedStreamId(version_, n); } QuicStreamId GetNthServerInitiatedStreamId(int n) { - return test::GetNthServerInitiatedStreamId(GetParam(), n); + return test::GetNthServerInitiatedStreamId(version_, n); } + const QuicTransportVersion version_; + const bool client_headers_include_h2_stream_dependency_; QuicFlagSaver flags_; // Save/restore all QUIC flag values. QuicCryptoClientConfig crypto_config_; TestNetLog net_log_; @@ -195,6 +207,7 @@ class QuicChromiumClientSessionTest MockCryptoClientStreamFactory crypto_client_stream_factory_; QuicClientPushPromiseIndex push_promise_index_; QuicServerId server_id_; + HostPortPair destination_; std::unique_ptr<TestingQuicChromiumClientSession> session_; TestServerPushDelegate test_push_delegate_; QuicConnectionVisitorInterface* visitor_; @@ -204,9 +217,58 @@ class QuicChromiumClientSessionTest ProofVerifyDetailsChromium verify_details_; }; -INSTANTIATE_TEST_CASE_P(Tests, - QuicChromiumClientSessionTest, - ::testing::ValuesIn(AllSupportedTransportVersions())); +INSTANTIATE_TEST_CASE_P( + VersionIncludeStreamDependencySequnece, + QuicChromiumClientSessionTest, + ::testing::Combine(::testing::ValuesIn(AllSupportedTransportVersions()), + ::testing::Bool())); + +TEST_P(QuicChromiumClientSessionTest, IsFatalErrorNotSetForNonFatalError) { + MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)}; + std::unique_ptr<QuicEncryptedPacket> settings_packet( + client_maker_.MakeInitialSettingsPacket(1, nullptr)); + MockWrite writes[] = { + MockWrite(ASYNC, settings_packet->data(), settings_packet->length(), 1)}; + socket_data_.reset(new SequencedSocketData(reads, arraysize(reads), writes, + arraysize(writes))); + Initialize(); + + SSLInfo ssl_info; + ProofVerifyDetailsChromium details; + details.cert_verify_result.verified_cert = + ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem"); + details.cert_verify_result.cert_status = + MapNetErrorToCertStatus(ERR_CERT_DATE_INVALID); + details.is_fatal_cert_error = false; + CompleteCryptoHandshake(); + session_->OnProofVerifyDetailsAvailable(details); + + ASSERT_TRUE(session_->GetSSLInfo(&ssl_info)); + EXPECT_FALSE(ssl_info.is_fatal_cert_error); +} + +TEST_P(QuicChromiumClientSessionTest, IsFatalErrorSetForFatalError) { + MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)}; + std::unique_ptr<QuicEncryptedPacket> settings_packet( + client_maker_.MakeInitialSettingsPacket(1, nullptr)); + MockWrite writes[] = { + MockWrite(ASYNC, settings_packet->data(), settings_packet->length(), 1)}; + socket_data_.reset(new SequencedSocketData(reads, arraysize(reads), writes, + arraysize(writes))); + Initialize(); + + SSLInfo ssl_info; + ProofVerifyDetailsChromium details; + details.cert_verify_result.verified_cert = + ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem"); + details.cert_verify_result.cert_status = + MapNetErrorToCertStatus(ERR_CERT_DATE_INVALID); + details.is_fatal_cert_error = true; + CompleteCryptoHandshake(); + session_->OnProofVerifyDetailsAvailable(details); + ASSERT_TRUE(session_->GetSSLInfo(&ssl_info)); + EXPECT_TRUE(ssl_info.is_fatal_cert_error); +} TEST_P(QuicChromiumClientSessionTest, CryptoConnect) { MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)}; @@ -234,10 +296,10 @@ TEST_P(QuicChromiumClientSessionTest, Handle) { EXPECT_EQ(&net_log_, session_net_log.net_log()); std::unique_ptr<QuicChromiumClientSession::Handle> handle = - session_->CreateHandle(); + session_->CreateHandle(destination_); EXPECT_TRUE(handle->IsConnected()); EXPECT_FALSE(handle->IsCryptoHandshakeConfirmed()); - EXPECT_EQ(GetParam(), handle->GetQuicVersion()); + EXPECT_EQ(version_, handle->GetQuicVersion()); EXPECT_EQ(server_id_, handle->server_id()); EXPECT_EQ(session_net_log.source().type, handle->net_log().source().type); EXPECT_EQ(session_net_log.source().id, handle->net_log().source().id); @@ -265,7 +327,7 @@ TEST_P(QuicChromiumClientSessionTest, Handle) { // Veirfy that the handle works correctly after the session is closed. EXPECT_FALSE(handle->IsConnected()); EXPECT_TRUE(handle->IsCryptoHandshakeConfirmed()); - EXPECT_EQ(GetParam(), handle->GetQuicVersion()); + EXPECT_EQ(version_, handle->GetQuicVersion()); EXPECT_EQ(server_id_, handle->server_id()); EXPECT_EQ(session_net_log.source().type, handle->net_log().source().type); EXPECT_EQ(session_net_log.source().id, handle->net_log().source().id); @@ -276,7 +338,7 @@ TEST_P(QuicChromiumClientSessionTest, Handle) { { // Verify that CreateHandle() works even after the session is closed. std::unique_ptr<QuicChromiumClientSession::Handle> handle2 = - session_->CreateHandle(); + session_->CreateHandle(destination_); EXPECT_FALSE(handle2->IsConnected()); EXPECT_TRUE(handle2->IsCryptoHandshakeConfirmed()); ASSERT_EQ(ERR_CONNECTION_CLOSED, @@ -289,7 +351,7 @@ TEST_P(QuicChromiumClientSessionTest, Handle) { // Veirfy that the handle works correctly after the session is deleted. EXPECT_FALSE(handle->IsConnected()); EXPECT_TRUE(handle->IsCryptoHandshakeConfirmed()); - EXPECT_EQ(GetParam(), handle->GetQuicVersion()); + EXPECT_EQ(version_, handle->GetQuicVersion()); EXPECT_EQ(server_id_, handle->server_id()); EXPECT_EQ(session_net_log.source().type, handle->net_log().source().type); EXPECT_EQ(session_net_log.source().id, handle->net_log().source().id); @@ -314,7 +376,7 @@ TEST_P(QuicChromiumClientSessionTest, StreamRequest) { // Request a stream and verify that a stream was created. std::unique_ptr<QuicChromiumClientSession::Handle> handle = - session_->CreateHandle(); + session_->CreateHandle(destination_); TestCompletionCallback callback; ASSERT_EQ(OK, handle->RequestStream(/*requires_confirmation=*/false, callback.callback())); @@ -337,7 +399,7 @@ TEST_P(QuicChromiumClientSessionTest, ConfirmationRequiredStreamRequest) { // Request a stream and verify that a stream was created. std::unique_ptr<QuicChromiumClientSession::Handle> handle = - session_->CreateHandle(); + session_->CreateHandle(destination_); TestCompletionCallback callback; ASSERT_EQ(OK, handle->RequestStream(/*requires_confirmation=*/true, callback.callback())); @@ -359,7 +421,7 @@ TEST_P(QuicChromiumClientSessionTest, StreamRequestBeforeConfirmation) { // Request a stream and verify that a stream was created. std::unique_ptr<QuicChromiumClientSession::Handle> handle = - session_->CreateHandle(); + session_->CreateHandle(destination_); TestCompletionCallback callback; ASSERT_EQ(ERR_IO_PENDING, handle->RequestStream(/*requires_confirmation=*/true, @@ -390,7 +452,7 @@ TEST_P(QuicChromiumClientSessionTest, CancelStreamRequestBeforeRelease) { // Request a stream and cancel it without releasing the stream. std::unique_ptr<QuicChromiumClientSession::Handle> handle = - session_->CreateHandle(); + session_->CreateHandle(destination_); TestCompletionCallback callback; ASSERT_EQ(OK, handle->RequestStream(/*requires_confirmation=*/false, callback.callback())); @@ -423,7 +485,7 @@ TEST_P(QuicChromiumClientSessionTest, AsyncStreamRequest) { // Request a stream and verify that it's pending. std::unique_ptr<QuicChromiumClientSession::Handle> handle = - session_->CreateHandle(); + session_->CreateHandle(destination_); TestCompletionCallback callback; ASSERT_EQ(ERR_IO_PENDING, handle->RequestStream(/*requires_confirmation=*/false, @@ -463,9 +525,9 @@ TEST_P(QuicChromiumClientSessionTest, ClosedWithAsyncStreamRequest) { // Request two streams which will both be pending. std::unique_ptr<QuicChromiumClientSession::Handle> handle = - session_->CreateHandle(); + session_->CreateHandle(destination_); std::unique_ptr<QuicChromiumClientSession::Handle> handle2 = - session_->CreateHandle(); + session_->CreateHandle(destination_); ASSERT_EQ(ERR_IO_PENDING, handle->RequestStream( @@ -512,7 +574,7 @@ TEST_P(QuicChromiumClientSessionTest, CancelPendingStreamRequest) { // Request a stream and verify that it's pending. std::unique_ptr<QuicChromiumClientSession::Handle> handle = - session_->CreateHandle(); + session_->CreateHandle(destination_); TestCompletionCallback callback; ASSERT_EQ(ERR_IO_PENDING, handle->RequestStream(/*requires_confirmation=*/false, @@ -547,7 +609,7 @@ TEST_P(QuicChromiumClientSessionTest, ConnectionCloseBeforeStreamRequest) { // Request a stream and verify that it failed. std::unique_ptr<QuicChromiumClientSession::Handle> handle = - session_->CreateHandle(); + session_->CreateHandle(destination_); TestCompletionCallback callback; ASSERT_EQ(ERR_CONNECTION_CLOSED, handle->RequestStream(/*requires_confirmation=*/false, @@ -567,7 +629,7 @@ TEST_P(QuicChromiumClientSessionTest, ConnectionCloseBeforeHandshakeConfirmed) { // Request a stream and verify that it's pending. std::unique_ptr<QuicChromiumClientSession::Handle> handle = - session_->CreateHandle(); + session_->CreateHandle(destination_); TestCompletionCallback callback; ASSERT_EQ(ERR_IO_PENDING, handle->RequestStream(/*requires_confirmation=*/true, @@ -604,7 +666,7 @@ TEST_P(QuicChromiumClientSessionTest, ConnectionCloseWithPendingStreamRequest) { // Request a stream and verify that it's pending. std::unique_ptr<QuicChromiumClientSession::Handle> handle = - session_->CreateHandle(); + session_->CreateHandle(destination_); TestCompletionCallback callback; ASSERT_EQ(ERR_IO_PENDING, handle->RequestStream(/*requires_confirmation=*/false, @@ -942,7 +1004,7 @@ TEST_P(QuicChromiumClientSessionTest, MaxNumStreamsViaRequest) { } std::unique_ptr<QuicChromiumClientSession::Handle> handle = - session_->CreateHandle(); + session_->CreateHandle(destination_); TestCompletionCallback callback; ASSERT_EQ(ERR_IO_PENDING, handle->RequestStream(/*requires_confirmation=*/false, diff --git a/chromium/net/quic/chromium/quic_chromium_client_stream_test.cc b/chromium/net/quic/chromium/quic_chromium_client_stream_test.cc index a23dc368084..e1f489c13fd 100644 --- a/chromium/net/quic/chromium/quic_chromium_client_stream_test.cc +++ b/chromium/net/quic/chromium/quic_chromium_client_stream_test.cc @@ -16,6 +16,7 @@ #include "net/quic/core/quic_spdy_client_session_base.h" #include "net/quic/core/quic_utils.h" #include "net/quic/core/spdy_utils.h" +#include "net/quic/core/tls_client_handshaker.h" #include "net/quic/platform/api/quic_ptr_util.h" #include "net/quic/test_tools/crypto_test_utils.h" #include "net/quic/test_tools/quic_spdy_session_peer.h" @@ -154,11 +155,14 @@ class QuicChromiumClientStreamTest : public ::testing::TestWithParam<QuicTransportVersion> { public: QuicChromiumClientStreamTest() - : crypto_config_(crypto_test_utils::ProofVerifierForTesting()), - session_(new MockQuicConnection(&helper_, - &alarm_factory_, - Perspective::IS_CLIENT, - SupportedTransportVersions(GetParam())), + : crypto_config_(crypto_test_utils::ProofVerifierForTesting(), + TlsClientHandshaker::CreateSslCtx()), + session_(new MockQuicConnection( + &helper_, + &alarm_factory_, + Perspective::IS_CLIENT, + SupportedVersions( + ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, GetParam()))), &push_promise_index_) { stream_ = new QuicChromiumClientStream(kTestStreamId, &session_, NetLogWithSource()); diff --git a/chromium/net/quic/chromium/quic_connection_logger.cc b/chromium/net/quic/chromium/quic_connection_logger.cc index 38794d10225..86f4d568f36 100644 --- a/chromium/net/quic/chromium/quic_connection_logger.cc +++ b/chromium/net/quic/chromium/quic_connection_logger.cc @@ -13,8 +13,8 @@ #include "base/bind.h" #include "base/callback.h" #include "base/metrics/histogram_base.h" +#include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" -#include "base/metrics/sparse_histogram.h" #include "base/strings/string_number_conversions.h" #include "base/values.h" #include "net/base/ip_address.h" @@ -56,7 +56,7 @@ std::unique_ptr<base::Value> NetLogQuicPacketSentCallback( std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); dict->SetInteger("transmission_type", transmission_type); dict->SetString("packet_number", - base::Uint64ToString(serialized_packet.packet_number)); + base::NumberToString(serialized_packet.packet_number)); dict->SetInteger("size", serialized_packet.encrypted_length); dict->SetString("sent_time_us", base::Int64ToString(sent_time.ToDebuggingValue())); @@ -68,8 +68,8 @@ std::unique_ptr<base::Value> NetLogQuicPacketRetransmittedCallback( QuicPacketNumber new_packet_number, NetLogCaptureMode /* capture_mode */) { std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); - dict->SetString("old_packet_number", base::Uint64ToString(old_packet_number)); - dict->SetString("new_packet_number", base::Uint64ToString(new_packet_number)); + dict->SetString("old_packet_number", base::NumberToString(old_packet_number)); + dict->SetString("new_packet_number", base::NumberToString(new_packet_number)); return std::move(dict); } @@ -77,7 +77,7 @@ std::unique_ptr<base::Value> NetLogQuicDuplicatePacketCallback( QuicPacketNumber packet_number, NetLogCaptureMode /* capture_mode */) { std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); - dict->SetString("packet_number", base::Uint64ToString(packet_number)); + dict->SetString("packet_number", base::NumberToString(packet_number)); return std::move(dict); } @@ -85,10 +85,10 @@ std::unique_ptr<base::Value> NetLogQuicPacketHeaderCallback( const QuicPacketHeader* header, NetLogCaptureMode /* capture_mode */) { std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); - dict->SetString("connection_id", base::Uint64ToString(header->connection_id)); + dict->SetString("connection_id", base::NumberToString(header->connection_id)); dict->SetInteger("reset_flag", header->reset_flag); dict->SetInteger("version_flag", header->version_flag); - dict->SetString("packet_number", base::Uint64ToString(header->packet_number)); + dict->SetString("packet_number", base::NumberToString(header->packet_number)); return std::move(dict); } @@ -98,7 +98,7 @@ std::unique_ptr<base::Value> NetLogQuicStreamFrameCallback( std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); dict->SetInteger("stream_id", frame->stream_id); dict->SetBoolean("fin", frame->fin); - dict->SetString("offset", base::Uint64ToString(frame->offset)); + dict->SetString("offset", base::NumberToString(frame->offset)); dict->SetInteger("length", frame->data_length); return std::move(dict); } @@ -108,7 +108,7 @@ std::unique_ptr<base::Value> NetLogQuicAckFrameCallback( NetLogCaptureMode /* capture_mode */) { auto dict = std::make_unique<base::DictionaryValue>(); dict->SetString("largest_observed", - base::Uint64ToString(frame->deprecated_largest_observed)); + base::NumberToString(frame->largest_acked)); dict->SetString("delta_time_largest_observed_us", base::Int64ToString(frame->ack_delay_time.ToMicroseconds())); @@ -117,9 +117,9 @@ std::unique_ptr<base::Value> NetLogQuicAckFrameCallback( // V34 and above express acked packets, but only print // missing packets, because it's typically a shorter list. for (QuicPacketNumber packet = frame->packets.Min(); - packet < frame->deprecated_largest_observed; ++packet) { + packet < frame->largest_acked; ++packet) { if (!frame->packets.Contains(packet)) { - missing->AppendString(base::Uint64ToString(packet)); + missing->AppendString(base::NumberToString(packet)); } } } @@ -163,7 +163,7 @@ std::unique_ptr<base::Value> NetLogQuicWindowUpdateFrameCallback( NetLogCaptureMode /* capture_mode */) { std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); dict->SetInteger("stream_id", frame->stream_id); - dict->SetString("byte_offset", base::Uint64ToString(frame->byte_offset)); + dict->SetString("byte_offset", base::NumberToString(frame->byte_offset)); return std::move(dict); } @@ -191,7 +191,7 @@ std::unique_ptr<base::Value> NetLogQuicStopWaitingFrameCallback( auto dict = std::make_unique<base::DictionaryValue>(); auto sent_info = std::make_unique<base::DictionaryValue>(); sent_info->SetString("least_unacked", - base::Uint64ToString(frame->least_unacked)); + base::NumberToString(frame->least_unacked)); dict->Set("sent_info", std::move(sent_info)); return std::move(dict); } @@ -201,9 +201,9 @@ std::unique_ptr<base::Value> NetLogQuicVersionNegotiationPacketCallback( NetLogCaptureMode /* capture_mode */) { auto dict = std::make_unique<base::DictionaryValue>(); auto versions = std::make_unique<base::ListValue>(); - for (QuicTransportVersionVector::const_iterator it = packet->versions.begin(); + for (ParsedQuicVersionVector::const_iterator it = packet->versions.begin(); it != packet->versions.end(); ++it) { - versions->AppendString(QuicVersionToString(*it)); + versions->AppendString(ParsedQuicVersionToString(*it)); } dict->Set("versions", std::move(versions)); return std::move(dict); @@ -356,8 +356,8 @@ void QuicConnectionLogger::OnFrameAddedToPacket(const QuicFrame& frame) { break; } case RST_STREAM_FRAME: - UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.RstStreamErrorCodeClient", - frame.rst_stream_frame->error_code); + base::UmaHistogramSparse("Net.QuicSession.RstStreamErrorCodeClient", + frame.rst_stream_frame->error_code); break; case CONNECTION_CLOSE_FRAME: break; @@ -398,8 +398,8 @@ void QuicConnectionLogger::OnFrameAddedToPacket(const QuicFrame& frame) { break; } case RST_STREAM_FRAME: - UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.RstStreamErrorCodeClient", - frame.rst_stream_frame->error_code); + base::UmaHistogramSparse("Net.QuicSession.RstStreamErrorCodeClient", + frame.rst_stream_frame->error_code); net_log_.AddEvent(NetLogEventType::QUIC_SESSION_RST_STREAM_FRAME_SENT, base::Bind(&NetLogQuicRstStreamFrameCallback, frame.rst_stream_frame)); @@ -522,7 +522,7 @@ void QuicConnectionLogger::OnDuplicatePacket(QuicPacketNumber packet_number) { } void QuicConnectionLogger::OnProtocolVersionMismatch( - QuicTransportVersion received_version) { + ParsedQuicVersion received_version) { // TODO(rtenneti): Add logging. } @@ -597,8 +597,8 @@ void QuicConnectionLogger::OnStopWaitingFrame( } void QuicConnectionLogger::OnRstStreamFrame(const QuicRstStreamFrame& frame) { - UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.RstStreamErrorCodeServer", - frame.error_code); + base::UmaHistogramSparse("Net.QuicSession.RstStreamErrorCodeServer", + frame.error_code); if (!net_log_is_capturing_) return; net_log_.AddEvent(NetLogEventType::QUIC_SESSION_RST_STREAM_FRAME_RECEIVED, diff --git a/chromium/net/quic/chromium/quic_connection_logger.h b/chromium/net/quic/chromium/quic_connection_logger.h index 173f85a7c93..07b6894e456 100644 --- a/chromium/net/quic/chromium/quic_connection_logger.h +++ b/chromium/net/quic/chromium/quic_connection_logger.h @@ -58,7 +58,7 @@ class NET_EXPORT_PRIVATE QuicConnectionLogger void OnIncorrectConnectionId(QuicConnectionId connection_id) override; void OnUndecryptablePacket() override; void OnDuplicatePacket(QuicPacketNumber packet_number) override; - void OnProtocolVersionMismatch(QuicTransportVersion version) override; + void OnProtocolVersionMismatch(ParsedQuicVersion version) override; void OnPacketHeader(const QuicPacketHeader& header) override; void OnStreamFrame(const QuicStreamFrame& frame) override; void OnAckFrame(const QuicAckFrame& frame) override; diff --git a/chromium/net/quic/chromium/quic_end_to_end_unittest.cc b/chromium/net/quic/chromium/quic_end_to_end_unittest.cc index b601451884d..0d041521e6a 100644 --- a/chromium/net/quic/chromium/quic_end_to_end_unittest.cc +++ b/chromium/net/quic/chromium/quic_end_to_end_unittest.cc @@ -132,12 +132,7 @@ class QuicEndToEndTest : public ::testing::TestWithParam<TestParams> { CertVerifyResult verify_result; verify_result.verified_cert = ImportCertFromFile( - GetTestCertsDirectory(), "quic_test.example.com.crt"); - cert_verifier_.AddResultForCertAndHost(verify_result.verified_cert.get(), - "test.example.com", verify_result, - OK); - verify_result.verified_cert = ImportCertFromFile( - GetTestCertsDirectory(), "quic_test_ecc.example.com.crt"); + GetTestCertsDirectory(), "quic-chain.pem"); cert_verifier_.AddResultForCertAndHost(verify_result.verified_cert.get(), "test.example.com", verify_result, OK); @@ -181,8 +176,7 @@ class QuicEndToEndTest : public ::testing::TestWithParam<TestParams> { server_config_options_.token_binding_params = QuicTagVector{kTB10, kP256}; server_.reset(new QuicSimpleServer( crypto_test_utils::ProofSourceForTesting(), server_config_, - server_config_options_, AllSupportedTransportVersions(), - &response_cache_)); + server_config_options_, AllSupportedVersions(), &response_cache_)); server_->Listen(server_address_); server_address_ = server_->server_address(); server_->StartReading(); diff --git a/chromium/net/quic/chromium/quic_http_stream.cc b/chromium/net/quic/chromium/quic_http_stream.cc index f0d4f17280b..9c503970fbc 100644 --- a/chromium/net/quic/chromium/quic_http_stream.cc +++ b/chromium/net/quic/chromium/quic_http_stream.cc @@ -50,6 +50,7 @@ QuicHttpStream::QuicHttpStream( next_state_(STATE_NONE), stream_(nullptr), request_info_(nullptr), + can_send_early_(false), request_body_stream_(nullptr), priority_(MINIMUM_PRIORITY), response_info_(nullptr), @@ -98,6 +99,7 @@ HttpResponseInfo::ConnectionInfo QuicHttpStream::ConnectionInfoFromQuicVersion( } int QuicHttpStream::InitializeStream(const HttpRequestInfo* request_info, + bool can_send_early, RequestPriority priority, const NetLogWithSource& stream_net_log, const CompletionCallback& callback) { @@ -114,9 +116,15 @@ int QuicHttpStream::InitializeStream(const HttpRequestInfo* request_info, stream_net_log.AddEvent( NetLogEventType::HTTP_STREAM_REQUEST_BOUND_TO_QUIC_SESSION, quic_session()->net_log().source().ToEventParametersCallback()); + stream_net_log.AddEvent( + NetLogEventType::QUIC_CONNECTION_MIGRATION_MODE, + NetLog::IntCallback( + "connection_migration_mode", + static_cast<int>(quic_session()->connection_migration_mode()))); stream_net_log_ = stream_net_log; request_info_ = request_info; + can_send_early_ = can_send_early; request_time_ = base::Time::Now(); priority_ = priority; @@ -378,8 +386,9 @@ bool QuicHttpStream::GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const { bool QuicHttpStream::GetAlternativeService( AlternativeService* alternative_service) const { alternative_service->protocol = kProtoQUIC; - alternative_service->host = quic_session()->server_id().host(); - alternative_service->port = quic_session()->server_id().port(); + const HostPortPair& destination = quic_session()->destination(); + alternative_service->host = destination.host(); + alternative_service->port = destination.port(); return true; } @@ -510,8 +519,9 @@ int QuicHttpStream::DoLoop(int rv) { int QuicHttpStream::DoRequestStream() { next_state_ = STATE_REQUEST_STREAM_COMPLETE; + return quic_session()->RequestStream( - request_info_->method == "POST", + !can_send_early_, base::Bind(&QuicHttpStream::OnIOComplete, weak_factory_.GetWeakPtr())); } @@ -548,6 +558,7 @@ int QuicHttpStream::DoSetRequestPriority() { // Set priority according to request DCHECK(stream_); DCHECK(response_info_); + SpdyPriority priority = ConvertRequestPriorityToQuicPriority(priority_); stream_->SetPriority(priority); next_state_ = STATE_SEND_HEADERS; diff --git a/chromium/net/quic/chromium/quic_http_stream.h b/chromium/net/quic/chromium/quic_http_stream.h index 77945b8f352..55d7732b2f4 100644 --- a/chromium/net/quic/chromium/quic_http_stream.h +++ b/chromium/net/quic/chromium/quic_http_stream.h @@ -44,6 +44,7 @@ class NET_EXPORT_PRIVATE QuicHttpStream : public MultiplexedHttpStream { // HttpStream implementation. int InitializeStream(const HttpRequestInfo* request_info, + bool can_send_early, RequestPriority priority, const NetLogWithSource& net_log, const CompletionCallback& callback) override; @@ -150,6 +151,9 @@ class NET_EXPORT_PRIVATE QuicHttpStream : public MultiplexedHttpStream { // Only valid before the response body is read. const HttpRequestInfo* request_info_; + // Whether this request can be sent without confirmation. + bool can_send_early_; + // The request body to send, if any, owned by the caller. UploadDataStream* request_body_stream_; // Time the request was issued. diff --git a/chromium/net/quic/chromium/quic_http_stream_test.cc b/chromium/net/quic/chromium/quic_http_stream_test.cc index 990e6e8869f..a1e3b7aec2c 100644 --- a/chromium/net/quic/chromium/quic_http_stream_test.cc +++ b/chromium/net/quic/chromium/quic_http_stream_test.cc @@ -43,6 +43,7 @@ #include "net/quic/core/quic_connection.h" #include "net/quic/core/quic_write_blocked_list.h" #include "net/quic/core/spdy_utils.h" +#include "net/quic/core/tls_client_handshaker.h" #include "net/quic/platform/api/quic_string_piece.h" #include "net/quic/test_tools/crypto_test_utils.h" #include "net/quic/test_tools/mock_clock.h" @@ -77,7 +78,7 @@ const uint16_t kDefaultServerPort = 443; class TestQuicConnection : public QuicConnection { public: - TestQuicConnection(const QuicTransportVersionVector& versions, + TestQuicConnection(const ParsedQuicVersionVector& versions, QuicConnectionId connection_id, IPEndPoint address, QuicChromiumConnectionHelper* helper, @@ -162,7 +163,7 @@ class QuicHttpStreamPeer { }; class QuicHttpStreamTest - : public ::testing::TestWithParam<QuicTransportVersion> { + : public ::testing::TestWithParam<std::tuple<QuicTransportVersion, bool>> { public: void CloseStream(QuicHttpStream* stream, int /*rv*/) { stream->Close(false); } @@ -183,21 +184,26 @@ class QuicHttpStreamTest }; QuicHttpStreamTest() - : crypto_config_(crypto_test_utils::ProofVerifierForTesting()), + : version_(std::get<0>(GetParam())), + client_headers_include_h2_stream_dependency_(std::get<1>(GetParam())), + crypto_config_(crypto_test_utils::ProofVerifierForTesting(), + TlsClientHandshaker::CreateSslCtx()), read_buffer_(new IOBufferWithSize(4096)), promise_id_(GetNthServerInitiatedStreamId(0)), stream_id_(GetNthClientInitiatedStreamId(0)), connection_id_(2), - client_maker_(GetParam(), + client_maker_(version_, connection_id_, &clock_, kDefaultServerHostName, - Perspective::IS_CLIENT), - server_maker_(GetParam(), + Perspective::IS_CLIENT, + client_headers_include_h2_stream_dependency_), + server_maker_(version_, connection_id_, &clock_, kDefaultServerHostName, - Perspective::IS_SERVER), + Perspective::IS_SERVER, + false), random_generator_(0), response_offset_(0) { IPAddress ip(192, 0, 2, 33); @@ -276,8 +282,9 @@ class QuicHttpStreamTest alarm_factory_.reset(new QuicChromiumAlarmFactory(runner_.get(), &clock_)); connection_ = new TestQuicConnection( - SupportedTransportVersions(GetParam()), connection_id_, peer_addr_, - helper_.get(), alarm_factory_.get(), + SupportedVersions( + net::ParsedQuicVersion(net::PROTOCOL_QUIC_CRYPTO, version_)), + connection_id_, peer_addr_, helper_.get(), alarm_factory_.get(), new QuicChromiumPacketWriter( socket.get(), base::ThreadTaskRunnerHandle::Get().get())); connection_->set_visitor(&visitor_); @@ -305,19 +312,23 @@ class QuicHttpStreamTest /*migrate_session_on_network_change*/ false, /*migrate_session_early_v2*/ false, /*migrate_session_on_network_change_v2*/ false, + base::TimeDelta::FromSeconds(kMaxTimeOnNonDefaultNetworkSecs), + kMaxMigrationsToNonDefaultNetworkOnPathDegrading, kQuicYieldAfterPacketsRead, QuicTime::Delta::FromMilliseconds(kQuicYieldAfterDurationMilliseconds), - /*cert_verify_flags=*/0, DefaultQuicConfig(), &crypto_config_, - "CONNECTION_UNKNOWN", dns_start, dns_end, &push_promise_index_, nullptr, + client_headers_include_h2_stream_dependency_, /*cert_verify_flags=*/0, + DefaultQuicConfig(), &crypto_config_, "CONNECTION_UNKNOWN", dns_start, + dns_end, &push_promise_index_, nullptr, base::ThreadTaskRunnerHandle::Get().get(), /*socket_performance_watcher=*/nullptr, net_log_.bound().net_log())); session_->Initialize(); TestCompletionCallback callback; session_->CryptoConnect(callback.callback()); - stream_.reset(new QuicHttpStream(session_->CreateHandle())); - promised_stream_.reset(new QuicHttpStream(session_->CreateHandle())); - + stream_ = std::make_unique<QuicHttpStream>( + session_->CreateHandle(HostPortPair("www.example.org", 443))); + promised_stream_ = std::make_unique<QuicHttpStream>( + session_->CreateHandle(HostPortPair("www.example.org", 443))); push_promise_[":path"] = "/bar"; push_promise_[":authority"] = "www.example.org"; push_promise_[":version"] = "HTTP/1.1"; @@ -384,11 +395,26 @@ class QuicHttpStreamTest RequestPriority request_priority, size_t* spdy_headers_frame_length, QuicStreamOffset* offset) { + return InnerConstructRequestHeadersPacket( + packet_number, stream_id, should_include_version, fin, request_priority, + 0, spdy_headers_frame_length, offset); + } + + std::unique_ptr<QuicReceivedPacket> InnerConstructRequestHeadersPacket( + QuicPacketNumber packet_number, + QuicStreamId stream_id, + bool should_include_version, + bool fin, + RequestPriority request_priority, + QuicStreamId parent_stream_id, + size_t* spdy_headers_frame_length, + QuicStreamOffset* offset) { SpdyPriority priority = ConvertRequestPriorityToQuicPriority(request_priority); return client_maker_.MakeRequestHeadersPacket( packet_number, stream_id, should_include_version, fin, priority, - std::move(request_headers_), spdy_headers_frame_length, offset); + std::move(request_headers_), parent_stream_id, + spdy_headers_frame_length, offset); } std::unique_ptr<QuicReceivedPacket> ConstructRequestHeadersPacket( @@ -530,13 +556,16 @@ class QuicHttpStreamTest } QuicStreamId GetNthClientInitiatedStreamId(int n) { - return test::GetNthClientInitiatedStreamId(GetParam(), n); + return test::GetNthClientInitiatedStreamId(version_, n); } QuicStreamId GetNthServerInitiatedStreamId(int n) { - return test::GetNthServerInitiatedStreamId(GetParam(), n); + return test::GetNthServerInitiatedStreamId(version_, n); } + const QuicTransportVersion version_; + const bool client_headers_include_h2_stream_dependency_; + BoundTestNetLog net_log_; MockSendAlgorithm* send_algorithm_; scoped_refptr<TestTaskRunner> runner_; @@ -583,9 +612,11 @@ class QuicHttpStreamTest QuicStreamOffset response_offset_; }; -INSTANTIATE_TEST_CASE_P(Version, - QuicHttpStreamTest, - ::testing::ValuesIn(AllSupportedTransportVersions())); +INSTANTIATE_TEST_CASE_P( + VersionIncludeStreamDependencySequnece, + QuicHttpStreamTest, + ::testing::Combine(::testing::ValuesIn(AllSupportedTransportVersions()), + ::testing::Bool())); TEST_P(QuicHttpStreamTest, RenewStreamForAuth) { Initialize(); @@ -601,7 +632,7 @@ TEST_P(QuicHttpStreamTest, DisableConnectionMigrationForStream) { request_.load_flags |= LOAD_DISABLE_CONNECTION_MIGRATION; Initialize(); EXPECT_EQ(OK, - stream_->InitializeStream(&request_, DEFAULT_PRIORITY, + stream_->InitializeStream(&request_, false, DEFAULT_PRIORITY, net_log_.bound(), callback_.callback())); QuicChromiumClientStream::Handle* client_stream = QuicHttpStreamPeer::GetQuicChromiumClientStream(stream_.get()); @@ -628,7 +659,7 @@ TEST_P(QuicHttpStreamTest, GetRequest) { EXPECT_TRUE(stream_->GetLoadTimingInfo(&load_timing_info)); EXPECT_EQ(OK, - stream_->InitializeStream(&request_, DEFAULT_PRIORITY, + stream_->InitializeStream(&request_, true, DEFAULT_PRIORITY, net_log_.bound(), callback_.callback())); EXPECT_EQ(OK, stream_->SendRequest(headers_, &response_, callback_.callback())); @@ -684,7 +715,8 @@ TEST_P(QuicHttpStreamTest, LoadTimingTwoRequests) { SetRequest("GET", "/", DEFAULT_PRIORITY); AddWrite(InnerConstructRequestHeadersPacket( 3, GetNthClientInitiatedStreamId(1), kIncludeVersion, kFin, - DEFAULT_PRIORITY, &spdy_request_header_frame_length, &offset)); + DEFAULT_PRIORITY, GetNthClientInitiatedStreamId(0), + &spdy_request_header_frame_length, &offset)); AddWrite(ConstructClientAckPacket(4, 3, 1, 1)); // Ack the responses. Initialize(); @@ -693,16 +725,17 @@ TEST_P(QuicHttpStreamTest, LoadTimingTwoRequests) { request_.url = GURL("https://www.example.org/"); // Start first request. EXPECT_EQ(OK, - stream_->InitializeStream(&request_, DEFAULT_PRIORITY, + stream_->InitializeStream(&request_, true, DEFAULT_PRIORITY, net_log_.bound(), callback_.callback())); EXPECT_EQ(OK, stream_->SendRequest(headers_, &response_, callback_.callback())); // Start a second request. - QuicHttpStream stream2(session_->CreateHandle()); + QuicHttpStream stream2( + session_->CreateHandle(HostPortPair("www.example.org", 443))); TestCompletionCallback callback2; EXPECT_EQ(OK, - stream2.InitializeStream(&request_, DEFAULT_PRIORITY, + stream2.InitializeStream(&request_, true, DEFAULT_PRIORITY, net_log_.bound(), callback2.callback())); EXPECT_EQ(OK, stream2.SendRequest(headers_, &response_, callback2.callback())); @@ -773,7 +806,7 @@ TEST_P(QuicHttpStreamTest, GetRequestWithTrailers) { request_.url = GURL("https://www.example.org/"); EXPECT_EQ(OK, - stream_->InitializeStream(&request_, DEFAULT_PRIORITY, + stream_->InitializeStream(&request_, true, DEFAULT_PRIORITY, net_log_.bound(), callback_.callback())); EXPECT_EQ(OK, @@ -866,7 +899,7 @@ TEST_P(QuicHttpStreamTest, GetRequestLargeResponse) { request_.url = GURL("https://www.example.org/"); EXPECT_EQ(OK, - stream_->InitializeStream(&request_, DEFAULT_PRIORITY, + stream_->InitializeStream(&request_, true, DEFAULT_PRIORITY, net_log_.bound(), callback_.callback())); EXPECT_EQ(OK, stream_->SendRequest(headers_, &response_, callback_.callback())); @@ -916,7 +949,7 @@ TEST_P(QuicHttpStreamTest, SessionClosedBeforeSendRequest) { request_.url = GURL("https://www.example.org/"); EXPECT_EQ(OK, - stream_->InitializeStream(&request_, DEFAULT_PRIORITY, + stream_->InitializeStream(&request_, true, DEFAULT_PRIORITY, net_log_.bound(), callback_.callback())); session_->connection()->CloseConnection( @@ -938,7 +971,7 @@ TEST_P(QuicHttpStreamTest, GetSSLInfoAfterSessionClosed) { request_.url = GURL("https://www.example.org/"); EXPECT_EQ(OK, - stream_->InitializeStream(&request_, DEFAULT_PRIORITY, + stream_->InitializeStream(&request_, true, DEFAULT_PRIORITY, net_log_.bound(), callback_.callback())); SSLInfo ssl_info; @@ -962,7 +995,7 @@ TEST_P(QuicHttpStreamTest, GetAlternativeService) { request_.url = GURL("https://www.example.org/"); EXPECT_EQ(OK, - stream_->InitializeStream(&request_, DEFAULT_PRIORITY, + stream_->InitializeStream(&request_, true, DEFAULT_PRIORITY, net_log_.bound(), callback_.callback())); AlternativeService alternative_service; @@ -995,7 +1028,7 @@ TEST_P(QuicHttpStreamTest, LogGranularQuicConnectionError) { request_.url = GURL("https://www.example.org/"); EXPECT_EQ(OK, - stream_->InitializeStream(&request_, DEFAULT_PRIORITY, + stream_->InitializeStream(&request_, true, DEFAULT_PRIORITY, net_log_.bound(), callback_.callback())); EXPECT_EQ(OK, stream_->SendRequest(headers_, &response_, callback_.callback())); @@ -1034,7 +1067,7 @@ TEST_P(QuicHttpStreamTest, LogGranularQuicErrorIfHandshakeNotConfirmed) { request_.url = GURL("https://www.example.org/"); EXPECT_EQ(OK, - stream_->InitializeStream(&request_, DEFAULT_PRIORITY, + stream_->InitializeStream(&request_, true, DEFAULT_PRIORITY, net_log_.bound(), callback_.callback())); EXPECT_EQ(OK, stream_->SendRequest(headers_, &response_, callback_.callback())); @@ -1069,7 +1102,7 @@ TEST_P(QuicHttpStreamTest, SessionClosedBeforeReadResponseHeaders) { request_.url = GURL("https://www.example.org/"); EXPECT_EQ(OK, - stream_->InitializeStream(&request_, DEFAULT_PRIORITY, + stream_->InitializeStream(&request_, true, DEFAULT_PRIORITY, net_log_.bound(), callback_.callback())); EXPECT_EQ(OK, @@ -1114,7 +1147,7 @@ TEST_P(QuicHttpStreamTest, SendPostRequest) { IsOk()); EXPECT_EQ(OK, - stream_->InitializeStream(&request_, DEFAULT_PRIORITY, + stream_->InitializeStream(&request_, false, DEFAULT_PRIORITY, net_log_.bound(), callback_.callback())); EXPECT_EQ(OK, stream_->SendRequest(headers_, &response_, callback_.callback())); @@ -1185,7 +1218,7 @@ TEST_P(QuicHttpStreamTest, SendPostRequestAndReceiveSoloFin) { IsOk()); EXPECT_EQ(OK, - stream_->InitializeStream(&request_, DEFAULT_PRIORITY, + stream_->InitializeStream(&request_, false, DEFAULT_PRIORITY, net_log_.bound(), callback_.callback())); EXPECT_EQ(OK, stream_->SendRequest(headers_, &response_, callback_.callback())); @@ -1260,7 +1293,7 @@ TEST_P(QuicHttpStreamTest, SendChunkedPostRequest) { TestCompletionCallback().callback(), NetLogWithSource())); ASSERT_EQ(OK, - stream_->InitializeStream(&request_, DEFAULT_PRIORITY, + stream_->InitializeStream(&request_, false, DEFAULT_PRIORITY, net_log_.bound(), callback_.callback())); ASSERT_EQ(ERR_IO_PENDING, stream_->SendRequest(headers_, &response_, callback_.callback())); @@ -1334,7 +1367,7 @@ TEST_P(QuicHttpStreamTest, SendChunkedPostRequestWithFinalEmptyDataPacket) { TestCompletionCallback().callback(), NetLogWithSource())); ASSERT_EQ(OK, - stream_->InitializeStream(&request_, DEFAULT_PRIORITY, + stream_->InitializeStream(&request_, false, DEFAULT_PRIORITY, net_log_.bound(), callback_.callback())); ASSERT_EQ(ERR_IO_PENDING, stream_->SendRequest(headers_, &response_, callback_.callback())); @@ -1402,7 +1435,7 @@ TEST_P(QuicHttpStreamTest, SendChunkedPostRequestWithOneEmptyDataPacket) { TestCompletionCallback().callback(), NetLogWithSource())); ASSERT_EQ(OK, - stream_->InitializeStream(&request_, DEFAULT_PRIORITY, + stream_->InitializeStream(&request_, false, DEFAULT_PRIORITY, net_log_.bound(), callback_.callback())); ASSERT_EQ(ERR_IO_PENDING, stream_->SendRequest(headers_, &response_, callback_.callback())); @@ -1462,7 +1495,7 @@ TEST_P(QuicHttpStreamTest, DestroyedEarly) { request_.url = GURL("https://www.example.org/"); EXPECT_EQ(OK, - stream_->InitializeStream(&request_, DEFAULT_PRIORITY, + stream_->InitializeStream(&request_, true, DEFAULT_PRIORITY, net_log_.bound(), callback_.callback())); EXPECT_EQ(OK, stream_->SendRequest(headers_, &response_, callback_.callback())); @@ -1506,8 +1539,9 @@ TEST_P(QuicHttpStreamTest, Priority) { request_.method = "GET"; request_.url = GURL("https://www.example.org/"); - EXPECT_EQ(OK, stream_->InitializeStream(&request_, MEDIUM, net_log_.bound(), - callback_.callback())); + EXPECT_EQ(OK, + stream_->InitializeStream(&request_, true, MEDIUM, net_log_.bound(), + callback_.callback())); // Check that priority is highest. QuicChromiumClientStream::Handle* reliable_stream = @@ -1573,7 +1607,7 @@ TEST_P(QuicHttpStreamTest, SessionClosedDuringDoLoop) { size_t chunk_size = strlen(kUploadData); chunked_upload_stream->AppendData(kUploadData, chunk_size, false); ASSERT_EQ(OK, - stream_->InitializeStream(&request_, DEFAULT_PRIORITY, + stream_->InitializeStream(&request_, false, DEFAULT_PRIORITY, net_log_.bound(), callback_.callback())); QuicHttpStream* stream = stream_.get(); DeleteStreamCallback delete_stream_callback(std::move(stream_)); @@ -1601,7 +1635,7 @@ TEST_P(QuicHttpStreamTest, SessionClosedBeforeSendHeadersComplete) { TestCompletionCallback().callback(), NetLogWithSource())); ASSERT_EQ(OK, - stream_->InitializeStream(&request_, DEFAULT_PRIORITY, + stream_->InitializeStream(&request_, false, DEFAULT_PRIORITY, net_log_.bound(), callback_.callback())); ASSERT_EQ(ERR_QUIC_PROTOCOL_ERROR, stream_->SendRequest(headers_, &response_, callback_.callback())); @@ -1635,7 +1669,7 @@ TEST_P(QuicHttpStreamTest, SessionClosedBeforeSendBodyComplete) { TestCompletionCallback().callback(), NetLogWithSource())); ASSERT_EQ(OK, - stream_->InitializeStream(&request_, DEFAULT_PRIORITY, + stream_->InitializeStream(&request_, false, DEFAULT_PRIORITY, net_log_.bound(), callback_.callback())); ASSERT_EQ(ERR_QUIC_PROTOCOL_ERROR, stream_->SendRequest(headers_, &response_, callback_.callback())); @@ -1650,7 +1684,7 @@ TEST_P(QuicHttpStreamTest, ServerPushGetRequest) { request_.url = GURL("https://www.example.org/"); EXPECT_EQ(OK, - stream_->InitializeStream(&request_, DEFAULT_PRIORITY, + stream_->InitializeStream(&request_, true, DEFAULT_PRIORITY, net_log_.bound(), callback_.callback())); // TODO(ckrasic) - could do this via constructing a PUSH_PROMISE @@ -1662,9 +1696,9 @@ TEST_P(QuicHttpStreamTest, ServerPushGetRequest) { // Make the second stream that will exercise the first step of the // server push rendezvous mechanism. - EXPECT_EQ(OK, promised_stream_->InitializeStream(&request_, DEFAULT_PRIORITY, - net_log_.bound(), - callback_.callback())); + EXPECT_EQ(OK, promised_stream_->InitializeStream( + &request_, true, DEFAULT_PRIORITY, net_log_.bound(), + callback_.callback())); // Receive the promised response headers. response_headers_ = promised_response_.Clone(); @@ -1716,7 +1750,7 @@ TEST_P(QuicHttpStreamTest, ServerPushGetRequestSlowResponse) { request_.url = GURL("https://www.example.org/"); EXPECT_EQ(OK, - stream_->InitializeStream(&request_, DEFAULT_PRIORITY, + stream_->InitializeStream(&request_, true, DEFAULT_PRIORITY, net_log_.bound(), callback_.callback())); // TODO(ckrasic) - could do this via constructing a PUSH_PROMISE @@ -1728,9 +1762,9 @@ TEST_P(QuicHttpStreamTest, ServerPushGetRequestSlowResponse) { // Make the second stream that will exercise the first step of the // server push rendezvous mechanism. - EXPECT_EQ(OK, promised_stream_->InitializeStream(&request_, DEFAULT_PRIORITY, - net_log_.bound(), - callback_.callback())); + EXPECT_EQ(OK, promised_stream_->InitializeStream( + &request_, true, DEFAULT_PRIORITY, net_log_.bound(), + callback_.callback())); // Now sending a matching request will rendezvous with the promised // stream, but pending secondary validation. @@ -1790,7 +1824,7 @@ TEST_P(QuicHttpStreamTest, ServerPushCancelHttpStreamBeforeResponse) { request_.url = GURL("https://www.example.org/"); EXPECT_EQ(OK, - stream_->InitializeStream(&request_, DEFAULT_PRIORITY, + stream_->InitializeStream(&request_, true, DEFAULT_PRIORITY, net_log_.bound(), callback_.callback())); // TODO(ckrasic) - could do this via constructing a PUSH_PROMISE @@ -1802,9 +1836,9 @@ TEST_P(QuicHttpStreamTest, ServerPushCancelHttpStreamBeforeResponse) { // Make the second stream that will exercise the first step of the // server push rendezvous mechanism. - EXPECT_EQ(OK, promised_stream_->InitializeStream(&request_, DEFAULT_PRIORITY, - net_log_.bound(), - callback_.callback())); + EXPECT_EQ(OK, promised_stream_->InitializeStream( + &request_, true, DEFAULT_PRIORITY, net_log_.bound(), + callback_.callback())); // Now sending a matching request will rendezvous with the promised // stream, but pending secondary validation. @@ -1832,7 +1866,7 @@ TEST_P(QuicHttpStreamTest, ServerPushCrossOriginOK) { request_.url = GURL("https://www.example.org/"); EXPECT_EQ(OK, - stream_->InitializeStream(&request_, DEFAULT_PRIORITY, + stream_->InitializeStream(&request_, true, DEFAULT_PRIORITY, net_log_.bound(), callback_.callback())); // TODO(ckrasic) - could do this via constructing a PUSH_PROMISE @@ -1848,9 +1882,9 @@ TEST_P(QuicHttpStreamTest, ServerPushCrossOriginOK) { // Make the second stream that will exercise the first step of the // server push rendezvous mechanism. - EXPECT_EQ(OK, promised_stream_->InitializeStream(&request_, DEFAULT_PRIORITY, - net_log_.bound(), - callback_.callback())); + EXPECT_EQ(OK, promised_stream_->InitializeStream( + &request_, true, DEFAULT_PRIORITY, net_log_.bound(), + callback_.callback())); // Receive the promised response headers. response_headers_ = promised_response_.Clone(); @@ -1902,7 +1936,7 @@ TEST_P(QuicHttpStreamTest, ServerPushCrossOriginFail) { request_.url = GURL("https://www.example.org/"); EXPECT_EQ(OK, - stream_->InitializeStream(&request_, DEFAULT_PRIORITY, + stream_->InitializeStream(&request_, true, DEFAULT_PRIORITY, net_log_.bound(), callback_.callback())); // TODO(ckrasic) - could do this via constructing a PUSH_PROMISE @@ -1925,7 +1959,7 @@ TEST_P(QuicHttpStreamTest, ServerPushVaryCheckOK) { request_.url = GURL("https://www.example.org/"); EXPECT_EQ(OK, - stream_->InitializeStream(&request_, DEFAULT_PRIORITY, + stream_->InitializeStream(&request_, true, DEFAULT_PRIORITY, net_log_.bound(), callback_.callback())); push_promise_["accept-encoding"] = "gzip"; @@ -1939,9 +1973,9 @@ TEST_P(QuicHttpStreamTest, ServerPushVaryCheckOK) { // Make the second stream that will exercise the first step of the // server push rendezvous mechanism. - EXPECT_EQ(OK, promised_stream_->InitializeStream(&request_, DEFAULT_PRIORITY, - net_log_.bound(), - callback_.callback())); + EXPECT_EQ(OK, promised_stream_->InitializeStream( + &request_, true, DEFAULT_PRIORITY, net_log_.bound(), + callback_.callback())); headers_.SetHeader("accept-encoding", "gzip"); @@ -2016,7 +2050,7 @@ TEST_P(QuicHttpStreamTest, ServerPushVaryCheckFail) { request_.url = GURL("https://www.example.org/"); EXPECT_EQ(OK, - stream_->InitializeStream(&request_, DEFAULT_PRIORITY, + stream_->InitializeStream(&request_, true, DEFAULT_PRIORITY, net_log_.bound(), callback_.callback())); push_promise_["accept-encoding"] = "gzip"; @@ -2030,9 +2064,9 @@ TEST_P(QuicHttpStreamTest, ServerPushVaryCheckFail) { // Make the second stream that will exercise the first step of the // server push rendezvous mechanism. - EXPECT_EQ(OK, promised_stream_->InitializeStream(&request_, DEFAULT_PRIORITY, - net_log_.bound(), - callback_.callback())); + EXPECT_EQ(OK, promised_stream_->InitializeStream( + &request_, true, DEFAULT_PRIORITY, net_log_.bound(), + callback_.callback())); headers_.SetHeader("accept-encoding", "sdch"); @@ -2131,7 +2165,7 @@ TEST_P(QuicHttpStreamTest, DataReadErrorSynchronous) { TestCompletionCallback().callback(), NetLogWithSource())); EXPECT_EQ(OK, - stream_->InitializeStream(&request_, DEFAULT_PRIORITY, + stream_->InitializeStream(&request_, false, DEFAULT_PRIORITY, net_log_.bound(), callback_.callback())); int result = stream_->SendRequest(headers_, &response_, callback_.callback()); @@ -2167,7 +2201,7 @@ TEST_P(QuicHttpStreamTest, DataReadErrorAsynchronous) { TestCompletionCallback().callback(), NetLogWithSource())); EXPECT_EQ(OK, - stream_->InitializeStream(&request_, DEFAULT_PRIORITY, + stream_->InitializeStream(&request_, false, DEFAULT_PRIORITY, net_log_.bound(), callback_.callback())); int result = stream_->SendRequest(headers_, &response_, callback_.callback()); diff --git a/chromium/net/quic/chromium/quic_http_utils.cc b/chromium/net/quic/chromium/quic_http_utils.cc index c811fee1f05..664ab42bd65 100644 --- a/chromium/net/quic/chromium/quic_http_utils.cc +++ b/chromium/net/quic/chromium/quic_http_utils.cc @@ -58,10 +58,7 @@ QuicTransportVersionVector FilterSupportedAltSvcVersions( for (uint32_t quic_version_label : quic_alt_svc.version) { for (QuicTransportVersion supported : supported_versions) { QuicVersionLabel supported_version_label_network_order = - FLAGS_quic_reloadable_flag_quic_use_net_byte_order_version_label - ? QuicVersionToQuicVersionLabel(supported) - : QuicEndian::HostToNet32( - QuicVersionToQuicVersionLabel(supported)); + QuicVersionToQuicVersionLabel(supported); if (supported_version_label_network_order == quic_version_label) { supported_alt_svc_versions.push_back(supported); RecordAltSvcFormat(IETF_FORMAT); diff --git a/chromium/net/quic/chromium/quic_http_utils_test.cc b/chromium/net/quic/chromium/quic_http_utils_test.cc index 74fff2d443f..cf506ccd2bf 100644 --- a/chromium/net/quic/chromium/quic_http_utils_test.cc +++ b/chromium/net/quic/chromium/quic_http_utils_test.cc @@ -48,12 +48,6 @@ TEST(QuicHttpUtilsTest, FilterSupportedAltSvcVersions) { QuicVersionToQuicVersionLabel(QUIC_VERSION_41), QuicVersionToQuicVersionLabel(QUIC_VERSION_42)}; - if (!FLAGS_quic_reloadable_flag_quic_use_net_byte_order_version_label) { - for (uint32_t& version_label : alt_svc_versions_ietf) { - version_label = QuicEndian::HostToNet32(version_label); - } - } - QuicTransportVersionVector supported_alt_svc_versions = {QUIC_VERSION_38, QUIC_VERSION_41}; SpdyAltSvcWireFormat::AlternativeService altsvc; diff --git a/chromium/net/quic/chromium/quic_network_transaction_unittest.cc b/chromium/net/quic/chromium/quic_network_transaction_unittest.cc index 253796bad1d..5cc6b57804b 100644 --- a/chromium/net/quic/chromium/quic_network_transaction_unittest.cc +++ b/chromium/net/quic/chromium/quic_network_transaction_unittest.cc @@ -119,12 +119,15 @@ struct PoolingTestParams { os << "DIFFERENT"; break; } + os << ", client_headers_include_h2_stream_dependency: " + << p.client_headers_include_h2_stream_dependency; os << " }"; return os; } QuicTransportVersion version; DestinationType destination_type; + bool client_headers_include_h2_stream_dependency; }; std::string GenerateQuicVersionsListForAltSvcHeader( @@ -143,9 +146,12 @@ std::vector<PoolingTestParams> GetPoolingTestParams() { QuicTransportVersionVector all_supported_versions = AllSupportedTransportVersions(); for (const QuicTransportVersion version : all_supported_versions) { - params.push_back(PoolingTestParams{version, SAME_AS_FIRST}); - params.push_back(PoolingTestParams{version, SAME_AS_SECOND}); - params.push_back(PoolingTestParams{version, DIFFERENT}); + params.push_back(PoolingTestParams{version, SAME_AS_FIRST, false}); + params.push_back(PoolingTestParams{version, SAME_AS_FIRST, true}); + params.push_back(PoolingTestParams{version, SAME_AS_SECOND, false}); + params.push_back(PoolingTestParams{version, SAME_AS_SECOND, true}); + params.push_back(PoolingTestParams{version, DIFFERENT, false}); + params.push_back(PoolingTestParams{version, DIFFERENT, true}); } return params; } @@ -234,23 +240,26 @@ class TestSocketPerformanceWatcherFactory DISALLOW_COPY_AND_ASSIGN(TestSocketPerformanceWatcherFactory); }; -class QuicNetworkTransactionTest - : public PlatformTest, - public ::testing::WithParamInterface<QuicTransportVersion> { +class QuicNetworkTransactionTest : public PlatformTest, + public ::testing::WithParamInterface< + std::tuple<QuicTransportVersion, bool>> { protected: QuicNetworkTransactionTest() - : version_(GetParam()), + : version_(std::get<0>(GetParam())), + client_headers_include_h2_stream_dependency_(std::get<1>(GetParam())), supported_versions_(SupportedTransportVersions(version_)), client_maker_(version_, 0, &clock_, kDefaultServerHostName, - Perspective::IS_CLIENT), + Perspective::IS_CLIENT, + client_headers_include_h2_stream_dependency_), server_maker_(version_, 0, &clock_, kDefaultServerHostName, - Perspective::IS_SERVER), + Perspective::IS_SERVER, + false), cert_transparency_verifier_(new MultiLogCTVerifier()), ssl_config_service_(new SSLConfigServiceDefaults), proxy_service_(ProxyService::CreateDirect()), @@ -448,11 +457,24 @@ class QuicNetworkTransactionTest bool fin, SpdyHeaderBlock headers, QuicStreamOffset* offset) { + return ConstructClientRequestHeadersPacket(packet_number, stream_id, + should_include_version, fin, + std::move(headers), 0, offset); + } + + std::unique_ptr<QuicEncryptedPacket> ConstructClientRequestHeadersPacket( + QuicPacketNumber packet_number, + QuicStreamId stream_id, + bool should_include_version, + bool fin, + SpdyHeaderBlock headers, + QuicStreamId parent_stream_id, + QuicStreamOffset* offset) { SpdyPriority priority = ConvertRequestPriorityToQuicPriority(DEFAULT_PRIORITY); return client_maker_.MakeRequestHeadersPacketWithOffsetTracking( packet_number, stream_id, should_include_version, fin, priority, - std::move(headers), offset); + std::move(headers), parent_stream_id, offset); } std::unique_ptr<QuicEncryptedPacket> ConstructClientRequestHeadersPacket( @@ -516,6 +538,8 @@ class QuicNetworkTransactionTest void CreateSession(const QuicTransportVersionVector& supported_versions) { session_params_.enable_quic = true; session_params_.quic_supported_versions = supported_versions; + session_params_.quic_headers_include_h2_stream_dependency = + client_headers_include_h2_stream_dependency_; session_context_.quic_clock = &clock_; session_context_.quic_random = &random_generator_; @@ -754,6 +778,7 @@ class QuicNetworkTransactionTest } const QuicTransportVersion version_; + const bool client_headers_include_h2_stream_dependency_; QuicTransportVersionVector supported_versions_; QuicFlagSaver flags_; // Save/restore all QUIC flag values. MockClock clock_; @@ -804,9 +829,11 @@ class QuicNetworkTransactionTest } }; -INSTANTIATE_TEST_CASE_P(Version, - QuicNetworkTransactionTest, - ::testing::ValuesIn(AllSupportedTransportVersions())); +INSTANTIATE_TEST_CASE_P( + VersionIncludeStreamDependencySequnece, + QuicNetworkTransactionTest, + ::testing::Combine(::testing::ValuesIn(AllSupportedTransportVersions()), + ::testing::Bool())); TEST_P(QuicNetworkTransactionTest, WriteErrorHandshakeConfirmed) { base::HistogramTester histograms; @@ -1942,7 +1969,7 @@ TEST_P(QuicNetworkTransactionTest, TimeoutAfterHandshakeConfirmed) { std::string request_data; quic_data.AddWrite(client_maker_.MakeRequestHeadersPacketAndSaveData( 1, GetNthClientInitiatedStreamId(0), true, true, priority, - GetRequestHeaders("GET", "https", "/"), nullptr, &header_stream_offset, + GetRequestHeaders("GET", "https", "/"), 0, nullptr, &header_stream_offset, &request_data)); std::string settings_data; @@ -1971,6 +1998,12 @@ TEST_P(QuicNetworkTransactionTest, TimeoutAfterHandshakeConfirmed) { quic_data.AddWrite(client_maker_.MakeDataPacket( 10, kHeadersStreamId, true, false, settings_offset, settings_data)); + if (FLAGS_quic_reloadable_flag_quic_explicit_close_after_tlp) { + quic_data.AddWrite(client_maker_.MakeAckAndConnectionClosePacket( + 11, true, QuicTime::Delta::Infinite(), 0, 1, 1, + QUIC_NETWORK_IDLE_TIMEOUT, "No recent network activity.")); + } + quic_data.AddRead(ASYNC, ERR_IO_PENDING); quic_data.AddRead(ASYNC, OK); quic_data.AddSocketDataToFactory(&socket_factory_); @@ -2032,7 +2065,7 @@ TEST_P(QuicNetworkTransactionTest, TooManyRtosAfterHandshakeConfirmed) { std::string request_data; quic_data.AddWrite(client_maker_.MakeRequestHeadersPacketAndSaveData( 1, GetNthClientInitiatedStreamId(0), true, true, priority, - GetRequestHeaders("GET", "https", "/"), nullptr, &header_stream_offset, + GetRequestHeaders("GET", "https", "/"), 0, nullptr, &header_stream_offset, &request_data)); std::string settings_data; @@ -2131,7 +2164,7 @@ TEST_P(QuicNetworkTransactionTest, std::string request_data; quic_data.AddWrite(client_maker_.MakeRequestHeadersPacketAndSaveData( 1, GetNthClientInitiatedStreamId(0), true, true, priority, - GetRequestHeaders("GET", "https", "/"), nullptr, &header_stream_offset, + GetRequestHeaders("GET", "https", "/"), 0, nullptr, &header_stream_offset, &request_data)); std::string settings_data; @@ -2299,7 +2332,7 @@ TEST_P(QuicNetworkTransactionTest, TimeoutAfterHandshakeConfirmedThenBroken) { std::string request_data; quic_data.AddWrite(client_maker_.MakeRequestHeadersPacketAndSaveData( 1, GetNthClientInitiatedStreamId(0), true, true, priority, - GetRequestHeaders("GET", "https", "/"), nullptr, &header_stream_offset, + GetRequestHeaders("GET", "https", "/"), 0, nullptr, &header_stream_offset, &request_data)); std::string settings_data; @@ -2328,6 +2361,12 @@ TEST_P(QuicNetworkTransactionTest, TimeoutAfterHandshakeConfirmedThenBroken) { quic_data.AddWrite(client_maker_.MakeDataPacket( 10, kHeadersStreamId, true, false, settings_offset, settings_data)); + if (FLAGS_quic_reloadable_flag_quic_explicit_close_after_tlp) { + quic_data.AddWrite(client_maker_.MakeAckAndConnectionClosePacket( + 11, true, QuicTime::Delta::Infinite(), 0, 1, 1, + QUIC_NETWORK_IDLE_TIMEOUT, "No recent network activity.")); + } + quic_data.AddRead(ASYNC, ERR_IO_PENDING); quic_data.AddRead(ASYNC, OK); quic_data.AddSocketDataToFactory(&socket_factory_); @@ -2416,7 +2455,7 @@ TEST_P(QuicNetworkTransactionTest, TimeoutAfterHandshakeConfirmedThenBroken2) { std::string request_data; quic_data.AddWrite(client_maker_.MakeRequestHeadersPacketAndSaveData( 1, GetNthClientInitiatedStreamId(0), true, true, priority, - GetRequestHeaders("GET", "https", "/"), nullptr, &header_stream_offset, + GetRequestHeaders("GET", "https", "/"), 0, nullptr, &header_stream_offset, &request_data)); std::string settings_data; @@ -2445,6 +2484,12 @@ TEST_P(QuicNetworkTransactionTest, TimeoutAfterHandshakeConfirmedThenBroken2) { quic_data.AddWrite(client_maker_.MakeDataPacket( 10, kHeadersStreamId, true, false, settings_offset, settings_data)); + if (FLAGS_quic_reloadable_flag_quic_explicit_close_after_tlp) { + quic_data.AddWrite(client_maker_.MakeAckAndConnectionClosePacket( + 11, true, QuicTime::Delta::Infinite(), 0, 1, 1, + QUIC_NETWORK_IDLE_TIMEOUT, "No recent network activity.")); + } + quic_data.AddRead(ASYNC, ERR_IO_PENDING); quic_data.AddRead(ASYNC, OK); quic_data.AddSocketDataToFactory(&socket_factory_); @@ -2536,7 +2581,7 @@ TEST_P(QuicNetworkTransactionTest, std::string request_data; quic_data.AddWrite(client_maker_.MakeRequestHeadersPacketAndSaveData( 1, GetNthClientInitiatedStreamId(0), true, true, priority, - GetRequestHeaders("GET", "https", "/"), nullptr, &header_stream_offset, + GetRequestHeaders("GET", "https", "/"), 0, nullptr, &header_stream_offset, &request_data)); std::string settings_data; @@ -2573,6 +2618,12 @@ TEST_P(QuicNetworkTransactionTest, quic_data.AddWrite(client_maker_.MakeDataPacket( 11, kHeadersStreamId, false, false, settings_offset, settings_data)); + if (FLAGS_quic_reloadable_flag_quic_explicit_close_after_tlp) { + quic_data.AddWrite(client_maker_.MakeAckAndConnectionClosePacket( + 12, false, QuicTime::Delta::FromMilliseconds(4200), 1, 1, 1, + QUIC_NETWORK_IDLE_TIMEOUT, "No recent network activity.")); + } + quic_data.AddRead(ASYNC, ERR_IO_PENDING); quic_data.AddRead(ASYNC, OK); quic_data.AddSocketDataToFactory(&socket_factory_); @@ -2648,7 +2699,7 @@ TEST_P(QuicNetworkTransactionTest, std::string request_data; quic_data.AddWrite(client_maker_.MakeRequestHeadersPacketAndSaveData( 1, GetNthClientInitiatedStreamId(0), true, true, priority, - GetRequestHeaders("GET", "https", "/"), nullptr, &header_stream_offset, + GetRequestHeaders("GET", "https", "/"), 0, nullptr, &header_stream_offset, &request_data)); std::string settings_data; @@ -2773,7 +2824,7 @@ TEST_P(QuicNetworkTransactionTest, std::string request_data; quic_data.AddWrite(client_maker_.MakeRequestHeadersPacketAndSaveData( 1, GetNthClientInitiatedStreamId(0), true, true, priority, - GetRequestHeaders("GET", "https", "/"), nullptr, &header_stream_offset, + GetRequestHeaders("GET", "https", "/"), 0, nullptr, &header_stream_offset, &request_data)); std::string settings_data; @@ -2968,7 +3019,7 @@ TEST_P(QuicNetworkTransactionTest, ResetAfterHandshakeConfirmedThenBroken) { std::string request_data; quic_data.AddWrite(client_maker_.MakeRequestHeadersPacketAndSaveData( 1, GetNthClientInitiatedStreamId(0), true, true, priority, - GetRequestHeaders("GET", "https", "/"), nullptr, &header_stream_offset, + GetRequestHeaders("GET", "https", "/"), 0, nullptr, &header_stream_offset, &request_data)); std::string settings_data; @@ -3045,6 +3096,72 @@ TEST_P(QuicNetworkTransactionTest, ResetAfterHandshakeConfirmedThenBroken) { ASSERT_TRUE(http_data.AllReadDataConsumed()); } +// Verify that when an origin has two alt-svc advertisements, one local and one +// remote, that when the local is broken the request will go over QUIC via +// the remote Alt-Svc. +// This is a regression test for crbug/825646. +TEST_P(QuicNetworkTransactionTest, RemoteAltSvcWorkingWhileLocalAltSvcBroken) { + session_params_.quic_allow_remote_alt_svc = true; + + GURL origin1 = request_.url; // mail.example.org + GURL origin2("https://www.example.org/"); + ASSERT_NE(origin1.host(), origin2.host()); + + scoped_refptr<X509Certificate> cert( + ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem")); + ASSERT_TRUE(cert->VerifyNameMatch("www.example.org", false)); + ASSERT_TRUE(cert->VerifyNameMatch("mail.example.org", false)); + + ProofVerifyDetailsChromium verify_details; + verify_details.cert_verify_result.verified_cert = cert; + verify_details.cert_verify_result.is_issued_by_known_root = true; + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); + + MockQuicData mock_quic_data; + QuicStreamOffset request_header_offset(0); + QuicStreamOffset response_header_offset(0); + mock_quic_data.AddWrite( + ConstructInitialSettingsPacket(1, &request_header_offset)); + mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket( + 2, GetNthClientInitiatedStreamId(0), true, true, + GetRequestHeaders("GET", "https", "/"), &request_header_offset)); + mock_quic_data.AddRead(ConstructServerResponseHeadersPacket( + 1, GetNthClientInitiatedStreamId(0), false, false, + GetResponseHeaders("200 OK"), &response_header_offset)); + mock_quic_data.AddRead(ConstructServerDataPacket( + 2, GetNthClientInitiatedStreamId(0), false, true, 0, "hello!")); + mock_quic_data.AddWrite(ConstructClientAckPacket(3, 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_); + MockQuicData mock_quic_data2; + mock_quic_data2.AddSocketDataToFactory(&socket_factory_); + AddHangingNonAlternateProtocolSocketData(); + + CreateSession(); + + // Set up alternative service for |origin1|. + AlternativeService local_alternative(kProtoQUIC, "mail.example.org", 443); + AlternativeService remote_alternative(kProtoQUIC, "www.example.org", 443); + base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1); + AlternativeServiceInfoVector alternative_services; + alternative_services.push_back( + AlternativeServiceInfo::CreateQuicAlternativeServiceInfo( + local_alternative, expiration, + session_->params().quic_supported_versions)); + alternative_services.push_back( + AlternativeServiceInfo::CreateQuicAlternativeServiceInfo( + remote_alternative, expiration, + session_->params().quic_supported_versions)); + http_server_properties_.SetAlternativeServices(url::SchemeHostPort(origin1), + alternative_services); + + http_server_properties_.MarkAlternativeServiceBroken(local_alternative); + + SendRequestAndExpectQuicResponse("hello!"); +} + // Verify that with retry_without_alt_svc_on_quic_errors enabled, if a QUIC // request is reset from, then QUIC will be marked as broken and the request // retried over TCP. Then, subsequent requests will go over a new QUIC @@ -3088,14 +3205,15 @@ TEST_P(QuicNetworkTransactionTest, // Second request will go over the pooled QUIC connection, but will be // reset by the server. - QuicTestPacketMaker client_maker2(version_, 0, &clock_, origin2.host(), - Perspective::IS_CLIENT); + QuicTestPacketMaker client_maker2( + version_, 0, &clock_, origin2.host(), Perspective::IS_CLIENT, + client_headers_include_h2_stream_dependency_); QuicTestPacketMaker server_maker2(version_, 0, &clock_, origin2.host(), - Perspective::IS_SERVER); + Perspective::IS_SERVER, false); mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket( 4, GetNthClientInitiatedStreamId(1), false, true, GetRequestHeaders("GET", "https", "/", &client_maker2), - &request_header_offset)); + GetNthClientInitiatedStreamId(0), &request_header_offset)); mock_quic_data.AddRead(ConstructServerRstPacket( 3, false, GetNthClientInitiatedStreamId(1), QUIC_HEADERS_TOO_LARGE)); mock_quic_data.AddRead(ASYNC, ERR_IO_PENDING); // No more data to read @@ -3118,52 +3236,23 @@ TEST_P(QuicNetworkTransactionTest, socket_factory_.AddSocketDataProvider(&http_data); socket_factory_.AddSSLSocketDataProvider(&ssl_data_); - // Then the next request to the second origin will go over a new QUIC - // connection. - MockQuicData mock_quic_data2; - QuicTestPacketMaker client_maker3(version_, 0, &clock_, origin2.host(), - Perspective::IS_CLIENT); - QuicTestPacketMaker server_maker3(version_, 0, &clock_, origin2.host(), - Perspective::IS_SERVER); - QuicStreamOffset request_header_offset2(0); - QuicStreamOffset response_header_offset2(0); - - crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); - - mock_quic_data2.AddWrite( - client_maker3.MakeInitialSettingsPacket(1, &request_header_offset2)); - mock_quic_data2.AddWrite( - client_maker3.MakeRequestHeadersPacketWithOffsetTracking( - 2, GetNthClientInitiatedStreamId(0), true, true, - ConvertRequestPriorityToQuicPriority(DEFAULT_PRIORITY), - GetRequestHeaders("GET", "https", "/", &client_maker3), - &request_header_offset2)); - mock_quic_data2.AddRead( - server_maker2.MakeResponseHeadersPacketWithOffsetTracking( - 1, GetNthClientInitiatedStreamId(0), false, false, - GetResponseHeaders("200 OK"), &response_header_offset2)); - mock_quic_data2.AddRead(server_maker2.MakeDataPacket( - 2, GetNthClientInitiatedStreamId(0), false, true, 0, "hello!")); - mock_quic_data2.AddWrite(ConstructClientAckPacket(3, 2, 1, 1)); - mock_quic_data2.AddRead(ASYNC, ERR_IO_PENDING); // No more data to read - mock_quic_data2.AddRead(ASYNC, 0); // EOF - - mock_quic_data2.AddSocketDataToFactory(&socket_factory_); + // Then the next request to the second origin will be sent over TCP. + socket_factory_.AddSocketDataProvider(&http_data); + socket_factory_.AddSSLSocketDataProvider(&ssl_data_); CreateSession(); // Set up alternative service for |origin1|. base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1); + AlternativeService alternative1(kProtoQUIC, origin1.host(), 443); http_server_properties_.SetQuicAlternativeService( - url::SchemeHostPort(origin1), - AlternativeService(kProtoQUIC, "mail.example.com", 443), expiration, + url::SchemeHostPort(origin1), alternative1, expiration, supported_versions_); // Set up alternative service for |origin2|. - AlternativeServiceInfoVector alternative_services; + AlternativeService alternative2(kProtoQUIC, origin2.host(), 443); http_server_properties_.SetQuicAlternativeService( - url::SchemeHostPort(origin2), - AlternativeService(kProtoQUIC, "www.example.com", 443), expiration, + url::SchemeHostPort(origin2), alternative2, expiration, supported_versions_); // First request opens connection to |destination1| @@ -3175,10 +3264,14 @@ TEST_P(QuicNetworkTransactionTest, // After it is reset, it will fail back to QUIC and mark QUIC as broken. request_.url = origin2; SendRequestAndExpectHttpResponse("hello world"); + EXPECT_FALSE(http_server_properties_.IsAlternativeServiceBroken(alternative1)) + << alternative1.ToString(); + EXPECT_TRUE(http_server_properties_.IsAlternativeServiceBroken(alternative2)) + << alternative2.ToString(); // The third request should use a new QUIC connection, not the broken // QUIC connection. - SendRequestAndExpectQuicResponse("hello!"); + SendRequestAndExpectHttpResponse("hello world"); } TEST_P(QuicNetworkTransactionTest, @@ -3250,7 +3343,8 @@ TEST_P(QuicNetworkTransactionTest, UseExistingAlternativeServiceForQuic) { // as version negotiation has been completed. mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket( 4, GetNthClientInitiatedStreamId(1), false, true, - GetRequestHeaders("GET", "https", "/"), &request_header_offset)); + GetRequestHeaders("GET", "https", "/"), GetNthClientInitiatedStreamId(0), + &request_header_offset)); mock_quic_data.AddRead(ConstructServerResponseHeadersPacket( 3, GetNthClientInitiatedStreamId(1), false, false, GetResponseHeaders("200 OK"), &response_header_offset)); @@ -3302,7 +3396,8 @@ TEST_P(QuicNetworkTransactionTest, UseExistingQUICAlternativeProxy) { // as version negotiation has been completed. mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket( 4, GetNthClientInitiatedStreamId(1), false, true, - GetRequestHeaders("GET", "http", "/"), &request_header_offset)); + GetRequestHeaders("GET", "http", "/"), GetNthClientInitiatedStreamId(0), + &request_header_offset)); mock_quic_data.AddRead(ConstructServerResponseHeadersPacket( 3, GetNthClientInitiatedStreamId(1), false, false, GetResponseHeaders("200 OK"), &response_header_offset)); @@ -3366,7 +3461,8 @@ TEST_P(QuicNetworkTransactionTest, PoolByOrigin) { // Second request. mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket( 4, GetNthClientInitiatedStreamId(1), false, true, - GetRequestHeaders("GET", "https", "/"), &request_header_offset)); + GetRequestHeaders("GET", "https", "/"), GetNthClientInitiatedStreamId(0), + &request_header_offset)); mock_quic_data.AddRead(ConstructServerResponseHeadersPacket( 3, GetNthClientInitiatedStreamId(1), false, false, GetResponseHeaders("200 OK"), &response_header_offset)); @@ -3433,14 +3529,15 @@ TEST_P(QuicNetworkTransactionTest, PoolByDestination) { mock_quic_data.AddWrite(ConstructClientAckPacket(3, 2, 1, 1)); // Second request. - QuicTestPacketMaker client_maker2(version_, 0, &clock_, origin2.host(), - Perspective::IS_CLIENT); + QuicTestPacketMaker client_maker2( + version_, 0, &clock_, origin2.host(), Perspective::IS_CLIENT, + client_headers_include_h2_stream_dependency_); QuicTestPacketMaker server_maker2(version_, 0, &clock_, origin2.host(), - Perspective::IS_SERVER); + Perspective::IS_SERVER, false); mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket( 4, GetNthClientInitiatedStreamId(1), false, true, GetRequestHeaders("GET", "https", "/", &client_maker2), - &request_header_offset)); + GetNthClientInitiatedStreamId(0), &request_header_offset)); mock_quic_data.AddRead(ConstructServerResponseHeadersPacket( 3, GetNthClientInitiatedStreamId(1), false, false, GetResponseHeaders("200 OK"), &response_header_offset)); @@ -3534,8 +3631,9 @@ TEST_P(QuicNetworkTransactionTest, QuicStreamOffset request_header_offset = 0; QuicStreamOffset response_header_offset = 0; - QuicTestPacketMaker client_maker(version_, 0, &clock_, "mail.example.org", - Perspective::IS_CLIENT); + QuicTestPacketMaker client_maker( + version_, 0, &clock_, "mail.example.org", Perspective::IS_CLIENT, + client_headers_include_h2_stream_dependency_); server_maker_.set_hostname("www.example.org"); client_maker_.set_hostname("www.example.org"); MockQuicData mock_quic_data; @@ -3557,7 +3655,7 @@ TEST_P(QuicNetworkTransactionTest, mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket( 4, GetNthClientInitiatedStreamId(1), false, true, GetRequestHeaders("GET", "https", "/", &client_maker), - &request_header_offset)); + GetNthClientInitiatedStreamId(0), &request_header_offset)); mock_quic_data.AddRead(ConstructServerResponseHeadersPacket( 3, GetNthClientInitiatedStreamId(1), false, false, GetResponseHeaders("200 OK"), &response_header_offset)); @@ -5327,6 +5425,8 @@ class QuicNetworkTransactionWithDestinationTest protected: QuicNetworkTransactionWithDestinationTest() : version_(GetParam().version), + client_headers_include_h2_stream_dependency_( + GetParam().client_headers_include_h2_stream_dependency), supported_versions_(SupportedTransportVersions(version_)), destination_type_(GetParam().destination_type), cert_transparency_verifier_(new MultiLogCTVerifier()), @@ -5345,6 +5445,8 @@ class QuicNetworkTransactionWithDestinationTest session_params.enable_quic = true; session_params.quic_allow_remote_alt_svc = true; session_params.quic_supported_versions = supported_versions_; + session_params.quic_headers_include_h2_stream_dependency = + client_headers_include_h2_stream_dependency_; HttpNetworkSession::Context session_context; @@ -5404,11 +5506,21 @@ class QuicNetworkTransactionWithDestinationTest url::SchemeHostPort("https", origin, 443), alternative_service, expiration, supported_versions_); } + std::unique_ptr<QuicEncryptedPacket> ConstructClientRequestHeadersPacket( + QuicPacketNumber packet_number, + QuicStreamId stream_id, + bool should_include_version, + QuicStreamOffset* offset, + QuicTestPacketMaker* maker) { + return ConstructClientRequestHeadersPacket( + packet_number, stream_id, should_include_version, 0, offset, maker); + } std::unique_ptr<QuicEncryptedPacket> ConstructClientRequestHeadersPacket( QuicPacketNumber packet_number, QuicStreamId stream_id, bool should_include_version, + QuicStreamId parent_stream_id, QuicStreamOffset* offset, QuicTestPacketMaker* maker) { SpdyPriority priority = @@ -5416,7 +5528,7 @@ class QuicNetworkTransactionWithDestinationTest SpdyHeaderBlock headers(maker->GetRequestHeaders("GET", "https", "/")); return maker->MakeRequestHeadersPacketWithOffsetTracking( packet_number, stream_id, should_include_version, true, priority, - std::move(headers), offset); + std::move(headers), parent_stream_id, offset); } std::unique_ptr<QuicEncryptedPacket> ConstructClientRequestHeadersPacket( @@ -5532,7 +5644,8 @@ class QuicNetworkTransactionWithDestinationTest } MockClock clock_; - QuicTransportVersion version_; + const QuicTransportVersion version_; + const bool client_headers_include_h2_stream_dependency_; QuicTransportVersionVector supported_versions_; DestinationType destination_type_; std::string origin1_; @@ -5557,7 +5670,7 @@ class QuicNetworkTransactionWithDestinationTest SSLSocketDataProvider ssl_data_; }; -INSTANTIATE_TEST_CASE_P(Version, +INSTANTIATE_TEST_CASE_P(VersionIncludeStreamDependencySequnece, QuicNetworkTransactionWithDestinationTest, ::testing::ValuesIn(GetPoolingTestParams())); @@ -5626,41 +5739,40 @@ TEST_P(QuicNetworkTransactionWithDestinationTest, PoolIfCertificateValid) { verify_details.cert_verify_result.is_issued_by_known_root = true; crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); - QuicTestPacketMaker client_maker1(version_, 0, &clock_, origin1_, - Perspective::IS_CLIENT); - QuicTestPacketMaker server_maker1(version_, 0, &clock_, origin1_, - Perspective::IS_SERVER); + QuicTestPacketMaker client_maker( + version_, 0, &clock_, origin1_, Perspective::IS_CLIENT, + client_headers_include_h2_stream_dependency_); + QuicTestPacketMaker server_maker(version_, 0, &clock_, origin1_, + Perspective::IS_SERVER, false); QuicStreamOffset request_header_offset(0); QuicStreamOffset response_header_offset(0); MockQuicData mock_quic_data; - mock_quic_data.AddWrite(ConstructInitialSettingsPacket( - 1, &request_header_offset, &client_maker1)); + mock_quic_data.AddWrite( + ConstructInitialSettingsPacket(1, &request_header_offset, &client_maker)); mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket( 2, GetNthClientInitiatedStreamId(0), true, &request_header_offset, - &client_maker1)); + &client_maker)); mock_quic_data.AddRead(ConstructServerResponseHeadersPacket( 1, GetNthClientInitiatedStreamId(0), &response_header_offset, - &server_maker1)); + &server_maker)); mock_quic_data.AddRead(ConstructServerDataPacket( - 2, GetNthClientInitiatedStreamId(0), &server_maker1)); - mock_quic_data.AddWrite(ConstructClientAckPacket(3, 2, 1, 1, &client_maker1)); + 2, GetNthClientInitiatedStreamId(0), &server_maker)); + mock_quic_data.AddWrite(ConstructClientAckPacket(3, 2, 1, 1, &client_maker)); - QuicTestPacketMaker client_maker2(version_, 0, &clock_, origin2_, - Perspective::IS_CLIENT); - QuicTestPacketMaker server_maker2(version_, 0, &clock_, origin2_, - Perspective::IS_SERVER); + client_maker.set_hostname(origin2_); + server_maker.set_hostname(origin2_); mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket( - 4, GetNthClientInitiatedStreamId(1), false, &request_header_offset, - &client_maker2)); + 4, GetNthClientInitiatedStreamId(1), false, + GetNthClientInitiatedStreamId(0), &request_header_offset, &client_maker)); mock_quic_data.AddRead(ConstructServerResponseHeadersPacket( 3, GetNthClientInitiatedStreamId(1), &response_header_offset, - &server_maker2)); + &server_maker)); mock_quic_data.AddRead(ConstructServerDataPacket( - 4, GetNthClientInitiatedStreamId(1), &server_maker2)); - mock_quic_data.AddWrite(ConstructClientAckPacket(5, 4, 3, 1, &client_maker2)); + 4, GetNthClientInitiatedStreamId(1), &server_maker)); + mock_quic_data.AddWrite(ConstructClientAckPacket(5, 4, 3, 1, &client_maker)); mock_quic_data.AddRead(ASYNC, ERR_IO_PENDING); // No more data to read mock_quic_data.AddRead(ASYNC, 0); // EOF @@ -5708,10 +5820,11 @@ TEST_P(QuicNetworkTransactionWithDestinationTest, verify_details2.cert_verify_result.is_issued_by_known_root = true; crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details2); - QuicTestPacketMaker client_maker1(version_, 0, &clock_, origin1_, - Perspective::IS_CLIENT); + QuicTestPacketMaker client_maker1( + version_, 0, &clock_, origin1_, Perspective::IS_CLIENT, + client_headers_include_h2_stream_dependency_); QuicTestPacketMaker server_maker1(version_, 0, &clock_, origin1_, - Perspective::IS_SERVER); + Perspective::IS_SERVER, false); MockQuicData mock_quic_data1; QuicStreamOffset header_stream_offset1 = 0; @@ -5731,12 +5844,11 @@ TEST_P(QuicNetworkTransactionWithDestinationTest, mock_quic_data1.AddSocketDataToFactory(&socket_factory_); - AddHangingSocketData(); - - QuicTestPacketMaker client_maker2(version_, 0, &clock_, origin2_, - Perspective::IS_CLIENT); + QuicTestPacketMaker client_maker2( + version_, 0, &clock_, origin2_, Perspective::IS_CLIENT, + client_headers_include_h2_stream_dependency_); QuicTestPacketMaker server_maker2(version_, 0, &clock_, origin2_, - Perspective::IS_SERVER); + Perspective::IS_SERVER, false); MockQuicData mock_quic_data2; QuicStreamOffset header_stream_offset2 = 0; @@ -5756,8 +5868,6 @@ TEST_P(QuicNetworkTransactionWithDestinationTest, mock_quic_data2.AddSocketDataToFactory(&socket_factory_); - AddHangingSocketData(); - SendRequestAndExpectQuicResponse(origin1_); SendRequestAndExpectQuicResponse(origin2_); diff --git a/chromium/net/quic/chromium/quic_proxy_client_socket.cc b/chromium/net/quic/chromium/quic_proxy_client_socket.cc index e1e39a1b2eb..82736b78460 100644 --- a/chromium/net/quic/chromium/quic_proxy_client_socket.cc +++ b/chromium/net/quic/chromium/quic_proxy_client_socket.cc @@ -16,6 +16,7 @@ #include "net/log/net_log_source.h" #include "net/log/net_log_source_type.h" #include "net/spdy/chromium/spdy_http_utils.h" +#include "net/traffic_annotation/network_traffic_annotation.h" namespace net { @@ -30,6 +31,7 @@ QuicProxyClientSocket::QuicProxyClientSocket( stream_(std::move(stream)), session_(std::move(session)), read_buf_(nullptr), + write_buf_len_(0), endpoint_(endpoint), auth_(auth_controller), user_agent_(user_agent), @@ -108,6 +110,7 @@ void QuicProxyClientSocket::Disconnect() { read_callback_.Reset(); read_buf_ = nullptr; write_callback_.Reset(); + write_buf_len_ = 0; next_state_ = STATE_DISCONNECTED; @@ -159,6 +162,11 @@ int64_t QuicProxyClientSocket::GetTotalReceivedBytes() const { return stream_->NumBytesConsumed(); } +void QuicProxyClientSocket::ApplySocketTag(const SocketTag& tag) { + // |session_| can be tagged, but |stream_| cannot. + CHECK(false); +} + int QuicProxyClientSocket::Read(IOBuffer* buf, int buf_len, const CompletionCallback& callback) { @@ -205,9 +213,11 @@ void QuicProxyClientSocket::OnReadComplete(int rv) { } } -int QuicProxyClientSocket::Write(IOBuffer* buf, - int buf_len, - const CompletionCallback& callback) { +int QuicProxyClientSocket::Write( + IOBuffer* buf, + int buf_len, + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& traffic_annotation) { DCHECK(connect_callback_.is_null()); DCHECK(write_callback_.is_null()); @@ -221,16 +231,24 @@ int QuicProxyClientSocket::Write(IOBuffer* buf, QuicStringPiece(buf->data(), buf_len), false, base::Bind(&QuicProxyClientSocket::OnWriteComplete, weak_factory_.GetWeakPtr())); + if (rv == OK) + return buf_len; - if (rv == ERR_IO_PENDING) + if (rv == ERR_IO_PENDING) { write_callback_ = callback; + write_buf_len_ = buf_len; + } return rv; } void QuicProxyClientSocket::OnWriteComplete(int rv) { - if (!write_callback_.is_null()) + if (!write_callback_.is_null()) { + if (rv == OK) + rv = write_buf_len_; + write_buf_len_ = 0; base::ResetAndReturn(&write_callback_).Run(rv); + } } int QuicProxyClientSocket::SetReceiveBufferSize(int32_t size) { diff --git a/chromium/net/quic/chromium/quic_proxy_client_socket.h b/chromium/net/quic/chromium/quic_proxy_client_socket.h index 3b0795eb9be..37f2b847333 100644 --- a/chromium/net/quic/chromium/quic_proxy_client_socket.h +++ b/chromium/net/quic/chromium/quic_proxy_client_socket.h @@ -13,6 +13,7 @@ #include "net/quic/chromium/quic_chromium_client_session.h" #include "net/quic/chromium/quic_chromium_client_stream.h" #include "net/spdy/chromium/spdy_read_queue.h" +#include "net/traffic_annotation/network_traffic_annotation.h" namespace net { @@ -34,7 +35,7 @@ class NET_EXPORT_PRIVATE QuicProxyClientSocket : public ProxyClientSocket { const NetLogWithSource& net_log, HttpAuthController* auth_controller); - /// On destruction Disconnect() is called. + // On destruction Disconnect() is called. ~QuicProxyClientSocket() override; // ProxyClientSocket methods: @@ -61,6 +62,7 @@ class NET_EXPORT_PRIVATE QuicProxyClientSocket : public ProxyClientSocket { void ClearConnectionAttempts() override {} void AddConnectionAttempts(const ConnectionAttempts& attempts) override {} int64_t GetTotalReceivedBytes() const override; + void ApplySocketTag(const SocketTag& tag) override; // Socket implementation. int Read(IOBuffer* buf, @@ -68,7 +70,8 @@ class NET_EXPORT_PRIVATE QuicProxyClientSocket : public ProxyClientSocket { const CompletionCallback& callback) override; int Write(IOBuffer* buf, int buf_len, - const CompletionCallback& callback) override; + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& traffic_annotation) override; int SetReceiveBufferSize(int32_t size) override; int SetSendBufferSize(int32_t size) override; int GetPeerAddress(IPEndPoint* address) const override; @@ -122,6 +125,8 @@ class NET_EXPORT_PRIVATE QuicProxyClientSocket : public ProxyClientSocket { IOBuffer* read_buf_; // Stores the callback for Write(). CompletionCallback write_callback_; + // Stores the write buffer length for Write(). + int write_buf_len_; // CONNECT request and response. HttpRequestInfo request_; diff --git a/chromium/net/quic/chromium/quic_proxy_client_socket_unittest.cc b/chromium/net/quic/chromium/quic_proxy_client_socket_unittest.cc index a91b5960fe6..87a39c6e666 100644 --- a/chromium/net/quic/chromium/quic_proxy_client_socket_unittest.cc +++ b/chromium/net/quic/chromium/quic_proxy_client_socket_unittest.cc @@ -28,6 +28,7 @@ #include "net/quic/chromium/quic_test_packet_maker.h" #include "net/quic/chromium/test_task_runner.h" #include "net/quic/core/crypto/null_encrypter.h" +#include "net/quic/core/tls_client_handshaker.h" #include "net/quic/test_tools/crypto_test_utils.h" #include "net/quic/test_tools/mock_clock.h" #include "net/quic/test_tools/mock_random.h" @@ -36,6 +37,7 @@ #include "net/socket/socket_test_util.h" #include "net/test/cert_test_util.h" #include "net/test/test_data_directory.h" +#include "net/traffic_annotation/network_traffic_annotation_test_helper.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -74,7 +76,7 @@ const QuicStreamId kClientDataStreamId1 = kHeadersStreamId + 2; } // namespace class QuicProxyClientSocketTest - : public ::testing::TestWithParam<QuicTransportVersion> { + : public ::testing::TestWithParam<std::tuple<QuicTransportVersion, bool>> { protected: static const bool kFin = true; static const bool kIncludeVersion = true; @@ -103,19 +105,23 @@ class QuicProxyClientSocketTest } QuicProxyClientSocketTest() - : version_(GetParam()), - crypto_config_(crypto_test_utils::ProofVerifierForTesting()), + : version_(std::get<0>(GetParam())), + client_headers_include_h2_stream_dependency_(std::get<1>(GetParam())), + crypto_config_(crypto_test_utils::ProofVerifierForTesting(), + TlsClientHandshaker::CreateSslCtx()), connection_id_(2), client_maker_(version_, connection_id_, &clock_, kProxyHost, - Perspective::IS_CLIENT), + Perspective::IS_CLIENT, + client_headers_include_h2_stream_dependency_), server_maker_(version_, connection_id_, &clock_, kProxyHost, - Perspective::IS_SERVER), + Perspective::IS_SERVER, + false), random_generator_(0), header_stream_offset_(0), response_offset_(0), @@ -169,7 +175,9 @@ class QuicProxyClientSocketTest QuicConnection* connection = new QuicConnection( connection_id_, QuicSocketAddress(QuicSocketAddressImpl(peer_addr_)), helper_.get(), alarm_factory_.get(), writer, true /* owns_writer */, - Perspective::IS_CLIENT, SupportedTransportVersions(GetParam())); + Perspective::IS_CLIENT, + SupportedVersions( + net::ParsedQuicVersion(net::PROTOCOL_QUIC_CRYPTO, version_))); connection->set_visitor(&visitor_); QuicConnectionPeer::SetSendAlgorithm(connection, send_algorithm_); @@ -195,16 +203,20 @@ class QuicProxyClientSocketTest /*migrate_session_on_network_change*/ false, /*migrate_session_early_v2*/ false, /*migrate_session_on_network_change_v2*/ false, + base::TimeDelta::FromSeconds(kMaxTimeOnNonDefaultNetworkSecs), + kMaxMigrationsToNonDefaultNetworkOnPathDegrading, kQuicYieldAfterPacketsRead, QuicTime::Delta::FromMilliseconds(kQuicYieldAfterDurationMilliseconds), - /*cert_verify_flags=*/0, DefaultQuicConfig(), &crypto_config_, - "CONNECTION_UNKNOWN", dns_start, dns_end, &push_promise_index_, nullptr, + client_headers_include_h2_stream_dependency_, /*cert_verify_flags=*/0, + DefaultQuicConfig(), &crypto_config_, "CONNECTION_UNKNOWN", dns_start, + dns_end, &push_promise_index_, nullptr, base::ThreadTaskRunnerHandle::Get().get(), /*socket_performance_watcher=*/nullptr, net_log_.bound().net_log())); writer->set_delegate(session_.get()); - session_handle_ = session_->CreateHandle(); + session_handle_ = + session_->CreateHandle(HostPortPair("mail.example.org", 80)); session_->Initialize(); TestCompletionCallback callback; @@ -281,8 +293,8 @@ class QuicProxyClientSocketTest PopulateConnectRequestIR(&block); return client_maker_.MakeRequestHeadersPacket( packet_number, kClientDataStreamId1, kIncludeVersion, !kFin, - ConvertRequestPriorityToQuicPriority(LOWEST), std::move(block), nullptr, - &header_stream_offset_); + ConvertRequestPriorityToQuicPriority(LOWEST), std::move(block), 0, + nullptr, &header_stream_offset_); } std::unique_ptr<QuicReceivedPacket> ConstructConnectAuthRequestPacket( @@ -292,8 +304,8 @@ class QuicProxyClientSocketTest block["proxy-authorization"] = "Basic Zm9vOmJhcg=="; return client_maker_.MakeRequestHeadersPacket( packet_number, kClientDataStreamId1, kIncludeVersion, !kFin, - ConvertRequestPriorityToQuicPriority(LOWEST), std::move(block), nullptr, - &header_stream_offset_); + ConvertRequestPriorityToQuicPriority(LOWEST), std::move(block), 0, + nullptr, &header_stream_offset_); } std::unique_ptr<QuicReceivedPacket> ConstructDataPacket( @@ -430,14 +442,15 @@ class QuicProxyClientSocketTest scoped_refptr<IOBufferWithSize> buf(new IOBufferWithSize(len)); memcpy(buf->data(), data, len); EXPECT_EQ(rv, - sock_->Write(buf.get(), buf->size(), write_callback_.callback())); + sock_->Write(buf.get(), buf->size(), write_callback_.callback(), + TRAFFIC_ANNOTATION_FOR_TESTS)); } void AssertSyncWriteSucceeds(const char* data, int len) { scoped_refptr<IOBufferWithSize> buf(new IOBufferWithSize(len)); memcpy(buf->data(), data, len); - EXPECT_THAT(sock_->Write(buf.get(), buf->size(), CompletionCallback()), - IsOk()); + EXPECT_EQ(len, sock_->Write(buf.get(), buf->size(), CompletionCallback(), + TRAFFIC_ANNOTATION_FOR_TESTS)); } void AssertSyncReadEquals(const char* data, int len) { @@ -476,7 +489,8 @@ class QuicProxyClientSocketTest ASSERT_EQ(SpdyString(data, len), SpdyString(read_buf_->data(), len)); } - QuicTransportVersion version_; + const QuicTransportVersion version_; + const bool client_headers_include_h2_stream_dependency_; // order of destruction of these members matter MockClock clock_; @@ -1103,7 +1117,7 @@ TEST_P(QuicProxyClientSocketTest, AsyncWriteAroundReads) { // asynchronous starting with the second time it's called while the UDP socket // is write-blocked. Therefore, at least two writes need to be called on // |sock_| to get an asynchronous one. - AssertWriteReturns(kMsg2, kLen2, OK); + AssertWriteReturns(kMsg2, kLen2, kLen2); AssertWriteReturns(kMsg2, kLen2, ERR_IO_PENDING); AssertAsyncReadEquals(kMsg3, kLen3); @@ -1112,7 +1126,7 @@ TEST_P(QuicProxyClientSocketTest, AsyncWriteAroundReads) { // Now the write will complete ResumeAndRun(); - EXPECT_EQ(OK, write_callback_.WaitForResult()); + EXPECT_EQ(kLen2, write_callback_.WaitForResult()); } // ----------- Reading/Writing on Closed socket @@ -1259,7 +1273,7 @@ TEST_P(QuicProxyClientSocketTest, WritePendingOnClose) { // asynchronous starting with the second time it's called while the UDP socket // is write-blocked. Therefore, at least two writes need to be called on // |sock_| to get an asynchronous one. - AssertWriteReturns(kMsg1, kLen1, OK); + AssertWriteReturns(kMsg1, kLen1, kLen1); // This second write will be async. This is the pending write that's being // tested. @@ -1288,7 +1302,7 @@ TEST_P(QuicProxyClientSocketTest, DisconnectWithWritePending) { // asynchronous starting with the second time it's called while the UDP socket // is write-blocked. Therefore, at least two writes need to be called on // |sock_| to get an asynchronous one. - AssertWriteReturns(kMsg1, kLen1, OK); + AssertWriteReturns(kMsg1, kLen1, kLen1); // This second write will be async. This is the pending write that's being // tested. @@ -1362,7 +1376,7 @@ TEST_P(QuicProxyClientSocketTest, RstWithReadAndWritePending) { // asynchronous starting with the second time it's called while the UDP socket // is write-blocked. Therefore, at least two writes need to be called on // |sock_| to get an asynchronous one. - AssertWriteReturns(kMsg2, kLen2, OK); + AssertWriteReturns(kMsg2, kLen2, kLen2); AssertWriteReturns(kMsg2, kLen2, ERR_IO_PENDING); ResumeAndRun(); @@ -1482,7 +1496,7 @@ TEST_P(QuicProxyClientSocketTest, RstWithReadAndWritePendingDelete) { // asynchronous starting with the second time it's called while the UDP socket // is write-blocked. Therefore, at least two writes need to be called on // |sock_| to get an asynchronous one. - AssertWriteReturns(kMsg1, kLen1, OK); + AssertWriteReturns(kMsg1, kLen1, kLen1); AssertWriteReturns(kMsg1, kLen1, ERR_IO_PENDING); ResumeAndRun(); @@ -1493,9 +1507,11 @@ TEST_P(QuicProxyClientSocketTest, RstWithReadAndWritePendingDelete) { EXPECT_FALSE(write_callback_.have_result()); } -INSTANTIATE_TEST_CASE_P(Version, - QuicProxyClientSocketTest, - ::testing::ValuesIn(AllSupportedTransportVersions())); +INSTANTIATE_TEST_CASE_P( + VersionIncludeStreamDependencySequnece, + QuicProxyClientSocketTest, + ::testing::Combine(::testing::ValuesIn(AllSupportedTransportVersions()), + ::testing::Bool())); } // namespace test } // namespace net diff --git a/chromium/net/quic/chromium/quic_stream_factory.cc b/chromium/net/quic/chromium/quic_stream_factory.cc index f680339d1e2..97a53067b4d 100644 --- a/chromium/net/quic/chromium/quic_stream_factory.cc +++ b/chromium/net/quic/chromium/quic_stream_factory.cc @@ -12,8 +12,8 @@ #include "base/callback_helpers.h" #include "base/location.h" #include "base/metrics/field_trial.h" +#include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" -#include "base/metrics/sparse_histogram.h" #include "base/rand_util.h" #include "base/single_thread_task_runner.h" #include "base/strings/string_number_conversions.h" @@ -49,6 +49,7 @@ #include "net/quic/core/crypto/quic_random.h" #include "net/quic/core/quic_client_promised_info.h" #include "net/quic/core/quic_connection.h" +#include "net/quic/core/tls_client_handshaker.h" #include "net/quic/platform/api/quic_clock.h" #include "net/quic/platform/api/quic_flags.h" #include "net/socket/client_socket_factory.h" @@ -317,7 +318,8 @@ class QuicStreamFactory::Job { ~Job(); - int Run(const CompletionCallback& callback); + int Run(const CompletionCallback& host_resolution_callback, + const CompletionCallback& callback); int DoLoop(int rv); int DoResolveHost(); @@ -340,6 +342,10 @@ class QuicStreamFactory::Job { void AddRequest(QuicStreamRequest* request) { stream_requests_.insert(request); + if (io_state_ == STATE_RESOLVE_HOST || + io_state_ == STATE_RESOLVE_HOST_COMPLETE) { + request->ExpectOnHostResolution(); + } } void RemoveRequest(QuicStreamRequest* request) { @@ -352,6 +358,10 @@ class QuicStreamFactory::Job { return stream_requests_; } + bool IsHostResolutionComplete() const { + return io_state_ == STATE_NONE || io_state_ >= STATE_CONNECT; + } + private: enum IoState { STATE_NONE, @@ -373,6 +383,7 @@ class QuicStreamFactory::Job { const NetLogWithSource net_log_; int num_sent_client_hellos_; QuicChromiumClientSession* session_; + CompletionCallback host_resolution_callback_; CompletionCallback callback_; AddressList address_list_; base::TimeTicks dns_resolution_start_time_; @@ -424,10 +435,14 @@ QuicStreamFactory::Job::~Job() { // non-null. } -int QuicStreamFactory::Job::Run(const CompletionCallback& callback) { +int QuicStreamFactory::Job::Run( + const CompletionCallback& host_resolution_callback, + const CompletionCallback& callback) { int rv = DoLoop(OK); - if (rv == ERR_IO_PENDING) + if (rv == ERR_IO_PENDING) { + host_resolution_callback_ = host_resolution_callback; callback_ = callback; + } return rv > 0 ? OK : rv; } @@ -462,7 +477,12 @@ int QuicStreamFactory::Job::DoLoop(int rv) { } void QuicStreamFactory::Job::OnIOComplete(int rv) { + IoState start_state = io_state_; rv = DoLoop(rv); + if (start_state == STATE_RESOLVE_HOST_COMPLETE && + !host_resolution_callback_.is_null()) { + base::ResetAndReturn(&host_resolution_callback_).Run(rv); + } if (rv != ERR_IO_PENDING && !callback_.is_null()) { base::ResetAndReturn(&callback_).Run(rv); } @@ -500,7 +520,7 @@ int QuicStreamFactory::Job::DoResolveHostComplete(int rv) { // Inform the factory of this resolution, which will set up // a session alias, if possible. - if (factory_->OnResolution(key_, address_list_)) + if (factory_->HasMatchingIpSession(key_, address_list_)) return OK; io_state_ = STATE_CONNECT; @@ -567,7 +587,7 @@ int QuicStreamFactory::Job::DoConnectComplete(int rv) { // existing session instead. AddressList address( session_->connection()->peer_address().impl().socket_address()); - if (factory_->OnResolution(key_, address)) { + if (factory_->HasMatchingIpSession(key_, address)) { session_->connection()->CloseConnection( QUIC_CONNECTION_IP_POOLED, "An active session exists for the given IP.", ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); @@ -581,7 +601,7 @@ int QuicStreamFactory::Job::DoConnectComplete(int rv) { } QuicStreamRequest::QuicStreamRequest(QuicStreamFactory* factory) - : factory_(factory) {} + : factory_(factory), expect_on_host_resolution_(false) {} QuicStreamRequest::~QuicStreamRequest() { if (factory_ && !callback_.is_null()) @@ -600,6 +620,7 @@ int QuicStreamRequest::Request(const HostPortPair& destination, DCHECK_NE(quic_version, QUIC_VERSION_UNSUPPORTED); DCHECK(net_error_details); DCHECK(callback_.is_null()); + DCHECK(host_resolution_callback_.is_null()); DCHECK(factory_); net_error_details_ = net_error_details; @@ -611,13 +632,24 @@ int QuicStreamRequest::Request(const HostPortPair& destination, net_log_ = net_log; callback_ = callback; } else { + DCHECK(!expect_on_host_resolution_); factory_ = nullptr; } + if (rv == OK) DCHECK(session_); return rv; } +bool QuicStreamRequest::WaitForHostResolution( + const CompletionCallback& callback) { + DCHECK(host_resolution_callback_.is_null()); + if (expect_on_host_resolution_) { + host_resolution_callback_ = callback; + } + return expect_on_host_resolution_; +} + void QuicStreamRequest::SetSession( std::unique_ptr<QuicChromiumClientSession::Handle> session) { session_ = move(session); @@ -628,6 +660,18 @@ void QuicStreamRequest::OnRequestComplete(int rv) { base::ResetAndReturn(&callback_).Run(rv); } +void QuicStreamRequest::ExpectOnHostResolution() { + expect_on_host_resolution_ = true; +} + +void QuicStreamRequest::OnHostResolutionComplete(int rv) { + DCHECK(expect_on_host_resolution_); + expect_on_host_resolution_ = false; + if (!host_resolution_callback_.is_null()) { + base::ResetAndReturn(&host_resolution_callback_).Run(rv); + } +} + base::TimeDelta QuicStreamRequest::GetTimeDelayForWaitingJob() const { if (!factory_) return base::TimeDelta(); @@ -671,9 +715,12 @@ QuicStreamFactory::QuicStreamFactory( bool migrate_sessions_early, bool migrate_sessions_on_network_change_v2, bool migrate_sessions_early_v2, + base::TimeDelta max_time_on_non_default_network, + int max_migrations_to_non_default_network_on_path_degrading, bool allow_server_migration, bool race_cert_verification, bool estimate_initial_rtt, + bool headers_include_h2_stream_dependency, const QuicTagVector& connection_options, const QuicTagVector& client_connection_options, bool enable_token_binding) @@ -701,7 +748,8 @@ QuicStreamFactory::QuicStreamFactory( std::make_unique<ProofVerifierChromium>(cert_verifier, ct_policy_enforcer, transport_security_state, - cert_transparency_verifier)), + cert_transparency_verifier), + TlsClientHandshaker::CreateSslCtx()), mark_quic_broken_when_network_blackholes_( mark_quic_broken_when_network_blackholes), store_server_configs_in_properties_(store_server_configs_in_properties), @@ -720,6 +768,9 @@ QuicStreamFactory::QuicStreamFactory( NetworkChangeNotifier::AreNetworkHandlesSupported()), migrate_sessions_early_v2_(migrate_sessions_early_v2 && migrate_sessions_on_network_change_v2_), + max_time_on_non_default_network_(max_time_on_non_default_network), + max_migrations_to_non_default_network_on_path_degrading_( + max_migrations_to_non_default_network_on_path_degrading), migrate_sessions_on_network_change_( !migrate_sessions_on_network_change_v2_ && migrate_sessions_on_network_change && @@ -730,6 +781,8 @@ QuicStreamFactory::QuicStreamFactory( allow_server_migration_(allow_server_migration), race_cert_verification_(race_cert_verification), estimate_initial_rtt(estimate_initial_rtt), + headers_include_h2_stream_dependency_( + headers_include_h2_stream_dependency), need_to_check_persisted_supports_quic_(true), num_push_streams_created_(0), task_runner_(nullptr), @@ -906,7 +959,7 @@ int QuicStreamFactory::Create(const QuicServerId& server_id, static_cast<QuicChromiumClientSession*>(promised->session()); DCHECK(session); if (session->server_id().privacy_mode() == server_id.privacy_mode()) { - request->SetSession(session->CreateHandle()); + request->SetSession(session->CreateHandle(destination)); ++num_push_streams_created_; return OK; } @@ -922,7 +975,7 @@ int QuicStreamFactory::Create(const QuicServerId& server_id, SessionMap::iterator it = active_sessions_.find(server_id); if (it != active_sessions_.end()) { QuicChromiumClientSession* session = it->second; - request->SetSession(session->CreateHandle()); + request->SetSession(session->CreateHandle(destination)); return OK; } } @@ -947,7 +1000,7 @@ int QuicStreamFactory::Create(const QuicServerId& server_id, QuicChromiumClientSession* session = key_value.second; if (destination.Equals(all_sessions_[session].destination()) && session->CanPool(server_id.host(), server_id.privacy_mode())) { - request->SetSession(session->CreateHandle()); + request->SetSession(session->CreateHandle(destination)); return OK; } } @@ -964,8 +1017,11 @@ int QuicStreamFactory::Create(const QuicServerId& server_id, std::unique_ptr<Job> job = std::make_unique<Job>( this, quic_version, host_resolver_, key, WasQuicRecentlyBroken(server_id), priority, cert_verify_flags, net_log); - int rv = job->Run(base::Bind(&QuicStreamFactory::OnJobComplete, - base::Unretained(this), job.get())); + int rv = job->Run( + base::BindRepeating(&QuicStreamFactory::OnJobHostResolutionComplete, + base::Unretained(this), job.get()), + base::BindRepeating(&QuicStreamFactory::OnJobComplete, + base::Unretained(this), job.get())); if (rv == ERR_IO_PENDING) { job->AddRequest(request); active_jobs_[server_id] = std::move(job); @@ -981,7 +1037,7 @@ int QuicStreamFactory::Create(const QuicServerId& server_id, if (it == active_sessions_.end()) return ERR_QUIC_PROTOCOL_ERROR; QuicChromiumClientSession* session = it->second; - request->SetSession(session->CreateHandle()); + request->SetSession(session->CreateHandle(destination)); } return rv; } @@ -1008,8 +1064,8 @@ size_t QuicStreamFactory::QuicSessionKey::EstimateMemoryUsage() const { EstimateServerIdMemoryUsage(server_id_); } -bool QuicStreamFactory::OnResolution(const QuicSessionKey& key, - const AddressList& address_list) { +bool QuicStreamFactory::HasMatchingIpSession(const QuicSessionKey& key, + const AddressList& address_list) { const QuicServerId& server_id(key.server_id()); DCHECK(!HasActiveSession(server_id)); for (const IPEndPoint& address : address_list) { @@ -1028,6 +1084,14 @@ bool QuicStreamFactory::OnResolution(const QuicSessionKey& key, return false; } +void QuicStreamFactory::OnJobHostResolutionComplete(Job* job, int rv) { + auto iter = active_jobs_.find(job->key().server_id()); + DCHECK(iter != active_jobs_.end()); + for (auto* request : iter->second->stream_requests()) { + request->OnHostResolutionComplete(rv); + } +} + void QuicStreamFactory::OnJobComplete(Job* job, int rv) { auto iter = active_jobs_.find(job->key().server_id()); DCHECK(iter != active_jobs_.end()); @@ -1040,7 +1104,7 @@ void QuicStreamFactory::OnJobComplete(Job* job, int rv) { QuicChromiumClientSession* session = session_it->second; for (auto* request : iter->second->stream_requests()) { // Do not notify |request| yet. - request->SetSession(session->CreateHandle()); + request->SetSession(session->CreateHandle(job->key().destination())); } } @@ -1060,19 +1124,6 @@ void QuicStreamFactory::OnCertVerifyJobComplete(CertVerifierJob* job, int rv) { active_cert_verifier_jobs_.erase(job->server_id()); } -bool QuicStreamFactory::IsQuicBroken(QuicChromiumClientSession* session) { - const AlternativeService alternative_service( - kProtoQUIC, session->server_id().host_port_pair()); - if (!http_server_properties_->IsAlternativeServiceBroken( - alternative_service)) { - return false; - } - // No longer send requests to a server for which QUIC is broken, but - // continue to service existing requests. - OnSessionGoingAway(session); - return true; -} - void QuicStreamFactory::OnIdleSession(QuicChromiumClientSession* session) {} void QuicStreamFactory::OnSessionGoingAway(QuicChromiumClientSession* session) { @@ -1128,7 +1179,7 @@ void QuicStreamFactory::CancelRequest(QuicStreamRequest* request) { } void QuicStreamFactory::CloseAllSessions(int error, QuicErrorCode quic_error) { - UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.CloseAllSessionsError", -error); + base::UmaHistogramSparse("Net.QuicSession.CloseAllSessionsError", -error); while (!active_sessions_.empty()) { size_t initial_size = active_sessions_.size(); active_sessions_.begin()->second->CloseSessionOnError(error, quic_error); @@ -1404,7 +1455,9 @@ int QuicStreamFactory::CreateSession(const QuicSessionKey& key, QuicConnection* connection = new QuicConnection( connection_id, QuicSocketAddress(QuicSocketAddressImpl(addr)), helper_.get(), alarm_factory_.get(), writer, true /* owns_writer */, - Perspective::IS_CLIENT, {quic_version}); + Perspective::IS_CLIENT, + ParsedQuicVersionVector{ + ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, quic_version)}); connection->set_ping_timeout(ping_timeout_); connection->SetMaxPacketLength(max_packet_length_); @@ -1435,11 +1488,14 @@ int QuicStreamFactory::CreateSession(const QuicSessionKey& key, clock_, transport_security_state_, std::move(server_info), server_id, require_confirmation, migrate_sessions_early_, migrate_sessions_on_network_change_, migrate_sessions_early_v2_, - migrate_sessions_on_network_change_v2_, yield_after_packets_, - yield_after_duration_, cert_verify_flags, config, &crypto_config_, - network_connection_.connection_description(), dns_resolution_start_time, - dns_resolution_end_time, &push_promise_index_, push_delegate_, - task_runner_, std::move(socket_performance_watcher), net_log.net_log()); + migrate_sessions_on_network_change_v2_, max_time_on_non_default_network_, + max_migrations_to_non_default_network_on_path_degrading_, + yield_after_packets_, yield_after_duration_, + headers_include_h2_stream_dependency_, cert_verify_flags, config, + &crypto_config_, network_connection_.connection_description(), + dns_resolution_start_time, dns_resolution_end_time, &push_promise_index_, + push_delegate_, task_runner_, std::move(socket_performance_watcher), + net_log.net_log()); all_sessions_[*session] = key; // owning pointer writer->set_delegate(*session); diff --git a/chromium/net/quic/chromium/quic_stream_factory.h b/chromium/net/quic/chromium/quic_stream_factory.h index ae26f7f4539..3607f5df51d 100644 --- a/chromium/net/quic/chromium/quic_stream_factory.h +++ b/chromium/net/quic/chromium/quic_stream_factory.h @@ -84,6 +84,7 @@ enum QuicConnectionMigrationStatus { MIGRATION_STATUS_NON_MIGRATABLE_STREAM, MIGRATION_STATUS_DISABLED, MIGRATION_STATUS_NO_ALTERNATE_NETWORK, + MIGRATION_STATUS_ON_PATH_DEGRADING_DISABLED, MIGRATION_STATUS_MAX }; @@ -118,6 +119,23 @@ class NET_EXPORT_PRIVATE QuicStreamRequest { NetErrorDetails* net_error_details, const CompletionCallback& callback); + // This function must be called after Request() returns ERR_IO_PENDING. + // Returns true if Request() requires host resolution and it hasn't completed + // yet. If true is returned, |callback| will run when host resolution + // completes. It will be called with the result after host resolution during + // the connection process. For example, if host resolution returns OK and then + // crypto handshake returns ERR_IO_PENDING, then |callback| will run with + // ERR_IO_PENDING. + bool WaitForHostResolution(const CompletionCallback& callback); + + // Tells QuicStreamRequest it should expect OnHostResolutionComplete() + // to be called in the future. + void ExpectOnHostResolution(); + + // Will be called by the associated QuicStreamFactory::Job when host + // resolution completes asynchronously after Request(). + void OnHostResolutionComplete(int rv); + void OnRequestComplete(int rv); // Helper method that calls |factory_|'s GetTimeDelayForWaitingJob(). It @@ -144,6 +162,12 @@ class NET_EXPORT_PRIVATE QuicStreamRequest { NetErrorDetails* net_error_details_; // Unowned. std::unique_ptr<QuicChromiumClientSession::Handle> session_; + // Set in Request(). If true, then OnHostResolutionComplete() is expected to + // be called in the future. + bool expect_on_host_resolution_; + // Callback passed to WaitForHostResolution(). + CompletionCallback host_resolution_callback_; + DISALLOW_COPY_AND_ASSIGN(QuicStreamRequest); }; @@ -211,9 +235,12 @@ class NET_EXPORT_PRIVATE QuicStreamFactory bool migrate_sessions_early, bool migrate_sessions_on_network_change_v2, bool migrate_sessions_early_v2, + base::TimeDelta max_time_on_non_default_network, + int max_migrations_to_non_default_network_on_path_degrading, bool allow_server_migration, bool race_cert_verification, bool estimate_initial_rtt, + bool headers_include_h2_stream_dependency, const QuicTagVector& connection_options, const QuicTagVector& client_connection_options, bool enable_token_binding); @@ -250,9 +277,6 @@ class NET_EXPORT_PRIVATE QuicStreamFactory // Called by a session when it becomes idle. void OnIdleSession(QuicChromiumClientSession* session); - // Returns true if QUIC is know to be broken for |session|. - bool IsQuicBroken(QuicChromiumClientSession* session); - // Called by a session when it is going away and no more streams should be // created on it. void OnSessionGoingAway(QuicChromiumClientSession* session); @@ -369,7 +393,9 @@ class NET_EXPORT_PRIVATE QuicStreamFactory typedef std::map<QuicServerId, std::unique_ptr<CertVerifierJob>> CertVerifierJobMap; - bool OnResolution(const QuicSessionKey& key, const AddressList& address_list); + bool HasMatchingIpSession(const QuicSessionKey& key, + const AddressList& address_list); + void OnJobHostResolutionComplete(Job* job, int rv); void OnJobComplete(Job* job, int rv); void OnCertVerifyJobComplete(CertVerifierJob* job, int rv); bool HasActiveSession(const QuicServerId& server_id) const; @@ -506,6 +532,13 @@ class NET_EXPORT_PRIVATE QuicStreamFactory // connection experiences poor connectivity. const bool migrate_sessions_early_v2_; + // Maximum time sessions could use on non-default network before try to + // migrate back to default network. + const base::TimeDelta max_time_on_non_default_network_; + + // Maximum number of migrations to non default network on path degrading. + const int max_migrations_to_non_default_network_on_path_degrading_; + // Set if migration should be attempted on active sessions when primary // interface changes. const bool migrate_sessions_on_network_change_; @@ -524,6 +557,10 @@ class NET_EXPORT_PRIVATE QuicStreamFactory // If true, estimate the initial RTT based on network type. bool estimate_initial_rtt; + // If true, client headers will include HTTP/2 stream dependency info + // derived from SpdyPriority. + bool headers_include_h2_stream_dependency_; + // Local address of socket that was created in CreateSession. IPEndPoint local_address_; // True if we need to check HttpServerProperties if QUIC was supported last diff --git a/chromium/net/quic/chromium/quic_stream_factory_fuzzer.cc b/chromium/net/quic/chromium/quic_stream_factory_fuzzer.cc index 8e34162add7..55ea51e2f41 100644 --- a/chromium/net/quic/chromium/quic_stream_factory_fuzzer.cc +++ b/chromium/net/quic/chromium/quic_stream_factory_fuzzer.cc @@ -7,8 +7,8 @@ #include "base/test/fuzzed_data_provider.h" #include "net/base/test_completion_callback.h" -#include "net/cert/cert_verifier.h" -#include "net/cert/multi_log_ct_verifier.h" +#include "net/cert/do_nothing_ct_verifier.h" +#include "net/cert/mock_cert_verifier.h" #include "net/cert/x509_certificate.h" #include "net/dns/fuzzed_host_resolver.h" #include "net/http/http_server_properties_impl.h" @@ -22,6 +22,7 @@ #include "net/socket/fuzzed_socket_factory.h" #include "net/ssl/channel_id_service.h" #include "net/ssl/default_channel_id_store.h" +#include "net/ssl/ssl_config_service_defaults.h" #include "net/test/gtest_util.h" namespace net { @@ -32,18 +33,6 @@ const char kCertData[] = { #include "net/data/ssl/certificates/wildcard.inc" }; -class MockSSLConfigService : public SSLConfigService { - public: - MockSSLConfigService() {} - - void GetSSLConfig(SSLConfig* config) override { *config = config_; } - - private: - ~MockSSLConfigService() override {} - - SSLConfig config_; -}; - } // namespace namespace test { @@ -62,12 +51,12 @@ const int kCertVerifyFlags = 0; struct Env { Env() : host_port_pair(kServerHostName, kServerPort), random_generator(0) { clock.AdvanceTime(QuicTime::Delta::FromSeconds(1)); - ssl_config_service = new MockSSLConfigService; + ssl_config_service = base::MakeRefCounted<SSLConfigServiceDefaults>(); crypto_client_stream_factory.set_use_mock_crypter(true); - cert_verifier = CertVerifier::CreateDefault(); + cert_verifier = std::make_unique<MockCertVerifier>(); channel_id_service = std::make_unique<ChannelIDService>(new DefaultChannelIDStore(nullptr)); - cert_transparency_verifier = std::make_unique<MultiLogCTVerifier>(); + cert_transparency_verifier = std::make_unique<DoNothingCTVerifier>(); verify_details.cert_verify_result.verified_cert = X509Certificate::CreateFromBytes(kCertData, arraysize(kCertData)); CHECK(verify_details.cert_verify_result.verified_cert); @@ -109,6 +98,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { bool allow_server_migration = data_provider.ConsumeBool(); bool race_cert_verification = data_provider.ConsumeBool(); bool estimate_initial_rtt = data_provider.ConsumeBool(); + bool headers_include_h2_stream_dependency = data_provider.ConsumeBool(); bool enable_token_binding = data_provider.ConsumeBool(); env->crypto_client_stream_factory.AddProofVerifyDetails(&env->verify_details); @@ -116,20 +106,19 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { bool migrate_sessions_on_network_change = false; bool migrate_sessions_early = false; bool migrate_sessions_early_v2 = false; - - bool migrate_sessions_on_network_change_v2 = data_provider.ConsumeBool(); - - if (migrate_sessions_on_network_change_v2) { - migrate_sessions_early_v2 = data_provider.ConsumeBool(); - } else { - migrate_sessions_on_network_change = data_provider.ConsumeBool(); - if (migrate_sessions_on_network_change) - migrate_sessions_early = data_provider.ConsumeBool(); + bool migrate_sessions_on_network_change_v2 = false; + + if (!close_sessions_on_ip_change) { + migrate_sessions_on_network_change_v2 = data_provider.ConsumeBool(); + if (migrate_sessions_on_network_change_v2) { + migrate_sessions_early_v2 = data_provider.ConsumeBool(); + } else { + migrate_sessions_on_network_change = data_provider.ConsumeBool(); + if (migrate_sessions_on_network_change) + migrate_sessions_early = data_provider.ConsumeBool(); + } } - if (migrate_sessions_on_network_change) - close_sessions_on_ip_change = false; - std::unique_ptr<QuicStreamFactory> factory = std::make_unique<QuicStreamFactory>( env->net_log.net_log(), &host_resolver, env->ssl_config_service.get(), @@ -144,8 +133,11 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { kMaxTimeForCryptoHandshakeSecs, kInitialIdleTimeoutSecs, connect_using_default_network, migrate_sessions_on_network_change, migrate_sessions_early, migrate_sessions_on_network_change_v2, - migrate_sessions_early_v2, allow_server_migration, - race_cert_verification, estimate_initial_rtt, env->connection_options, + migrate_sessions_early_v2, + base::TimeDelta::FromSeconds(kMaxTimeOnNonDefaultNetworkSecs), + kMaxMigrationsToNonDefaultNetworkOnPathDegrading, + allow_server_migration, race_cert_verification, estimate_initial_rtt, + headers_include_h2_stream_dependency, env->connection_options, env->client_connection_options, enable_token_binding); QuicStreamRequest request(factory.get()); @@ -167,7 +159,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { HttpRequestInfo request_info; request_info.method = kMethod; request_info.url = GURL(kUrl); - stream->InitializeStream(&request_info, DEFAULT_PRIORITY, env->net_log, + stream->InitializeStream(&request_info, true, DEFAULT_PRIORITY, env->net_log, CompletionCallback()); HttpResponseInfo response; diff --git a/chromium/net/quic/chromium/quic_stream_factory_peer.cc b/chromium/net/quic/chromium/quic_stream_factory_peer.cc index b338abdd021..21a7b74fae4 100644 --- a/chromium/net/quic/chromium/quic_stream_factory_peer.cc +++ b/chromium/net/quic/chromium/quic_stream_factory_peer.cc @@ -8,6 +8,7 @@ #include <vector> #include "net/cert/x509_certificate.h" +#include "net/cert/x509_util.h" #include "net/quic/chromium/quic_chromium_client_session.h" #include "net/quic/chromium/quic_http_stream.h" #include "net/quic/chromium/quic_stream_factory.h" @@ -137,11 +138,7 @@ void QuicStreamFactoryPeer::CacheDummyServerConfig( scoped_refptr<X509Certificate> cert( ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem")); DCHECK(cert); - std::string der_bytes; - bool success = - X509Certificate::GetDEREncoded(cert->os_cert_handle(), &der_bytes); - DCHECK(success); - certs.push_back(der_bytes); + certs.emplace_back(x509_util::CryptoBufferAsStringPiece(cert->cert_buffer())); QuicCryptoClientConfig* crypto_config = &factory->crypto_config_; QuicCryptoClientConfig::CachedState* cached = diff --git a/chromium/net/quic/chromium/quic_stream_factory_test.cc b/chromium/net/quic/chromium/quic_stream_factory_test.cc index 7f484e21662..5cec9cce259 100644 --- a/chromium/net/quic/chromium/quic_stream_factory_test.cc +++ b/chromium/net/quic/chromium/quic_stream_factory_test.cc @@ -14,9 +14,9 @@ #include "base/run_loop.h" #include "base/strings/string_util.h" #include "net/base/mock_network_change_notifier.h" -#include "net/cert/cert_verifier.h" #include "net/cert/ct_policy_enforcer.h" -#include "net/cert/multi_log_ct_verifier.h" +#include "net/cert/do_nothing_ct_verifier.h" +#include "net/cert/mock_cert_verifier.h" #include "net/dns/mock_host_resolver.h" #include "net/http/http_response_headers.h" #include "net/http/http_response_info.h" @@ -102,19 +102,24 @@ const char kServer4Url[] = "https://images.example.org/"; // and enable_connection_racting. struct TestParams { friend std::ostream& operator<<(std::ostream& os, const TestParams& p) { - os << "{ version: " << QuicVersionToString(p.version) << " }"; + os << "{ version: " << QuicVersionToString(p.version) + << ", client_headers_include_h2_stream_dependency: " + << p.client_headers_include_h2_stream_dependency << " }"; return os; } QuicTransportVersion version; + bool client_headers_include_h2_stream_dependency; }; std::vector<TestParams> GetTestParams() { std::vector<TestParams> params; QuicTransportVersionVector all_supported_versions = AllSupportedTransportVersions(); - for (const auto& version : all_supported_versions) - params.push_back(TestParams{version}); + for (const auto& version : all_supported_versions) { + params.push_back(TestParams{version, false}); + params.push_back(TestParams{version, true}); + } return params; } @@ -136,12 +141,15 @@ struct PoolingTestParams { os << "DIFFERENT"; break; } + os << ", client_headers_include_h2_stream_dependency: " + << p.client_headers_include_h2_stream_dependency; os << " }"; return os; } QuicTransportVersion version; DestinationType destination_type; + bool client_headers_include_h2_stream_dependency; }; std::vector<PoolingTestParams> GetPoolingTestParams() { @@ -149,9 +157,12 @@ std::vector<PoolingTestParams> GetPoolingTestParams() { QuicTransportVersionVector all_supported_versions = AllSupportedTransportVersions(); for (const QuicTransportVersion version : all_supported_versions) { - params.push_back(PoolingTestParams{version, SAME_AS_FIRST}); - params.push_back(PoolingTestParams{version, SAME_AS_SECOND}); - params.push_back(PoolingTestParams{version, DIFFERENT}); + params.push_back(PoolingTestParams{version, SAME_AS_FIRST, false}); + params.push_back(PoolingTestParams{version, SAME_AS_FIRST, true}); + params.push_back(PoolingTestParams{version, SAME_AS_SECOND, false}); + params.push_back(PoolingTestParams{version, SAME_AS_SECOND, true}); + params.push_back(PoolingTestParams{version, DIFFERENT, false}); + params.push_back(PoolingTestParams{version, DIFFERENT, true}); } return params; } @@ -193,26 +204,31 @@ class TestConnectionMigrationSocketFactory : public MockClientSocketFactory { class QuicStreamFactoryTestBase { protected: - explicit QuicStreamFactoryTestBase(QuicTransportVersion version) + QuicStreamFactoryTestBase(QuicTransportVersion version, + bool client_headers_include_h2_stream_dependency) : ssl_config_service_(new MockSSLConfigService), socket_factory_(new MockClientSocketFactory), random_generator_(0), runner_(new TestTaskRunner(&clock_)), version_(version), + client_headers_include_h2_stream_dependency_( + client_headers_include_h2_stream_dependency), client_maker_(version_, 0, &clock_, kDefaultServerHostName, - Perspective::IS_CLIENT), + Perspective::IS_CLIENT, + client_headers_include_h2_stream_dependency_), server_maker_(version_, 0, &clock_, kDefaultServerHostName, - Perspective::IS_SERVER), - cert_verifier_(CertVerifier::CreateDefault()), + Perspective::IS_SERVER, + false), + cert_verifier_(std::make_unique<MockCertVerifier>()), channel_id_service_( new ChannelIDService(new DefaultChannelIDStore(nullptr))), - cert_transparency_verifier_(new MultiLogCTVerifier()), + cert_transparency_verifier_(std::make_unique<DoNothingCTVerifier>()), scoped_mock_network_change_notifier_(nullptr), factory_(nullptr), host_port_pair_(kDefaultServerHostName, kDefaultServerPort), @@ -256,9 +272,11 @@ class QuicStreamFactoryTestBase { /*connect_using_default_network*/ true, migrate_sessions_on_network_change_, migrate_sessions_early_, migrate_sessions_on_network_change_v2_, migrate_sessions_early_v2_, + base::TimeDelta::FromSeconds(kMaxTimeOnNonDefaultNetworkSecs), + kMaxMigrationsToNonDefaultNetworkOnPathDegrading, allow_server_migration_, race_cert_verification_, estimate_initial_rtt_, - connection_options_, client_connection_options_, - /*enable_token_binding*/ false)); + client_headers_include_h2_stream_dependency_, connection_options_, + client_connection_options_, /*enable_token_binding*/ false)); } void InitializeConnectionMigrationTest( @@ -412,7 +430,7 @@ class QuicStreamFactoryTestBase { size_t spdy_headers_frame_len; return client_maker_.MakeRequestHeadersPacket( packet_number, stream_id, should_include_version, fin, priority, - std::move(headers), &spdy_headers_frame_len); + std::move(headers), 0, &spdy_headers_frame_len); } std::unique_ptr<QuicEncryptedPacket> ConstructGetRequestPacket( @@ -428,7 +446,7 @@ class QuicStreamFactoryTestBase { size_t spdy_headers_frame_len; return client_maker_.MakeRequestHeadersPacket( packet_number, stream_id, should_include_version, fin, priority, - std::move(headers), &spdy_headers_frame_len, offset); + std::move(headers), 0, &spdy_headers_frame_len, offset); } std::unique_ptr<QuicEncryptedPacket> ConstructOkResponsePacket( @@ -499,8 +517,9 @@ class QuicStreamFactoryTestBase { HttpRequestInfo request_info; request_info.method = "GET"; request_info.url = GURL("https://www.example.org/"); - EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY, - net_log_, CompletionCallback())); + EXPECT_EQ(OK, + stream->InitializeStream(&request_info, true, DEFAULT_PRIORITY, + net_log_, CompletionCallback())); // Ensure that session is alive and active. QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); @@ -759,7 +778,8 @@ class QuicStreamFactoryTestBase { MockRandom random_generator_; MockClock clock_; scoped_refptr<TestTaskRunner> runner_; - QuicTransportVersion version_; + const QuicTransportVersion version_; + const bool client_headers_include_h2_stream_dependency_; QuicTestPacketMaker client_maker_; QuicTestPacketMaker server_maker_; HttpServerPropertiesImpl http_server_properties_; @@ -803,10 +823,13 @@ class QuicStreamFactoryTestBase { class QuicStreamFactoryTest : public QuicStreamFactoryTestBase, public ::testing::TestWithParam<TestParams> { protected: - QuicStreamFactoryTest() : QuicStreamFactoryTestBase(GetParam().version) {} + QuicStreamFactoryTest() + : QuicStreamFactoryTestBase( + GetParam().version, + GetParam().client_headers_include_h2_stream_dependency) {} }; -INSTANTIATE_TEST_CASE_P(Version, +INSTANTIATE_TEST_CASE_P(VersionIncludeStreamDependencySequnece, QuicStreamFactoryTest, ::testing::ValuesIn(GetTestParams())); @@ -1569,8 +1592,9 @@ TEST_P(QuicStreamFactoryTest, MaxOpenStream) { } std::unique_ptr<HttpStream> stream = CreateStream(&request); EXPECT_TRUE(stream); - EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY, - net_log_, CompletionCallback())); + EXPECT_EQ(OK, + stream->InitializeStream(&request_info, false, DEFAULT_PRIORITY, + net_log_, CompletionCallback())); streams.push_back(std::move(stream)); } @@ -1582,8 +1606,8 @@ TEST_P(QuicStreamFactoryTest, MaxOpenStream) { std::unique_ptr<HttpStream> stream = CreateStream(&request); EXPECT_TRUE(stream); EXPECT_EQ(ERR_IO_PENDING, - stream->InitializeStream(&request_info, DEFAULT_PRIORITY, net_log_, - callback_.callback())); + stream->InitializeStream(&request_info, false, DEFAULT_PRIORITY, + net_log_, callback_.callback())); // Close the first stream. streams.front()->Close(false); @@ -1700,7 +1724,7 @@ TEST_P(QuicStreamFactoryTest, CloseAllSessions) { EXPECT_THAT(callback_.WaitForResult(), IsOk()); std::unique_ptr<HttpStream> stream = CreateStream(&request); HttpRequestInfo request_info; - EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY, + EXPECT_EQ(OK, stream->InitializeStream(&request_info, false, DEFAULT_PRIORITY, net_log_, CompletionCallback())); // Close the session and verify that stream saw the error. @@ -1884,7 +1908,7 @@ TEST_P(QuicStreamFactoryTest, OnIPAddressChanged) { EXPECT_THAT(callback_.WaitForResult(), IsOk()); std::unique_ptr<HttpStream> stream = CreateStream(&request); HttpRequestInfo request_info; - EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY, + EXPECT_EQ(OK, stream->InitializeStream(&request_info, false, DEFAULT_PRIORITY, net_log_, CompletionCallback())); IPAddress last_address; @@ -1939,7 +1963,7 @@ TEST_P(QuicStreamFactoryTest, OnIPAddressChangedWithConnectionMigration) { EXPECT_THAT(callback_.WaitForResult(), IsOk()); std::unique_ptr<HttpStream> stream = CreateStream(&request); HttpRequestInfo request_info; - EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY, + EXPECT_EQ(OK, stream->InitializeStream(&request_info, false, DEFAULT_PRIORITY, net_log_, CompletionCallback())); IPAddress last_address; @@ -2008,7 +2032,7 @@ void QuicStreamFactoryTestBase::OnNetworkMadeDefault(bool async_write_before) { HttpRequestInfo request_info; request_info.method = "GET"; request_info.url = url_; - EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY, + EXPECT_EQ(OK, stream->InitializeStream(&request_info, true, DEFAULT_PRIORITY, net_log_, CompletionCallback())); // Ensure that session is alive and active. @@ -2140,7 +2164,7 @@ void QuicStreamFactoryTestBase::OnNetworkDisconnected(bool async_write_before) { HttpRequestInfo request_info; request_info.method = "GET"; request_info.url = url_; - EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY, + EXPECT_EQ(OK, stream->InitializeStream(&request_info, true, DEFAULT_PRIORITY, net_log_, CompletionCallback())); // Ensure that session is alive and active. @@ -2250,7 +2274,7 @@ void QuicStreamFactoryTestBase::OnNetworkDisconnectedWithNetworkList( // Cause QUIC stream to be created. HttpRequestInfo request_info; - EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY, + EXPECT_EQ(OK, stream->InitializeStream(&request_info, false, DEFAULT_PRIORITY, net_log_, CompletionCallback())); // Ensure that session is alive and active. @@ -2310,7 +2334,7 @@ TEST_P(QuicStreamFactoryTest, OnNetworkMadeDefaultNonMigratableStream) { // Cause QUIC stream to be created, but marked as non-migratable. HttpRequestInfo request_info; request_info.load_flags |= LOAD_DISABLE_CONNECTION_MIGRATION; - EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY, + EXPECT_EQ(OK, stream->InitializeStream(&request_info, false, DEFAULT_PRIORITY, net_log_, CompletionCallback())); // Ensure that session is alive and active. @@ -2360,7 +2384,7 @@ TEST_P(QuicStreamFactoryTest, OnNetworkMadeDefaultNonMigratableStreamV2) { // Cause QUIC stream to be created, but marked as non-migratable. HttpRequestInfo request_info; request_info.load_flags |= LOAD_DISABLE_CONNECTION_MIGRATION; - EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY, + EXPECT_EQ(OK, stream->InitializeStream(&request_info, false, DEFAULT_PRIORITY, net_log_, CompletionCallback())); // Ensure that session is alive and active. @@ -2409,7 +2433,7 @@ TEST_P(QuicStreamFactoryTest, OnNetworkMadeDefaultConnectionMigrationDisabled) { // Cause QUIC stream to be created. HttpRequestInfo request_info; - EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY, + EXPECT_EQ(OK, stream->InitializeStream(&request_info, false, DEFAULT_PRIORITY, net_log_, CompletionCallback())); // Ensure that session is alive and active. @@ -2463,7 +2487,7 @@ TEST_P(QuicStreamFactoryTest, // Cause QUIC stream to be created. HttpRequestInfo request_info; - EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY, + EXPECT_EQ(OK, stream->InitializeStream(&request_info, false, DEFAULT_PRIORITY, net_log_, CompletionCallback())); // Ensure that session is alive and active. @@ -2517,7 +2541,7 @@ TEST_P(QuicStreamFactoryTest, OnNetworkDisconnectedNonMigratableStream) { // Cause QUIC stream to be created, but marked as non-migratable. HttpRequestInfo request_info; request_info.load_flags |= LOAD_DISABLE_CONNECTION_MIGRATION; - EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY, + EXPECT_EQ(OK, stream->InitializeStream(&request_info, false, DEFAULT_PRIORITY, net_log_, CompletionCallback())); // Ensure that session is alive and active. @@ -2565,7 +2589,7 @@ TEST_P(QuicStreamFactoryTest, OnNetworkDisconnectedNonMigratableStreamV2) { // Cause QUIC stream to be created, but marked as non-migratable. HttpRequestInfo request_info; request_info.load_flags |= LOAD_DISABLE_CONNECTION_MIGRATION; - EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY, + EXPECT_EQ(OK, stream->InitializeStream(&request_info, false, DEFAULT_PRIORITY, net_log_, CompletionCallback())); // Ensure that session is alive and active. @@ -2613,7 +2637,7 @@ TEST_P(QuicStreamFactoryTest, // Cause QUIC stream to be created. HttpRequestInfo request_info; - EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY, + EXPECT_EQ(OK, stream->InitializeStream(&request_info, false, DEFAULT_PRIORITY, net_log_, CompletionCallback())); // Ensure that session is alive and active. @@ -2665,7 +2689,7 @@ TEST_P(QuicStreamFactoryTest, // Cause QUIC stream to be created. HttpRequestInfo request_info; - EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY, + EXPECT_EQ(OK, stream->InitializeStream(&request_info, false, DEFAULT_PRIORITY, net_log_, CompletionCallback())); // Ensure that session is alive and active. @@ -2882,7 +2906,7 @@ TEST_P(QuicStreamFactoryTest, NewNetworkConnectedAfterNoNetwork) { HttpRequestInfo request_info; request_info.method = "GET"; request_info.url = url_; - EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY, + EXPECT_EQ(OK, stream->InitializeStream(&request_info, true, DEFAULT_PRIORITY, net_log_, CompletionCallback())); // Ensure that session is alive and active. @@ -2989,7 +3013,7 @@ TEST_P(QuicStreamFactoryTest, OnNetworkChangeDisconnectedPauseBeforeConnected) { HttpRequestInfo request_info; request_info.method = "GET"; request_info.url = url_; - EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY, + EXPECT_EQ(OK, stream->InitializeStream(&request_info, true, DEFAULT_PRIORITY, net_log_, CompletionCallback())); // Ensure that session is alive and active. @@ -3128,8 +3152,9 @@ TEST_P(QuicStreamFactoryTest, HttpRequestInfo request_info1; request_info1.method = "GET"; request_info1.url = url_; - EXPECT_EQ(OK, stream1->InitializeStream(&request_info1, DEFAULT_PRIORITY, - net_log_, CompletionCallback())); + EXPECT_EQ(OK, + stream1->InitializeStream(&request_info1, true, DEFAULT_PRIORITY, + net_log_, CompletionCallback())); HttpResponseInfo response1; HttpRequestHeaders request_headers1; EXPECT_EQ(OK, stream1->SendRequest(request_headers1, &response1, @@ -3140,8 +3165,9 @@ TEST_P(QuicStreamFactoryTest, HttpRequestInfo request_info2; request_info2.method = "GET"; request_info2.url = url_; - EXPECT_EQ(OK, stream2->InitializeStream(&request_info2, DEFAULT_PRIORITY, - net_log_, CompletionCallback())); + EXPECT_EQ(OK, + stream2->InitializeStream(&request_info2, true, DEFAULT_PRIORITY, + net_log_, CompletionCallback())); HttpResponseInfo response2; HttpRequestHeaders request_headers2; EXPECT_EQ(OK, stream2->SendRequest(request_headers2, &response2, @@ -3210,7 +3236,7 @@ TEST_P(QuicStreamFactoryTest, MigrateSessionEarly) { HttpRequestInfo request_info; request_info.method = "GET"; request_info.url = url_; - EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY, + EXPECT_EQ(OK, stream->InitializeStream(&request_info, true, DEFAULT_PRIORITY, net_log_, CompletionCallback())); // Ensure that session is alive and active. @@ -3337,7 +3363,7 @@ TEST_P(QuicStreamFactoryTest, MigrateSessionEarlyWithAsyncWrites) { HttpRequestInfo request_info; request_info.method = "GET"; request_info.url = url_; - EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY, + EXPECT_EQ(OK, stream->InitializeStream(&request_info, true, DEFAULT_PRIORITY, net_log_, CompletionCallback())); // Ensure that session is alive and active. @@ -3456,7 +3482,7 @@ TEST_P(QuicStreamFactoryTest, MigrateSessionEarlyNoNewNetwork) { // Cause QUIC stream to be created. HttpRequestInfo request_info; - EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY, + EXPECT_EQ(OK, stream->InitializeStream(&request_info, false, DEFAULT_PRIORITY, net_log_, CompletionCallback())); // Ensure that session is alive and active. @@ -3510,7 +3536,7 @@ TEST_P(QuicStreamFactoryTest, MigrateSessionEarlyNonMigratableStream) { // Cause QUIC stream to be created, but marked as non-migratable. HttpRequestInfo request_info; request_info.load_flags |= LOAD_DISABLE_CONNECTION_MIGRATION; - EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY, + EXPECT_EQ(OK, stream->InitializeStream(&request_info, false, DEFAULT_PRIORITY, net_log_, CompletionCallback())); // Ensure that session is alive and active. @@ -3562,7 +3588,7 @@ TEST_P(QuicStreamFactoryTest, MigrateSessionEarlyConnectionMigrationDisabled) { // Cause QUIC stream to be created. HttpRequestInfo request_info; - EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY, + EXPECT_EQ(OK, stream->InitializeStream(&request_info, false, DEFAULT_PRIORITY, net_log_, CompletionCallback())); // Ensure that session is alive and active. @@ -3623,7 +3649,7 @@ void QuicStreamFactoryTestBase::TestMigrationOnWriteError( HttpRequestInfo request_info; request_info.method = "GET"; request_info.url = GURL("https://www.example.org/"); - EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY, + EXPECT_EQ(OK, stream->InitializeStream(&request_info, true, DEFAULT_PRIORITY, net_log_, CompletionCallback())); // Ensure that session is alive and active. @@ -3713,7 +3739,7 @@ void QuicStreamFactoryTestBase::TestMigrationOnWriteErrorNoNewNetwork( HttpRequestInfo request_info; request_info.method = "GET"; request_info.url = GURL("https://www.example.org/"); - EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY, + EXPECT_EQ(OK, stream->InitializeStream(&request_info, true, DEFAULT_PRIORITY, net_log_, CompletionCallback())); // Ensure that session is alive and active. @@ -3804,7 +3830,7 @@ void QuicStreamFactoryTestBase::TestMigrationOnWriteErrorNonMigratableStream( request_info.load_flags |= LOAD_DISABLE_CONNECTION_MIGRATION; request_info.method = "GET"; request_info.url = GURL("https://www.example.org/"); - EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY, + EXPECT_EQ(OK, stream->InitializeStream(&request_info, true, DEFAULT_PRIORITY, net_log_, CompletionCallback())); // Ensure that session is alive and active. @@ -3868,7 +3894,7 @@ void QuicStreamFactoryTestBase::TestMigrationOnWriteErrorMigrationDisabled( HttpRequestInfo request_info; request_info.method = "GET"; request_info.url = GURL("https://www.example.org/"); - EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY, + EXPECT_EQ(OK, stream->InitializeStream(&request_info, true, DEFAULT_PRIORITY, net_log_, CompletionCallback())); // Ensure that session is alive and active. @@ -3948,7 +3974,7 @@ void QuicStreamFactoryTestBase::TestMigrationOnMultipleWriteErrors( HttpRequestInfo request_info; request_info.method = "GET"; request_info.url = GURL("https://www.example.org/"); - EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY, + EXPECT_EQ(OK, stream->InitializeStream(&request_info, true, DEFAULT_PRIORITY, net_log_, CompletionCallback())); // Ensure that session is alive and active. @@ -4029,7 +4055,7 @@ void QuicStreamFactoryTestBase::TestMigrationOnWriteErrorWithNotificationQueued( HttpRequestInfo request_info; request_info.method = "GET"; request_info.url = GURL("https://www.example.org/"); - EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY, + EXPECT_EQ(OK, stream->InitializeStream(&request_info, true, DEFAULT_PRIORITY, net_log_, CompletionCallback())); // Ensure that session is alive and active. @@ -4128,7 +4154,7 @@ void QuicStreamFactoryTestBase::TestMigrationOnNotificationWithWriteErrorQueued( HttpRequestInfo request_info; request_info.method = "GET"; request_info.url = GURL("https://www.example.org/"); - EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY, + EXPECT_EQ(OK, stream->InitializeStream(&request_info, true, DEFAULT_PRIORITY, net_log_, CompletionCallback())); // Ensure that session is alive and active. @@ -4228,7 +4254,7 @@ void QuicStreamFactoryTestBase::TestMigrationOnWriteErrorPauseBeforeConnected( HttpRequestInfo request_info; request_info.method = "GET"; request_info.url = GURL("https://www.example.org/"); - EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY, + EXPECT_EQ(OK, stream->InitializeStream(&request_info, true, DEFAULT_PRIORITY, net_log_, CompletionCallback())); // Ensure that session is alive and active. @@ -4363,7 +4389,7 @@ void QuicStreamFactoryTestBase:: HttpRequestInfo request_info; request_info.method = "GET"; request_info.url = GURL("https://www.example.org/"); - EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY, + EXPECT_EQ(OK, stream->InitializeStream(&request_info, true, DEFAULT_PRIORITY, net_log_, CompletionCallback())); // Ensure that session is alive and active. @@ -4519,7 +4545,7 @@ TEST_P(QuicStreamFactoryTest, MigrateSessionEarlyToBadSocket) { HttpRequestInfo request_info; request_info.method = "GET"; request_info.url = url_; - EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY, + EXPECT_EQ(OK, stream->InitializeStream(&request_info, true, DEFAULT_PRIORITY, net_log_, CompletionCallback())); // Ensure that session is alive and active. @@ -4583,7 +4609,7 @@ TEST_P(QuicStreamFactoryTest, ServerMigration) { HttpRequestInfo request_info; request_info.method = "GET"; request_info.url = GURL("https://www.example.org/"); - EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY, + EXPECT_EQ(OK, stream->InitializeStream(&request_info, true, DEFAULT_PRIORITY, net_log_, CompletionCallback())); // Ensure that session is alive and active. @@ -4727,7 +4753,7 @@ TEST_P(QuicStreamFactoryTest, ServerMigrationIPv4ToIPv6Fails) { HttpRequestInfo request_info; request_info.method = "GET"; request_info.url = GURL("https://www.example.org/"); - EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY, + EXPECT_EQ(OK, stream->InitializeStream(&request_info, true, DEFAULT_PRIORITY, net_log_, CompletionCallback())); // Ensure that session is alive and active. @@ -4778,7 +4804,7 @@ TEST_P(QuicStreamFactoryTest, OnSSLConfigChanged) { EXPECT_THAT(callback_.WaitForResult(), IsOk()); std::unique_ptr<HttpStream> stream = CreateStream(&request); HttpRequestInfo request_info; - EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY, + EXPECT_EQ(OK, stream->InitializeStream(&request_info, false, DEFAULT_PRIORITY, net_log_, CompletionCallback())); ssl_config_service_->NotifySSLConfigChange(); @@ -4833,7 +4859,7 @@ TEST_P(QuicStreamFactoryTest, OnCertDBChanged) { EXPECT_THAT(callback_.WaitForResult(), IsOk()); std::unique_ptr<HttpStream> stream = CreateStream(&request); HttpRequestInfo request_info; - EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY, + EXPECT_EQ(OK, stream->InitializeStream(&request_info, false, DEFAULT_PRIORITY, net_log_, CompletionCallback())); // Change the CA cert and verify that stream saw the event. @@ -5013,7 +5039,7 @@ TEST_P(QuicStreamFactoryTest, ReducePingTimeoutOnConnectionTimeOutOpenStreams) { std::unique_ptr<HttpStream> stream = CreateStream(&request); EXPECT_TRUE(stream.get()); HttpRequestInfo request_info; - EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY, + EXPECT_EQ(OK, stream->InitializeStream(&request_info, false, DEFAULT_PRIORITY, net_log_, CompletionCallback())); DVLOG(1) @@ -5044,8 +5070,9 @@ TEST_P(QuicStreamFactoryTest, ReducePingTimeoutOnConnectionTimeOutOpenStreams) { std::unique_ptr<HttpStream> stream2 = CreateStream(&request2); EXPECT_TRUE(stream2.get()); - EXPECT_EQ(OK, stream2->InitializeStream(&request_info, DEFAULT_PRIORITY, - net_log_, CompletionCallback())); + EXPECT_EQ(OK, + stream2->InitializeStream(&request_info, false, DEFAULT_PRIORITY, + net_log_, CompletionCallback())); session2->connection()->CloseConnection( QUIC_NETWORK_IDLE_TIMEOUT, "test", ConnectionCloseBehavior::SILENT_CLOSE); // Need to spin the loop now to ensure that @@ -5376,7 +5403,9 @@ class QuicStreamFactoryWithDestinationTest public ::testing::TestWithParam<PoolingTestParams> { protected: QuicStreamFactoryWithDestinationTest() - : QuicStreamFactoryTestBase(GetParam().version), + : QuicStreamFactoryTestBase( + GetParam().version, + GetParam().client_headers_include_h2_stream_dependency), destination_type_(GetParam().destination_type), hanging_read_(SYNCHRONOUS, ERR_IO_PENDING, 0) {} @@ -5419,7 +5448,7 @@ class QuicStreamFactoryWithDestinationTest sequenced_socket_data_vector_; }; -INSTANTIATE_TEST_CASE_P(Version, +INSTANTIATE_TEST_CASE_P(VersionIncludeStreamDependencySequnece, QuicStreamFactoryWithDestinationTest, ::testing::ValuesIn(GetPoolingTestParams())); @@ -5804,5 +5833,239 @@ TEST_P(QuicStreamFactoryTest, ConfigMaxTimeBeforeCryptoHandshake) { config->max_idle_time_before_crypto_handshake()); } +// Verify ResultAfterHostResolutionCallback behavior when host resolution +// succeeds asynchronously, then crypto handshake fails synchronously. +TEST_P(QuicStreamFactoryTest, ResultAfterHostResolutionCallbackAsyncSync) { + Initialize(); + ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); + + host_resolver_.set_ondemand_mode(true); + + MockQuicData socket_data; + socket_data.AddRead(SYNCHRONOUS, ERR_FAILED); + socket_data.AddWrite(SYNCHRONOUS, ERR_FAILED); + socket_data.AddSocketDataToFactory(socket_factory_.get()); + + QuicStreamRequest request(factory_.get()); + EXPECT_EQ(ERR_IO_PENDING, + request.Request(host_port_pair_, version_, privacy_mode_, + DEFAULT_PRIORITY, + /*cert_verify_flags=*/0, url_, net_log_, + &net_error_details_, callback_.callback())); + + TestCompletionCallback host_resolution_callback; + EXPECT_TRUE( + request.WaitForHostResolution(host_resolution_callback.callback())); + + // |host_resolver_| has not finished host resolution at this point, so + // |host_resolution_callback| should not have a result. + base::RunLoop().RunUntilIdle(); + EXPECT_FALSE(host_resolution_callback.have_result()); + + // Allow |host_resolver_| to finish host resolution. + // Since the request fails immediately after host resolution (getting + // ERR_FAILED from socket reads/writes), |host_resolution_callback| should be + // called with ERR_QUIC_PROTOCOL_ERROR since that's the next result in + // forming the connection. + host_resolver_.ResolveAllPending(); + base::RunLoop().RunUntilIdle(); + EXPECT_TRUE(host_resolution_callback.have_result()); + EXPECT_EQ(ERR_QUIC_PROTOCOL_ERROR, host_resolution_callback.WaitForResult()); + + // Calling WaitForHostResolution() a second time should return + // false since host resolution has finished already. + EXPECT_FALSE( + request.WaitForHostResolution(host_resolution_callback.callback())); + + EXPECT_TRUE(callback_.have_result()); + EXPECT_EQ(ERR_QUIC_PROTOCOL_ERROR, callback_.WaitForResult()); +} + +// Verify ResultAfterHostResolutionCallback behavior when host resolution +// succeeds asynchronously, then crypto handshake fails asynchronously. +TEST_P(QuicStreamFactoryTest, ResultAfterHostResolutionCallbackAsyncAsync) { + Initialize(); + ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); + + host_resolver_.set_ondemand_mode(true); + crypto_client_stream_factory_.set_handshake_mode( + MockCryptoClientStream::ZERO_RTT); + factory_->set_require_confirmation(true); + + MockQuicData socket_data; + socket_data.AddRead(ASYNC, ERR_IO_PENDING); // Pause + socket_data.AddRead(ASYNC, ERR_FAILED); + socket_data.AddWrite(ASYNC, ERR_FAILED); + socket_data.AddSocketDataToFactory(socket_factory_.get()); + + QuicStreamRequest request(factory_.get()); + EXPECT_EQ(ERR_IO_PENDING, + request.Request(host_port_pair_, version_, privacy_mode_, + DEFAULT_PRIORITY, + /*cert_verify_flags=*/0, url_, net_log_, + &net_error_details_, callback_.callback())); + + TestCompletionCallback host_resolution_callback; + EXPECT_TRUE( + request.WaitForHostResolution(host_resolution_callback.callback())); + + // |host_resolver_| has not finished host resolution at this point, so + // |host_resolution_callback| should not have a result. + base::RunLoop().RunUntilIdle(); + EXPECT_FALSE(host_resolution_callback.have_result()); + + // Allow |host_resolver_| to finish host resolution. Since crypto handshake + // will hang after host resolution, |host_resolution_callback| should run with + // ERR_IO_PENDING since that's the next result in forming the connection. + host_resolver_.ResolveAllPending(); + base::RunLoop().RunUntilIdle(); + EXPECT_TRUE(host_resolution_callback.have_result()); + EXPECT_EQ(ERR_IO_PENDING, host_resolution_callback.WaitForResult()); + + // Calling WaitForHostResolution() a second time should return + // false since host resolution has finished already. + EXPECT_FALSE( + request.WaitForHostResolution(host_resolution_callback.callback())); + + EXPECT_FALSE(callback_.have_result()); + socket_data.GetSequencedSocketData()->Resume(); + base::RunLoop().RunUntilIdle(); + EXPECT_TRUE(callback_.have_result()); + EXPECT_EQ(ERR_QUIC_PROTOCOL_ERROR, callback_.WaitForResult()); +} + +// Verify ResultAfterHostResolutionCallback behavior when host resolution +// succeeds synchronously, then crypto handshake fails synchronously. +TEST_P(QuicStreamFactoryTest, ResultAfterHostResolutionCallbackSyncSync) { + Initialize(); + ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); + + host_resolver_.set_synchronous_mode(true); + + MockQuicData socket_data; + socket_data.AddRead(SYNCHRONOUS, ERR_FAILED); + socket_data.AddWrite(SYNCHRONOUS, ERR_FAILED); + socket_data.AddSocketDataToFactory(socket_factory_.get()); + + QuicStreamRequest request(factory_.get()); + EXPECT_EQ( + ERR_QUIC_PROTOCOL_ERROR, + request.Request(host_port_pair_, version_, privacy_mode_, + DEFAULT_PRIORITY, /*cert_verify_flags=*/0, url_, net_log_, + &net_error_details_, callback_.callback())); + + // WaitForHostResolution() should return false since host + // resolution has finished already. + TestCompletionCallback host_resolution_callback; + EXPECT_FALSE( + request.WaitForHostResolution(host_resolution_callback.callback())); + base::RunLoop().RunUntilIdle(); + EXPECT_FALSE(host_resolution_callback.have_result()); + EXPECT_FALSE(callback_.have_result()); +} + +// Verify ResultAfterHostResolutionCallback behavior when host resolution +// succeeds synchronously, then crypto handshake fails asynchronously. +TEST_P(QuicStreamFactoryTest, ResultAfterHostResolutionCallbackSyncAsync) { + Initialize(); + ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); + + // Host resolution will succeed synchronously, but Request() as a whole + // will fail asynchronously. + host_resolver_.set_synchronous_mode(true); + crypto_client_stream_factory_.set_handshake_mode( + MockCryptoClientStream::ZERO_RTT); + factory_->set_require_confirmation(true); + + MockQuicData socket_data; + socket_data.AddRead(ASYNC, ERR_IO_PENDING); // Pause + socket_data.AddRead(ASYNC, ERR_FAILED); + socket_data.AddWrite(ASYNC, ERR_FAILED); + socket_data.AddSocketDataToFactory(socket_factory_.get()); + + QuicStreamRequest request(factory_.get()); + EXPECT_EQ( + ERR_IO_PENDING, + request.Request(host_port_pair_, version_, privacy_mode_, + DEFAULT_PRIORITY, /*cert_verify_flags=*/0, url_, net_log_, + &net_error_details_, callback_.callback())); + + // WaitForHostResolution() should return false since host + // resolution has finished already. + TestCompletionCallback host_resolution_callback; + EXPECT_FALSE( + request.WaitForHostResolution(host_resolution_callback.callback())); + base::RunLoop().RunUntilIdle(); + EXPECT_FALSE(host_resolution_callback.have_result()); + + EXPECT_FALSE(callback_.have_result()); + socket_data.GetSequencedSocketData()->Resume(); + base::RunLoop().RunUntilIdle(); + EXPECT_TRUE(callback_.have_result()); + EXPECT_EQ(ERR_QUIC_PROTOCOL_ERROR, callback_.WaitForResult()); +} + +// Verify ResultAfterHostResolutionCallback behavior when host resolution fails +// synchronously. +TEST_P(QuicStreamFactoryTest, ResultAfterHostResolutionCallbackFailSync) { + Initialize(); + ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); + + // Host resolution will fail synchronously. + host_resolver_.rules()->AddSimulatedFailure(host_port_pair_.host()); + host_resolver_.set_synchronous_mode(true); + + QuicStreamRequest request(factory_.get()); + EXPECT_EQ( + ERR_NAME_NOT_RESOLVED, + request.Request(host_port_pair_, version_, privacy_mode_, + DEFAULT_PRIORITY, /*cert_verify_flags=*/0, url_, net_log_, + &net_error_details_, callback_.callback())); + + // WaitForHostResolution() should return false since host + // resolution has failed already. + TestCompletionCallback host_resolution_callback; + EXPECT_FALSE( + request.WaitForHostResolution(host_resolution_callback.callback())); + base::RunLoop().RunUntilIdle(); + EXPECT_FALSE(host_resolution_callback.have_result()); +} + +// Verify ResultAfterHostResolutionCallback behavior when host resolution fails +// asynchronously. +TEST_P(QuicStreamFactoryTest, ResultAfterHostResolutionCallbackFailAsync) { + Initialize(); + ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); + + host_resolver_.rules()->AddSimulatedFailure(host_port_pair_.host()); + + QuicStreamRequest request(factory_.get()); + EXPECT_EQ( + ERR_IO_PENDING, + request.Request(host_port_pair_, version_, privacy_mode_, + DEFAULT_PRIORITY, /*cert_verify_flags=*/0, url_, net_log_, + &net_error_details_, callback_.callback())); + + TestCompletionCallback host_resolution_callback; + EXPECT_TRUE( + request.WaitForHostResolution(host_resolution_callback.callback())); + + // Allow |host_resolver_| to fail host resolution. |host_resolution_callback| + // Should run with ERR_NAME_NOT_RESOLVED since that's the error host + // resolution failed with. + base::RunLoop().RunUntilIdle(); + EXPECT_TRUE(host_resolution_callback.have_result()); + EXPECT_EQ(ERR_NAME_NOT_RESOLVED, host_resolution_callback.WaitForResult()); + + EXPECT_TRUE(callback_.have_result()); + EXPECT_EQ(ERR_NAME_NOT_RESOLVED, callback_.WaitForResult()); +} + } // namespace test } // namespace net diff --git a/chromium/net/quic/chromium/quic_test_packet_maker.cc b/chromium/net/quic/chromium/quic_test_packet_maker.cc index c39b2073f4f..435250f978f 100644 --- a/chromium/net/quic/chromium/quic_test_packet_maker.cc +++ b/chromium/net/quic/chromium/quic_test_packet_maker.cc @@ -18,24 +18,31 @@ namespace { QuicAckFrame MakeAckFrame(QuicPacketNumber largest_observed) { QuicAckFrame ack; - ack.deprecated_largest_observed = largest_observed; + ack.largest_acked = largest_observed; return ack; } } // namespace -QuicTestPacketMaker::QuicTestPacketMaker(QuicTransportVersion version, - QuicConnectionId connection_id, - MockClock* clock, - const std::string& host, - Perspective perspective) +QuicTestPacketMaker::QuicTestPacketMaker( + QuicTransportVersion version, + QuicConnectionId connection_id, + MockClock* clock, + const std::string& host, + Perspective perspective, + bool client_headers_include_h2_stream_dependency) : version_(version), connection_id_(connection_id), clock_(clock), host_(host), spdy_request_framer_(SpdyFramer::ENABLE_COMPRESSION), spdy_response_framer_(SpdyFramer::ENABLE_COMPRESSION), - perspective_(perspective) {} + perspective_(perspective), + client_headers_include_h2_stream_dependency_( + client_headers_include_h2_stream_dependency) { + DCHECK(!(perspective_ == Perspective::IS_SERVER && + client_headers_include_h2_stream_dependency_)); +} QuicTestPacketMaker::~QuicTestPacketMaker() {} @@ -137,8 +144,9 @@ std::unique_ptr<QuicReceivedPacket> QuicTestPacketMaker::MakeAckAndRstPacket( frames.push_back(QuicFrame(&rst)); DVLOG(1) << "Adding frame: " << frames[2]; - QuicFramer framer(SupportedTransportVersions(version_), clock_->Now(), - perspective_); + QuicFramer framer( + SupportedVersions(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version_)), + clock_->Now(), perspective_); std::unique_ptr<QuicPacket> packet( BuildUnsizedDataPacket(&framer, header, frames)); char buffer[kMaxPacketSize]; @@ -190,8 +198,10 @@ QuicTestPacketMaker::MakeAckAndConnectionClosePacket( frames.push_back(QuicFrame(&close)); DVLOG(1) << "Adding frame: " << frames[2]; - QuicFramer framer(SupportedTransportVersions(version_), clock_->Now(), - perspective_); + QuicFramer framer( + SupportedVersions(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version_)), + clock_->Now(), perspective_); + std::unique_ptr<QuicPacket> packet( BuildUnsizedDataPacket(&framer, header, frames)); char buffer[kMaxPacketSize]; @@ -269,9 +279,9 @@ std::unique_ptr<QuicReceivedPacket> QuicTestPacketMaker::MakeAckPacket( if (largest_received > 0) { ack.packets.AddRange(1, largest_received + 1); } - - QuicFramer framer(SupportedTransportVersions(version_), clock_->Now(), - perspective_); + QuicFramer framer( + SupportedVersions(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version_)), + clock_->Now(), perspective_); QuicFrames frames; QuicFrame ack_frame(&ack); DVLOG(1) << "Adding frame: " << ack_frame; @@ -373,16 +383,13 @@ QuicTestPacketMaker::MakeRequestHeadersAndMultipleDataFramesPacket( bool fin, SpdyPriority priority, SpdyHeaderBlock headers, + QuicStreamId parent_stream_id, QuicStreamOffset* header_stream_offset, size_t* spdy_headers_frame_length, const std::vector<std::string>& data_writes) { InitializeHeader(packet_number, should_include_version); - SpdySerializedFrame spdy_frame; - SpdyHeadersIR headers_frame(stream_id, std::move(headers)); - headers_frame.set_fin(fin); - headers_frame.set_weight(Spdy3PriorityToHttp2Weight(priority)); - headers_frame.set_has_priority(true); - spdy_frame = spdy_request_framer_.SerializeFrame(headers_frame); + SpdySerializedFrame spdy_frame = MakeSpdyHeadersFrame( + stream_id, fin, priority, std::move(headers), parent_stream_id); if (spdy_headers_frame_length) { *spdy_headers_frame_length = spdy_frame.size(); @@ -423,10 +430,11 @@ QuicTestPacketMaker::MakeRequestHeadersPacket( bool fin, SpdyPriority priority, SpdyHeaderBlock headers, + QuicStreamId parent_stream_id, size_t* spdy_headers_frame_length) { return MakeRequestHeadersPacket( packet_number, stream_id, should_include_version, fin, priority, - std::move(headers), spdy_headers_frame_length, nullptr); + std::move(headers), parent_stream_id, spdy_headers_frame_length, nullptr); } // If |offset| is provided, will use the value when creating the packet. @@ -438,12 +446,13 @@ QuicTestPacketMaker::MakeRequestHeadersPacket(QuicPacketNumber packet_number, bool fin, SpdyPriority priority, SpdyHeaderBlock headers, + QuicStreamId parent_stream_id, size_t* spdy_headers_frame_length, QuicStreamOffset* offset) { std::string unused_stream_data; return MakeRequestHeadersPacketAndSaveData( packet_number, stream_id, should_include_version, fin, priority, - std::move(headers), spdy_headers_frame_length, offset, + std::move(headers), parent_stream_id, spdy_headers_frame_length, offset, &unused_stream_data); } @@ -455,16 +464,13 @@ QuicTestPacketMaker::MakeRequestHeadersPacketAndSaveData( bool fin, SpdyPriority priority, SpdyHeaderBlock headers, + QuicStreamId parent_stream_id, size_t* spdy_headers_frame_length, QuicStreamOffset* offset, std::string* stream_data) { InitializeHeader(packet_number, should_include_version); - SpdySerializedFrame spdy_frame; - SpdyHeadersIR headers_frame(stream_id, std::move(headers)); - headers_frame.set_fin(fin); - headers_frame.set_weight(Spdy3PriorityToHttp2Weight(priority)); - headers_frame.set_has_priority(true); - spdy_frame = spdy_request_framer_.SerializeFrame(headers_frame); + SpdySerializedFrame spdy_frame = MakeSpdyHeadersFrame( + stream_id, fin, priority, std::move(headers), parent_stream_id); *stream_data = std::string(spdy_frame.data(), spdy_frame.size()); if (spdy_headers_frame_length) @@ -485,6 +491,28 @@ QuicTestPacketMaker::MakeRequestHeadersPacketAndSaveData( } } +SpdySerializedFrame QuicTestPacketMaker::MakeSpdyHeadersFrame( + QuicStreamId stream_id, + bool fin, + SpdyPriority priority, + SpdyHeaderBlock headers, + QuicStreamId parent_stream_id) { + SpdyHeadersIR headers_frame(stream_id, std::move(headers)); + headers_frame.set_fin(fin); + headers_frame.set_weight(Spdy3PriorityToHttp2Weight(priority)); + headers_frame.set_has_priority(true); + + if (client_headers_include_h2_stream_dependency_) { + headers_frame.set_parent_stream_id(parent_stream_id); + headers_frame.set_exclusive(true); + } else { + headers_frame.set_parent_stream_id(0); + headers_frame.set_exclusive(false); + } + + return spdy_request_framer_.SerializeFrame(headers_frame); +} + // Convenience method for calling MakeRequestHeadersPacket with nullptr for // |spdy_headers_frame_length|. std::unique_ptr<QuicReceivedPacket> @@ -495,10 +523,11 @@ QuicTestPacketMaker::MakeRequestHeadersPacketWithOffsetTracking( bool fin, SpdyPriority priority, SpdyHeaderBlock headers, + QuicStreamId parent_stream_id, QuicStreamOffset* offset) { - return MakeRequestHeadersPacket(packet_number, stream_id, - should_include_version, fin, priority, - std::move(headers), nullptr, offset); + return MakeRequestHeadersPacket( + packet_number, stream_id, should_include_version, fin, priority, + std::move(headers), parent_stream_id, nullptr, offset); } // If |offset| is provided, will use the value when creating the packet. @@ -657,8 +686,9 @@ std::unique_ptr<QuicReceivedPacket> QuicTestPacketMaker::MakePacket( std::unique_ptr<QuicReceivedPacket> QuicTestPacketMaker::MakeMultipleFramesPacket(const QuicPacketHeader& header, const QuicFrames& frames) { - QuicFramer framer(SupportedTransportVersions(version_), clock_->Now(), - perspective_); + QuicFramer framer( + SupportedVersions(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version_)), + clock_->Now(), perspective_); std::unique_ptr<QuicPacket> packet( BuildUnsizedDataPacket(&framer, header, frames)); char buffer[kMaxPacketSize]; diff --git a/chromium/net/quic/chromium/quic_test_packet_maker.h b/chromium/net/quic/chromium/quic_test_packet_maker.h index c476d828c04..201f5fdb0ca 100644 --- a/chromium/net/quic/chromium/quic_test_packet_maker.h +++ b/chromium/net/quic/chromium/quic_test_packet_maker.h @@ -27,11 +27,18 @@ namespace test { class QuicTestPacketMaker { public: + // |client_headers_include_h2_stream_dependency| affects the output of + // the MakeRequestHeaders...() methods. If its value is true, then request + // headers are constructed with the exclusive flag set to true and the parent + // stream id set to the |parent_stream_id| param of MakeRequestHeaders...(). + // Otherwise, headers are constructed with the exclusive flag set to false and + // the parent stream ID set to 0 (ignoring the |parent_stream_id| param). QuicTestPacketMaker(QuicTransportVersion version, QuicConnectionId connection_id, MockClock* clock, const std::string& host, - Perspective perspective); + Perspective perspective, + bool client_headers_include_h2_stream_dependency); ~QuicTestPacketMaker(); void set_hostname(const std::string& host); @@ -137,6 +144,7 @@ class QuicTestPacketMaker { bool fin, SpdyPriority priority, SpdyHeaderBlock headers, + QuicStreamId parent_stream_id, QuicStreamOffset* header_stream_offset, size_t* spdy_headers_frame_length, const std::vector<std::string>& data_writes); @@ -150,6 +158,7 @@ class QuicTestPacketMaker { bool fin, SpdyPriority priority, SpdyHeaderBlock headers, + QuicStreamId parent_stream_id, size_t* spdy_headers_frame_length); std::unique_ptr<QuicReceivedPacket> MakeRequestHeadersPacket( @@ -159,6 +168,7 @@ class QuicTestPacketMaker { bool fin, SpdyPriority priority, SpdyHeaderBlock headers, + QuicStreamId parent_stream_id, size_t* spdy_headers_frame_length, QuicStreamOffset* offset); @@ -170,6 +180,7 @@ class QuicTestPacketMaker { bool fin, SpdyPriority priority, SpdyHeaderBlock headers, + QuicStreamId parent_stream_id, size_t* spdy_headers_frame_length, QuicStreamOffset* offset, std::string* stream_data); @@ -183,6 +194,7 @@ class QuicTestPacketMaker { bool fin, SpdyPriority priority, SpdyHeaderBlock headers, + QuicStreamId parent_stream_id, QuicStreamOffset* offset); // If |spdy_headers_frame_length| is non-null, it will be set to the size of @@ -257,6 +269,12 @@ class QuicTestPacketMaker { void InitializeHeader(QuicPacketNumber packet_number, bool should_include_version); + SpdySerializedFrame MakeSpdyHeadersFrame(QuicStreamId stream_id, + bool fin, + SpdyPriority priority, + SpdyHeaderBlock headers, + QuicStreamId parent_stream_id); + QuicTransportVersion version_; QuicConnectionId connection_id_; MockClock* clock_; // Owned by QuicStreamFactory. @@ -267,6 +285,10 @@ class QuicTestPacketMaker { QuicPacketHeader header_; Perspective perspective_; + // If true, generated request headers will include non-default HTTP2 stream + // dependency info. + bool client_headers_include_h2_stream_dependency_; + DISALLOW_COPY_AND_ASSIGN(QuicTestPacketMaker); }; diff --git a/chromium/net/quic/core/congestion_control/bbr_sender.cc b/chromium/net/quic/core/congestion_control/bbr_sender.cc index 6f2f5a01da0..4da5df3d93f 100644 --- a/chromium/net/quic/core/congestion_control/bbr_sender.cc +++ b/chromium/net/quic/core/congestion_control/bbr_sender.cc @@ -9,7 +9,6 @@ #include "net/quic/core/congestion_control/rtt_stats.h" #include "net/quic/core/crypto/crypto_protocol.h" -#include "net/quic/core/proto/cached_network_parameters.pb.h" #include "net/quic/platform/api/quic_bug_tracker.h" #include "net/quic/platform/api/quic_flag_utils.h" #include "net/quic/platform/api/quic_flags.h" @@ -22,7 +21,7 @@ namespace { const QuicByteCount kMaxSegmentSize = kDefaultTCPMSS; // The minimum CWND to ensure delayed acks don't reduce bandwidth measurements. // Does not inflate the pacing rate. -const QuicByteCount kMinimumCongestionWindow = 4 * kMaxSegmentSize; +const QuicByteCount kDefaultMinimumCongestionWindow = 4 * kMaxSegmentSize; // The gain used for the slow start, equal to 2/ln(2). const float kHighGain = 2.885f; @@ -100,6 +99,7 @@ BbrSender::BbrSender(const RttStats* rtt_stats, initial_congestion_window_(initial_tcp_congestion_window * kDefaultTCPMSS), max_congestion_window_(max_tcp_congestion_window * kDefaultTCPMSS), + min_congestion_window_(kDefaultMinimumCongestionWindow), pacing_rate_(QuicBandwidth::Zero()), pacing_gain_(1), congestion_window_gain_(1), @@ -211,7 +211,7 @@ void BbrSender::SetFromConfig(const QuicConfig& config, if (config.HasClientRequestedIndependentOption(k2RTT, perspective)) { num_startup_rtts_ = 2; } - if (FLAGS_quic_reloadable_flag_quic_bbr_rate_recovery && + if (GetQuicReloadableFlag(quic_bbr_rate_recovery) && config.HasClientRequestedIndependentOption(kBBRR, perspective)) { rate_based_recovery_ = true; } @@ -221,61 +221,47 @@ void BbrSender::SetFromConfig(const QuicConfig& config, if (config.HasClientRequestedIndependentOption(kBBR2, perspective)) { max_aggregation_bytes_multiplier_ = 2; } - if (FLAGS_quic_reloadable_flag_quic_bbr_slower_startup && - config.HasClientRequestedIndependentOption(kBBRS, perspective)) { - QUIC_FLAG_COUNT(quic_reloadable_flag_quic_bbr_slower_startup); + if (config.HasClientRequestedIndependentOption(kBBRS, perspective)) { slower_startup_ = true; } - if (FLAGS_quic_reloadable_flag_quic_bbr_fully_drain_queue && - config.HasClientRequestedIndependentOption(kBBR3, perspective)) { - QUIC_FLAG_COUNT(quic_reloadable_flag_quic_bbr_fully_drain_queue); + if (config.HasClientRequestedIndependentOption(kBBR3, perspective)) { fully_drain_queue_ = true; } - if (FLAGS_quic_reloadable_flag_quic_bbr_conservation_in_startup && - config.HasClientRequestedIndependentOption(kBBS1, perspective)) { - QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_bbr_conservation_in_startup, 1, - 3); + if (config.HasClientRequestedIndependentOption(kBBS1, perspective)) { rate_based_startup_ = true; } - if (FLAGS_quic_reloadable_flag_quic_bbr_conservation_in_startup && - config.HasClientRequestedIndependentOption(kBBS2, perspective)) { - QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_bbr_conservation_in_startup, 2, - 3); + if (config.HasClientRequestedIndependentOption(kBBS2, perspective)) { initial_conservation_in_startup_ = MEDIUM_GROWTH; } - if (FLAGS_quic_reloadable_flag_quic_bbr_conservation_in_startup && - config.HasClientRequestedIndependentOption(kBBS3, perspective)) { - QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_bbr_conservation_in_startup, 3, - 3); + if (config.HasClientRequestedIndependentOption(kBBS3, perspective)) { initial_conservation_in_startup_ = GROWTH; } - if (FLAGS_quic_reloadable_flag_quic_bbr_ack_aggregation_window && - config.HasClientRequestedIndependentOption(kBBR4, perspective)) { - QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_bbr_ack_aggregation_window, 1, - 2); + if (config.HasClientRequestedIndependentOption(kBBR4, perspective)) { max_ack_height_.SetWindowLength(2 * kBandwidthWindowSize); } - if (FLAGS_quic_reloadable_flag_quic_bbr_ack_aggregation_window && - config.HasClientRequestedIndependentOption(kBBR5, perspective)) { - QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_bbr_ack_aggregation_window, 2, - 2); + if (config.HasClientRequestedIndependentOption(kBBR5, perspective)) { max_ack_height_.SetWindowLength(4 * kBandwidthWindowSize); } - if (FLAGS_quic_reloadable_flag_quic_bbr_less_probe_rtt && + if (GetQuicReloadableFlag(quic_bbr_less_probe_rtt) && config.HasClientRequestedIndependentOption(kBBR6, perspective)) { QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_bbr_less_probe_rtt, 1, 3); probe_rtt_based_on_bdp_ = true; } - if (FLAGS_quic_reloadable_flag_quic_bbr_less_probe_rtt && + if (GetQuicReloadableFlag(quic_bbr_less_probe_rtt) && config.HasClientRequestedIndependentOption(kBBR7, perspective)) { QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_bbr_less_probe_rtt, 2, 3); probe_rtt_skipped_if_similar_rtt_ = true; } - if (FLAGS_quic_reloadable_flag_quic_bbr_less_probe_rtt && + if (GetQuicReloadableFlag(quic_bbr_less_probe_rtt) && config.HasClientRequestedIndependentOption(kBBR8, perspective)) { QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_bbr_less_probe_rtt, 3, 3); probe_rtt_disabled_if_app_limited_ = true; } + if (GetQuicReloadableFlag(quic_one_tlp) && + config.HasClientRequestedIndependentOption(kMIN1, perspective)) { + QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_one_tlp, 2, 2); + min_congestion_window_ = kMaxSegmentSize; + } } void BbrSender::AdjustNetworkParameters(QuicBandwidth bandwidth, @@ -373,14 +359,14 @@ QuicByteCount BbrSender::GetTargetCongestionWindow(float gain) const { congestion_window = gain * initial_congestion_window_; } - return std::max(congestion_window, kMinimumCongestionWindow); + return std::max(congestion_window, min_congestion_window_); } QuicByteCount BbrSender::ProbeRttCongestionWindow() const { if (probe_rtt_based_on_bdp_) { return GetTargetCongestionWindow(kModerateProbeRttMultiplier); } - return kMinimumCongestionWindow; + return min_congestion_window_; } void BbrSender::EnterStartupMode() { @@ -719,7 +705,7 @@ void BbrSender::CalculateCongestionWindow(QuicByteCount bytes_acked) { target_window += max_ack_height_.GetBest(); } - if (FLAGS_quic_reloadable_flag_quic_bbr_add_tso_cwnd) { + if (GetQuicReloadableFlag(quic_bbr_add_tso_cwnd)) { // QUIC doesn't have TSO, but it does have similarly quantized pacing, so // allow extra CWND to make QUIC's BBR CWND identical to TCP's. QuicByteCount tso_segs_goal = 0; @@ -749,7 +735,7 @@ void BbrSender::CalculateCongestionWindow(QuicByteCount bytes_acked) { } // Enforce the limits on the congestion window. - congestion_window_ = std::max(congestion_window_, kMinimumCongestionWindow); + congestion_window_ = std::max(congestion_window_, min_congestion_window_); congestion_window_ = std::min(congestion_window_, max_congestion_window_); } @@ -766,7 +752,7 @@ void BbrSender::CalculateRecoveryWindow(QuicByteCount bytes_acked, // Set up the initial recovery window. if (recovery_window_ == 0) { recovery_window_ = unacked_packets_->bytes_in_flight() + bytes_acked; - recovery_window_ = std::max(kMinimumCongestionWindow, recovery_window_); + recovery_window_ = std::max(min_congestion_window_, recovery_window_); return; } @@ -789,7 +775,7 @@ void BbrSender::CalculateRecoveryWindow(QuicByteCount bytes_acked, // |bytes_acked| in response. recovery_window_ = std::max( recovery_window_, unacked_packets_->bytes_in_flight() + bytes_acked); - recovery_window_ = std::max(kMinimumCongestionWindow, recovery_window_); + recovery_window_ = std::max(min_congestion_window_, recovery_window_); } std::string BbrSender::GetDebugState() const { diff --git a/chromium/net/quic/core/congestion_control/bbr_sender.h b/chromium/net/quic/core/congestion_control/bbr_sender.h index 149bc06c811..122abe35db1 100644 --- a/chromium/net/quic/core/congestion_control/bbr_sender.h +++ b/chromium/net/quic/core/congestion_control/bbr_sender.h @@ -268,6 +268,9 @@ class QUIC_EXPORT_PRIVATE BbrSender : public SendAlgorithmInterface { // The largest value the |congestion_window_| can achieve. QuicByteCount max_congestion_window_; + // The smallest value the |congestion_window_| can achieve. + QuicByteCount min_congestion_window_; + // The current pacing rate of the connection. QuicBandwidth pacing_rate_; diff --git a/chromium/net/quic/core/congestion_control/bbr_sender_test.cc b/chromium/net/quic/core/congestion_control/bbr_sender_test.cc index 450f610d8d5..a229e8ac06f 100644 --- a/chromium/net/quic/core/congestion_control/bbr_sender_test.cc +++ b/chromium/net/quic/core/congestion_control/bbr_sender_test.cc @@ -92,7 +92,7 @@ class BbrSenderTest : public QuicTest { receiver_multiplexer_("Receiver multiplexer", {&receiver_, &competing_receiver_}) { // These will be changed by the appropriate tests as necessary. - FLAGS_quic_reloadable_flag_quic_bbr_add_tso_cwnd = false; + SetQuicReloadableFlag(quic_bbr_add_tso_cwnd, false); rtt_stats_ = bbr_sender_.connection()->sent_packet_manager().GetRttStats(); sender_ = SetupBbrSender(&bbr_sender_); @@ -253,7 +253,7 @@ class BbrSenderTest : public QuicTest { // Test a simple long data transfer in the default setup. TEST_F(BbrSenderTest, SimpleTransfer) { // Adding TSO CWND causes packet loss before exiting startup. - FLAGS_quic_reloadable_flag_quic_bbr_add_tso_cwnd = false; + SetQuicReloadableFlag(quic_bbr_add_tso_cwnd, false); CreateDefaultSetup(); // At startup make sure we are at the default. @@ -301,7 +301,7 @@ TEST_F(BbrSenderTest, SimpleTransferSmallBuffer) { // Test a simple long data transfer with 2 rtts of aggregation. TEST_F(BbrSenderTest, SimpleTransfer2RTTAggregationBytes) { - FLAGS_quic_reloadable_flag_quic_bbr_add_tso_cwnd = false; + SetQuicReloadableFlag(quic_bbr_add_tso_cwnd, false); CreateDefaultSetup(); // 2 RTTs of aggregation, with a max of 10kb. EnableAggregation(10 * 1024, 2 * kTestRtt); @@ -361,7 +361,7 @@ TEST_F(BbrSenderTest, SimpleTransferAckDecimation) { // Test a simple long data transfer with 2 rtts of aggregation. TEST_F(BbrSenderTest, SimpleTransfer2RTTAggregationBytes4) { - FLAGS_quic_reloadable_flag_quic_bbr_add_tso_cwnd = false; + SetQuicReloadableFlag(quic_bbr_add_tso_cwnd, false); CreateDefaultSetup(); // Enable ack aggregation that forces the queue to be drained. @@ -427,8 +427,7 @@ TEST_F(BbrSenderTest, SimpleTransferAckDecimation4) { // Test a simple long data transfer with 2 rtts of aggregation. TEST_F(BbrSenderTest, SimpleTransfer2RTTAggregationBytes20RTTWindow) { - FLAGS_quic_reloadable_flag_quic_bbr_add_tso_cwnd = false; - FLAGS_quic_reloadable_flag_quic_bbr_ack_aggregation_window = true; + SetQuicReloadableFlag(quic_bbr_add_tso_cwnd, false); CreateDefaultSetup(); SetConnectionOption(kBBR4); // 2 RTTs of aggregation, with a max of 10kb. @@ -454,8 +453,7 @@ TEST_F(BbrSenderTest, SimpleTransfer2RTTAggregationBytes20RTTWindow) { // Test a simple long data transfer with 2 rtts of aggregation. TEST_F(BbrSenderTest, SimpleTransfer2RTTAggregationBytes40RTTWindow) { - FLAGS_quic_reloadable_flag_quic_bbr_add_tso_cwnd = false; - FLAGS_quic_reloadable_flag_quic_bbr_ack_aggregation_window = true; + SetQuicReloadableFlag(quic_bbr_add_tso_cwnd, false); CreateDefaultSetup(); SetConnectionOption(kBBR5); // 2 RTTs of aggregation, with a max of 10kb. @@ -552,7 +550,6 @@ TEST_F(BbrSenderTest, StartupMediumRecoveryStates) { const QuicTime::Delta timeout = QuicTime::Delta::FromSeconds(10); bool simulator_result; CreateSmallBufferSetup(); - FLAGS_quic_reloadable_flag_quic_bbr_conservation_in_startup = true; SetConnectionOption(kBBS2); bbr_sender_.AddBytesToTransfer(100 * 1024 * 1024); @@ -603,7 +600,6 @@ TEST_F(BbrSenderTest, StartupGrowthRecoveryStates) { const QuicTime::Delta timeout = QuicTime::Delta::FromSeconds(10); bool simulator_result; CreateSmallBufferSetup(); - FLAGS_quic_reloadable_flag_quic_bbr_conservation_in_startup = true; SetConnectionOption(kBBS3); bbr_sender_.AddBytesToTransfer(100 * 1024 * 1024); @@ -748,7 +744,7 @@ TEST_F(BbrSenderTest, ProbeRtt) { // Verify that the connection enters and exits PROBE_RTT correctly. TEST_F(BbrSenderTest, ProbeRttBDPBasedCWNDTarget) { CreateDefaultSetup(); - FLAGS_quic_reloadable_flag_quic_bbr_less_probe_rtt = true; + SetQuicReloadableFlag(quic_bbr_less_probe_rtt, true); SetConnectionOption(kBBR6); DriveOutOfStartup(); @@ -777,7 +773,7 @@ TEST_F(BbrSenderTest, ProbeRttBDPBasedCWNDTarget) { // Verify that the connection enters does not enter PROBE_RTT. TEST_F(BbrSenderTest, ProbeRttSkippedAfterAppLimitedAndStableRtt) { CreateDefaultSetup(); - FLAGS_quic_reloadable_flag_quic_bbr_less_probe_rtt = true; + SetQuicReloadableFlag(quic_bbr_less_probe_rtt, true); SetConnectionOption(kBBR7); DriveOutOfStartup(); @@ -798,7 +794,7 @@ TEST_F(BbrSenderTest, ProbeRttSkippedAfterAppLimitedAndStableRtt) { // Verify that the connection enters does not enter PROBE_RTT. TEST_F(BbrSenderTest, ProbeRttSkippedAfterAppLimited) { CreateDefaultSetup(); - FLAGS_quic_reloadable_flag_quic_bbr_less_probe_rtt = true; + SetQuicReloadableFlag(quic_bbr_less_probe_rtt, true); SetConnectionOption(kBBR8); DriveOutOfStartup(); @@ -919,7 +915,7 @@ TEST_F(BbrSenderTest, SimpleTransfer1RTTStartup) { // Test exiting STARTUP earlier due to the 2RTT connection option. TEST_F(BbrSenderTest, SimpleTransfer2RTTStartup) { // Adding TSO CWND causes packet loss before exiting startup. - FLAGS_quic_reloadable_flag_quic_bbr_add_tso_cwnd = false; + SetQuicReloadableFlag(quic_bbr_add_tso_cwnd, false); CreateDefaultSetup(); SetConnectionOption(k2RTT); @@ -1005,8 +1001,7 @@ TEST_F(BbrSenderTest, SimpleTransferLRTTStartupSmallBuffer) { // Test slower pacing after loss in STARTUP due to the BBRS connection option. TEST_F(BbrSenderTest, SimpleTransferSlowerStartup) { // Adding TSO CWND causes packet loss before exiting startup. - FLAGS_quic_reloadable_flag_quic_bbr_add_tso_cwnd = false; - FLAGS_quic_reloadable_flag_quic_bbr_slower_startup = true; + SetQuicReloadableFlag(quic_bbr_add_tso_cwnd, false); CreateSmallBufferSetup(); SetConnectionOption(kBBRS); @@ -1042,8 +1037,7 @@ TEST_F(BbrSenderTest, SimpleTransferSlowerStartup) { // Ensures no change in congestion window in STARTUP after loss. TEST_F(BbrSenderTest, SimpleTransferNoConservationInStartup) { // Adding TSO CWND causes packet loss before exiting startup. - FLAGS_quic_reloadable_flag_quic_bbr_add_tso_cwnd = false; - FLAGS_quic_reloadable_flag_quic_bbr_conservation_in_startup = true; + SetQuicReloadableFlag(quic_bbr_add_tso_cwnd, false); CreateSmallBufferSetup(); SetConnectionOption(kBBS1); @@ -1108,5 +1102,36 @@ TEST_F(BbrSenderTest, ResumeConnectionState) { DriveOutOfStartup(); } +// Test with a min CWND of 1 instead of 4 packets. +TEST_F(BbrSenderTest, ProbeRTTMinCWND1) { + SetQuicReloadableFlag(quic_one_tlp, true); + CreateDefaultSetup(); + SetConnectionOption(kMIN1); + DriveOutOfStartup(); + + // We have no intention of ever finishing this transfer. + bbr_sender_.AddBytesToTransfer(100 * 1024 * 1024); + + // Wait until the connection enters PROBE_RTT. + const QuicTime::Delta timeout = QuicTime::Delta::FromSeconds(12); + bool simulator_result = simulator_.RunUntilOrTimeout( + [this]() { + return sender_->ExportDebugState().mode == BbrSender::PROBE_RTT; + }, + timeout); + ASSERT_TRUE(simulator_result); + ASSERT_EQ(BbrSender::PROBE_RTT, sender_->ExportDebugState().mode); + // The PROBE_RTT CWND should be 1 if the min CWND is 1. + EXPECT_EQ(kDefaultTCPMSS, sender_->GetCongestionWindow()); + + // Exit PROBE_RTT. + const QuicTime probe_rtt_start = clock_->Now(); + const QuicTime::Delta time_to_exit_probe_rtt = + kTestRtt + QuicTime::Delta::FromMilliseconds(200); + simulator_.RunFor(1.5 * time_to_exit_probe_rtt); + EXPECT_EQ(BbrSender::PROBE_BW, sender_->ExportDebugState().mode); + EXPECT_GE(sender_->ExportDebugState().min_rtt_timestamp, probe_rtt_start); +} + } // namespace test } // namespace net diff --git a/chromium/net/quic/core/congestion_control/cubic.cc b/chromium/net/quic/core/congestion_control/cubic.cc deleted file mode 100644 index 37d0aafb712..00000000000 --- a/chromium/net/quic/core/congestion_control/cubic.cc +++ /dev/null @@ -1,227 +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/quic/core/congestion_control/cubic.h" - -#include <algorithm> -#include <cmath> -#include <cstdint> - -#include "net/quic/core/quic_packets.h" -#include "net/quic/platform/api/quic_flag_utils.h" -#include "net/quic/platform/api/quic_flags.h" -#include "net/quic/platform/api/quic_logging.h" - -namespace net { - -namespace { - -// Constants based on TCP defaults. -// The following constants are in 2^10 fractions of a second instead of ms to -// allow a 10 shift right to divide. -const int kCubeScale = 40; // 1024*1024^3 (first 1024 is from 0.100^3) - // where 0.100 is 100 ms which is the scaling - // round trip time. -const int kCubeCongestionWindowScale = 410; -const uint64_t kCubeFactor = - (UINT64_C(1) << kCubeScale) / kCubeCongestionWindowScale; - -const uint32_t kDefaultNumConnections = 2; -const float kBeta = 0.7f; // Default Cubic backoff factor. -// Additional backoff factor when loss occurs in the concave part of the Cubic -// curve. This additional backoff factor is expected to give up bandwidth to -// new concurrent flows and speed up convergence. -const float kBetaLastMax = 0.85f; - -} // namespace - -Cubic::Cubic(const QuicClock* clock) - : clock_(clock), - num_connections_(kDefaultNumConnections), - epoch_(QuicTime::Zero()), - app_limited_start_time_(QuicTime::Zero()), - last_update_time_(QuicTime::Zero()), - fix_convex_mode_(FLAGS_quic_reloadable_flag_quic_enable_cubic_fixes), - fix_beta_last_max_(fix_convex_mode_), - allow_per_ack_updates_(fix_convex_mode_) { - ResetCubicState(); - if (fix_convex_mode_) { - QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_enable_cubic_fixes, 1, 2); - } -} - -void Cubic::SetNumConnections(int num_connections) { - num_connections_ = num_connections; -} - -float Cubic::Alpha() const { - // TCPFriendly alpha is described in Section 3.3 of the CUBIC paper. Note that - // beta here is a cwnd multiplier, and is equal to 1-beta from the paper. - // We derive the equivalent alpha for an N-connection emulation as: - const float beta = Beta(); - return 3 * num_connections_ * num_connections_ * (1 - beta) / (1 + beta); -} - -float Cubic::Beta() const { - // kNConnectionBeta is the backoff factor after loss for our N-connection - // emulation, which emulates the effective backoff of an ensemble of N - // TCP-Reno connections on a single loss event. The effective multiplier is - // computed as: - return (num_connections_ - 1 + kBeta) / num_connections_; -} - -float Cubic::BetaLastMax() const { - // BetaLastMax is the additional backoff factor after loss for our - // N-connection emulation, which emulates the additional backoff of - // an ensemble of N TCP-Reno connections on a single loss event. The - // effective multiplier is computed as: - return fix_beta_last_max_ - ? (num_connections_ - 1 + kBetaLastMax) / num_connections_ - : kBetaLastMax; -} - -void Cubic::ResetCubicState() { - epoch_ = QuicTime::Zero(); // Reset time. - app_limited_start_time_ = QuicTime::Zero(); - last_update_time_ = QuicTime::Zero(); // Reset time. - last_congestion_window_ = 0; - last_max_congestion_window_ = 0; - acked_packets_count_ = 0; - epoch_packets_count_ = 0; - estimated_tcp_congestion_window_ = 0; - origin_point_congestion_window_ = 0; - time_to_origin_point_ = 0; - last_target_congestion_window_ = 0; -} - -void Cubic::OnApplicationLimited() { - // When sender is not using the available congestion window, Cubic's epoch - // should not continue growing. Reset the epoch when in such a period. - epoch_ = QuicTime::Zero(); -} - -void Cubic::SetFixConvexMode(bool fix_convex_mode) { - fix_convex_mode_ = fix_convex_mode; -} - -void Cubic::SetFixBetaLastMax(bool fix_beta_last_max) { - fix_beta_last_max_ = fix_beta_last_max; -} - -void Cubic::SetAllowPerAckUpdates(bool allow_per_ack_updates) { - allow_per_ack_updates_ = allow_per_ack_updates; -} - -QuicPacketCount Cubic::CongestionWindowAfterPacketLoss( - QuicPacketCount current_congestion_window) { - if (current_congestion_window < last_max_congestion_window_) { - // We never reached the old max, so assume we are competing with another - // flow. Use our extra back off factor to allow the other flow to go up. - last_max_congestion_window_ = - static_cast<int>(BetaLastMax() * current_congestion_window); - } else { - last_max_congestion_window_ = current_congestion_window; - } - epoch_ = QuicTime::Zero(); // Reset time. - return static_cast<int>(current_congestion_window * Beta()); -} - -QuicPacketCount Cubic::CongestionWindowAfterAck( - QuicPacketCount current_congestion_window, - QuicTime::Delta delay_min, - QuicTime event_time) { - acked_packets_count_ += 1; // Packets acked. - epoch_packets_count_ += 1; - // Cubic is "independent" of RTT, the update is limited by the time elapsed. - if (!allow_per_ack_updates_ && - last_congestion_window_ == current_congestion_window && - (event_time - last_update_time_ <= MaxCubicTimeInterval())) { - return std::max(last_target_congestion_window_, - estimated_tcp_congestion_window_); - } - last_congestion_window_ = current_congestion_window; - last_update_time_ = event_time; - - if (!epoch_.IsInitialized()) { - // First ACK after a loss event. - epoch_ = event_time; // Start of epoch. - acked_packets_count_ = 1; // Reset count. - epoch_packets_count_ = 1; - // Reset estimated_tcp_congestion_window_ to be in sync with cubic. - estimated_tcp_congestion_window_ = current_congestion_window; - if (last_max_congestion_window_ <= current_congestion_window) { - time_to_origin_point_ = 0; - origin_point_congestion_window_ = current_congestion_window; - } else { - time_to_origin_point_ = static_cast<uint32_t>( - cbrt(kCubeFactor * - (last_max_congestion_window_ - current_congestion_window))); - origin_point_congestion_window_ = last_max_congestion_window_; - } - } - - // Change the time unit from microseconds to 2^10 fractions per second. Take - // the round trip time in account. This is done to allow us to use shift as a - // divide operator. - const int64_t elapsed_time = - ((event_time + delay_min - epoch_).ToMicroseconds() << 10) / - kNumMicrosPerSecond; - DCHECK_GE(elapsed_time, 0); - - int64_t offset = time_to_origin_point_ - elapsed_time; - if (fix_convex_mode_) { - // Right-shifts of negative, signed numbers have - // implementation-dependent behavior. Force the offset to be - // positive, similar to the kernel implementation. - offset = std::abs(time_to_origin_point_ - elapsed_time); - } - - QuicPacketCount delta_congestion_window = - (kCubeCongestionWindowScale * offset * offset * offset) >> kCubeScale; - - const bool add_delta = elapsed_time > time_to_origin_point_; - DCHECK(add_delta || - (origin_point_congestion_window_ > delta_congestion_window)); - QuicPacketCount target_congestion_window = - (fix_convex_mode_ && add_delta) - ? origin_point_congestion_window_ + delta_congestion_window - : origin_point_congestion_window_ - delta_congestion_window; - - // Limit the CWND increase to half the acked packets rounded up to the - // nearest packet. - target_congestion_window = - std::min(target_congestion_window, - current_congestion_window + (epoch_packets_count_ + 1) / 2); - - DCHECK_LT(0u, estimated_tcp_congestion_window_); - // With dynamic beta/alpha based on number of active streams, it is possible - // for the required_ack_count to become much lower than acked_packets_count_ - // suddenly, leading to more than one iteration through the following loop. - while (true) { - // Update estimated TCP congestion_window. - QuicPacketCount required_ack_count = static_cast<QuicPacketCount>( - estimated_tcp_congestion_window_ / Alpha()); - if (acked_packets_count_ < required_ack_count) { - break; - } - acked_packets_count_ -= required_ack_count; - estimated_tcp_congestion_window_++; - } - epoch_packets_count_ = 0; - - // We have a new cubic congestion window. - last_target_congestion_window_ = target_congestion_window; - - // Compute target congestion_window based on cubic target and estimated TCP - // congestion_window, use highest (fastest). - if (target_congestion_window < estimated_tcp_congestion_window_) { - target_congestion_window = estimated_tcp_congestion_window_; - } - - QUIC_DVLOG(1) << "Final target congestion_window: " - << target_congestion_window; - return target_congestion_window; -} - -} // namespace net diff --git a/chromium/net/quic/core/congestion_control/cubic.h b/chromium/net/quic/core/congestion_control/cubic.h deleted file mode 100644 index a2f99463032..00000000000 --- a/chromium/net/quic/core/congestion_control/cubic.h +++ /dev/null @@ -1,144 +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. -// -// Cubic algorithm, helper class to TCP cubic. -// For details see http://netsrv.csc.ncsu.edu/export/cubic_a_new_tcp_2008.pdf. - -#ifndef NET_QUIC_CORE_CONGESTION_CONTROL_CUBIC_H_ -#define NET_QUIC_CORE_CONGESTION_CONTROL_CUBIC_H_ - -#include <cstdint> - -#include "base/macros.h" -#include "net/quic/core/quic_bandwidth.h" -#include "net/quic/core/quic_connection_stats.h" -#include "net/quic/core/quic_time.h" -#include "net/quic/platform/api/quic_clock.h" -#include "net/quic/platform/api/quic_export.h" - -namespace net { - -namespace test { -class CubicTest; -} // namespace test - -class QUIC_EXPORT_PRIVATE Cubic { - public: - explicit Cubic(const QuicClock* clock); - - void SetNumConnections(int num_connections); - - // Call after a timeout to reset the cubic state. - void ResetCubicState(); - - // Compute a new congestion window to use after a loss event. - // Returns the new congestion window in packets. The new congestion window is - // a multiplicative decrease of our current window. - QuicPacketCount CongestionWindowAfterPacketLoss(QuicPacketCount current); - - // Compute a new congestion window to use after a received ACK. - // Returns the new congestion window in packets. The new congestion - // window follows a cubic function that depends on the time passed - // since last packet loss. - QuicPacketCount CongestionWindowAfterAck(QuicPacketCount current, - QuicTime::Delta delay_min, - QuicTime event_time); - - // Call on ack arrival when sender is unable to use the available congestion - // window. Resets Cubic state during quiescence. - void OnApplicationLimited(); - - // Methods for enabling experimental modes. - // If true, enable the fix for the convex-mode signing bug. See - // b/32170105 for more information about the bug. - // TODO(jokulik): Remove once the fix is enabled by default. - void SetFixConvexMode(bool fix_convex_mode); - // If true, enable per-ack updates. See b/32170105 for more - // information about the bug. TODO(jokulik): Remove once this - // change is enabled by default. - void SetAllowPerAckUpdates(bool allow_per_ack_updates); - - // If true, enable the fix for scaling BetaLastMax for n-nonnection - // emulation. See b/33272010 for more information about the bug. - // TODO(jokulik): Remove once the fix is enabled by default. - void SetFixBetaLastMax(bool fix_bet_last_max); - - private: - friend class test::CubicTest; - - static const QuicTime::Delta MaxCubicTimeInterval() { - return QuicTime::Delta::FromMilliseconds(30); - } - - // Compute the TCP Cubic alpha, beta, and beta-last-max based on the - // current number of connections. - float Alpha() const; - float Beta() const; - float BetaLastMax() const; - - QuicByteCount last_max_congestion_window() const { - return last_max_congestion_window_; - } - - const QuicClock* clock_; - - // Number of connections to simulate. - int num_connections_; - - // Time when this cycle started, after last loss event. - QuicTime epoch_; - - // Time when sender went into application-limited period. Zero if not in - // application-limited period. - QuicTime app_limited_start_time_; - - // Time when we updated last_congestion_window. - QuicTime last_update_time_; - - // Last congestion window (in packets) used. - QuicPacketCount last_congestion_window_; - - // Max congestion window (in packets) used just before last loss event. - // Note: to improve fairness to other streams an additional back off is - // applied to this value if the new value is below our latest value. - QuicPacketCount last_max_congestion_window_; - - // Number of acked packets accumulated to increase the CWND via Reno - // 'tcp friendly' mode. - QuicPacketCount acked_packets_count_; - - // Number of acked packets since the cycle started (epoch). - // Used to limit CWND increases to 1/2 the number of acked packets. - QuicPacketCount epoch_packets_count_; - - // TCP Reno equivalent congestion window in packets. - QuicPacketCount estimated_tcp_congestion_window_; - - // Origin point of cubic function. - QuicPacketCount origin_point_congestion_window_; - - // Time to origin point of cubic function in 2^10 fractions of a second. - uint32_t time_to_origin_point_; - - // Last congestion window in packets computed by cubic function. - QuicPacketCount last_target_congestion_window_; - - // Fix convex mode for cubic. - // TODO(jokulik): Remove once the cubic convex experiment is done. - bool fix_convex_mode_; - - // Fix beta last max for n-connection-emulation. - // TODO(jokulik): Remove once the corresponding experiment is done. - bool fix_beta_last_max_; - - // Allow cubic per ack updates. - // TODO(jokulik): Remove once the per ack update experiment is done. - bool allow_per_ack_updates_; - - DISALLOW_COPY_AND_ASSIGN(Cubic); -}; - -} // namespace net - -#endif // NET_QUIC_CORE_CONGESTION_CONTROL_CUBIC_H_ diff --git a/chromium/net/quic/core/congestion_control/cubic_bytes.cc b/chromium/net/quic/core/congestion_control/cubic_bytes.cc index 33dc0de7e60..1df0fd44da1 100644 --- a/chromium/net/quic/core/congestion_control/cubic_bytes.cc +++ b/chromium/net/quic/core/congestion_control/cubic_bytes.cc @@ -40,16 +40,8 @@ const float kBetaLastMax = 0.85f; CubicBytes::CubicBytes(const QuicClock* clock) : clock_(clock), num_connections_(kDefaultNumConnections), - epoch_(QuicTime::Zero()), - last_update_time_(QuicTime::Zero()), - fix_convex_mode_(FLAGS_quic_reloadable_flag_quic_enable_cubic_fixes), - fix_cubic_quantization_(fix_convex_mode_), - fix_beta_last_max_(fix_convex_mode_), - allow_per_ack_updates_(fix_convex_mode_) { + epoch_(QuicTime::Zero()) { ResetCubicState(); - if (fix_convex_mode_) { - QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_enable_cubic_fixes, 2, 2); - } } void CubicBytes::SetNumConnections(int num_connections) { @@ -77,15 +69,11 @@ float CubicBytes::BetaLastMax() const { // N-connection emulation, which emulates the additional backoff of // an ensemble of N TCP-Reno connections on a single loss event. The // effective multiplier is computed as: - return fix_beta_last_max_ - ? (num_connections_ - 1 + kBetaLastMax) / num_connections_ - : kBetaLastMax; + return (num_connections_ - 1 + kBetaLastMax) / num_connections_; } void CubicBytes::ResetCubicState() { epoch_ = QuicTime::Zero(); // Reset time. - last_update_time_ = QuicTime::Zero(); // Reset time. - last_congestion_window_ = 0; last_max_congestion_window_ = 0; acked_bytes_count_ = 0; estimated_tcp_congestion_window_ = 0; @@ -94,22 +82,6 @@ void CubicBytes::ResetCubicState() { last_target_congestion_window_ = 0; } -void CubicBytes::SetFixConvexMode(bool fix_convex_mode) { - fix_convex_mode_ = fix_convex_mode; -} - -void CubicBytes::SetFixCubicQuantization(bool fix_cubic_quantization) { - fix_cubic_quantization_ = fix_cubic_quantization; -} - -void CubicBytes::SetFixBetaLastMax(bool fix_beta_last_max) { - fix_beta_last_max_ = fix_beta_last_max; -} - -void CubicBytes::SetAllowPerAckUpdates(bool allow_per_ack_updates) { - allow_per_ack_updates_ = allow_per_ack_updates; -} - void CubicBytes::OnApplicationLimited() { // When sender is not using the available congestion window, the window does // not grow. But to be RTT-independent, Cubic assumes that the sender has been @@ -127,9 +99,7 @@ QuicByteCount CubicBytes::CongestionWindowAfterPacketLoss( // Since bytes-mode Reno mode slightly under-estimates the cwnd, we // may never reach precisely the last cwnd over the course of an // RTT. Do not interpret a slight under-estimation as competing traffic. - const QuicByteCount last_window_delta = - fix_beta_last_max_ ? kDefaultTCPMSS : 0; - if (current_congestion_window + last_window_delta < + if (current_congestion_window + kDefaultTCPMSS < last_max_congestion_window_) { // We never reached the old max, so assume we are competing with // another flow. Use our extra back off factor to allow the other @@ -149,15 +119,6 @@ QuicByteCount CubicBytes::CongestionWindowAfterAck( QuicTime::Delta delay_min, QuicTime event_time) { acked_bytes_count_ += acked_bytes; - // Cubic is "independent" of RTT, the update is limited by the time elapsed. - if (!allow_per_ack_updates_ && - (last_congestion_window_ == current_congestion_window && - (event_time - last_update_time_ <= MaxCubicTimeInterval()))) { - return std::max(last_target_congestion_window_, - estimated_tcp_congestion_window_); - } - last_congestion_window_ = current_congestion_window; - last_update_time_ = event_time; if (!epoch_.IsInitialized()) { // First ACK after a loss event. @@ -183,32 +144,20 @@ QuicByteCount CubicBytes::CongestionWindowAfterAck( ((event_time + delay_min - epoch_).ToMicroseconds() << 10) / kNumMicrosPerSecond; - // TODO(ianswett): Change to uint64_t once fix_convex_mode_ is always enabled. - int64_t offset = time_to_origin_point_ - elapsed_time; - if (fix_convex_mode_) { - // Right-shifts of negative, signed numbers have - // implementation-dependent behavior. In the fix, force the - // offset to be positive, as is done in the kernel. - const int64_t positive_offset = - std::abs(time_to_origin_point_ - elapsed_time); - offset = positive_offset; - } - QuicByteCount delta_congestion_window = - fix_cubic_quantization_ - ? (kCubeCongestionWindowScale * offset * offset * offset * - kDefaultTCPMSS) >> - kCubeScale - : ((kCubeCongestionWindowScale * offset * offset * offset) >> - kCubeScale) * - kDefaultTCPMSS; + // Right-shifts of negative, signed numbers have implementation-dependent + // behavior, so force the offset to be positive, as is done in the kernel. + uint64_t offset = std::abs(time_to_origin_point_ - elapsed_time); + + QuicByteCount delta_congestion_window = (kCubeCongestionWindowScale * offset * + offset * offset * kDefaultTCPMSS) >> + kCubeScale; const bool add_delta = elapsed_time > time_to_origin_point_; DCHECK(add_delta || (origin_point_congestion_window_ > delta_congestion_window)); QuicByteCount target_congestion_window = - (fix_convex_mode_ && add_delta) - ? origin_point_congestion_window_ + delta_congestion_window - : origin_point_congestion_window_ - delta_congestion_window; + add_delta ? origin_point_congestion_window_ + delta_congestion_window + : origin_point_congestion_window_ - delta_congestion_window; // Limit the CWND increase to half the acked bytes. target_congestion_window = std::min(target_congestion_window, diff --git a/chromium/net/quic/core/congestion_control/cubic_bytes.h b/chromium/net/quic/core/congestion_control/cubic_bytes.h index 55f55591369..8c31b95cb7d 100644 --- a/chromium/net/quic/core/congestion_control/cubic_bytes.h +++ b/chromium/net/quic/core/congestion_control/cubic_bytes.h @@ -50,23 +50,6 @@ class QUIC_EXPORT_PRIVATE CubicBytes { // window. Resets Cubic state during quiescence. void OnApplicationLimited(); - // If true, enable the fix for the convex-mode signing bug. See - // b/32170105 for more information about the bug. - // TODO(jokulik): Remove once the fix is enabled by default. - void SetFixConvexMode(bool fix_convex_mode); - // If true, fix CubicBytes quantization bug. See b/33273459 for - // more information about the bug. - // TODO(jokulik): Remove once the fix is enabled by default. - void SetFixCubicQuantization(bool fix_cubic_quantization); - // If true, enable the fix for scaling BetaLastMax for n-nonnection - // emulation. See b/33272010 for more information about the bug. - // TODO(jokulik): Remove once the fix is enabled by default. - void SetFixBetaLastMax(bool fix_beta_last_max); - // If true, unconditionally enable each ack to update the congestion - // window. See b/33410956 for further information about this bug. - // TODO(jokulik): Remove once the fix is enabled by default. - void SetAllowPerAckUpdates(bool allow_per_ack_updates); - private: friend class test::CubicBytesTest; @@ -92,12 +75,6 @@ class QUIC_EXPORT_PRIVATE CubicBytes { // Time when this cycle started, after last loss event. QuicTime epoch_; - // Time when we updated last_congestion_window. - QuicTime last_update_time_; - - // Last congestion window used. - QuicByteCount last_congestion_window_; - // Max congestion window used just before last loss event. // Note: to improve fairness to other streams an additional back off is // applied to this value if the new value is below our latest value. @@ -118,23 +95,6 @@ class QUIC_EXPORT_PRIVATE CubicBytes { // Last congestion window in packets computed by cubic function. QuicByteCount last_target_congestion_window_; - // Fix convex mode for cubic. - // TODO(jokulik): Remove once the cubic convex experiment is done. - bool fix_convex_mode_; - - // Fix for quantization in cubic mode. - // TODO(jokulik): Remove once the experiment is done. - bool fix_cubic_quantization_; - - // Fix beta last max for n-connection-emulation. - // TODO(jokulik): Remove once the corresponding experiment is done. - bool fix_beta_last_max_; - - // Allow per ack updates, rather than limiting the frequency of - // updates when in cubic-mode. - // TODO(jokulik): Remove once the experiment is done. - bool allow_per_ack_updates_; - DISALLOW_COPY_AND_ASSIGN(CubicBytes); }; diff --git a/chromium/net/quic/core/congestion_control/cubic_bytes_test.cc b/chromium/net/quic/core/congestion_control/cubic_bytes_test.cc index b009b1d258d..6d6468e5ebe 100644 --- a/chromium/net/quic/core/congestion_control/cubic_bytes_test.cc +++ b/chromium/net/quic/core/congestion_control/cubic_bytes_test.cc @@ -26,67 +26,14 @@ const float kNConnectionBetaLastMax = const float kNConnectionAlpha = 3 * kNumConnections * kNumConnections * (1 - kNConnectionBeta) / (1 + kNConnectionBeta); -struct TestParams { - TestParams(bool fix_convex_mode, - bool fix_cubic_quantization, - bool fix_beta_last_max, - bool allow_per_ack_updates) - : fix_convex_mode(fix_convex_mode), - fix_cubic_quantization(fix_cubic_quantization), - fix_beta_last_max(fix_beta_last_max), - allow_per_ack_updates(allow_per_ack_updates) {} - - friend std::ostream& operator<<(std::ostream& os, const TestParams& p) { - os << "{ fix_convex_mode: " << p.fix_convex_mode - << " fix_cubic_quantization: " << p.fix_cubic_quantization - << " fix_beta_last_max: " << p.fix_beta_last_max - << " allow_per_ack_updates: " << p.allow_per_ack_updates << " }"; - return os; - } - - bool fix_convex_mode; - bool fix_cubic_quantization; - bool fix_beta_last_max; - bool allow_per_ack_updates; -}; - -string TestParamToString(const testing::TestParamInfo<TestParams>& params) { - return QuicStrCat("convex_mode_", params.param.fix_convex_mode, "_", - "cubic_quantization_", params.param.fix_cubic_quantization, - "_", "beta_last_max_", params.param.fix_beta_last_max, "_", - "allow_per_ack_updates_", - params.param.allow_per_ack_updates); -} - -std::vector<TestParams> GetTestParams() { - std::vector<TestParams> params; - for (bool fix_convex_mode : {true, false}) { - for (bool fix_cubic_quantization : {true, false}) { - for (bool fix_beta_last_max : {true, false}) { - for (bool allow_per_ack_updates : {true, false}) { - TestParams param(fix_convex_mode, fix_cubic_quantization, - fix_beta_last_max, allow_per_ack_updates); - params.push_back(param); - } - } - } - } - return params; -} - } // namespace -class CubicBytesTest : public QuicTestWithParam<TestParams> { +class CubicBytesTest : public QuicTest { protected: CubicBytesTest() : one_ms_(QuicTime::Delta::FromMilliseconds(1)), hundred_ms_(QuicTime::Delta::FromMilliseconds(100)), - cubic_(&clock_) { - cubic_.SetFixConvexMode(GetParam().fix_convex_mode); - cubic_.SetFixCubicQuantization(GetParam().fix_cubic_quantization); - cubic_.SetFixBetaLastMax(GetParam().fix_beta_last_max); - cubic_.SetAllowPerAckUpdates(GetParam().allow_per_ack_updates); - } + cubic_(&clock_) {} QuicByteCount RenoCwndInBytes(QuicByteCount current_cwnd) { QuicByteCount reno_estimated_cwnd = @@ -106,9 +53,7 @@ class CubicBytesTest : public QuicTestWithParam<TestParams> { const int64_t offset = ((elapsed_time + rtt).ToMicroseconds() << 10) / 1000000; const QuicByteCount delta_congestion_window = - GetParam().fix_cubic_quantization - ? ((410 * offset * offset * offset) * kDefaultTCPMSS >> 40) - : ((410 * offset * offset * offset) >> 40) * kDefaultTCPMSS; + ((410 * offset * offset * offset) * kDefaultTCPMSS >> 40); const QuicByteCount cubic_cwnd = initial_cwnd + delta_congestion_window; return cubic_cwnd; } @@ -127,27 +72,11 @@ class CubicBytesTest : public QuicTestWithParam<TestParams> { CubicBytes cubic_; }; -INSTANTIATE_TEST_CASE_P(CubicBytesTests, - CubicBytesTest, - ::testing::ValuesIn(GetTestParams()), - TestParamToString); - // TODO(jokulik): The original "AboveOrigin" test, below, is very // loose. It's nearly impossible to make the test tighter without // deploying the fix for convex mode. Once cubic convex is deployed, // replace "AboveOrigin" with this test. -TEST_P(CubicBytesTest, AboveOriginWithTighterBounds) { - if (!GetParam().fix_convex_mode) { - // Without convex mode fixed, the behavior of the algorithm is so - // far from expected, there's no point in doing a tighter test. - return; - } - if (!GetParam().fix_cubic_quantization && GetParam().allow_per_ack_updates) { - // Without quantization mode fixed, the behavior of per ack - // updates is so far from expected, there is no point of a tighter - // test. - return; - } +TEST_F(CubicBytesTest, AboveOriginWithTighterBounds) { // Convex growth. const QuicTime::Delta rtt_min = hundred_ms_; int64_t rtt_min_ms = rtt_min.ToMilliseconds(); @@ -166,13 +95,8 @@ TEST_P(CubicBytesTest, AboveOriginWithTighterBounds) { // The maximum number of expected Reno RTTs is calculated by // finding the point where the cubic curve and the reno curve meet. const int max_reno_rtts = - GetParam().fix_cubic_quantization - ? std::sqrt(kNConnectionAlpha / - (.4 * rtt_min_s * rtt_min_s * rtt_min_s)) - - 2 - : std::sqrt(kNConnectionAlpha / - (.4 * rtt_min_s * rtt_min_s * rtt_min_s)) - - 1; + std::sqrt(kNConnectionAlpha / (.4 * rtt_min_s * rtt_min_s * rtt_min_s)) - + 2; for (int i = 0; i < max_reno_rtts; ++i) { // Alternatively, we expect it to increase by one, every time we // receive current_cwnd/Alpha acks back. (This is another way of @@ -198,19 +122,6 @@ TEST_P(CubicBytesTest, AboveOriginWithTighterBounds) { clock_.AdvanceTime(hundred_ms_); } - if (!GetParam().fix_cubic_quantization) { - // Because our byte-wise Reno under-estimates the cwnd, we switch to - // conservative increases for a few acks before switching to true - // cubic increases. - for (int i = 0; i < 3; ++i) { - const QuicByteCount next_expected_cwnd = - ConservativeCwndInBytes(current_cwnd); - current_cwnd = cubic_.CongestionWindowAfterAck( - kDefaultTCPMSS, current_cwnd, rtt_min, clock_.ApproximateNow()); - ASSERT_EQ(next_expected_cwnd, current_cwnd); - } - } - for (int i = 0; i < 54; ++i) { const uint64_t max_acks_this_epoch = current_cwnd / kDefaultTCPMSS; const QuicTime::Delta interval = QuicTime::Delta::FromMicroseconds( @@ -221,20 +132,10 @@ TEST_P(CubicBytesTest, AboveOriginWithTighterBounds) { kDefaultTCPMSS, current_cwnd, rtt_min, clock_.ApproximateNow()); const QuicByteCount expected_cwnd = CubicConvexCwndInBytes( initial_cwnd, rtt_min, (clock_.ApproximateNow() - initial_time)); - if (GetParam().allow_per_ack_updates) { - // If we allow per-ack updates, every update is a small cubic update. - ASSERT_EQ(expected_cwnd, current_cwnd); - } else { - // If we do not allow per-ack updates, we get sporadic cubic updates. - ASSERT_GE(expected_cwnd, current_cwnd); - } + // If we allow per-ack updates, every update is a small cubic update. + ASSERT_EQ(expected_cwnd, current_cwnd); } } - if (!GetParam().allow_per_ack_updates) { - // If we don't allow per-ack updates, we need to artificially - // advance the clock to make the cwnd increase. - clock_.AdvanceTime(MaxCubicTimeInterval()); - } const QuicByteCount expected_cwnd = CubicConvexCwndInBytes( initial_cwnd, rtt_min, (clock_.ApproximateNow() - initial_time)); current_cwnd = cubic_.CongestionWindowAfterAck( @@ -242,24 +143,15 @@ TEST_P(CubicBytesTest, AboveOriginWithTighterBounds) { ASSERT_EQ(expected_cwnd, current_cwnd); } -TEST_P(CubicBytesTest, AboveOrigin) { - if ((!GetParam().fix_convex_mode && GetParam().fix_cubic_quantization) || - GetParam().allow_per_ack_updates) { - // Without convex mode fixed, the behavior of the algorithm does - // not fit the exact pattern of this test. - // TODO(jokulik): Once the convex mode fix becomes default, this - // test can be replaced with the better AboveOriginTighterBounds - // test. - return; - } +// TODO(ianswett): This test was disabled when all fixes were enabled, but it +// may be worth fixing. +TEST_F(CubicBytesTest, DISABLED_AboveOrigin) { // Convex growth. const QuicTime::Delta rtt_min = hundred_ms_; QuicByteCount current_cwnd = 10 * kDefaultTCPMSS; // Without the signed-integer, cubic-convex fix, we start out in the // wrong mode. - QuicPacketCount expected_cwnd = GetParam().fix_convex_mode - ? RenoCwndInBytes(current_cwnd) - : ConservativeCwndInBytes(current_cwnd); + QuicPacketCount expected_cwnd = RenoCwndInBytes(current_cwnd); // Initialize the state. clock_.AdvanceTime(one_ms_); ASSERT_EQ(expected_cwnd, @@ -280,16 +172,11 @@ TEST_P(CubicBytesTest, AboveOrigin) { clock_.AdvanceTime(hundred_ms_); current_cwnd = cubic_.CongestionWindowAfterAck( kDefaultTCPMSS, current_cwnd, rtt_min, clock_.ApproximateNow()); - if (GetParam().fix_convex_mode) { - // When we fix convex mode and the uint64 arithmetic, we - // increase the expected_cwnd only after after the first 100ms, - // rather than after the initial 1ms. - expected_cwnd += kDefaultTCPMSS; - ASSERT_NEAR(expected_cwnd, current_cwnd, kDefaultTCPMSS); - } else { - ASSERT_NEAR(expected_cwnd, current_cwnd, kDefaultTCPMSS); - expected_cwnd += kDefaultTCPMSS; - } + // When we fix convex mode and the uint64 arithmetic, we + // increase the expected_cwnd only after after the first 100ms, + // rather than after the initial 1ms. + expected_cwnd += kDefaultTCPMSS; + ASSERT_NEAR(expected_cwnd, current_cwnd, kDefaultTCPMSS); } // Cubic phase. for (int i = 0; i < 52; ++i) { @@ -310,10 +197,6 @@ TEST_P(CubicBytesTest, AboveOrigin) { expected_cwnd = initial_cwnd / kDefaultTCPMSS + (elapsed_time_s * elapsed_time_s * elapsed_time_s * 410) / 1024; - // Without the convex mode fix, the result is off by one. - if (!GetParam().fix_convex_mode) { - ++expected_cwnd; - } EXPECT_EQ(expected_cwnd, current_cwnd / kDefaultTCPMSS); } @@ -326,12 +209,7 @@ TEST_P(CubicBytesTest, AboveOrigin) { // // - Sets an artificially large initial cwnd to prevent Reno from the // convex increases on every ack. -TEST_P(CubicBytesTest, AboveOriginFineGrainedCubing) { - if (!GetParam().fix_convex_mode || !GetParam().fix_cubic_quantization) { - // Without these two fixes, this test cannot pass. - return; - } - +TEST_F(CubicBytesTest, AboveOriginFineGrainedCubing) { // Start the test with an artificially large cwnd to prevent Reno // from over-taking cubic. QuicByteCount current_cwnd = 1000 * kDefaultTCPMSS; @@ -373,13 +251,7 @@ TEST_P(CubicBytesTest, AboveOriginFineGrainedCubing) { // cwnd. When we limit per-ack updates, this would cause the // cessation of cubic updates for 30ms. When we allow per-ack // updates, the window continues to grow on every ack. -TEST_P(CubicBytesTest, PerAckUpdates) { - if (!GetParam().fix_convex_mode || !GetParam().fix_cubic_quantization || - !GetParam().allow_per_ack_updates) { - // Without these fixes, this test will fail. - return; - } - +TEST_F(CubicBytesTest, PerAckUpdates) { // Start the test with a large cwnd and RTT, to force the first // increase to be a cubic increase. QuicPacketCount initial_cwnd_packets = 150; @@ -431,14 +303,12 @@ TEST_P(CubicBytesTest, PerAckUpdates) { EXPECT_LT(minimum_expected_increase + initial_cwnd, current_cwnd); } -TEST_P(CubicBytesTest, LossEvents) { +TEST_F(CubicBytesTest, LossEvents) { const QuicTime::Delta rtt_min = hundred_ms_; QuicByteCount current_cwnd = 422 * kDefaultTCPMSS; // Without the signed-integer, cubic-convex fix, we mistakenly // increment cwnd after only one_ms_ and a single ack. - QuicPacketCount expected_cwnd = GetParam().fix_convex_mode - ? RenoCwndInBytes(current_cwnd) - : current_cwnd + kDefaultTCPMSS / 2; + QuicPacketCount expected_cwnd = RenoCwndInBytes(current_cwnd); // Initialize the state. clock_.AdvanceTime(one_ms_); EXPECT_EQ(expected_cwnd, @@ -466,27 +336,13 @@ TEST_P(CubicBytesTest, LossEvents) { current_cwnd = expected_cwnd; EXPECT_GT(pre_loss_cwnd, LastMaxCongestionWindow()); QuicByteCount expected_last_max = - GetParam().fix_beta_last_max - ? static_cast<QuicByteCount>(pre_loss_cwnd * kNConnectionBetaLastMax) - : static_cast<QuicByteCount>(pre_loss_cwnd * kBetaLastMax); + static_cast<QuicByteCount>(pre_loss_cwnd * kNConnectionBetaLastMax); EXPECT_EQ(expected_last_max, LastMaxCongestionWindow()); - if (GetParam().fix_beta_last_max) { - EXPECT_LT(expected_cwnd, LastMaxCongestionWindow()); - } else { - // If we don't scale kLastBetaMax, the current window is exactly - // equal to the last max congestion window, which would cause us - // to land above the origin on the next increase. - EXPECT_EQ(expected_cwnd, LastMaxCongestionWindow()); - } + EXPECT_LT(expected_cwnd, LastMaxCongestionWindow()); // Simulate an increase, and check that we are below the origin. current_cwnd = cubic_.CongestionWindowAfterAck( kDefaultTCPMSS, current_cwnd, rtt_min, clock_.ApproximateNow()); - if (GetParam().fix_beta_last_max) { - EXPECT_GT(LastMaxCongestionWindow(), current_cwnd); - } else { - // Without the bug fix, we will be at or above the origin. - EXPECT_LE(LastMaxCongestionWindow(), current_cwnd); - } + EXPECT_GT(LastMaxCongestionWindow(), current_cwnd); // On the final loss, simulate the condition where the congestion // window had a chance to grow nearly to the last congestion window. @@ -495,22 +351,17 @@ TEST_P(CubicBytesTest, LossEvents) { expected_cwnd = static_cast<QuicByteCount>(current_cwnd * kNConnectionBeta); EXPECT_EQ(expected_cwnd, cubic_.CongestionWindowAfterPacketLoss(current_cwnd)); - expected_last_max = - GetParam().fix_beta_last_max - ? pre_loss_cwnd - : static_cast<QuicByteCount>(pre_loss_cwnd * kBetaLastMax); + expected_last_max = pre_loss_cwnd; ASSERT_EQ(expected_last_max, LastMaxCongestionWindow()); } -TEST_P(CubicBytesTest, BelowOrigin) { +TEST_F(CubicBytesTest, BelowOrigin) { // Concave growth. const QuicTime::Delta rtt_min = hundred_ms_; QuicByteCount current_cwnd = 422 * kDefaultTCPMSS; // Without the signed-integer, cubic-convex fix, we mistakenly // increment cwnd after only one_ms_ and a single ack. - QuicPacketCount expected_cwnd = GetParam().fix_convex_mode - ? RenoCwndInBytes(current_cwnd) - : current_cwnd + kDefaultTCPMSS / 2; + QuicPacketCount expected_cwnd = RenoCwndInBytes(current_cwnd); // Initialize the state. clock_.AdvanceTime(one_ms_); EXPECT_EQ(expected_cwnd, diff --git a/chromium/net/quic/core/congestion_control/cubic_test.cc b/chromium/net/quic/core/congestion_control/cubic_test.cc deleted file mode 100644 index 47733b7d087..00000000000 --- a/chromium/net/quic/core/congestion_control/cubic_test.cc +++ /dev/null @@ -1,367 +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/quic/core/congestion_control/cubic.h" - -#include <cstdint> - -#include "net/quic/platform/api/quic_flags.h" -#include "net/quic/platform/api/quic_str_cat.h" -#include "net/quic/platform/api/quic_test.h" -#include "net/quic/test_tools/mock_clock.h" - -using std::string; - -namespace net { -namespace test { -namespace { - -const float kBeta = 0.7f; // Default Cubic backoff factor. -const float kBetaLastMax = 0.85f; // Default Cubic backoff factor. -const uint32_t kNumConnections = 2; -const float kNConnectionBeta = (kNumConnections - 1 + kBeta) / kNumConnections; -const float kNConnectionBetaLastMax = - (kNumConnections - 1 + kBetaLastMax) / kNumConnections; -const float kNConnectionAlpha = 3 * kNumConnections * kNumConnections * - (1 - kNConnectionBeta) / (1 + kNConnectionBeta); - -struct TestParams { - TestParams(bool fix_convex_mode, - bool fix_beta_last_max, - bool allow_per_ack_updates) - : fix_convex_mode(fix_convex_mode), - fix_beta_last_max(fix_beta_last_max), - allow_per_ack_updates(allow_per_ack_updates) {} - - friend std::ostream& operator<<(std::ostream& os, const TestParams& p) { - os << "{ fix_convex_mode: " << p.fix_convex_mode - << " fix_beta_last_max: " << p.fix_beta_last_max - << " allow_per_ack_updates: " << p.allow_per_ack_updates << " }"; - return os; - } - - bool fix_convex_mode; - bool fix_beta_last_max; - bool allow_per_ack_updates; -}; - -string TestParamToString(const testing::TestParamInfo<TestParams>& params) { - return QuicStrCat("convex_mode_", params.param.fix_convex_mode, "_", - "beta_last_max_", params.param.fix_beta_last_max, "_", - "allow_per_ack_updates_", - params.param.allow_per_ack_updates); -} - -std::vector<TestParams> GetTestParams() { - std::vector<TestParams> params; - for (bool fix_convex_mode : {true, false}) { - for (bool fix_beta_last_max : {true, false}) { - for (bool allow_per_ack_updates : {true, false}) { - TestParams param(fix_convex_mode, fix_beta_last_max, - allow_per_ack_updates); - params.push_back(param); - } - } - } - return params; -} - -} // namespace - -// TODO(jokulik): Once we've rolled out the cubic convex fix, we will -// no longer need a parameterized test. -class CubicTest : public QuicTestWithParam<TestParams> { - protected: - CubicTest() - : one_ms_(QuicTime::Delta::FromMilliseconds(1)), - hundred_ms_(QuicTime::Delta::FromMilliseconds(100)), - cubic_(&clock_) { - cubic_.SetFixConvexMode(GetParam().fix_convex_mode); - cubic_.SetFixBetaLastMax(GetParam().fix_beta_last_max); - cubic_.SetAllowPerAckUpdates(GetParam().allow_per_ack_updates); - } - - QuicByteCount LastMaxCongestionWindow() { - return cubic_.last_max_congestion_window(); - } - - QuicPacketCount CubicConvexCwnd(QuicByteCount initial_cwnd, - QuicTime::Delta rtt, - QuicTime::Delta elapsed_time) { - const int64_t offset = - ((elapsed_time + rtt).ToMicroseconds() << 10) / 1000000; - const QuicPacketCount delta_congestion_window = - (410 * offset * offset * offset) >> 40; - const QuicPacketCount cubic_cwnd = initial_cwnd + delta_congestion_window; - return cubic_cwnd; - } - - QuicTime::Delta MaxCubicTimeInterval() { - return cubic_.MaxCubicTimeInterval(); - } - - const QuicTime::Delta one_ms_; - const QuicTime::Delta hundred_ms_; - MockClock clock_; - Cubic cubic_; -}; - -INSTANTIATE_TEST_CASE_P(CubicTests, - CubicTest, - ::testing::ValuesIn(GetTestParams()), - TestParamToString); - -TEST_P(CubicTest, AboveOrigin) { - if (GetParam().allow_per_ack_updates) { - // Don't even test a scenario where we fix per ack updates without - // the signing bug fix. - return; - } - - // Convex growth. - const QuicTime::Delta rtt_min = hundred_ms_; - const float rtt_min_s = rtt_min.ToMilliseconds() / 1000.0; - QuicPacketCount current_cwnd = 10; - // Without the signed-integer, cubic-convex fix, we mistakenly - // increment cwnd after only one_ms_ and a single ack. - QuicPacketCount expected_cwnd = - GetParam().fix_convex_mode ? current_cwnd : current_cwnd + 1; - // Initialize the state. - clock_.AdvanceTime(one_ms_); - const QuicTime initial_time = clock_.ApproximateNow(); - current_cwnd = - cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min, initial_time); - ASSERT_EQ(expected_cwnd, current_cwnd); - const QuicPacketCount initial_cwnd = current_cwnd; - // Normal TCP phase. - // The maximum number of expected reno RTTs can be calculated by - // finding the point where the cubic curve and the reno curve meet. - int max_reno_rtts = - std::sqrt(kNConnectionAlpha / (.4 * rtt_min_s * rtt_min_s * rtt_min_s)) - - 1; - QuicPacketCount reno_acked_packet_count = 1; - for (int i = 0; i < max_reno_rtts; ++i) { - const QuicPacketCount max_acks_before_increase = - current_cwnd / kNConnectionAlpha; - while (reno_acked_packet_count < max_acks_before_increase - 1) { - // Call once per ACK. - const QuicByteCount next_cwnd = cubic_.CongestionWindowAfterAck( - current_cwnd, rtt_min, clock_.ApproximateNow()); - ASSERT_EQ(current_cwnd, next_cwnd); - ++reno_acked_packet_count; - } - if (!GetParam().allow_per_ack_updates) { - // If we do not allow per-ack updates, the clock must be - // advanced in order for the window updates to take affect. - clock_.AdvanceTime(hundred_ms_); - } - // If we allow per-ack updates, the window can increase even - // before the clock has. - current_cwnd = cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min, - clock_.ApproximateNow()); - if (GetParam().fix_convex_mode) { - if (GetParam().allow_per_ack_updates) { - // If we allow per-ack updates, the cwnd can increase even after - // the ack. - clock_.AdvanceTime(hundred_ms_); - } - // When we fix convex mode and the uint64 arithmetic, we - // increase the expected_cwnd only after the first 100ms, rather - // than after the initial 1ms. - expected_cwnd++; - ASSERT_EQ(expected_cwnd, current_cwnd); - } else { - ASSERT_EQ(expected_cwnd, current_cwnd); - expected_cwnd++; - } - reno_acked_packet_count = 0; - } - // Cubic phase. - for (int i = 0; i < 52; ++i) { - for (QuicPacketCount n = 1; n < current_cwnd; ++n) { - // Call once per ACK. - const QuicPacketCount next_cwnd = cubic_.CongestionWindowAfterAck( - current_cwnd, rtt_min, clock_.ApproximateNow()); - ; - if (GetParam().allow_per_ack_updates) { - // If we allow per-ack increases, the cwnd may gently increase - // up to the cubic value, rather than jumping up after a 30ms - // delay. - ASSERT_LE(current_cwnd, next_cwnd); - current_cwnd = next_cwnd; - } else { - ASSERT_EQ(current_cwnd, next_cwnd); - } - } - if (!GetParam().allow_per_ack_updates) { - // If we do not allow per-ack increases, we have to artificially - // move the clock past the MaxCubicTimeInterval() in order for - // the increases to take effect. - clock_.AdvanceTime(hundred_ms_); - } - const QuicTime::Delta elapsed_time = clock_.ApproximateNow() - initial_time; - const QuicPacketCount expected_cwnd = - CubicConvexCwnd(initial_cwnd, rtt_min, elapsed_time); - current_cwnd = cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min, - clock_.ApproximateNow()); - if (GetParam().allow_per_ack_updates) { - ASSERT_EQ(expected_cwnd, current_cwnd); - clock_.AdvanceTime(hundred_ms_); - } - } - if (!GetParam().allow_per_ack_updates) { - QuicTime::Delta elapsed_time = clock_.ApproximateNow() - initial_time; - const QuicPacketCount final_cwnd = - CubicConvexCwnd(initial_cwnd, rtt_min, elapsed_time); - ASSERT_EQ(final_cwnd, current_cwnd); - } -} - -// Constructs an artificial scenario to show what happens when we -// allow per-ack updates, rather than limiting update freqency. In -// this scenario, the first two acks of the epoch produce the same -// cwnd. When we limit per-ack updates, this would cause the -// cessation of cubic updates for 30ms, which is longer than an RTT. -// When we allow per-ack updates, the window continues to grow on -// every ack. -TEST_P(CubicTest, PerAckUpdates) { - if (!GetParam().fix_convex_mode) { - // Without this fix, this test cannot pass. - return; - } - - // Pick an RTT smaller than the MaxCubicTimeInterval() - QuicPacketCount current_cwnd = 5; - const QuicTime::Delta rtt_min = 20 * one_ms_; - ASSERT_LT(rtt_min, MaxCubicTimeInterval()); - - // Initialize the epoch - clock_.AdvanceTime(one_ms_); - current_cwnd = cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min, - clock_.ApproximateNow()); - const QuicPacketCount initial_cwnd = current_cwnd; - - // Simulate the return of cwnd packets over the course of an RTT, - // which is less than the MaxCubicTimeInterval() - const QuicPacketCount max_acks = current_cwnd / kNConnectionAlpha - 1; - const QuicTime::Delta interval = QuicTime::Delta::FromMicroseconds( - rtt_min.ToMicroseconds() / (max_acks + 2)); - for (QuicPacketCount n = 1; n < max_acks; ++n) { - clock_.AdvanceTime(interval); - ASSERT_EQ(current_cwnd, - cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min, - clock_.ApproximateNow())); - } - clock_.AdvanceTime(interval); - current_cwnd = cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min, - clock_.ApproximateNow()); - - if (GetParam().allow_per_ack_updates) { - // After all the acks are returned from the epoch, we expect the - // cwnd to have increased by one. - EXPECT_EQ(initial_cwnd + 1, current_cwnd); - } else { - // If we do not allow per-ack updates, no increases occur at all - // because we have not moved pass the MaxCubicTimeInterval() - EXPECT_EQ(initial_cwnd, current_cwnd); - } -} - -TEST_P(CubicTest, LossEvents) { - const QuicTime::Delta rtt_min = hundred_ms_; - QuicPacketCount current_cwnd = 422; - // Without the signed-integer, cubic-convex fix, we mistakenly - // increment cwnd after only one_ms_ and a single ack. - QuicPacketCount expected_cwnd = - GetParam().fix_convex_mode ? current_cwnd : current_cwnd + 1; - // Initialize the state. - clock_.AdvanceTime(one_ms_); - EXPECT_EQ(expected_cwnd, cubic_.CongestionWindowAfterAck( - current_cwnd, rtt_min, clock_.ApproximateNow())); - - // On the first loss, the last max congestion window is set to the - // congestion window before the loss. - QuicByteCount pre_loss_cwnd = current_cwnd; - expected_cwnd = static_cast<QuicPacketCount>(current_cwnd * kNConnectionBeta); - ASSERT_EQ(0u, LastMaxCongestionWindow()); - EXPECT_EQ(expected_cwnd, - cubic_.CongestionWindowAfterPacketLoss(current_cwnd)); - ASSERT_EQ(pre_loss_cwnd, LastMaxCongestionWindow()); - current_cwnd = expected_cwnd; - - // On the second loss, the current congestion window is - // significantly lower than the last max congestion window. The - // last max congestion window will be reduced by an additional - // backoff factor to allow for competition. - pre_loss_cwnd = current_cwnd; - expected_cwnd = static_cast<QuicPacketCount>(current_cwnd * kNConnectionBeta); - ASSERT_EQ(expected_cwnd, - cubic_.CongestionWindowAfterPacketLoss(current_cwnd)); - current_cwnd = expected_cwnd; - EXPECT_GT(pre_loss_cwnd, LastMaxCongestionWindow()); - QuicByteCount expected_last_max = - GetParam().fix_beta_last_max - ? static_cast<QuicPacketCount>(pre_loss_cwnd * - kNConnectionBetaLastMax) - : static_cast<QuicPacketCount>(pre_loss_cwnd * kBetaLastMax); - EXPECT_EQ(expected_last_max, LastMaxCongestionWindow()); - if (GetParam().fix_beta_last_max) { - EXPECT_LT(expected_cwnd, LastMaxCongestionWindow()); - } else { - // If we don't scale kLastBetaMax, the current window is exactly - // equal to the last max congestion window, which would cause us - // to land above the origin on the next increase. - EXPECT_EQ(expected_cwnd, LastMaxCongestionWindow()); - } - // Simulate an increase, and check that we are below the origin. - current_cwnd = cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min, - clock_.ApproximateNow()); - if (GetParam().fix_beta_last_max) { - EXPECT_GT(LastMaxCongestionWindow(), current_cwnd); - } else { - // Without the bug fix, we will be at or above the origin. - EXPECT_LE(LastMaxCongestionWindow(), current_cwnd); - } - - // On the final loss, simulate the condition where the congestion - // window had a chance to grow back to the last congestion window. - current_cwnd = LastMaxCongestionWindow(); - pre_loss_cwnd = current_cwnd; - expected_cwnd = static_cast<QuicPacketCount>(current_cwnd * kNConnectionBeta); - EXPECT_EQ(expected_cwnd, - cubic_.CongestionWindowAfterPacketLoss(current_cwnd)); - ASSERT_EQ(pre_loss_cwnd, LastMaxCongestionWindow()); -} - -TEST_P(CubicTest, BelowOrigin) { - // Concave growth. - const QuicTime::Delta rtt_min = hundred_ms_; - QuicPacketCount current_cwnd = 422; - // Without the signed-integer, cubic-convex fix, we mistakenly - // increment cwnd after only one_ms_ and a single ack. - QuicPacketCount expected_cwnd = - GetParam().fix_convex_mode ? current_cwnd : current_cwnd + 1; - // Initialize the state. - clock_.AdvanceTime(one_ms_); - EXPECT_EQ(expected_cwnd, cubic_.CongestionWindowAfterAck( - current_cwnd, rtt_min, clock_.ApproximateNow())); - expected_cwnd = static_cast<QuicPacketCount>(current_cwnd * kNConnectionBeta); - EXPECT_EQ(expected_cwnd, - cubic_.CongestionWindowAfterPacketLoss(current_cwnd)); - current_cwnd = expected_cwnd; - // First update after loss to initialize the epoch. - current_cwnd = cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min, - clock_.ApproximateNow()); - // Cubic phase. - for (int i = 0; i < 40; ++i) { - clock_.AdvanceTime(hundred_ms_); - current_cwnd = cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min, - clock_.ApproximateNow()); - } - expected_cwnd = 399; - EXPECT_EQ(expected_cwnd, current_cwnd); -} - -} // namespace test -} // namespace net diff --git a/chromium/net/quic/core/congestion_control/general_loss_algorithm.cc b/chromium/net/quic/core/congestion_control/general_loss_algorithm.cc index 8833ddffdd2..b6f54e92e92 100644 --- a/chromium/net/quic/core/congestion_control/general_loss_algorithm.cc +++ b/chromium/net/quic/core/congestion_control/general_loss_algorithm.cc @@ -144,7 +144,7 @@ void GeneralLossAlgorithm::SpuriousRetransmitDetected( // Increase the reordering fraction until enough time would be allowed. QuicTime::Delta max_rtt = std::max(rtt_stats.previous_srtt(), rtt_stats.latest_rtt()); - if (FLAGS_quic_reloadable_flag_quic_fix_adaptive_time_loss) { + if (GetQuicReloadableFlag(quic_fix_adaptive_time_loss)) { QUIC_FLAG_COUNT(quic_reloadable_flag_quic_fix_adaptive_time_loss); while ((max_rtt >> reordering_shift_) <= extra_time_needed && reordering_shift_ > 0) { diff --git a/chromium/net/quic/core/congestion_control/general_loss_algorithm_test.cc b/chromium/net/quic/core/congestion_control/general_loss_algorithm_test.cc index 7a90f9bbd92..b3d0e717e28 100644 --- a/chromium/net/quic/core/congestion_control/general_loss_algorithm_test.cc +++ b/chromium/net/quic/core/congestion_control/general_loss_algorithm_test.cc @@ -420,7 +420,7 @@ TEST_F(GeneralLossAlgorithmTest, IncreaseThresholdUponSpuriousLoss) { // Advance the time 1/4 RTT and indicate the loss was spurious. // The new threshold should be 1/2 RTT. clock_.AdvanceTime(rtt_stats_.smoothed_rtt() * (1.0f / 4)); - if (FLAGS_quic_reloadable_flag_quic_fix_adaptive_time_loss) { + if (GetQuicReloadableFlag(quic_fix_adaptive_time_loss)) { // The flag fixes an issue where adaptive time loss would increase the // reordering threshold by an extra factor of two. clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1)); diff --git a/chromium/net/quic/core/congestion_control/send_algorithm_interface.cc b/chromium/net/quic/core/congestion_control/send_algorithm_interface.cc index b74d299cc5e..305811cd29b 100644 --- a/chromium/net/quic/core/congestion_control/send_algorithm_interface.cc +++ b/chromium/net/quic/core/congestion_control/send_algorithm_interface.cc @@ -32,7 +32,7 @@ SendAlgorithmInterface* SendAlgorithmInterface::Create( initial_congestion_window, max_congestion_window, random); case kPCC: - if (FLAGS_quic_reloadable_flag_quic_enable_pcc) { + if (GetQuicReloadableFlag(quic_enable_pcc)) { return CreatePccSender(clock, rtt_stats, unacked_packets, random, stats, initial_congestion_window, max_congestion_window); diff --git a/chromium/net/quic/core/congestion_control/send_algorithm_test.cc b/chromium/net/quic/core/congestion_control/send_algorithm_test.cc index ca83556773f..59cd51d1fa7 100644 --- a/chromium/net/quic/core/congestion_control/send_algorithm_test.cc +++ b/chromium/net/quic/core/congestion_control/send_algorithm_test.cc @@ -120,42 +120,22 @@ const char* CongestionControlTypeToString(CongestionControlType cc_type) { } struct TestParams { - explicit TestParams(CongestionControlType congestion_control_type, - bool fix_convex_mode, - bool fix_cubic_quantization, - bool fix_beta_last_max, - bool allow_per_ack_updates) - : congestion_control_type(congestion_control_type), - fix_convex_mode(fix_convex_mode), - fix_cubic_quantization(fix_cubic_quantization), - fix_beta_last_max(fix_beta_last_max), - allow_per_ack_updates(allow_per_ack_updates) {} + explicit TestParams(CongestionControlType congestion_control_type) + : congestion_control_type(congestion_control_type) {} friend std::ostream& operator<<(std::ostream& os, const TestParams& p) { os << "{ congestion_control_type: " << CongestionControlTypeToString(p.congestion_control_type); - os << " fix_convex_mode: " << p.fix_convex_mode - << " fix_cubic_quantization: " << p.fix_cubic_quantization - << " fix_beta_last_max: " << p.fix_beta_last_max; - os << " allow_per_ack_updates: " << p.allow_per_ack_updates; os << " }"; return os; } - CongestionControlType congestion_control_type; - bool fix_convex_mode; - bool fix_cubic_quantization; - bool fix_beta_last_max; - bool allow_per_ack_updates; + const CongestionControlType congestion_control_type; }; string TestParamToString(const testing::TestParamInfo<TestParams>& params) { return QuicStrCat( - CongestionControlTypeToString(params.param.congestion_control_type), "_", - "convex_mode_", params.param.fix_convex_mode, "_", "cubic_quantization_", - params.param.fix_cubic_quantization, "_", "beta_last_max_", - params.param.fix_beta_last_max, "_", "allow_per_ack_updates_", - params.param.allow_per_ack_updates); + CongestionControlTypeToString(params.param.congestion_control_type), "_"); } // Constructs various test permutations. @@ -163,13 +143,7 @@ std::vector<TestParams> GetTestParams() { std::vector<TestParams> params; for (const CongestionControlType congestion_control_type : {kBBR, kCubicBytes, kRenoBytes, kPCC}) { - params.push_back( - TestParams(congestion_control_type, false, false, false, false)); - if (congestion_control_type != kCubicBytes) { - continue; - } - params.push_back( - TestParams(congestion_control_type, true, true, true, true)); + params.push_back(TestParams(congestion_control_type)); } return params; } @@ -199,8 +173,6 @@ class SendAlgorithmTest : public QuicTestWithParam<TestParams> { GetParam().congestion_control_type, &random_, &stats_, kInitialCongestionWindowPackets); - SetExperimentalOptionsInServerConfig(); - QuicConnectionPeer::SetSendAlgorithm(quic_sender_.connection(), sender_); // TODO(jokulik): Remove once b/38032710 is fixed. // Disable pacing for PCC. @@ -217,30 +189,6 @@ class SendAlgorithmTest : public QuicTestWithParam<TestParams> { QUIC_LOG(INFO) << "SendAlgorithmTest simulator set up. Seed: " << seed; } - // Sets experimental options in the server config, as if they had - // been sent by the client. - void SetExperimentalOptionsInServerConfig() { - QuicConfig client_config; - QuicTagVector options; - if (GetParam().fix_convex_mode) { - options.push_back(kCCVX); - } - if (GetParam().fix_cubic_quantization) { - options.push_back(kCBQT); - } - if (GetParam().fix_beta_last_max) { - options.push_back(kBLMX); - } - if (GetParam().allow_per_ack_updates) { - options.push_back(kCPAU); - } - - if (!options.empty()) { - client_config.SetInitialReceivedConnectionOptions(options); - sender_->SetFromConfig(client_config, Perspective::IS_SERVER); - } - } - // Creates a simulated network, with default settings between the // sender and the switch and the given settings from the switch to // the receiver. diff --git a/chromium/net/quic/core/congestion_control/tcp_cubic_sender_base.cc b/chromium/net/quic/core/congestion_control/tcp_cubic_sender_base.cc deleted file mode 100644 index f76b0efceb5..00000000000 --- a/chromium/net/quic/core/congestion_control/tcp_cubic_sender_base.cc +++ /dev/null @@ -1,262 +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/quic/core/congestion_control/tcp_cubic_sender_base.h" - -#include <algorithm> - -#include "net/quic/core/congestion_control/prr_sender.h" -#include "net/quic/core/congestion_control/rtt_stats.h" -#include "net/quic/core/crypto/crypto_protocol.h" -#include "net/quic/core/proto/cached_network_parameters.pb.h" -#include "net/quic/platform/api/quic_bug_tracker.h" - -namespace net { - -namespace { -// Constants based on TCP defaults. -// The minimum cwnd based on RFC 3782 (TCP NewReno) for cwnd reductions on a -// fast retransmission. The cwnd after a timeout is still 1. -const QuicByteCount kMaxBurstBytes = 3 * kDefaultTCPMSS; -const float kRenoBeta = 0.7f; // Reno backoff factor. -const uint32_t kDefaultNumConnections = 2; // N-connection emulation. -} // namespace - -TcpCubicSenderBase::TcpCubicSenderBase(const QuicClock* clock, - const RttStats* rtt_stats, - bool reno, - QuicConnectionStats* stats) - : rtt_stats_(rtt_stats), - stats_(stats), - reno_(reno), - num_connections_(kDefaultNumConnections), - largest_sent_packet_number_(0), - largest_acked_packet_number_(0), - largest_sent_at_last_cutback_(0), - min4_mode_(false), - last_cutback_exited_slowstart_(false), - slow_start_large_reduction_(false), - no_prr_(false) {} - -TcpCubicSenderBase::~TcpCubicSenderBase() {} - -void TcpCubicSenderBase::SetFromConfig(const QuicConfig& config, - Perspective perspective) { - if (perspective == Perspective::IS_SERVER) { - if (config.HasReceivedConnectionOptions() && - ContainsQuicTag(config.ReceivedConnectionOptions(), kIW03)) { - // Initial window experiment. - SetCongestionWindowInPackets(3); - } - if (config.HasReceivedConnectionOptions() && - ContainsQuicTag(config.ReceivedConnectionOptions(), kIW10)) { - // Initial window experiment. - SetCongestionWindowInPackets(10); - } - if (config.HasReceivedConnectionOptions() && - ContainsQuicTag(config.ReceivedConnectionOptions(), kIW20)) { - // Initial window experiment. - SetCongestionWindowInPackets(20); - } - if (config.HasReceivedConnectionOptions() && - ContainsQuicTag(config.ReceivedConnectionOptions(), kIW50)) { - // Initial window experiment. - SetCongestionWindowInPackets(50); - } - if (config.HasReceivedConnectionOptions() && - ContainsQuicTag(config.ReceivedConnectionOptions(), kMIN1)) { - // Min CWND experiment. - SetMinCongestionWindowInPackets(1); - } - if (config.HasReceivedConnectionOptions() && - ContainsQuicTag(config.ReceivedConnectionOptions(), kMIN4)) { - // Min CWND of 4 experiment. - min4_mode_ = true; - SetMinCongestionWindowInPackets(1); - } - if (config.HasReceivedConnectionOptions() && - ContainsQuicTag(config.ReceivedConnectionOptions(), kSSLR)) { - // Slow Start Fast Exit experiment. - slow_start_large_reduction_ = true; - } - if (config.HasReceivedConnectionOptions() && - ContainsQuicTag(config.ReceivedConnectionOptions(), kNPRR)) { - // Use unity pacing instead of PRR. - no_prr_ = true; - } - } -} - -void TcpCubicSenderBase::AdjustNetworkParameters(QuicBandwidth bandwidth, - QuicTime::Delta rtt) { - if (bandwidth.IsZero() || rtt.IsZero()) { - return; - } - - SetCongestionWindowFromBandwidthAndRtt(bandwidth, rtt); -} - -void TcpCubicSenderBase::SetNumEmulatedConnections(int num_connections) { - num_connections_ = std::max(1, num_connections); -} - -float TcpCubicSenderBase::RenoBeta() const { - // kNConnectionBeta is the backoff factor after loss for our N-connection - // emulation, which emulates the effective backoff of an ensemble of N - // TCP-Reno connections on a single loss event. The effective multiplier is - // computed as: - return (num_connections_ - 1 + kRenoBeta) / num_connections_; -} - -void TcpCubicSenderBase::OnCongestionEvent( - bool rtt_updated, - QuicByteCount prior_in_flight, - QuicTime event_time, - const AckedPacketVector& acked_packets, - const LostPacketVector& lost_packets) { - if (rtt_updated && InSlowStart() && - hybrid_slow_start_.ShouldExitSlowStart( - rtt_stats_->latest_rtt(), rtt_stats_->min_rtt(), - GetCongestionWindow() / kDefaultTCPMSS)) { - ExitSlowstart(); - } - for (const LostPacket& lost_packet : lost_packets) { - OnPacketLost(lost_packet.packet_number, lost_packet.bytes_lost, - prior_in_flight); - } - for (const AckedPacket acked_packet : acked_packets) { - OnPacketAcked(acked_packet.packet_number, acked_packet.bytes_acked, - prior_in_flight, event_time); - } -} - -void TcpCubicSenderBase::OnPacketAcked(QuicPacketNumber acked_packet_number, - QuicByteCount acked_bytes, - QuicByteCount prior_in_flight, - QuicTime event_time) { - largest_acked_packet_number_ = - std::max(acked_packet_number, largest_acked_packet_number_); - if (InRecovery()) { - if (!no_prr_) { - // PRR is used when in recovery. - prr_.OnPacketAcked(acked_bytes); - } - return; - } - MaybeIncreaseCwnd(acked_packet_number, acked_bytes, prior_in_flight, - event_time); - if (InSlowStart()) { - hybrid_slow_start_.OnPacketAcked(acked_packet_number); - } -} - -void TcpCubicSenderBase::OnPacketSent( - QuicTime /*sent_time*/, - QuicByteCount /*bytes_in_flight*/, - QuicPacketNumber packet_number, - QuicByteCount bytes, - HasRetransmittableData is_retransmittable) { - if (InSlowStart()) { - ++(stats_->slowstart_packets_sent); - } - - if (is_retransmittable != HAS_RETRANSMITTABLE_DATA) { - return; - } - if (InRecovery()) { - // PRR is used when in recovery. - prr_.OnPacketSent(bytes); - } - DCHECK_LT(largest_sent_packet_number_, packet_number); - largest_sent_packet_number_ = packet_number; - hybrid_slow_start_.OnPacketSent(packet_number); -} - -bool TcpCubicSenderBase::CanSend(QuicByteCount bytes_in_flight) { - if (!no_prr_ && InRecovery()) { - // PRR is used when in recovery. - return prr_.CanSend(GetCongestionWindow(), bytes_in_flight, - GetSlowStartThreshold()); - } - if (GetCongestionWindow() > bytes_in_flight) { - return true; - } - if (min4_mode_ && bytes_in_flight < 4 * kDefaultTCPMSS) { - return true; - } - return false; -} - -QuicBandwidth TcpCubicSenderBase::PacingRate( - QuicByteCount /* bytes_in_flight */) const { - // We pace at twice the rate of the underlying sender's bandwidth estimate - // during slow start and 1.25x during congestion avoidance to ensure pacing - // doesn't prevent us from filling the window. - QuicTime::Delta srtt = rtt_stats_->smoothed_rtt(); - if (srtt.IsZero()) { - srtt = QuicTime::Delta::FromMicroseconds(rtt_stats_->initial_rtt_us()); - } - const QuicBandwidth bandwidth = - QuicBandwidth::FromBytesAndTimeDelta(GetCongestionWindow(), srtt); - return bandwidth * (InSlowStart() ? 2 : (no_prr_ && InRecovery() ? 1 : 1.25)); -} - -QuicBandwidth TcpCubicSenderBase::BandwidthEstimate() const { - QuicTime::Delta srtt = rtt_stats_->smoothed_rtt(); - if (srtt.IsZero()) { - // If we haven't measured an rtt, the bandwidth estimate is unknown. - return QuicBandwidth::Zero(); - } - return QuicBandwidth::FromBytesAndTimeDelta(GetCongestionWindow(), srtt); -} - -bool TcpCubicSenderBase::InSlowStart() const { - return GetCongestionWindow() < GetSlowStartThreshold(); -} - -bool TcpCubicSenderBase::IsCwndLimited(QuicByteCount bytes_in_flight) const { - const QuicByteCount congestion_window = GetCongestionWindow(); - if (bytes_in_flight >= congestion_window) { - return true; - } - const QuicByteCount available_bytes = congestion_window - bytes_in_flight; - const bool slow_start_limited = - InSlowStart() && bytes_in_flight > congestion_window / 2; - return slow_start_limited || available_bytes <= kMaxBurstBytes; -} - -bool TcpCubicSenderBase::InRecovery() const { - return largest_acked_packet_number_ <= largest_sent_at_last_cutback_ && - largest_acked_packet_number_ != 0; -} - -bool TcpCubicSenderBase::IsProbingForMoreBandwidth() const { - return false; -} - -void TcpCubicSenderBase::OnRetransmissionTimeout(bool packets_retransmitted) { - largest_sent_at_last_cutback_ = 0; - if (!packets_retransmitted) { - return; - } - hybrid_slow_start_.Restart(); - HandleRetransmissionTimeout(); -} - -void TcpCubicSenderBase::OnConnectionMigration() { - hybrid_slow_start_.Restart(); - prr_ = PrrSender(); - largest_sent_packet_number_ = 0; - largest_acked_packet_number_ = 0; - largest_sent_at_last_cutback_ = 0; - last_cutback_exited_slowstart_ = false; -} - -std::string TcpCubicSenderBase::GetDebugState() const { - return ""; -} - -void TcpCubicSenderBase::OnApplicationLimited(QuicByteCount bytes_in_flight) {} - -} // namespace net diff --git a/chromium/net/quic/core/congestion_control/tcp_cubic_sender_base.h b/chromium/net/quic/core/congestion_control/tcp_cubic_sender_base.h deleted file mode 100644 index 721662c50fe..00000000000 --- a/chromium/net/quic/core/congestion_control/tcp_cubic_sender_base.h +++ /dev/null @@ -1,158 +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. -// -// TCP cubic send side congestion algorithm, emulates the behavior of TCP cubic. - -#ifndef NET_QUIC_CORE_CONGESTION_CONTROL_TCP_CUBIC_SENDER_BASE_H_ -#define NET_QUIC_CORE_CONGESTION_CONTROL_TCP_CUBIC_SENDER_BASE_H_ - -#include <cstdint> - -#include "base/compiler_specific.h" -#include "base/macros.h" -#include "net/quic/core/congestion_control/hybrid_slow_start.h" -#include "net/quic/core/congestion_control/prr_sender.h" -#include "net/quic/core/congestion_control/send_algorithm_interface.h" -#include "net/quic/core/quic_bandwidth.h" -#include "net/quic/core/quic_connection_stats.h" -#include "net/quic/core/quic_packets.h" -#include "net/quic/core/quic_time.h" -#include "net/quic/platform/api/quic_export.h" - -namespace net { - -class RttStats; - -// Maximum window to allow when doing bandwidth resumption. -const QuicPacketCount kMaxResumptionCongestionWindow = 200; - -namespace test { -class TcpCubicSenderBasePeer; -} // namespace test - -class QUIC_EXPORT_PRIVATE TcpCubicSenderBase : public SendAlgorithmInterface { - public: - // Reno option and max_tcp_congestion_window are provided for testing. - TcpCubicSenderBase(const QuicClock* clock, - const RttStats* rtt_stats, - bool reno, - QuicConnectionStats* stats); - - ~TcpCubicSenderBase() override; - - // Start implementation of SendAlgorithmInterface. - void SetFromConfig(const QuicConfig& config, - Perspective perspective) override; - void AdjustNetworkParameters(QuicBandwidth bandwidth, - QuicTime::Delta rtt) override; - void SetNumEmulatedConnections(int num_connections) override; - void OnCongestionEvent(bool rtt_updated, - QuicByteCount prior_in_flight, - QuicTime event_time, - const AckedPacketVector& acked_packets, - const LostPacketVector& lost_packets) override; - void OnPacketSent(QuicTime sent_time, - QuicByteCount bytes_in_flight, - QuicPacketNumber packet_number, - QuicByteCount bytes, - HasRetransmittableData is_retransmittable) override; - void OnRetransmissionTimeout(bool packets_retransmitted) override; - void OnConnectionMigration() override; - bool CanSend(QuicByteCount bytes_in_flight) override; - QuicBandwidth PacingRate(QuicByteCount bytes_in_flight) const override; - QuicBandwidth BandwidthEstimate() const override; - bool InSlowStart() const override; - bool InRecovery() const override; - bool IsProbingForMoreBandwidth() const override; - std::string GetDebugState() const override; - void OnApplicationLimited(QuicByteCount bytes_in_flight) override; - - protected: - // Called when resuming a previous bandwidth. - virtual void SetCongestionWindowFromBandwidthAndRtt(QuicBandwidth bandwidth, - QuicTime::Delta rtt) = 0; - - // Called when initializing the congestion window. - virtual void SetCongestionWindowInPackets( - QuicPacketCount congestion_window) = 0; - - // Called when initializing the minimum congestion window. - virtual void SetMinCongestionWindowInPackets( - QuicPacketCount congestion_window) = 0; - - // Called when slow start is exited to set SSTHRESH. - virtual void ExitSlowstart() = 0; - - // Called when a packet is lost. - virtual void OnPacketLost(QuicPacketNumber largest_loss, - QuicByteCount lost_bytes, - QuicByteCount prior_in_flight) = 0; - - // Called when a packet has been acked to possibly increase the congestion - // window. - virtual void MaybeIncreaseCwnd(QuicPacketNumber acked_packet_number, - QuicByteCount acked_bytes, - QuicByteCount prior_in_flight, - QuicTime event_time) = 0; - - // Called when a retransmission has occured which resulted in packets - // being retransmitted. - virtual void HandleRetransmissionTimeout() = 0; - - // Compute the TCP Reno beta based on the current number of connections. - float RenoBeta() const; - - bool IsCwndLimited(QuicByteCount bytes_in_flight) const; - - private: - friend class test::TcpCubicSenderBasePeer; - - // TODO(ianswett): Remove these and migrate to OnCongestionEvent. - void OnPacketAcked(QuicPacketNumber acked_packet_number, - QuicByteCount acked_bytes, - QuicByteCount prior_in_flight, - QuicTime event_time); - - protected: - // TODO(rch): Make these private and clean up subclass access to them. - HybridSlowStart hybrid_slow_start_; - PrrSender prr_; - const RttStats* rtt_stats_; - QuicConnectionStats* stats_; - - // If true, Reno congestion control is used instead of Cubic. - const bool reno_; - - // Number of connections to simulate. - uint32_t num_connections_; - - // Track the largest packet that has been sent. - QuicPacketNumber largest_sent_packet_number_; - - // Track the largest packet that has been acked. - QuicPacketNumber largest_acked_packet_number_; - - // Track the largest packet number outstanding when a CWND cutback occurs. - QuicPacketNumber largest_sent_at_last_cutback_; - - // Whether to use 4 packets as the actual min, but pace lower. - bool min4_mode_; - - // Whether the last loss event caused us to exit slowstart. - // Used for stats collection of slowstart_packets_lost - bool last_cutback_exited_slowstart_; - - // When true, exit slow start with large cutback of congestion window. - bool slow_start_large_reduction_; - - // When true, use unity pacing instead of PRR. - bool no_prr_; - - private: - DISALLOW_COPY_AND_ASSIGN(TcpCubicSenderBase); -}; - -} // namespace net - -#endif // NET_QUIC_CORE_CONGESTION_CONTROL_TCP_CUBIC_SENDER_BASE_H_ diff --git a/chromium/net/quic/core/congestion_control/tcp_cubic_sender_bytes.cc b/chromium/net/quic/core/congestion_control/tcp_cubic_sender_bytes.cc index 60063a4fcda..1cb6e772ceb 100644 --- a/chromium/net/quic/core/congestion_control/tcp_cubic_sender_bytes.cc +++ b/chromium/net/quic/core/congestion_control/tcp_cubic_sender_bytes.cc @@ -18,6 +18,9 @@ namespace net { namespace { // Constants based on TCP defaults. +const QuicByteCount kMaxBurstBytes = 3 * kDefaultTCPMSS; +const float kRenoBeta = 0.7f; // Reno backoff factor. +const uint32_t kDefaultNumConnections = 2; // N-connection emulation. // The minimum cwnd based on RFC 3782 (TCP NewReno) for cwnd reductions on a // fast retransmission. const QuicByteCount kDefaultMinimumCongestionWindow = 2 * kDefaultTCPMSS; @@ -30,7 +33,17 @@ TcpCubicSenderBytes::TcpCubicSenderBytes( QuicPacketCount initial_tcp_congestion_window, QuicPacketCount max_congestion_window, QuicConnectionStats* stats) - : TcpCubicSenderBase(clock, rtt_stats, reno, stats), + : rtt_stats_(rtt_stats), + stats_(stats), + reno_(reno), + num_connections_(kDefaultNumConnections), + largest_sent_packet_number_(0), + largest_acked_packet_number_(0), + largest_sent_at_last_cutback_(0), + min4_mode_(false), + last_cutback_exited_slowstart_(false), + slow_start_large_reduction_(false), + no_prr_(false), cubic_(clock), num_acked_packets_(0), congestion_window_(initial_tcp_congestion_window * kDefaultTCPMSS), @@ -47,25 +60,209 @@ TcpCubicSenderBytes::~TcpCubicSenderBytes() {} void TcpCubicSenderBytes::SetFromConfig(const QuicConfig& config, Perspective perspective) { - TcpCubicSenderBase::SetFromConfig(config, perspective); - if (config.HasReceivedConnectionOptions() && - ContainsQuicTag(config.ReceivedConnectionOptions(), kCCVX)) { - cubic_.SetFixConvexMode(true); + if (perspective == Perspective::IS_SERVER) { + if (config.HasReceivedConnectionOptions() && + ContainsQuicTag(config.ReceivedConnectionOptions(), kIW03)) { + // Initial window experiment. + SetCongestionWindowInPackets(3); + } + if (config.HasReceivedConnectionOptions() && + ContainsQuicTag(config.ReceivedConnectionOptions(), kIW10)) { + // Initial window experiment. + SetCongestionWindowInPackets(10); + } + if (config.HasReceivedConnectionOptions() && + ContainsQuicTag(config.ReceivedConnectionOptions(), kIW20)) { + // Initial window experiment. + SetCongestionWindowInPackets(20); + } + if (config.HasReceivedConnectionOptions() && + ContainsQuicTag(config.ReceivedConnectionOptions(), kIW50)) { + // Initial window experiment. + SetCongestionWindowInPackets(50); + } + if (config.HasReceivedConnectionOptions() && + ContainsQuicTag(config.ReceivedConnectionOptions(), kMIN1)) { + // Min CWND experiment. + SetMinCongestionWindowInPackets(1); + } + if (config.HasReceivedConnectionOptions() && + ContainsQuicTag(config.ReceivedConnectionOptions(), kMIN4)) { + // Min CWND of 4 experiment. + min4_mode_ = true; + SetMinCongestionWindowInPackets(1); + } + if (config.HasReceivedConnectionOptions() && + ContainsQuicTag(config.ReceivedConnectionOptions(), kSSLR)) { + // Slow Start Fast Exit experiment. + slow_start_large_reduction_ = true; + } + if (config.HasReceivedConnectionOptions() && + ContainsQuicTag(config.ReceivedConnectionOptions(), kNPRR)) { + // Use unity pacing instead of PRR. + no_prr_ = true; + } + } +} + +void TcpCubicSenderBytes::AdjustNetworkParameters(QuicBandwidth bandwidth, + QuicTime::Delta rtt) { + if (bandwidth.IsZero() || rtt.IsZero()) { + return; + } + + SetCongestionWindowFromBandwidthAndRtt(bandwidth, rtt); +} + +float TcpCubicSenderBytes::RenoBeta() const { + // kNConnectionBeta is the backoff factor after loss for our N-connection + // emulation, which emulates the effective backoff of an ensemble of N + // TCP-Reno connections on a single loss event. The effective multiplier is + // computed as: + return (num_connections_ - 1 + kRenoBeta) / num_connections_; +} + +void TcpCubicSenderBytes::OnCongestionEvent( + bool rtt_updated, + QuicByteCount prior_in_flight, + QuicTime event_time, + const AckedPacketVector& acked_packets, + const LostPacketVector& lost_packets) { + if (rtt_updated && InSlowStart() && + hybrid_slow_start_.ShouldExitSlowStart( + rtt_stats_->latest_rtt(), rtt_stats_->min_rtt(), + GetCongestionWindow() / kDefaultTCPMSS)) { + ExitSlowstart(); + } + for (const LostPacket& lost_packet : lost_packets) { + OnPacketLost(lost_packet.packet_number, lost_packet.bytes_lost, + prior_in_flight); + } + for (const AckedPacket acked_packet : acked_packets) { + OnPacketAcked(acked_packet.packet_number, acked_packet.bytes_acked, + prior_in_flight, event_time); + } +} + +void TcpCubicSenderBytes::OnPacketAcked(QuicPacketNumber acked_packet_number, + QuicByteCount acked_bytes, + QuicByteCount prior_in_flight, + QuicTime event_time) { + largest_acked_packet_number_ = + std::max(acked_packet_number, largest_acked_packet_number_); + if (InRecovery()) { + if (!no_prr_) { + // PRR is used when in recovery. + prr_.OnPacketAcked(acked_bytes); + } + return; + } + MaybeIncreaseCwnd(acked_packet_number, acked_bytes, prior_in_flight, + event_time); + if (InSlowStart()) { + hybrid_slow_start_.OnPacketAcked(acked_packet_number); + } +} + +void TcpCubicSenderBytes::OnPacketSent( + QuicTime /*sent_time*/, + QuicByteCount /*bytes_in_flight*/, + QuicPacketNumber packet_number, + QuicByteCount bytes, + HasRetransmittableData is_retransmittable) { + if (InSlowStart()) { + ++(stats_->slowstart_packets_sent); + } + + if (is_retransmittable != HAS_RETRANSMITTABLE_DATA) { + return; + } + if (InRecovery()) { + // PRR is used when in recovery. + prr_.OnPacketSent(bytes); } - if (config.HasReceivedConnectionOptions() && - ContainsQuicTag(config.ReceivedConnectionOptions(), kCBQT)) { - cubic_.SetFixCubicQuantization(true); + DCHECK_LT(largest_sent_packet_number_, packet_number); + largest_sent_packet_number_ = packet_number; + hybrid_slow_start_.OnPacketSent(packet_number); +} + +bool TcpCubicSenderBytes::CanSend(QuicByteCount bytes_in_flight) { + if (!no_prr_ && InRecovery()) { + // PRR is used when in recovery. + return prr_.CanSend(GetCongestionWindow(), bytes_in_flight, + GetSlowStartThreshold()); + } + if (GetCongestionWindow() > bytes_in_flight) { + return true; + } + if (min4_mode_ && bytes_in_flight < 4 * kDefaultTCPMSS) { + return true; + } + return false; +} + +QuicBandwidth TcpCubicSenderBytes::PacingRate( + QuicByteCount /* bytes_in_flight */) const { + // We pace at twice the rate of the underlying sender's bandwidth estimate + // during slow start and 1.25x during congestion avoidance to ensure pacing + // doesn't prevent us from filling the window. + QuicTime::Delta srtt = rtt_stats_->smoothed_rtt(); + if (srtt.IsZero()) { + srtt = QuicTime::Delta::FromMicroseconds(rtt_stats_->initial_rtt_us()); + } + const QuicBandwidth bandwidth = + QuicBandwidth::FromBytesAndTimeDelta(GetCongestionWindow(), srtt); + return bandwidth * (InSlowStart() ? 2 : (no_prr_ && InRecovery() ? 1 : 1.25)); +} + +QuicBandwidth TcpCubicSenderBytes::BandwidthEstimate() const { + QuicTime::Delta srtt = rtt_stats_->smoothed_rtt(); + if (srtt.IsZero()) { + // If we haven't measured an rtt, the bandwidth estimate is unknown. + return QuicBandwidth::Zero(); } - if (config.HasReceivedConnectionOptions() && - ContainsQuicTag(config.ReceivedConnectionOptions(), kBLMX)) { - cubic_.SetFixBetaLastMax(true); + return QuicBandwidth::FromBytesAndTimeDelta(GetCongestionWindow(), srtt); +} + +bool TcpCubicSenderBytes::InSlowStart() const { + return GetCongestionWindow() < GetSlowStartThreshold(); +} + +bool TcpCubicSenderBytes::IsCwndLimited(QuicByteCount bytes_in_flight) const { + const QuicByteCount congestion_window = GetCongestionWindow(); + if (bytes_in_flight >= congestion_window) { + return true; } - if (config.HasReceivedConnectionOptions() && - ContainsQuicTag(config.ReceivedConnectionOptions(), kCPAU)) { - cubic_.SetAllowPerAckUpdates(true); + const QuicByteCount available_bytes = congestion_window - bytes_in_flight; + const bool slow_start_limited = + InSlowStart() && bytes_in_flight > congestion_window / 2; + return slow_start_limited || available_bytes <= kMaxBurstBytes; +} + +bool TcpCubicSenderBytes::InRecovery() const { + return largest_acked_packet_number_ <= largest_sent_at_last_cutback_ && + largest_acked_packet_number_ != 0; +} + +bool TcpCubicSenderBytes::IsProbingForMoreBandwidth() const { + return false; +} + +void TcpCubicSenderBytes::OnRetransmissionTimeout(bool packets_retransmitted) { + largest_sent_at_last_cutback_ = 0; + if (!packets_retransmitted) { + return; } + hybrid_slow_start_.Restart(); + HandleRetransmissionTimeout(); } +std::string TcpCubicSenderBytes::GetDebugState() const { + return ""; +} + +void TcpCubicSenderBytes::OnApplicationLimited(QuicByteCount bytes_in_flight) {} + void TcpCubicSenderBytes::SetCongestionWindowFromBandwidthAndRtt( QuicBandwidth bandwidth, QuicTime::Delta rtt) { @@ -88,7 +285,7 @@ void TcpCubicSenderBytes::SetMinCongestionWindowInPackets( } void TcpCubicSenderBytes::SetNumEmulatedConnections(int num_connections) { - TcpCubicSenderBase::SetNumEmulatedConnections(num_connections); + num_connections_ = std::max(1, num_connections); cubic_.SetNumConnections(num_connections_); } @@ -215,7 +412,12 @@ void TcpCubicSenderBytes::HandleRetransmissionTimeout() { } void TcpCubicSenderBytes::OnConnectionMigration() { - TcpCubicSenderBase::OnConnectionMigration(); + hybrid_slow_start_.Restart(); + prr_ = PrrSender(); + largest_sent_packet_number_ = 0; + largest_acked_packet_number_ = 0; + largest_sent_at_last_cutback_ = 0; + last_cutback_exited_slowstart_ = false; cubic_.ResetCubicState(); num_acked_packets_ = 0; congestion_window_ = initial_tcp_congestion_window_; diff --git a/chromium/net/quic/core/congestion_control/tcp_cubic_sender_bytes.h b/chromium/net/quic/core/congestion_control/tcp_cubic_sender_bytes.h index d49543f71a9..83189bfcf14 100644 --- a/chromium/net/quic/core/congestion_control/tcp_cubic_sender_bytes.h +++ b/chromium/net/quic/core/congestion_control/tcp_cubic_sender_bytes.h @@ -13,7 +13,7 @@ #include "net/quic/core/congestion_control/cubic_bytes.h" #include "net/quic/core/congestion_control/hybrid_slow_start.h" #include "net/quic/core/congestion_control/prr_sender.h" -#include "net/quic/core/congestion_control/tcp_cubic_sender_base.h" +#include "net/quic/core/congestion_control/send_algorithm_interface.h" #include "net/quic/core/quic_bandwidth.h" #include "net/quic/core/quic_connection_stats.h" #include "net/quic/core/quic_packets.h" @@ -24,11 +24,14 @@ namespace net { class RttStats; +// Maximum window to allow when doing bandwidth resumption. +const QuicPacketCount kMaxResumptionCongestionWindow = 200; + namespace test { class TcpCubicSenderBytesPeer; } // namespace test -class QUIC_EXPORT_PRIVATE TcpCubicSenderBytes : public TcpCubicSenderBase { +class QUIC_EXPORT_PRIVATE TcpCubicSenderBytes : public SendAlgorithmInterface { public: TcpCubicSenderBytes(const QuicClock* clock, const RttStats* rtt_stats, @@ -41,35 +44,97 @@ class QUIC_EXPORT_PRIVATE TcpCubicSenderBytes : public TcpCubicSenderBase { // Start implementation of SendAlgorithmInterface. void SetFromConfig(const QuicConfig& config, Perspective perspective) override; + void AdjustNetworkParameters(QuicBandwidth bandwidth, + QuicTime::Delta rtt) override; void SetNumEmulatedConnections(int num_connections) override; void OnConnectionMigration() override; + void OnCongestionEvent(bool rtt_updated, + QuicByteCount prior_in_flight, + QuicTime event_time, + const AckedPacketVector& acked_packets, + const LostPacketVector& lost_packets) override; + void OnPacketSent(QuicTime sent_time, + QuicByteCount bytes_in_flight, + QuicPacketNumber packet_number, + QuicByteCount bytes, + HasRetransmittableData is_retransmittable) override; + void OnRetransmissionTimeout(bool packets_retransmitted) override; + bool CanSend(QuicByteCount bytes_in_flight) override; + QuicBandwidth PacingRate(QuicByteCount bytes_in_flight) const override; + QuicBandwidth BandwidthEstimate() const override; QuicByteCount GetCongestionWindow() const override; QuicByteCount GetSlowStartThreshold() const override; CongestionControlType GetCongestionControlType() const override; + bool InSlowStart() const override; + bool InRecovery() const override; + bool IsProbingForMoreBandwidth() const override; + std::string GetDebugState() const override; + void OnApplicationLimited(QuicByteCount bytes_in_flight) override; // End implementation of SendAlgorithmInterface. QuicByteCount min_congestion_window() const { return min_congestion_window_; } protected: - // TcpCubicSenderBase methods + // Compute the TCP Reno beta based on the current number of connections. + float RenoBeta() const; + + bool IsCwndLimited(QuicByteCount bytes_in_flight) const; + + // TODO(ianswett): Remove these and migrate to OnCongestionEvent. + void OnPacketAcked(QuicPacketNumber acked_packet_number, + QuicByteCount acked_bytes, + QuicByteCount prior_in_flight, + QuicTime event_time); void SetCongestionWindowFromBandwidthAndRtt(QuicBandwidth bandwidth, - QuicTime::Delta rtt) override; - void SetCongestionWindowInPackets(QuicPacketCount congestion_window) override; - void SetMinCongestionWindowInPackets( - QuicPacketCount congestion_window) override; - void ExitSlowstart() override; + QuicTime::Delta rtt); + void SetCongestionWindowInPackets(QuicPacketCount congestion_window); + void SetMinCongestionWindowInPackets(QuicPacketCount congestion_window); + void ExitSlowstart(); void OnPacketLost(QuicPacketNumber largest_loss, QuicByteCount lost_bytes, - QuicByteCount prior_in_flight) override; + QuicByteCount prior_in_flight); void MaybeIncreaseCwnd(QuicPacketNumber acked_packet_number, QuicByteCount acked_bytes, QuicByteCount prior_in_flight, - QuicTime event_time) override; - void HandleRetransmissionTimeout() override; + QuicTime event_time); + void HandleRetransmissionTimeout(); private: friend class test::TcpCubicSenderBytesPeer; + HybridSlowStart hybrid_slow_start_; + PrrSender prr_; + const RttStats* rtt_stats_; + QuicConnectionStats* stats_; + + // If true, Reno congestion control is used instead of Cubic. + const bool reno_; + + // Number of connections to simulate. + uint32_t num_connections_; + + // Track the largest packet that has been sent. + QuicPacketNumber largest_sent_packet_number_; + + // Track the largest packet that has been acked. + QuicPacketNumber largest_acked_packet_number_; + + // Track the largest packet number outstanding when a CWND cutback occurs. + QuicPacketNumber largest_sent_at_last_cutback_; + + // Whether to use 4 packets as the actual min, but pace lower. + bool min4_mode_; + + // Whether the last loss event caused us to exit slowstart. + // Used for stats collection of slowstart_packets_lost + bool last_cutback_exited_slowstart_; + + // When true, exit slow start with large cutback of congestion window. + bool slow_start_large_reduction_; + + // When true, use unity pacing instead of PRR. + bool no_prr_; + CubicBytes cubic_; // ACK counter for the Reno implementation. diff --git a/chromium/net/quic/core/congestion_control/tcp_cubic_sender_bytes_test.cc b/chromium/net/quic/core/congestion_control/tcp_cubic_sender_bytes_test.cc index 1cd69ab1c7b..4bdcf440b12 100644 --- a/chromium/net/quic/core/congestion_control/tcp_cubic_sender_bytes_test.cc +++ b/chromium/net/quic/core/congestion_control/tcp_cubic_sender_bytes_test.cc @@ -11,7 +11,6 @@ #include "net/quic/core/congestion_control/rtt_stats.h" #include "net/quic/core/congestion_control/send_algorithm_interface.h" #include "net/quic/core/crypto/crypto_protocol.h" -#include "net/quic/core/proto/cached_network_parameters.pb.h" #include "net/quic/core/quic_packets.h" #include "net/quic/core/quic_utils.h" #include "net/quic/platform/api/quic_logging.h" @@ -805,13 +804,9 @@ TEST_F(TcpCubicSenderBytesTest, LimitCwndIncreaseInCongestionAvoidance) { AckNPackets(1); SendAvailableSendWindow(); } - if (FLAGS_quic_reloadable_flag_quic_enable_cubic_fixes) { - // Bytes in flight may be larger than the CWND if the CWND isn't an exact - // multiple of the packet sizes being sent. - EXPECT_GE(bytes_in_flight_, sender_->GetCongestionWindow()); - } else { - EXPECT_EQ(bytes_in_flight_, sender_->GetCongestionWindow()); - } + // Bytes in flight may be larger than the CWND if the CWND isn't an exact + // multiple of the packet sizes being sent. + EXPECT_GE(bytes_in_flight_, sender_->GetCongestionWindow()); saved_cwnd = sender_->GetCongestionWindow(); // Advance time 2 seconds waiting for an ack. diff --git a/chromium/net/quic/core/crypto/aead_base_decrypter.cc b/chromium/net/quic/core/crypto/aead_base_decrypter.cc index 7fa1f692d0d..c036441c778 100644 --- a/chromium/net/quic/core/crypto/aead_base_decrypter.cc +++ b/chromium/net/quic/core/crypto/aead_base_decrypter.cc @@ -7,6 +7,7 @@ #include <cstdint> #include "net/quic/core/quic_utils.h" +#include "net/quic/platform/api/quic_arraysize.h" #include "net/quic/platform/api/quic_bug_tracker.h" #include "net/quic/platform/api/quic_logging.h" #include "third_party/boringssl/src/include/openssl/err.h" @@ -32,7 +33,7 @@ void DLogOpenSslErrors() { #else while (uint32_t error = ERR_get_error()) { char buf[120]; - ERR_error_string_n(error, buf, arraysize(buf)); + ERR_error_string_n(error, buf, QUIC_ARRAYSIZE(buf)); QUIC_DLOG(ERROR) << "OpenSSL error: " << buf; } #endif @@ -175,6 +176,14 @@ bool AeadBaseDecrypter::DecryptPacket(QuicTransportVersion /*version*/, return true; } +size_t AeadBaseDecrypter::GetKeySize() const { + return key_size_; +} + +size_t AeadBaseDecrypter::GetIVSize() const { + return nonce_size_; +} + QuicStringPiece AeadBaseDecrypter::GetKey() const { return QuicStringPiece(reinterpret_cast<const char*>(key_), key_size_); } diff --git a/chromium/net/quic/core/crypto/aead_base_decrypter.h b/chromium/net/quic/core/crypto/aead_base_decrypter.h index 5e983007b8c..66c5b3499df 100644 --- a/chromium/net/quic/core/crypto/aead_base_decrypter.h +++ b/chromium/net/quic/core/crypto/aead_base_decrypter.h @@ -39,6 +39,8 @@ class QUIC_EXPORT_PRIVATE AeadBaseDecrypter : public QuicDecrypter { char* output, size_t* output_length, size_t max_output_length) override; + size_t GetKeySize() const override; + size_t GetIVSize() const override; QuicStringPiece GetKey() const override; QuicStringPiece GetNoncePrefix() const override; diff --git a/chromium/net/quic/core/crypto/aead_base_encrypter.cc b/chromium/net/quic/core/crypto/aead_base_encrypter.cc index c7303165a7a..50a66166ace 100644 --- a/chromium/net/quic/core/crypto/aead_base_encrypter.cc +++ b/chromium/net/quic/core/crypto/aead_base_encrypter.cc @@ -8,6 +8,7 @@ #include "net/quic/core/quic_utils.h" #include "net/quic/platform/api/quic_aligned.h" +#include "net/quic/platform/api/quic_arraysize.h" #include "net/quic/platform/api/quic_bug_tracker.h" #include "net/quic/platform/api/quic_logging.h" #include "third_party/boringssl/src/include/openssl/err.h" @@ -26,7 +27,7 @@ void DLogOpenSslErrors() { #else while (unsigned long error = ERR_get_error()) { char buf[120]; - ERR_error_string_n(error, buf, arraysize(buf)); + ERR_error_string_n(error, buf, QUIC_ARRAYSIZE(buf)); QUIC_DLOG(ERROR) << "OpenSSL error: " << buf; } #endif @@ -157,6 +158,10 @@ size_t AeadBaseEncrypter::GetNoncePrefixSize() const { return nonce_size_ - sizeof(QuicPacketNumber); } +size_t AeadBaseEncrypter::GetIVSize() const { + return nonce_size_; +} + size_t AeadBaseEncrypter::GetMaxPlaintextSize(size_t ciphertext_size) const { return ciphertext_size - auth_tag_size_; } diff --git a/chromium/net/quic/core/crypto/aead_base_encrypter.h b/chromium/net/quic/core/crypto/aead_base_encrypter.h index 748bc461158..c9cadd987a7 100644 --- a/chromium/net/quic/core/crypto/aead_base_encrypter.h +++ b/chromium/net/quic/core/crypto/aead_base_encrypter.h @@ -39,6 +39,7 @@ class QUIC_EXPORT_PRIVATE AeadBaseEncrypter : public QuicEncrypter { size_t max_output_length) override; size_t GetKeySize() const override; size_t GetNoncePrefixSize() const override; + size_t GetIVSize() const override; size_t GetMaxPlaintextSize(size_t ciphertext_size) const override; size_t GetCiphertextSize(size_t plaintext_size) const override; QuicStringPiece GetKey() const override; diff --git a/chromium/net/quic/core/crypto/aes_128_gcm_12_decrypter.cc b/chromium/net/quic/core/crypto/aes_128_gcm_12_decrypter.cc index 7bad0551d38..a8910b1d49c 100644 --- a/chromium/net/quic/core/crypto/aes_128_gcm_12_decrypter.cc +++ b/chromium/net/quic/core/crypto/aes_128_gcm_12_decrypter.cc @@ -4,8 +4,6 @@ #include "net/quic/core/crypto/aes_128_gcm_12_decrypter.h" -#include "net/quic/platform/api/quic_flag_utils.h" -#include "net/quic/platform/api/quic_flags.h" #include "third_party/boringssl/src/include/openssl/aead.h" #include "third_party/boringssl/src/include/openssl/tls1.h" @@ -31,11 +29,7 @@ Aes128Gcm12Decrypter::Aes128Gcm12Decrypter() Aes128Gcm12Decrypter::~Aes128Gcm12Decrypter() {} uint32_t Aes128Gcm12Decrypter::cipher_id() const { - if (FLAGS_quic_reloadable_flag_quic_use_tls13_cipher_suites) { - QUIC_FLAG_COUNT(quic_reloadable_flag_quic_use_tls13_cipher_suites); - return TLS1_CK_AES_128_GCM_SHA256; - } - return TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256; + return TLS1_CK_AES_128_GCM_SHA256; } } // namespace net diff --git a/chromium/net/quic/core/crypto/aes_128_gcm_12_decrypter_test.cc b/chromium/net/quic/core/crypto/aes_128_gcm_12_decrypter_test.cc index 3f439767bc5..44aa748e475 100644 --- a/chromium/net/quic/core/crypto/aes_128_gcm_12_decrypter_test.cc +++ b/chromium/net/quic/core/crypto/aes_128_gcm_12_decrypter_test.cc @@ -7,6 +7,7 @@ #include <memory> #include "net/quic/core/quic_utils.h" +#include "net/quic/platform/api/quic_arraysize.h" #include "net/quic/platform/api/quic_test.h" #include "net/quic/platform/api/quic_text_utils.h" #include "net/quic/test_tools/quic_test_utils.h" @@ -212,7 +213,7 @@ QuicData* DecryptWithNonce(Aes128Gcm12Decrypter* decrypter, std::unique_ptr<char[]> output(new char[ciphertext.length()]); size_t output_length = 0; const bool success = decrypter->DecryptPacket( - QuicVersionMax(), packet_number, associated_data, ciphertext, + QuicTransportVersionMax(), packet_number, associated_data, ciphertext, output.get(), &output_length, ciphertext.length()); if (!success) { return nullptr; @@ -223,7 +224,7 @@ QuicData* DecryptWithNonce(Aes128Gcm12Decrypter* decrypter, class Aes128Gcm12DecrypterTest : public QuicTest {}; TEST_F(Aes128Gcm12DecrypterTest, Decrypt) { - for (size_t i = 0; i < arraysize(test_group_array); i++) { + for (size_t i = 0; i < QUIC_ARRAYSIZE(test_group_array); i++) { SCOPED_TRACE(i); const TestVector* test_vectors = test_group_array[i]; const TestGroupInfo& test_info = test_group_info[i]; diff --git a/chromium/net/quic/core/crypto/aes_128_gcm_12_encrypter_test.cc b/chromium/net/quic/core/crypto/aes_128_gcm_12_encrypter_test.cc index 029a278b36c..e51e376c8e7 100644 --- a/chromium/net/quic/core/crypto/aes_128_gcm_12_encrypter_test.cc +++ b/chromium/net/quic/core/crypto/aes_128_gcm_12_encrypter_test.cc @@ -7,6 +7,7 @@ #include <memory> #include "net/quic/core/quic_utils.h" +#include "net/quic/platform/api/quic_arraysize.h" #include "net/quic/platform/api/quic_test.h" #include "net/quic/platform/api/quic_text_utils.h" #include "net/quic/test_tools/quic_test_utils.h" @@ -175,7 +176,7 @@ QuicData* EncryptWithNonce(Aes128Gcm12Encrypter* encrypter, class Aes128Gcm12EncrypterTest : public QuicTest {}; TEST_F(Aes128Gcm12EncrypterTest, Encrypt) { - for (size_t i = 0; i < arraysize(test_group_array); i++) { + for (size_t i = 0; i < QUIC_ARRAYSIZE(test_group_array); i++) { SCOPED_TRACE(i); const TestVector* test_vectors = test_group_array[i]; const TestGroupInfo& test_info = test_group_info[i]; diff --git a/chromium/net/quic/core/crypto/aes_128_gcm_decrypter_test.cc b/chromium/net/quic/core/crypto/aes_128_gcm_decrypter_test.cc index 336d5d800b4..86474c986ba 100644 --- a/chromium/net/quic/core/crypto/aes_128_gcm_decrypter_test.cc +++ b/chromium/net/quic/core/crypto/aes_128_gcm_decrypter_test.cc @@ -7,6 +7,7 @@ #include <memory> #include "net/quic/core/quic_utils.h" +#include "net/quic/platform/api/quic_arraysize.h" #include "net/quic/platform/api/quic_test.h" #include "net/quic/platform/api/quic_text_utils.h" #include "net/quic/test_tools/quic_test_utils.h" @@ -207,7 +208,7 @@ QuicData* DecryptWithNonce(Aes128GcmDecrypter* decrypter, std::unique_ptr<char[]> output(new char[ciphertext.length()]); size_t output_length = 0; const bool success = decrypter->DecryptPacket( - QuicVersionMax(), 0, associated_data, ciphertext, output.get(), + QuicTransportVersionMax(), 0, associated_data, ciphertext, output.get(), &output_length, ciphertext.length()); if (!success) { return nullptr; @@ -218,7 +219,7 @@ QuicData* DecryptWithNonce(Aes128GcmDecrypter* decrypter, class Aes128GcmDecrypterTest : public QuicTest {}; TEST_F(Aes128GcmDecrypterTest, Decrypt) { - for (size_t i = 0; i < arraysize(test_group_array); i++) { + for (size_t i = 0; i < QUIC_ARRAYSIZE(test_group_array); i++) { SCOPED_TRACE(i); const TestVector* test_vectors = test_group_array[i]; const TestGroupInfo& test_info = test_group_info[i]; diff --git a/chromium/net/quic/core/crypto/aes_128_gcm_encrypter_test.cc b/chromium/net/quic/core/crypto/aes_128_gcm_encrypter_test.cc index 7d770fad0fb..fb752f79d1e 100644 --- a/chromium/net/quic/core/crypto/aes_128_gcm_encrypter_test.cc +++ b/chromium/net/quic/core/crypto/aes_128_gcm_encrypter_test.cc @@ -7,6 +7,7 @@ #include <memory> #include "net/quic/core/quic_utils.h" +#include "net/quic/platform/api/quic_arraysize.h" #include "net/quic/platform/api/quic_test.h" #include "net/quic/platform/api/quic_text_utils.h" #include "net/quic/test_tools/quic_test_utils.h" @@ -175,7 +176,7 @@ QuicData* EncryptWithNonce(Aes128GcmEncrypter* encrypter, class Aes128GcmEncrypterTest : public QuicTest {}; TEST_F(Aes128GcmEncrypterTest, Encrypt) { - for (size_t i = 0; i < arraysize(test_group_array); i++) { + for (size_t i = 0; i < QUIC_ARRAYSIZE(test_group_array); i++) { SCOPED_TRACE(i); const TestVector* test_vectors = test_group_array[i]; const TestGroupInfo& test_info = test_group_info[i]; diff --git a/chromium/net/quic/core/crypto/aes_256_gcm_decrypter_test.cc b/chromium/net/quic/core/crypto/aes_256_gcm_decrypter_test.cc index 90adceee721..c52767bbd53 100644 --- a/chromium/net/quic/core/crypto/aes_256_gcm_decrypter_test.cc +++ b/chromium/net/quic/core/crypto/aes_256_gcm_decrypter_test.cc @@ -7,6 +7,7 @@ #include <memory> #include "net/quic/core/quic_utils.h" +#include "net/quic/platform/api/quic_arraysize.h" #include "net/quic/platform/api/quic_test.h" #include "net/quic/platform/api/quic_text_utils.h" #include "net/quic/test_tools/quic_test_utils.h" @@ -211,7 +212,7 @@ QuicData* DecryptWithNonce(Aes256GcmDecrypter* decrypter, std::unique_ptr<char[]> output(new char[ciphertext.length()]); size_t output_length = 0; const bool success = decrypter->DecryptPacket( - QuicVersionMax(), 0, associated_data, ciphertext, output.get(), + QuicTransportVersionMax(), 0, associated_data, ciphertext, output.get(), &output_length, ciphertext.length()); if (!success) { return nullptr; @@ -222,7 +223,7 @@ QuicData* DecryptWithNonce(Aes256GcmDecrypter* decrypter, class Aes256GcmDecrypterTest : public QuicTest {}; TEST_F(Aes256GcmDecrypterTest, Decrypt) { - for (size_t i = 0; i < arraysize(test_group_array); i++) { + for (size_t i = 0; i < QUIC_ARRAYSIZE(test_group_array); i++) { SCOPED_TRACE(i); const TestVector* test_vectors = test_group_array[i]; const TestGroupInfo& test_info = test_group_info[i]; diff --git a/chromium/net/quic/core/crypto/aes_256_gcm_encrypter_test.cc b/chromium/net/quic/core/crypto/aes_256_gcm_encrypter_test.cc index 16683cc5cd2..cea40bd777f 100644 --- a/chromium/net/quic/core/crypto/aes_256_gcm_encrypter_test.cc +++ b/chromium/net/quic/core/crypto/aes_256_gcm_encrypter_test.cc @@ -7,6 +7,7 @@ #include <memory> #include "net/quic/core/quic_utils.h" +#include "net/quic/platform/api/quic_arraysize.h" #include "net/quic/platform/api/quic_test.h" #include "net/quic/platform/api/quic_text_utils.h" #include "net/quic/test_tools/quic_test_utils.h" @@ -182,7 +183,7 @@ QuicData* EncryptWithNonce(Aes256GcmEncrypter* encrypter, class Aes256GcmEncrypterTest : public QuicTest {}; TEST_F(Aes256GcmEncrypterTest, Encrypt) { - for (size_t i = 0; i < arraysize(test_group_array); i++) { + for (size_t i = 0; i < QUIC_ARRAYSIZE(test_group_array); i++) { SCOPED_TRACE(i); const TestVector* test_vectors = test_group_array[i]; const TestGroupInfo& test_info = test_group_info[i]; diff --git a/chromium/net/quic/core/crypto/chacha20_poly1305_decrypter.cc b/chromium/net/quic/core/crypto/chacha20_poly1305_decrypter.cc index f28b1b6a8db..ec37f86d269 100644 --- a/chromium/net/quic/core/crypto/chacha20_poly1305_decrypter.cc +++ b/chromium/net/quic/core/crypto/chacha20_poly1305_decrypter.cc @@ -4,8 +4,6 @@ #include "net/quic/core/crypto/chacha20_poly1305_decrypter.h" -#include "net/quic/platform/api/quic_flag_utils.h" -#include "net/quic/platform/api/quic_flags.h" #include "third_party/boringssl/src/include/openssl/aead.h" #include "third_party/boringssl/src/include/openssl/tls1.h" @@ -31,11 +29,7 @@ ChaCha20Poly1305Decrypter::ChaCha20Poly1305Decrypter() ChaCha20Poly1305Decrypter::~ChaCha20Poly1305Decrypter() {} uint32_t ChaCha20Poly1305Decrypter::cipher_id() const { - if (FLAGS_quic_reloadable_flag_quic_use_tls13_cipher_suites) { - QUIC_FLAG_COUNT(quic_reloadable_flag_quic_use_tls13_cipher_suites); - return TLS1_CK_CHACHA20_POLY1305_SHA256; - } - return TLS1_CK_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256; + return TLS1_CK_CHACHA20_POLY1305_SHA256; } } // namespace net diff --git a/chromium/net/quic/core/crypto/chacha20_poly1305_decrypter_test.cc b/chromium/net/quic/core/crypto/chacha20_poly1305_decrypter_test.cc index c9307450890..2a02280f5e8 100644 --- a/chromium/net/quic/core/crypto/chacha20_poly1305_decrypter_test.cc +++ b/chromium/net/quic/core/crypto/chacha20_poly1305_decrypter_test.cc @@ -126,7 +126,7 @@ QuicData* DecryptWithNonce(ChaCha20Poly1305Decrypter* decrypter, std::unique_ptr<char[]> output(new char[ciphertext.length()]); size_t output_length = 0; const bool success = decrypter->DecryptPacket( - QuicVersionMax(), packet_number, associated_data, ciphertext, + QuicTransportVersionMax(), packet_number, associated_data, ciphertext, output.get(), &output_length, ciphertext.length()); if (!success) { return nullptr; diff --git a/chromium/net/quic/core/crypto/chacha20_poly1305_encrypter_test.cc b/chromium/net/quic/core/crypto/chacha20_poly1305_encrypter_test.cc index 544ad0a6a22..e92e407f3c0 100644 --- a/chromium/net/quic/core/crypto/chacha20_poly1305_encrypter_test.cc +++ b/chromium/net/quic/core/crypto/chacha20_poly1305_encrypter_test.cc @@ -8,6 +8,7 @@ #include "net/quic/core/crypto/chacha20_poly1305_decrypter.h" #include "net/quic/core/quic_utils.h" +#include "net/quic/platform/api/quic_arraysize.h" #include "net/quic/platform/api/quic_test.h" #include "net/quic/platform/api/quic_text_utils.h" #include "net/quic/test_tools/quic_test_utils.h" @@ -101,14 +102,14 @@ TEST_F(ChaCha20Poly1305EncrypterTest, EncryptThenDecrypt) { string plaintext = "plaintext"; char encrypted[1024]; size_t len; - ASSERT_TRUE(encrypter.EncryptPacket(QuicVersionMax(), packet_number, + ASSERT_TRUE(encrypter.EncryptPacket(QuicTransportVersionMax(), packet_number, associated_data, plaintext, encrypted, - &len, arraysize(encrypted))); + &len, QUIC_ARRAYSIZE(encrypted))); QuicStringPiece ciphertext(encrypted, len); char decrypted[1024]; - ASSERT_TRUE(decrypter.DecryptPacket(QuicVersionMax(), packet_number, + ASSERT_TRUE(decrypter.DecryptPacket(QuicTransportVersionMax(), packet_number, associated_data, ciphertext, decrypted, - &len, arraysize(decrypted))); + &len, QUIC_ARRAYSIZE(decrypted))); } TEST_F(ChaCha20Poly1305EncrypterTest, Encrypt) { diff --git a/chromium/net/quic/core/crypto/chacha20_poly1305_tls_decrypter_test.cc b/chromium/net/quic/core/crypto/chacha20_poly1305_tls_decrypter_test.cc index 910f53ea3f3..4b2af650e0e 100644 --- a/chromium/net/quic/core/crypto/chacha20_poly1305_tls_decrypter_test.cc +++ b/chromium/net/quic/core/crypto/chacha20_poly1305_tls_decrypter_test.cc @@ -121,7 +121,7 @@ QuicData* DecryptWithNonce(ChaCha20Poly1305TlsDecrypter* decrypter, std::unique_ptr<char[]> output(new char[ciphertext.length()]); size_t output_length = 0; const bool success = decrypter->DecryptPacket( - QuicVersionMax(), 0, associated_data, ciphertext, output.get(), + QuicTransportVersionMax(), 0, associated_data, ciphertext, output.get(), &output_length, ciphertext.length()); if (!success) { return nullptr; diff --git a/chromium/net/quic/core/crypto/chacha20_poly1305_tls_encrypter_test.cc b/chromium/net/quic/core/crypto/chacha20_poly1305_tls_encrypter_test.cc index c4751763494..800b400cfe5 100644 --- a/chromium/net/quic/core/crypto/chacha20_poly1305_tls_encrypter_test.cc +++ b/chromium/net/quic/core/crypto/chacha20_poly1305_tls_encrypter_test.cc @@ -8,6 +8,7 @@ #include "net/quic/core/crypto/chacha20_poly1305_tls_decrypter.h" #include "net/quic/core/quic_utils.h" +#include "net/quic/platform/api/quic_arraysize.h" #include "net/quic/platform/api/quic_test.h" #include "net/quic/platform/api/quic_text_utils.h" #include "net/quic/test_tools/quic_test_utils.h" @@ -100,14 +101,14 @@ TEST_F(ChaCha20Poly1305TlsEncrypterTest, EncryptThenDecrypt) { string plaintext = "plaintext"; char encrypted[1024]; size_t len; - ASSERT_TRUE(encrypter.EncryptPacket(QuicVersionMax(), packet_number, + ASSERT_TRUE(encrypter.EncryptPacket(QuicTransportVersionMax(), packet_number, associated_data, plaintext, encrypted, - &len, arraysize(encrypted))); + &len, QUIC_ARRAYSIZE(encrypted))); QuicStringPiece ciphertext(encrypted, len); char decrypted[1024]; - ASSERT_TRUE(decrypter.DecryptPacket(QuicVersionMax(), packet_number, + ASSERT_TRUE(decrypter.DecryptPacket(QuicTransportVersionMax(), packet_number, associated_data, ciphertext, decrypted, - &len, arraysize(decrypted))); + &len, QUIC_ARRAYSIZE(decrypted))); } TEST_F(ChaCha20Poly1305TlsEncrypterTest, Encrypt) { diff --git a/chromium/net/quic/core/crypto/common_cert_set.cc b/chromium/net/quic/core/crypto/common_cert_set.cc index 9ef68d8cc00..83c3e976706 100644 --- a/chromium/net/quic/core/crypto/common_cert_set.cc +++ b/chromium/net/quic/core/crypto/common_cert_set.cc @@ -9,7 +9,7 @@ #include "base/macros.h" #include "base/memory/singleton.h" #include "net/quic/core/quic_utils.h" - +#include "net/quic/platform/api/quic_arraysize.h" namespace net { @@ -77,11 +77,11 @@ class CommonCertSetsQUIC : public CommonCertSets { // CommonCertSets interface. QuicStringPiece GetCommonHashes() const override { return QuicStringPiece(reinterpret_cast<const char*>(kSetHashes), - sizeof(uint64_t) * arraysize(kSetHashes)); + sizeof(uint64_t) * QUIC_ARRAYSIZE(kSetHashes)); } QuicStringPiece GetCert(uint64_t hash, uint32_t index) const override { - for (size_t i = 0; i < arraysize(kSets); i++) { + for (size_t i = 0; i < QUIC_ARRAYSIZE(kSets); i++) { if (kSets[i].hash == hash) { if (index < kSets[i].num_certs) { return QuicStringPiece( @@ -108,7 +108,7 @@ class CommonCertSetsQUIC : public CommonCertSets { memcpy(&hash, common_set_hashes.data() + i * sizeof(uint64_t), sizeof(uint64_t)); - for (size_t j = 0; j < arraysize(kSets); j++) { + for (size_t j = 0; j < QUIC_ARRAYSIZE(kSets); j++) { if (kSets[j].hash != hash) { continue; } diff --git a/chromium/net/quic/core/crypto/crypto_framer_test.cc b/chromium/net/quic/core/crypto/crypto_framer_test.cc index 9d61aa4ecf1..74691d0aab0 100644 --- a/chromium/net/quic/core/crypto/crypto_framer_test.cc +++ b/chromium/net/quic/core/crypto/crypto_framer_test.cc @@ -11,6 +11,7 @@ #include "net/quic/core/crypto/crypto_handshake.h" #include "net/quic/core/crypto/crypto_protocol.h" #include "net/quic/core/quic_packets.h" +#include "net/quic/platform/api/quic_arraysize.h" #include "net/quic/platform/api/quic_logging.h" #include "net/quic/platform/api/quic_test.h" #include "net/quic/test_tools/crypto_test_utils.h" @@ -92,7 +93,7 @@ TEST_P(CryptoFramerTest, ConstructHandshakeMessage) { ASSERT_TRUE(data.get() != nullptr); test::CompareCharArraysWithHexError("constructed packet", data->data(), data->length(), AsChars(packet), - arraysize(packet)); + QUIC_ARRAYSIZE(packet)); } TEST_P(CryptoFramerTest, ConstructHandshakeMessageWithTwoKeys) { @@ -129,7 +130,7 @@ TEST_P(CryptoFramerTest, ConstructHandshakeMessageWithTwoKeys) { test::CompareCharArraysWithHexError("constructed packet", data->data(), data->length(), AsChars(packet), - arraysize(packet)); + QUIC_ARRAYSIZE(packet)); } TEST_P(CryptoFramerTest, ConstructHandshakeMessageZeroLength) { @@ -157,7 +158,7 @@ TEST_P(CryptoFramerTest, ConstructHandshakeMessageZeroLength) { test::CompareCharArraysWithHexError("constructed packet", data->data(), data->length(), AsChars(packet), - arraysize(packet)); + QUIC_ARRAYSIZE(packet)); } TEST_P(CryptoFramerTest, ConstructHandshakeMessageTooManyEntries) { @@ -209,7 +210,7 @@ TEST_P(CryptoFramerTest, ConstructHandshakeMessageMinimumSize) { test::CompareCharArraysWithHexError("constructed packet", data->data(), data->length(), AsChars(packet), - arraysize(packet)); + QUIC_ARRAYSIZE(packet)); } TEST_P(CryptoFramerTest, ConstructHandshakeMessageMinimumSizePadLast) { @@ -246,7 +247,7 @@ TEST_P(CryptoFramerTest, ConstructHandshakeMessageMinimumSizePadLast) { test::CompareCharArraysWithHexError("constructed packet", data->data(), data->length(), AsChars(packet), - arraysize(packet)); + QUIC_ARRAYSIZE(packet)); } TEST_P(CryptoFramerTest, ProcessInput) { @@ -276,7 +277,7 @@ TEST_P(CryptoFramerTest, ProcessInput) { }; EXPECT_TRUE(framer.ProcessInput( - QuicStringPiece(AsChars(input), arraysize(input)), GetParam())); + QuicStringPiece(AsChars(input), QUIC_ARRAYSIZE(input)), GetParam())); EXPECT_EQ(0u, framer.InputBytesRemaining()); EXPECT_EQ(0, visitor.error_count_); ASSERT_EQ(1u, visitor.messages_.size()); @@ -320,7 +321,7 @@ TEST_P(CryptoFramerTest, ProcessInputWithThreeKeys) { }; EXPECT_TRUE(framer.ProcessInput( - QuicStringPiece(AsChars(input), arraysize(input)), GetParam())); + QuicStringPiece(AsChars(input), QUIC_ARRAYSIZE(input)), GetParam())); EXPECT_EQ(0u, framer.InputBytesRemaining()); EXPECT_EQ(0, visitor.error_count_); ASSERT_EQ(1u, visitor.messages_.size()); @@ -358,7 +359,7 @@ TEST_P(CryptoFramerTest, ProcessInputIncrementally) { 'g', 'h', 'i', 'j', 'k', }; - for (size_t i = 0; i < arraysize(input); i++) { + for (size_t i = 0; i < QUIC_ARRAYSIZE(input); i++) { EXPECT_TRUE(framer.ProcessInput(QuicStringPiece(AsChars(input) + i, 1), GetParam())); } @@ -394,7 +395,7 @@ TEST_P(CryptoFramerTest, ProcessInputTagsOutOfOrder) { }; EXPECT_FALSE(framer.ProcessInput( - QuicStringPiece(AsChars(input), arraysize(input)), GetParam())); + QuicStringPiece(AsChars(input), QUIC_ARRAYSIZE(input)), GetParam())); EXPECT_EQ(QUIC_CRYPTO_TAGS_OUT_OF_ORDER, framer.error()); EXPECT_EQ(1, visitor.error_count_); } @@ -422,7 +423,7 @@ TEST_P(CryptoFramerTest, ProcessEndOffsetsOutOfOrder) { }; EXPECT_FALSE(framer.ProcessInput( - QuicStringPiece(AsChars(input), arraysize(input)), GetParam())); + QuicStringPiece(AsChars(input), QUIC_ARRAYSIZE(input)), GetParam())); EXPECT_EQ(QUIC_CRYPTO_TAGS_OUT_OF_ORDER, framer.error()); EXPECT_EQ(1, visitor.error_count_); } @@ -442,7 +443,7 @@ TEST_P(CryptoFramerTest, ProcessInputTooManyEntries) { }; EXPECT_FALSE(framer.ProcessInput( - QuicStringPiece(AsChars(input), arraysize(input)), GetParam())); + QuicStringPiece(AsChars(input), QUIC_ARRAYSIZE(input)), GetParam())); EXPECT_EQ(QUIC_CRYPTO_TOO_MANY_ENTRIES, framer.error()); EXPECT_EQ(1, visitor.error_count_); } @@ -470,7 +471,7 @@ TEST_P(CryptoFramerTest, ProcessInputZeroLength) { }; EXPECT_TRUE(framer.ProcessInput( - QuicStringPiece(AsChars(input), arraysize(input)), GetParam())); + QuicStringPiece(AsChars(input), QUIC_ARRAYSIZE(input)), GetParam())); EXPECT_EQ(0, visitor.error_count_); } diff --git a/chromium/net/quic/core/crypto/crypto_handshake_message.cc b/chromium/net/quic/core/crypto/crypto_handshake_message.cc index 9081294bc98..037156a4d03 100644 --- a/chromium/net/quic/core/crypto/crypto_handshake_message.cc +++ b/chromium/net/quic/core/crypto/crypto_handshake_message.cc @@ -76,28 +76,16 @@ void CryptoHandshakeMessage::SetVersionVector( QuicTransportVersionVector versions) { QuicVersionLabelVector version_labels; for (QuicTransportVersion version : versions) { - if (!FLAGS_quic_reloadable_flag_quic_use_net_byte_order_version_label) { - version_labels.push_back(QuicVersionToQuicVersionLabel(version)); - } else { - QUIC_FLAG_COUNT_N( - quic_reloadable_flag_quic_use_net_byte_order_version_label, 7, 10); - version_labels.push_back( - QuicEndian::HostToNet32(QuicVersionToQuicVersionLabel(version))); - } + version_labels.push_back( + QuicEndian::HostToNet32(QuicVersionToQuicVersionLabel(version))); } SetVector(tag, version_labels); } void CryptoHandshakeMessage::SetVersion(QuicTag tag, QuicTransportVersion version) { - if (!FLAGS_quic_reloadable_flag_quic_use_net_byte_order_version_label) { - SetValue(tag, QuicVersionToQuicVersionLabel(version)); - } else { - QUIC_FLAG_COUNT_N( - quic_reloadable_flag_quic_use_net_byte_order_version_label, 8, 10); - SetValue(tag, - QuicEndian::HostToNet32(QuicVersionToQuicVersionLabel(version))); - } + SetValue(tag, + QuicEndian::HostToNet32(QuicVersionToQuicVersionLabel(version))); } void CryptoHandshakeMessage::SetStringPiece(QuicTag tag, @@ -139,12 +127,6 @@ QuicErrorCode CryptoHandshakeMessage::GetTaglist( QuicErrorCode CryptoHandshakeMessage::GetVersionLabelList( QuicTag tag, QuicVersionLabelVector* out) const { - if (!FLAGS_quic_reloadable_flag_quic_use_net_byte_order_version_label) { - return GetTaglist(tag, out); - } - - QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_use_net_byte_order_version_label, - 9, 10); QuicErrorCode error = GetTaglist(tag, out); if (error != QUIC_NO_ERROR) { return error; @@ -160,12 +142,6 @@ QuicErrorCode CryptoHandshakeMessage::GetVersionLabelList( QuicErrorCode CryptoHandshakeMessage::GetVersionLabel( QuicTag tag, QuicVersionLabel* out) const { - if (!FLAGS_quic_reloadable_flag_quic_use_net_byte_order_version_label) { - return GetUint32(tag, out); - } - - QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_use_net_byte_order_version_label, - 10, 10); QuicErrorCode error = GetUint32(tag, out); if (error != QUIC_NO_ERROR) { return error; diff --git a/chromium/net/quic/core/crypto/crypto_protocol.h b/chromium/net/quic/core/crypto/crypto_protocol.h index e02a5c504cc..cec1e357433 100644 --- a/chromium/net/quic/core/crypto/crypto_protocol.h +++ b/chromium/net/quic/core/crypto/crypto_protocol.h @@ -113,6 +113,7 @@ const QuicTag kIW20 = TAG('I', 'W', '2', '0'); // Force ICWND to 20 const QuicTag kIW50 = TAG('I', 'W', '5', '0'); // Force ICWND to 50 const QuicTag k1CON = TAG('1', 'C', 'O', 'N'); // Emulate a single connection const QuicTag kNTLP = TAG('N', 'T', 'L', 'P'); // No tail loss probe +const QuicTag k1TLP = TAG('1', 'T', 'L', 'P'); // 1 tail loss probe const QuicTag kNCON = TAG('N', 'C', 'O', 'N'); // N Connection Congestion Ctrl const QuicTag kNRTO = TAG('N', 'R', 'T', 'O'); // CWND reduction on loss const QuicTag kTIME = TAG('T', 'I', 'M', 'E'); // Time based loss detection @@ -146,10 +147,6 @@ const QuicTag kLFAK = TAG('L', 'F', 'A', 'K'); // Don't invoke FACK on the // MAX_HEADER_LIST_SIZE settings frame should be supported. const QuicTag kSMHL = TAG('S', 'M', 'H', 'L'); // Support MAX_HEADER_LIST_SIZE // settings frame. -const QuicTag kCCVX = TAG('C', 'C', 'V', 'X'); // Fix Cubic convex bug. -const QuicTag kCBQT = TAG('C', 'B', 'Q', 'T'); // Fix CubicBytes quantization. -const QuicTag kBLMX = TAG('B', 'L', 'M', 'X'); // Fix Cubic BetaLastMax bug. -const QuicTag kCPAU = TAG('C', 'P', 'A', 'U'); // Allow Cubic per-ack-updates. const QuicTag kNSTP = TAG('N', 'S', 'T', 'P'); // No stop waiting frames. // Optional support of truncated Connection IDs. If sent by a peer, the value diff --git a/chromium/net/quic/core/crypto/crypto_server_test.cc b/chromium/net/quic/core/crypto/crypto_server_test.cc index 346cc2a9990..0bf9d04355c 100644 --- a/chromium/net/quic/core/crypto/crypto_server_test.cc +++ b/chromium/net/quic/core/crypto/crypto_server_test.cc @@ -18,6 +18,8 @@ #include "net/quic/core/crypto/quic_random.h" #include "net/quic/core/quic_socket_address_coder.h" #include "net/quic/core/quic_utils.h" +#include "net/quic/core/tls_server_handshaker.h" +#include "net/quic/platform/api/quic_arraysize.h" #include "net/quic/platform/api/quic_endian.h" #include "net/quic/platform/api/quic_flags.h" #include "net/quic/platform/api/quic_string_piece.h" @@ -108,7 +110,8 @@ class CryptoServerTest : public QuicTestWithParam<TestParams> { client_address_(QuicIpAddress::Loopback4(), 1234), config_(QuicCryptoServerConfig::TESTING, rand_, - crypto_test_utils::ProofSourceForTesting()), + crypto_test_utils::ProofSourceForTesting(), + TlsServerHandshaker::CreateSslCtx()), peer_(&config_), compressed_certs_cache_( QuicCompressedCertsCache::kQuicCompressedCertsCacheSize), @@ -122,8 +125,8 @@ class CryptoServerTest : public QuicTestWithParam<TestParams> { client_version_string_ = QuicVersionLabelToString( QuicVersionToQuicVersionLabel(client_version_)); - FLAGS_quic_reloadable_flag_enable_quic_stateless_reject_support = - GetParam().enable_stateless_rejects; + SetQuicReloadableFlag(enable_quic_stateless_reject_support, + GetParam().enable_stateless_rejects); use_stateless_rejects_ = GetParam().use_stateless_rejects; } @@ -165,7 +168,7 @@ class CryptoServerTest : public QuicTestWithParam<TestParams> { CheckRejectTag(); const HandshakeFailureReason kRejectReasons[] = { SERVER_CONFIG_INCHOATE_HELLO_FAILURE}; - CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); + CheckRejectReasons(kRejectReasons, QUIC_ARRAYSIZE(kRejectReasons)); CheckForServerDesignatedConnectionId(); QuicStringPiece srct; @@ -347,7 +350,8 @@ class CryptoServerTest : public QuicTestWithParam<TestParams> { EXPECT_EQ(expected_count, reject_reasons.size()); for (size_t i = 0; i < reject_reasons.size(); ++i) { - EXPECT_EQ(expected_handshake_failures[i], reject_reasons[i]); + EXPECT_EQ(static_cast<QuicTag>(expected_handshake_failures[i]), + reject_reasons[i]); } } @@ -430,7 +434,7 @@ TEST_P(CryptoServerTest, BadSNI) { }; // clang-format on - for (size_t i = 0; i < arraysize(kBadSNIs); i++) { + for (size_t i = 0; i < QUIC_ARRAYSIZE(kBadSNIs); i++) { CryptoHandshakeMessage msg = crypto_test_utils::CreateCHLO({{"PDMD", "X509"}, {"SNI", kBadSNIs[i]}, @@ -439,7 +443,7 @@ TEST_P(CryptoServerTest, BadSNI) { ShouldFailMentioning("SNI", msg); const HandshakeFailureReason kRejectReasons[] = { SERVER_CONFIG_INCHOATE_HELLO_FAILURE}; - CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); + CheckRejectReasons(kRejectReasons, QUIC_ARRAYSIZE(kRejectReasons)); } } @@ -465,7 +469,7 @@ TEST_P(CryptoServerTest, DefaultCert) { EXPECT_NE(0u, proof.size()); const HandshakeFailureReason kRejectReasons[] = { SERVER_CONFIG_INCHOATE_HELLO_FAILURE}; - CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); + CheckRejectReasons(kRejectReasons, QUIC_ARRAYSIZE(kRejectReasons)); EXPECT_LT(0u, cert_sct.size()); } @@ -492,7 +496,7 @@ TEST_P(CryptoServerTest, RejectTooLarge) { EXPECT_FALSE(out_.GetStringPiece(kCertificateSCTTag, &cert_sct)); const HandshakeFailureReason kRejectReasons[] = { SERVER_CONFIG_INCHOATE_HELLO_FAILURE}; - CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); + CheckRejectReasons(kRejectReasons, QUIC_ARRAYSIZE(kRejectReasons)); } TEST_P(CryptoServerTest, RejectNotTooLarge) { @@ -519,7 +523,7 @@ TEST_P(CryptoServerTest, RejectNotTooLarge) { EXPECT_TRUE(out_.GetStringPiece(kCertificateSCTTag, &cert_sct)); const HandshakeFailureReason kRejectReasons[] = { SERVER_CONFIG_INCHOATE_HELLO_FAILURE}; - CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); + CheckRejectReasons(kRejectReasons, QUIC_ARRAYSIZE(kRejectReasons)); } TEST_P(CryptoServerTest, RejectTooLargeButValidSTK) { @@ -548,7 +552,7 @@ TEST_P(CryptoServerTest, RejectTooLargeButValidSTK) { EXPECT_NE(0u, proof.size()); const HandshakeFailureReason kRejectReasons[] = { SERVER_CONFIG_INCHOATE_HELLO_FAILURE}; - CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); + CheckRejectReasons(kRejectReasons, QUIC_ARRAYSIZE(kRejectReasons)); } TEST_P(CryptoServerTest, TooSmall) { @@ -559,7 +563,7 @@ TEST_P(CryptoServerTest, TooSmall) { const HandshakeFailureReason kRejectReasons[] = { SERVER_CONFIG_INCHOATE_HELLO_FAILURE}; - CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); + CheckRejectReasons(kRejectReasons, QUIC_ARRAYSIZE(kRejectReasons)); } TEST_P(CryptoServerTest, BadSourceAddressToken) { @@ -573,7 +577,7 @@ TEST_P(CryptoServerTest, BadSourceAddressToken) { }; // clang-format on - for (size_t i = 0; i < arraysize(kBadSourceAddressTokens); i++) { + for (size_t i = 0; i < QUIC_ARRAYSIZE(kBadSourceAddressTokens); i++) { CryptoHandshakeMessage msg = crypto_test_utils::CreateCHLO({{"PDMD", "X509"}, {"STK", kBadSourceAddressTokens[i]}, @@ -582,7 +586,7 @@ TEST_P(CryptoServerTest, BadSourceAddressToken) { ShouldSucceed(msg); const HandshakeFailureReason kRejectReasons[] = { SERVER_CONFIG_INCHOATE_HELLO_FAILURE}; - CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); + CheckRejectReasons(kRejectReasons, QUIC_ARRAYSIZE(kRejectReasons)); } } @@ -595,7 +599,7 @@ TEST_P(CryptoServerTest, BadClientNonce) { }; // clang-format on - for (size_t i = 0; i < arraysize(kBadNonces); i++) { + for (size_t i = 0; i < QUIC_ARRAYSIZE(kBadNonces); i++) { // Invalid nonces should be ignored, in an inchoate CHLO. CryptoHandshakeMessage msg = @@ -607,7 +611,7 @@ TEST_P(CryptoServerTest, BadClientNonce) { ShouldSucceed(msg); const HandshakeFailureReason kRejectReasons[] = { SERVER_CONFIG_INCHOATE_HELLO_FAILURE}; - CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); + CheckRejectReasons(kRejectReasons, QUIC_ARRAYSIZE(kRejectReasons)); // Invalid nonces should result in CLIENT_NONCE_INVALID_FAILURE. CryptoHandshakeMessage msg1 = @@ -628,7 +632,7 @@ TEST_P(CryptoServerTest, BadClientNonce) { CheckRejectTag(); const HandshakeFailureReason kRejectReasons1[] = { CLIENT_NONCE_INVALID_FAILURE}; - CheckRejectReasons(kRejectReasons1, arraysize(kRejectReasons1)); + CheckRejectReasons(kRejectReasons1, QUIC_ARRAYSIZE(kRejectReasons1)); } } @@ -642,7 +646,7 @@ TEST_P(CryptoServerTest, NoClientNonce) { ShouldSucceed(msg); const HandshakeFailureReason kRejectReasons[] = { SERVER_CONFIG_INCHOATE_HELLO_FAILURE}; - CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); + CheckRejectReasons(kRejectReasons, QUIC_ARRAYSIZE(kRejectReasons)); CryptoHandshakeMessage msg1 = crypto_test_utils::CreateCHLO({{"PDMD", "X509"}, @@ -659,7 +663,7 @@ TEST_P(CryptoServerTest, NoClientNonce) { CheckRejectTag(); const HandshakeFailureReason kRejectReasons1[] = { SERVER_CONFIG_INCHOATE_HELLO_FAILURE}; - CheckRejectReasons(kRejectReasons1, arraysize(kRejectReasons1)); + CheckRejectReasons(kRejectReasons1, QUIC_ARRAYSIZE(kRejectReasons1)); } TEST_P(CryptoServerTest, DowngradeAttack) { @@ -678,7 +682,7 @@ TEST_P(CryptoServerTest, DowngradeAttack) { ShouldFailMentioning("Downgrade", msg); const HandshakeFailureReason kRejectReasons[] = { SERVER_CONFIG_INCHOATE_HELLO_FAILURE}; - CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); + CheckRejectReasons(kRejectReasons, QUIC_ARRAYSIZE(kRejectReasons)); } TEST_P(CryptoServerTest, CorruptServerConfig) { @@ -698,7 +702,7 @@ TEST_P(CryptoServerTest, CorruptServerConfig) { CheckRejectTag(); const HandshakeFailureReason kRejectReasons[] = { SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE}; - CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); + CheckRejectReasons(kRejectReasons, QUIC_ARRAYSIZE(kRejectReasons)); } TEST_P(CryptoServerTest, CorruptSourceAddressToken) { @@ -719,7 +723,7 @@ TEST_P(CryptoServerTest, CorruptSourceAddressToken) { CheckRejectTag(); const HandshakeFailureReason kRejectReasons[] = { SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE}; - CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); + CheckRejectReasons(kRejectReasons, QUIC_ARRAYSIZE(kRejectReasons)); } TEST_P(CryptoServerTest, CorruptClientNonceAndSourceAddressToken) { @@ -740,7 +744,7 @@ TEST_P(CryptoServerTest, CorruptClientNonceAndSourceAddressToken) { CheckRejectTag(); const HandshakeFailureReason kRejectReasons[] = { SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE, CLIENT_NONCE_INVALID_FAILURE}; - CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); + CheckRejectReasons(kRejectReasons, QUIC_ARRAYSIZE(kRejectReasons)); } TEST_P(CryptoServerTest, CorruptMultipleTags) { @@ -764,7 +768,7 @@ TEST_P(CryptoServerTest, CorruptMultipleTags) { const HandshakeFailureReason kRejectReasons[] = { SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE, CLIENT_NONCE_INVALID_FAILURE}; - CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); + CheckRejectReasons(kRejectReasons, QUIC_ARRAYSIZE(kRejectReasons)); } TEST_P(CryptoServerTest, NoServerNonce) { @@ -813,7 +817,7 @@ TEST_P(CryptoServerTest, ProofForSuppliedServerConfig) { CheckRejectTag(); const HandshakeFailureReason kRejectReasons[] = { SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE}; - CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); + CheckRejectReasons(kRejectReasons, QUIC_ARRAYSIZE(kRejectReasons)); QuicStringPiece cert, proof, scfg_str; EXPECT_TRUE(out_.GetStringPiece(kCertificateTag, &cert)); @@ -874,7 +878,7 @@ TEST_P(CryptoServerTest, RejectInvalidXlct) { const HandshakeFailureReason kRejectReasons[] = { INVALID_EXPECTED_LEAF_CERTIFICATE}; - CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); + CheckRejectReasons(kRejectReasons, QUIC_ARRAYSIZE(kRejectReasons)); } TEST_P(CryptoServerTest, ValidXlct) { @@ -942,6 +946,57 @@ TEST_P(CryptoServerTest, ProofSourceFailure) { ShouldFailMentioning("", msg); } +// Regression test for crbug.com/723604 +// For 2RTT, if the first CHLO from the client contains hashes of cached +// certs (stored in CCRT tag) but the second CHLO does not, then the second REJ +// from the server should not contain hashes of cached certs. +TEST_P(CryptoServerTest, TwoRttServerDropCachedCerts) { + // Send inchoate CHLO to get cert chain from server. This CHLO is only for + // the purpose of getting the server's certs; it is not part of the 2RTT + // handshake. + CryptoHandshakeMessage msg = crypto_test_utils::CreateCHLO( + {{"PDMD", "X509"}, {"VER\0", client_version_string_}}, + kClientHelloMinimumSize); + ShouldSucceed(msg); + + // Decompress cert chain from server to individual certs. + QuicStringPiece certs_compressed; + ASSERT_TRUE(out_.GetStringPiece(kCertificateTag, &certs_compressed)); + ASSERT_NE(0u, certs_compressed.size()); + std::vector<string> certs; + ASSERT_TRUE(CertCompressor::DecompressChain( + certs_compressed, /*cached_certs=*/{}, /*common_sets=*/nullptr, &certs)); + + // Start 2-RTT. Client sends CHLO with bad source-address token and hashes of + // the certs, which tells the server that the client has cached those certs. + config_.set_chlo_multiplier(1); + const char kBadSourceAddressToken[] = ""; + msg.SetStringPiece(kSourceAddressTokenTag, kBadSourceAddressToken); + std::vector<uint64_t> hashes(certs.size()); + for (size_t i = 0; i < certs.size(); ++i) { + hashes[i] = QuicUtils::QuicUtils::FNV1a_64_Hash(certs[i]); + } + msg.SetVector(kCCRT, hashes); + ShouldSucceed(msg); + + // Server responds with inchoate REJ containing valid source-address token. + QuicStringPiece srct; + ASSERT_TRUE(out_.GetStringPiece(kSourceAddressTokenTag, &srct)); + + // Client now drops cached certs; sends CHLO with updated source-address + // token but no hashes of certs. + msg.SetStringPiece(kSourceAddressTokenTag, srct); + msg.Erase(kCCRT); + ShouldSucceed(msg); + + // Server response's cert chain should not contain hashes of + // previously-cached certs. + ASSERT_TRUE(out_.GetStringPiece(kCertificateTag, &certs_compressed)); + ASSERT_NE(0u, certs_compressed.size()); + ASSERT_TRUE(CertCompressor::DecompressChain( + certs_compressed, /*cached_certs=*/{}, /*common_sets=*/nullptr, &certs)); +} + class CryptoServerConfigGenerationTest : public QuicTest {}; TEST_F(CryptoServerConfigGenerationTest, Determinism) { @@ -953,9 +1008,11 @@ TEST_F(CryptoServerConfigGenerationTest, Determinism) { MockClock clock; QuicCryptoServerConfig a(QuicCryptoServerConfig::TESTING, &rand_a, - crypto_test_utils::ProofSourceForTesting()); + crypto_test_utils::ProofSourceForTesting(), + TlsServerHandshaker::CreateSslCtx()); QuicCryptoServerConfig b(QuicCryptoServerConfig::TESTING, &rand_b, - crypto_test_utils::ProofSourceForTesting()); + crypto_test_utils::ProofSourceForTesting(), + TlsServerHandshaker::CreateSslCtx()); std::unique_ptr<CryptoHandshakeMessage> scfg_a( a.AddDefaultConfig(&rand_a, &clock, options)); std::unique_ptr<CryptoHandshakeMessage> scfg_b( @@ -974,10 +1031,12 @@ TEST_F(CryptoServerConfigGenerationTest, SCIDVaries) { MockClock clock; QuicCryptoServerConfig a(QuicCryptoServerConfig::TESTING, &rand_a, - crypto_test_utils::ProofSourceForTesting()); + crypto_test_utils::ProofSourceForTesting(), + TlsServerHandshaker::CreateSslCtx()); rand_b.ChangeValue(); QuicCryptoServerConfig b(QuicCryptoServerConfig::TESTING, &rand_b, - crypto_test_utils::ProofSourceForTesting()); + crypto_test_utils::ProofSourceForTesting(), + TlsServerHandshaker::CreateSslCtx()); std::unique_ptr<CryptoHandshakeMessage> scfg_a( a.AddDefaultConfig(&rand_a, &clock, options)); std::unique_ptr<CryptoHandshakeMessage> scfg_b( @@ -996,7 +1055,8 @@ TEST_F(CryptoServerConfigGenerationTest, SCIDIsHashOfServerConfig) { MockClock clock; QuicCryptoServerConfig a(QuicCryptoServerConfig::TESTING, &rand_a, - crypto_test_utils::ProofSourceForTesting()); + crypto_test_utils::ProofSourceForTesting(), + TlsServerHandshaker::CreateSslCtx()); std::unique_ptr<CryptoHandshakeMessage> scfg( a.AddDefaultConfig(&rand_a, &clock, options)); @@ -1034,7 +1094,7 @@ TEST_P(CryptoServerTestNoConfig, DontCrash) { const HandshakeFailureReason kRejectReasons[] = { SERVER_CONFIG_INCHOATE_HELLO_FAILURE}; - CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); + CheckRejectReasons(kRejectReasons, QUIC_ARRAYSIZE(kRejectReasons)); } class CryptoServerTestOldVersion : public CryptoServerTest { diff --git a/chromium/net/quic/core/crypto/crypto_utils.cc b/chromium/net/quic/core/crypto/crypto_utils.cc index 8cdda7a16b7..62668344158 100644 --- a/chromium/net/quic/core/crypto/crypto_utils.cc +++ b/chromium/net/quic/core/crypto/crypto_utils.cc @@ -14,8 +14,11 @@ #include "net/quic/core/crypto/quic_random.h" #include "net/quic/core/quic_time.h" #include "net/quic/core/quic_utils.h" +#include "net/quic/platform/api/quic_arraysize.h" #include "net/quic/platform/api/quic_bug_tracker.h" #include "net/quic/platform/api/quic_logging.h" +#include "third_party/boringssl/src/include/openssl/bytestring.h" +#include "third_party/boringssl/src/include/openssl/hkdf.h" #include "third_party/boringssl/src/include/openssl/sha.h" using std::string; @@ -23,6 +26,39 @@ using std::string; namespace net { // static +std::vector<uint8_t> CryptoUtils::HkdfExpandLabel( + const EVP_MD* prf, + const std::vector<uint8_t>& secret, + const string& label, + size_t out_len) { + CBB hkdf_label, inner_label; + const char label_prefix[] = "tls13 "; + if (!CBB_init(&hkdf_label, 1) || !CBB_add_u16(&hkdf_label, out_len) || + !CBB_add_u8_length_prefixed(&hkdf_label, &inner_label) || + !CBB_add_bytes(&inner_label, + reinterpret_cast<const uint8_t*>(label_prefix), + QUIC_ARRAYSIZE(label_prefix) - 1) || + !CBB_add_bytes(&inner_label, + reinterpret_cast<const uint8_t*>(label.data()), + label.size()) || + !CBB_add_u8(&hkdf_label, 0) || !CBB_flush(&hkdf_label)) { + QUIC_LOG(ERROR) << "Building HKDF label failed"; + CBB_cleanup(&hkdf_label); + std::vector<uint8_t>(); + } + std::vector<uint8_t> out; + out.resize(out_len); + if (!HKDF_expand(out.data(), out_len, prf, secret.data(), secret.size(), + CBB_data(&hkdf_label), CBB_len(&hkdf_label))) { + QUIC_LOG(ERROR) << "Running HKDF-Expand-Label failed"; + CBB_cleanup(&hkdf_label); + std::vector<uint8_t>(); + } + CBB_cleanup(&hkdf_label); + return out; +} + +// static void CryptoUtils::GenerateNonce(QuicWallTime now, QuicRandom* random_generator, QuicStringPiece orbit, @@ -59,8 +95,8 @@ bool CryptoUtils::DeriveKeys(QuicStringPiece premaster_secret, Diversification diversification, CrypterPair* crypters, string* subkey_secret) { - crypters->encrypter.reset(QuicEncrypter::Create(aead)); - crypters->decrypter.reset(QuicDecrypter::Create(aead)); + crypters->encrypter = QuicEncrypter::Create(aead); + crypters->decrypter = QuicDecrypter::Create(aead); size_t key_bytes = crypters->encrypter->GetKeySize(); size_t nonce_prefix_bytes = crypters->encrypter->GetNoncePrefixSize(); size_t subkey_secret_bytes = diff --git a/chromium/net/quic/core/crypto/crypto_utils.h b/chromium/net/quic/core/crypto/crypto_utils.h index 537f15051af..ca42d901ba2 100644 --- a/chromium/net/quic/core/crypto/crypto_utils.h +++ b/chromium/net/quic/core/crypto/crypto_utils.h @@ -19,6 +19,7 @@ #include "net/quic/core/quic_time.h" #include "net/quic/platform/api/quic_export.h" #include "net/quic/platform/api/quic_string_piece.h" +#include "third_party/boringssl/src/include/openssl/evp.h" namespace net { @@ -68,6 +69,22 @@ class QUIC_EXPORT_PRIVATE CryptoUtils { DiversificationNonce* nonce_; }; + // Implements the HKDF-Expand-Label function as defined in section 7.1 of TLS + // 1.3. The HKDF-Expand-Label definition assumes that the TLS connection's PRF + // will be used as the Hash function for HKDF; in this function it is + // explicitly passed in as |prf|. The inputs to HKDF-Expand-Label are as + // follows: + // + // Secret: |secret| + // Label: |label| + // Context: zero-length context + // Length: |out_len| + static std::vector<uint8_t> HkdfExpandLabel( + const EVP_MD* prf, + const std::vector<uint8_t>& secret, + const std::string& label, + size_t out_len); + // Generates the connection nonce. The nonce is formed as: // <4 bytes> current time // <8 bytes> |orbit| (or random if |orbit| is empty) diff --git a/chromium/net/quic/core/crypto/crypto_utils_test.cc b/chromium/net/quic/core/crypto/crypto_utils_test.cc index ef00ced4653..ad5ad9953ff 100644 --- a/chromium/net/quic/core/crypto/crypto_utils_test.cc +++ b/chromium/net/quic/core/crypto/crypto_utils_test.cc @@ -5,6 +5,7 @@ #include "net/quic/core/crypto/crypto_utils.h" #include "net/quic/core/quic_utils.h" +#include "net/quic/platform/api/quic_arraysize.h" #include "net/quic/platform/api/quic_test.h" #include "net/quic/platform/api/quic_text_utils.h" #include "net/quic/test_tools/quic_test_utils.h" @@ -17,6 +18,25 @@ namespace { class CryptoUtilsTest : public QuicTest {}; +TEST_F(CryptoUtilsTest, TestHkdfExpandLabel) { + // This test vector is from + // https://github.com/quicwg/base-drafts/wiki/Test-Vector-for-the-Clear-Text-AEAD-key-derivation + const std::vector<uint8_t> secret = { + 0x8f, 0x01, 0x00, 0x67, 0x9c, 0x96, 0x5a, 0xc5, 0x9f, 0x28, 0x3a, + 0x02, 0x52, 0x2a, 0x6e, 0x43, 0xcf, 0xae, 0xf6, 0x3c, 0x45, 0x48, + 0xb0, 0xa6, 0x8f, 0x91, 0x91, 0x40, 0xee, 0x7d, 0x9a, 0x48}; + const string label = "QUIC client cleartext Secret"; + std::vector<uint8_t> out = + CryptoUtils::HkdfExpandLabel(EVP_sha256(), secret, label, 32); + + std::vector<uint8_t> expected_out = { + 0x31, 0xba, 0x96, 0x68, 0x73, 0xf7, 0xf4, 0x53, 0xe6, 0xc8, 0xa1, + 0xbf, 0x78, 0xed, 0x70, 0x13, 0xfa, 0xd8, 0x3f, 0xfc, 0xee, 0xfc, + 0x95, 0x68, 0x81, 0xcd, 0x24, 0x1c, 0x0a, 0xe3, 0xa7, 0xa6}; + + EXPECT_EQ(out, expected_out); +} + TEST_F(CryptoUtilsTest, TestExportKeyingMaterial) { const struct TestVector { // Input (strings of hexadecimal digits): @@ -48,7 +68,7 @@ TEST_F(CryptoUtilsTest, TestExportKeyingMaterial) { "c9a46ed0757bd1812f1f21b4d41e62125fec8364a21db7"}, }; - for (size_t i = 0; i < arraysize(test_vector); i++) { + for (size_t i = 0; i < QUIC_ARRAYSIZE(test_vector); i++) { // Decode the test vector. string subkey_secret = QuicTextUtils::HexDecode(test_vector[i].subkey_secret); diff --git a/chromium/net/quic/core/crypto/null_decrypter.cc b/chromium/net/quic/core/crypto/null_decrypter.cc index 6dc7cad8667..8d76dfb7b0b 100644 --- a/chromium/net/quic/core/crypto/null_decrypter.cc +++ b/chromium/net/quic/core/crypto/null_decrypter.cc @@ -69,6 +69,14 @@ bool NullDecrypter::DecryptPacket(QuicTransportVersion version, return true; } +size_t NullDecrypter::GetKeySize() const { + return 0; +} + +size_t NullDecrypter::GetIVSize() const { + return 0; +} + QuicStringPiece NullDecrypter::GetKey() const { return QuicStringPiece(); } diff --git a/chromium/net/quic/core/crypto/null_decrypter.h b/chromium/net/quic/core/crypto/null_decrypter.h index 63d923b1b33..0ca74fe8cc0 100644 --- a/chromium/net/quic/core/crypto/null_decrypter.h +++ b/chromium/net/quic/core/crypto/null_decrypter.h @@ -41,6 +41,8 @@ class QUIC_EXPORT_PRIVATE NullDecrypter : public QuicDecrypter { char* output, size_t* output_length, size_t max_output_length) override; + size_t GetKeySize() const override; + size_t GetIVSize() const override; QuicStringPiece GetKey() const override; QuicStringPiece GetNoncePrefix() const override; diff --git a/chromium/net/quic/core/crypto/null_decrypter_test.cc b/chromium/net/quic/core/crypto/null_decrypter_test.cc index fe6a252e2ea..3b83c20c2a2 100644 --- a/chromium/net/quic/core/crypto/null_decrypter_test.cc +++ b/chromium/net/quic/core/crypto/null_decrypter_test.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "net/quic/core/crypto/null_decrypter.h" +#include "net/quic/platform/api/quic_arraysize.h" #include "net/quic/platform/api/quic_test.h" #include "net/quic/test_tools/quic_test_utils.h" @@ -19,7 +20,7 @@ TEST_F(NullDecrypterTest, DecryptClient) { 'g', 'o', 'o', 'd', 'b', 'y', 'e', '!', }; const char* data = reinterpret_cast<const char*>(expected); - size_t len = arraysize(expected); + size_t len = QUIC_ARRAYSIZE(expected); NullDecrypter decrypter(Perspective::IS_SERVER); char buffer[256]; size_t length = 0; @@ -38,7 +39,7 @@ TEST_F(NullDecrypterTest, DecryptServer) { 'g', 'o', 'o', 'd', 'b', 'y', 'e', '!', }; const char* data = reinterpret_cast<const char*>(expected); - size_t len = arraysize(expected); + size_t len = QUIC_ARRAYSIZE(expected); NullDecrypter decrypter(Perspective::IS_CLIENT); char buffer[256]; size_t length = 0; @@ -57,7 +58,7 @@ TEST_F(NullDecrypterTest, DecryptClientPre37) { 'g', 'o', 'o', 'd', 'b', 'y', 'e', '!', }; const char* data = reinterpret_cast<const char*>(expected); - size_t len = arraysize(expected); + size_t len = QUIC_ARRAYSIZE(expected); NullDecrypter decrypter(Perspective::IS_CLIENT); char buffer[256]; size_t length = 0; @@ -76,7 +77,7 @@ TEST_F(NullDecrypterTest, DecryptServerPre37) { 'g', 'o', 'o', 'd', 'b', 'y', 'e', '!', }; const char* data = reinterpret_cast<const char*>(expected); - size_t len = arraysize(expected); + size_t len = QUIC_ARRAYSIZE(expected); NullDecrypter decrypter(Perspective::IS_SERVER); char buffer[256]; size_t length = 0; @@ -95,7 +96,7 @@ TEST_F(NullDecrypterTest, BadHash) { 'g', 'o', 'o', 'd', 'b', 'y', 'e', '!', }; const char* data = reinterpret_cast<const char*>(expected); - size_t len = arraysize(expected); + size_t len = QUIC_ARRAYSIZE(expected); NullDecrypter decrypter(Perspective::IS_CLIENT); char buffer[256]; size_t length = 0; @@ -110,7 +111,7 @@ TEST_F(NullDecrypterTest, ShortInput) { 0x46, 0x11, 0xea, 0x5f, 0xcf, 0x1d, 0x66, 0x5b, 0xba, 0xf0, 0xbc, }; const char* data = reinterpret_cast<const char*>(expected); - size_t len = arraysize(expected); + size_t len = QUIC_ARRAYSIZE(expected); NullDecrypter decrypter(Perspective::IS_CLIENT); char buffer[256]; size_t length = 0; diff --git a/chromium/net/quic/core/crypto/null_encrypter.cc b/chromium/net/quic/core/crypto/null_encrypter.cc index 0cc7f3d8162..999d717c85b 100644 --- a/chromium/net/quic/core/crypto/null_encrypter.cc +++ b/chromium/net/quic/core/crypto/null_encrypter.cc @@ -68,6 +68,10 @@ size_t NullEncrypter::GetNoncePrefixSize() const { return 0; } +size_t NullEncrypter::GetIVSize() const { + return 0; +} + size_t NullEncrypter::GetMaxPlaintextSize(size_t ciphertext_size) const { return ciphertext_size - GetHashLength(); } diff --git a/chromium/net/quic/core/crypto/null_encrypter.h b/chromium/net/quic/core/crypto/null_encrypter.h index d6f114eb530..919a222737f 100644 --- a/chromium/net/quic/core/crypto/null_encrypter.h +++ b/chromium/net/quic/core/crypto/null_encrypter.h @@ -37,6 +37,7 @@ class QUIC_EXPORT_PRIVATE NullEncrypter : public QuicEncrypter { size_t max_output_length) override; size_t GetKeySize() const override; size_t GetNoncePrefixSize() const override; + size_t GetIVSize() const override; size_t GetMaxPlaintextSize(size_t ciphertext_size) const override; size_t GetCiphertextSize(size_t plaintext_size) const override; QuicStringPiece GetKey() const override; diff --git a/chromium/net/quic/core/crypto/null_encrypter_test.cc b/chromium/net/quic/core/crypto/null_encrypter_test.cc index 00f24cdbe12..21aa85e5c56 100644 --- a/chromium/net/quic/core/crypto/null_encrypter_test.cc +++ b/chromium/net/quic/core/crypto/null_encrypter_test.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "net/quic/core/crypto/null_encrypter.h" +#include "net/quic/platform/api/quic_arraysize.h" #include "net/quic/platform/api/quic_test.h" #include "net/quic/test_tools/quic_test_utils.h" @@ -26,7 +27,7 @@ TEST_F(NullEncrypterTest, EncryptClient) { 256)); test::CompareCharArraysWithHexError( "encrypted data", encrypted, encrypted_len, - reinterpret_cast<const char*>(expected), arraysize(expected)); + reinterpret_cast<const char*>(expected), QUIC_ARRAYSIZE(expected)); } TEST_F(NullEncrypterTest, EncryptServer) { @@ -44,7 +45,7 @@ TEST_F(NullEncrypterTest, EncryptServer) { 256)); test::CompareCharArraysWithHexError( "encrypted data", encrypted, encrypted_len, - reinterpret_cast<const char*>(expected), arraysize(expected)); + reinterpret_cast<const char*>(expected), QUIC_ARRAYSIZE(expected)); } TEST_F(NullEncrypterTest, EncryptClientPre37) { @@ -62,7 +63,7 @@ TEST_F(NullEncrypterTest, EncryptClientPre37) { 256)); test::CompareCharArraysWithHexError( "encrypted data", encrypted, encrypted_len, - reinterpret_cast<const char*>(expected), arraysize(expected)); + reinterpret_cast<const char*>(expected), QUIC_ARRAYSIZE(expected)); } TEST_F(NullEncrypterTest, EncryptServerPre37) { @@ -80,7 +81,7 @@ TEST_F(NullEncrypterTest, EncryptServerPre37) { 256)); test::CompareCharArraysWithHexError( "encrypted data", encrypted, encrypted_len, - reinterpret_cast<const char*>(expected), arraysize(expected)); + reinterpret_cast<const char*>(expected), QUIC_ARRAYSIZE(expected)); } TEST_F(NullEncrypterTest, GetMaxPlaintextSize) { diff --git a/chromium/net/quic/core/crypto/quic_crypto_client_config.cc b/chromium/net/quic/core/crypto/quic_crypto_client_config.cc index 9c77f54f02b..8f0f0fcd894 100644 --- a/chromium/net/quic/core/crypto/quic_crypto_client_config.cc +++ b/chromium/net/quic/core/crypto/quic_crypto_client_config.cc @@ -21,6 +21,7 @@ #include "net/quic/core/crypto/quic_encrypter.h" #include "net/quic/core/crypto/quic_random.h" #include "net/quic/core/quic_utils.h" +#include "net/quic/platform/api/quic_arraysize.h" #include "net/quic/platform/api/quic_bug_tracker.h" #include "net/quic/platform/api/quic_endian.h" #include "net/quic/platform/api/quic_hostname_utils.h" @@ -28,6 +29,7 @@ #include "net/quic/platform/api/quic_map_util.h" #include "net/quic/platform/api/quic_ptr_util.h" #include "net/quic/platform/api/quic_text_utils.h" +#include "third_party/boringssl/src/include/openssl/ssl.h" using std::string; @@ -55,8 +57,9 @@ void RecordDiskCacheServerConfigState( } // namespace QuicCryptoClientConfig::QuicCryptoClientConfig( - std::unique_ptr<ProofVerifier> proof_verifier) - : proof_verifier_(std::move(proof_verifier)) { + std::unique_ptr<ProofVerifier> proof_verifier, + bssl::UniquePtr<SSL_CTX> ssl_ctx) + : proof_verifier_(std::move(proof_verifier)), ssl_ctx_(std::move(ssl_ctx)) { DCHECK(proof_verifier_.get()); SetDefaults(); } @@ -466,9 +469,9 @@ void QuicCryptoClientConfig::FillInchoateClientHello( } char proof_nonce[32]; - rand->RandBytes(proof_nonce, arraysize(proof_nonce)); - out->SetStringPiece(kNONP, - QuicStringPiece(proof_nonce, arraysize(proof_nonce))); + rand->RandBytes(proof_nonce, QUIC_ARRAYSIZE(proof_nonce)); + out->SetStringPiece( + kNONP, QuicStringPiece(proof_nonce, QUIC_ARRAYSIZE(proof_nonce))); out->SetVector(kPDMD, QuicTagVector{kX509}); @@ -923,6 +926,10 @@ ChannelIDSource* QuicCryptoClientConfig::channel_id_source() const { return channel_id_source_.get(); } +SSL_CTX* QuicCryptoClientConfig::ssl_ctx() const { + return ssl_ctx_.get(); +} + void QuicCryptoClientConfig::SetChannelIDSource(ChannelIDSource* source) { channel_id_source_.reset(source); } diff --git a/chromium/net/quic/core/crypto/quic_crypto_client_config.h b/chromium/net/quic/core/crypto/quic_crypto_client_config.h index e5b413e4f7a..db8b23ef182 100644 --- a/chromium/net/quic/core/crypto/quic_crypto_client_config.h +++ b/chromium/net/quic/core/crypto/quic_crypto_client_config.h @@ -18,6 +18,7 @@ #include "net/quic/platform/api/quic_export.h" #include "net/quic/platform/api/quic_reference_counted.h" #include "net/quic/platform/api/quic_string_piece.h" +#include "third_party/boringssl/src/include/openssl/base.h" namespace net { @@ -206,8 +207,8 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig { virtual bool Matches(const QuicServerId& server_id) const = 0; }; - explicit QuicCryptoClientConfig( - std::unique_ptr<ProofVerifier> proof_verifier); + QuicCryptoClientConfig(std::unique_ptr<ProofVerifier> proof_verifier, + bssl::UniquePtr<SSL_CTX> ssl_ctx); ~QuicCryptoClientConfig(); // LookupOrCreate returns a CachedState for the given |server_id|. If no such @@ -313,6 +314,8 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig { ChannelIDSource* channel_id_source() const; + SSL_CTX* ssl_ctx() const; + // SetChannelIDSource sets a ChannelIDSource that will be called, when the // server supports channel IDs, to obtain a channel ID for signing a message // proving possession of the channel ID. This object takes ownership of @@ -385,6 +388,7 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig { std::unique_ptr<ProofVerifier> proof_verifier_; std::unique_ptr<ChannelIDSource> channel_id_source_; + bssl::UniquePtr<SSL_CTX> ssl_ctx_; // The |user_agent_id_| passed in QUIC's CHLO message. std::string user_agent_id_; diff --git a/chromium/net/quic/core/crypto/quic_crypto_client_config_test.cc b/chromium/net/quic/core/crypto/quic_crypto_client_config_test.cc index 642e6a84719..d006c0f9ae7 100644 --- a/chromium/net/quic/core/crypto/quic_crypto_client_config_test.cc +++ b/chromium/net/quic/core/crypto/quic_crypto_client_config_test.cc @@ -7,6 +7,7 @@ #include "net/quic/core/crypto/proof_verifier.h" #include "net/quic/core/quic_server_id.h" #include "net/quic/core/quic_utils.h" +#include "net/quic/core/tls_client_handshaker.h" #include "net/quic/platform/api/quic_endian.h" #include "net/quic/platform/api/quic_test.h" #include "net/quic/test_tools/crypto_test_utils.h" @@ -173,7 +174,8 @@ TEST_F(QuicCryptoClientConfigTest, CachedState_InitializeFrom) { TEST_F(QuicCryptoClientConfigTest, InchoateChlo) { QuicCryptoClientConfig::CachedState state; - QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting()); + QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting(), + TlsClientHandshaker::CreateSslCtx()); config.set_user_agent_id("quic-tester"); config.set_alpn("hq"); QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params( @@ -181,12 +183,13 @@ TEST_F(QuicCryptoClientConfigTest, InchoateChlo) { CryptoHandshakeMessage msg; QuicServerId server_id("www.google.com", 443, PRIVACY_MODE_DISABLED); MockRandom rand; - config.FillInchoateClientHello(server_id, QuicVersionMax(), &state, &rand, + config.FillInchoateClientHello(server_id, QuicTransportVersionMax(), &state, + &rand, /* demand_x509_proof= */ true, params, &msg); QuicVersionLabel cver; EXPECT_EQ(QUIC_NO_ERROR, msg.GetVersionLabel(kVER, &cver)); - EXPECT_EQ(QuicVersionToQuicVersionLabel(QuicVersionMax()), cver); + EXPECT_EQ(QuicVersionToQuicVersionLabel(QuicTransportVersionMax()), cver); QuicStringPiece proof_nonce; EXPECT_TRUE(msg.GetStringPiece(kNONP, &proof_nonce)); EXPECT_EQ(string(32, 'r'), proof_nonce); @@ -199,7 +202,8 @@ TEST_F(QuicCryptoClientConfigTest, InchoateChlo) { } TEST_F(QuicCryptoClientConfigTest, PreferAesGcm) { - QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting()); + QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting(), + TlsClientHandshaker::CreateSslCtx()); if (config.aead.size() > 1) EXPECT_NE(kAESG, config.aead[0]); config.PreferAesGcm(); @@ -208,13 +212,15 @@ TEST_F(QuicCryptoClientConfigTest, PreferAesGcm) { TEST_F(QuicCryptoClientConfigTest, InchoateChloSecure) { QuicCryptoClientConfig::CachedState state; - QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting()); + QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting(), + TlsClientHandshaker::CreateSslCtx()); QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params( new QuicCryptoNegotiatedParameters); CryptoHandshakeMessage msg; QuicServerId server_id("www.google.com", 443, PRIVACY_MODE_DISABLED); MockRandom rand; - config.FillInchoateClientHello(server_id, QuicVersionMax(), &state, &rand, + config.FillInchoateClientHello(server_id, QuicTransportVersionMax(), &state, + &rand, /* demand_x509_proof= */ true, params, &msg); QuicTag pdmd; @@ -238,13 +244,15 @@ TEST_F(QuicCryptoClientConfigTest, InchoateChloSecureWithSCIDNoEXPY) { scfg.GetSerialized(Perspective::IS_CLIENT).AsStringPiece(), now, expiry, &details); - QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting()); + QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting(), + TlsClientHandshaker::CreateSslCtx()); QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params( new QuicCryptoNegotiatedParameters); CryptoHandshakeMessage msg; QuicServerId server_id("www.google.com", 443, PRIVACY_MODE_DISABLED); MockRandom rand; - config.FillInchoateClientHello(server_id, QuicVersionMax(), &state, &rand, + config.FillInchoateClientHello(server_id, QuicTransportVersionMax(), &state, + &rand, /* demand_x509_proof= */ true, params, &msg); QuicStringPiece scid; @@ -265,13 +273,15 @@ TEST_F(QuicCryptoClientConfigTest, InchoateChloSecureWithSCID) { QuicWallTime::FromUNIXSeconds(1), QuicWallTime::FromUNIXSeconds(0), &details); - QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting()); + QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting(), + TlsClientHandshaker::CreateSslCtx()); QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params( new QuicCryptoNegotiatedParameters); CryptoHandshakeMessage msg; QuicServerId server_id("www.google.com", 443, PRIVACY_MODE_DISABLED); MockRandom rand; - config.FillInchoateClientHello(server_id, QuicVersionMax(), &state, &rand, + config.FillInchoateClientHello(server_id, QuicTransportVersionMax(), &state, + &rand, /* demand_x509_proof= */ true, params, &msg); QuicStringPiece scid; @@ -281,7 +291,8 @@ TEST_F(QuicCryptoClientConfigTest, InchoateChloSecureWithSCID) { TEST_F(QuicCryptoClientConfigTest, FillClientHello) { QuicCryptoClientConfig::CachedState state; - QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting()); + QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting(), + TlsClientHandshaker::CreateSslCtx()); QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params( new QuicCryptoNegotiatedParameters); QuicConnectionId kConnectionId = 1234; @@ -289,15 +300,15 @@ TEST_F(QuicCryptoClientConfigTest, FillClientHello) { MockRandom rand; CryptoHandshakeMessage chlo; QuicServerId server_id("www.google.com", 443, PRIVACY_MODE_DISABLED); - config.FillClientHello(server_id, kConnectionId, QuicVersionMax(), &state, - QuicWallTime::Zero(), &rand, + config.FillClientHello(server_id, kConnectionId, QuicTransportVersionMax(), + &state, QuicWallTime::Zero(), &rand, nullptr, // channel_id_key params, &chlo, &error_details); // Verify that the version label has been set correctly in the CHLO. QuicVersionLabel cver; EXPECT_EQ(QUIC_NO_ERROR, chlo.GetVersionLabel(kVER, &cver)); - EXPECT_EQ(QuicVersionToQuicVersionLabel(QuicVersionMax()), cver); + EXPECT_EQ(QuicVersionToQuicVersionLabel(QuicTransportVersionMax()), cver); } TEST_F(QuicCryptoClientConfigTest, ProcessServerDowngradeAttack) { @@ -321,7 +332,8 @@ TEST_F(QuicCryptoClientConfigTest, ProcessServerDowngradeAttack) { QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> out_params( new QuicCryptoNegotiatedParameters); string error; - QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting()); + QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting(), + TlsClientHandshaker::CreateSslCtx()); EXPECT_EQ(QUIC_VERSION_NEGOTIATION_MISMATCH, config.ProcessServerHello(msg, 0, supported_versions.front(), supported_versions, &cached, out_params, @@ -330,7 +342,8 @@ TEST_F(QuicCryptoClientConfigTest, ProcessServerDowngradeAttack) { } TEST_F(QuicCryptoClientConfigTest, InitializeFrom) { - QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting()); + QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting(), + TlsClientHandshaker::CreateSslCtx()); QuicServerId canonical_server_id("www.google.com", 443, PRIVACY_MODE_DISABLED); QuicCryptoClientConfig::CachedState* state = @@ -351,7 +364,8 @@ TEST_F(QuicCryptoClientConfigTest, InitializeFrom) { } TEST_F(QuicCryptoClientConfigTest, Canonical) { - QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting()); + QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting(), + TlsClientHandshaker::CreateSslCtx()); config.AddCanonicalSuffix(".google.com"); QuicServerId canonical_id1("www.google.com", 443, PRIVACY_MODE_DISABLED); QuicServerId canonical_id2("mail.google.com", 443, PRIVACY_MODE_DISABLED); @@ -375,7 +389,8 @@ TEST_F(QuicCryptoClientConfigTest, Canonical) { } TEST_F(QuicCryptoClientConfigTest, CanonicalNotUsedIfNotValid) { - QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting()); + QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting(), + TlsClientHandshaker::CreateSslCtx()); config.AddCanonicalSuffix(".google.com"); QuicServerId canonical_id1("www.google.com", 443, PRIVACY_MODE_DISABLED); QuicServerId canonical_id2("mail.google.com", 443, PRIVACY_MODE_DISABLED); @@ -390,7 +405,8 @@ TEST_F(QuicCryptoClientConfigTest, CanonicalNotUsedIfNotValid) { } TEST_F(QuicCryptoClientConfigTest, ClearCachedStates) { - QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting()); + QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting(), + TlsClientHandshaker::CreateSslCtx()); // Create two states on different origins. struct TestCase { @@ -486,7 +502,8 @@ TEST_F(QuicCryptoClientConfigTest, ProcessReject) { QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> out_params( new QuicCryptoNegotiatedParameters); string error; - QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting()); + QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting(), + TlsClientHandshaker::CreateSslCtx()); EXPECT_EQ(QUIC_NO_ERROR, config.ProcessRejection(rej, QuicWallTime::FromUNIXSeconds(0), AllSupportedTransportVersions().front(), "", @@ -507,7 +524,8 @@ TEST_F(QuicCryptoClientConfigTest, ProcessRejectWithLongTTL) { QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> out_params( new QuicCryptoNegotiatedParameters); string error; - QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting()); + QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting(), + TlsClientHandshaker::CreateSslCtx()); EXPECT_EQ(QUIC_NO_ERROR, config.ProcessRejection(rej, QuicWallTime::FromUNIXSeconds(0), AllSupportedTransportVersions().front(), "", @@ -534,7 +552,8 @@ TEST_F(QuicCryptoClientConfigTest, ProcessStatelessReject) { QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> out_params( new QuicCryptoNegotiatedParameters); string error; - QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting()); + QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting(), + TlsClientHandshaker::CreateSslCtx()); EXPECT_EQ(QUIC_NO_ERROR, config.ProcessRejection(rej, QuicWallTime::FromUNIXSeconds(0), AllSupportedTransportVersions().front(), "", @@ -556,7 +575,8 @@ TEST_F(QuicCryptoClientConfigTest, BadlyFormattedStatelessReject) { QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> out_params( new QuicCryptoNegotiatedParameters); string error; - QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting()); + QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting(), + TlsClientHandshaker::CreateSslCtx()); EXPECT_EQ(QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND, config.ProcessRejection(rej, QuicWallTime::FromUNIXSeconds(0), AllSupportedTransportVersions().front(), "", @@ -575,7 +595,8 @@ TEST_F(QuicCryptoClientConfigTest, ServerNonceinSHLO) { supported_versions.push_back(version); msg.SetVersionVector(kVER, supported_versions); - QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting()); + QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting(), + TlsClientHandshaker::CreateSslCtx()); QuicCryptoClientConfig::CachedState cached; QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> out_params( new QuicCryptoNegotiatedParameters); diff --git a/chromium/net/quic/core/crypto/quic_crypto_server_config.cc b/chromium/net/quic/core/crypto/quic_crypto_server_config.cc index 99a1655a53a..56c717e1999 100644 --- a/chromium/net/quic/core/crypto/quic_crypto_server_config.cc +++ b/chromium/net/quic/core/crypto/quic_crypto_server_config.cc @@ -35,12 +35,14 @@ #include "net/quic/platform/api/quic_bug_tracker.h" #include "net/quic/platform/api/quic_clock.h" #include "net/quic/platform/api/quic_endian.h" +#include "net/quic/platform/api/quic_flag_utils.h" #include "net/quic/platform/api/quic_flags.h" #include "net/quic/platform/api/quic_hostname_utils.h" #include "net/quic/platform/api/quic_logging.h" #include "net/quic/platform/api/quic_reference_counted.h" #include "net/quic/platform/api/quic_text_utils.h" #include "third_party/boringssl/src/include/openssl/sha.h" +#include "third_party/boringssl/src/include/openssl/ssl.h" using std::string; @@ -151,13 +153,15 @@ QuicCryptoServerConfig::ConfigOptions::~ConfigOptions() {} QuicCryptoServerConfig::QuicCryptoServerConfig( QuicStringPiece source_address_token_secret, QuicRandom* server_nonce_entropy, - std::unique_ptr<ProofSource> proof_source) + std::unique_ptr<ProofSource> proof_source, + bssl::UniquePtr<SSL_CTX> ssl_ctx) : replay_protection_(true), chlo_multiplier_(kMultiplier), configs_lock_(), primary_config_(nullptr), next_config_promotion_time_(QuicWallTime::Zero()), proof_source_(std::move(proof_source)), + ssl_ctx_(std::move(ssl_ctx)), source_address_token_future_secs_(3600), source_address_token_lifetime_secs_(86400), enable_serving_sct_(false), @@ -1313,7 +1317,7 @@ void QuicCryptoServerConfig::EvaluateClientHelloAfterGetProof( QUIC_DVLOG(1) << "No 0-RTT replay protection in QUIC_VERSION_33 and higher."; // If the server nonce is empty and we're requiring handshake confirmation // for DoS reasons then we must reject the CHLO. - if (FLAGS_quic_reloadable_flag_quic_require_handshake_confirmation && + if (GetQuicReloadableFlag(quic_require_handshake_confirmation) && info->server_nonce.empty()) { info->reject_reasons.push_back(SERVER_NONCE_REQUIRED_FAILURE); } @@ -1451,7 +1455,7 @@ void QuicCryptoServerConfig::BuildRejection( QuicByteCount total_framing_overhead, QuicByteCount chlo_packet_size, CryptoHandshakeMessage* out) const { - if (FLAGS_quic_reloadable_flag_enable_quic_stateless_reject_support && + if (GetQuicReloadableFlag(enable_quic_stateless_reject_support) && use_stateless_rejects) { QUIC_DVLOG(1) << "QUIC Crypto server config returning stateless reject " << "with server-designated connection ID " @@ -1490,6 +1494,12 @@ void QuicCryptoServerConfig::BuildRejection( QuicStringPiece client_cached_cert_hashes; if (client_hello.GetStringPiece(kCCRT, &client_cached_cert_hashes)) { params->client_cached_cert_hashes = client_cached_cert_hashes.as_string(); + } else { + if (GetQuicReloadableFlag(quic_2rtt_drop_client_cached_certs)) { + params->client_cached_cert_hashes.clear(); + QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_2rtt_drop_client_cached_certs, + 1, 2); + } } const string compressed = @@ -1553,9 +1563,18 @@ string QuicCryptoServerConfig::CompressChain( return *cached_value; } - const string compressed = - CertCompressor::CompressChain(chain->certs, client_common_set_hashes, - client_common_set_hashes, common_sets); + string compressed; + if (GetQuicReloadableFlag(quic_2rtt_drop_client_cached_certs)) { + compressed = + CertCompressor::CompressChain(chain->certs, client_common_set_hashes, + client_cached_cert_hashes, common_sets); + QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_2rtt_drop_client_cached_certs, + 2, 2); + } else { + compressed = + CertCompressor::CompressChain(chain->certs, client_common_set_hashes, + client_common_set_hashes, common_sets); + } // Insert the newly compressed cert to cache. compressed_certs_cache->Insert(chain, client_common_set_hashes, @@ -1787,6 +1806,14 @@ int QuicCryptoServerConfig::NumberOfConfigs() const { return configs_.size(); } +ProofSource* QuicCryptoServerConfig::proof_source() const { + return proof_source_.get(); +} + +SSL_CTX* QuicCryptoServerConfig::ssl_ctx() const { + return ssl_ctx_.get(); +} + HandshakeFailureReason QuicCryptoServerConfig::ParseSourceAddressToken( const Config& config, QuicStringPiece token, diff --git a/chromium/net/quic/core/crypto/quic_crypto_server_config.h b/chromium/net/quic/core/crypto/quic_crypto_server_config.h index 861eae6b4d1..826c98c8743 100644 --- a/chromium/net/quic/core/crypto/quic_crypto_server_config.h +++ b/chromium/net/quic/core/crypto/quic_crypto_server_config.h @@ -28,6 +28,7 @@ #include "net/quic/platform/api/quic_reference_counted.h" #include "net/quic/platform/api/quic_socket_address.h" #include "net/quic/platform/api/quic_string_piece.h" +#include "third_party/boringssl/src/include/openssl/base.h" namespace net { @@ -194,9 +195,11 @@ class QUIC_EXPORT_PRIVATE QuicCryptoServerConfig { // server. Not owned. // |proof_source|: provides certificate chains and signatures. This class // takes ownership of |proof_source|. + // |ssl_ctx|: The SSL_CTX used for doing TLS handshakes. QuicCryptoServerConfig(QuicStringPiece source_address_token_secret, QuicRandom* server_nonce_entropy, - std::unique_ptr<ProofSource> proof_source); + std::unique_ptr<ProofSource> proof_source, + bssl::UniquePtr<SSL_CTX> ssl_ctx); ~QuicCryptoServerConfig(); // TESTING is a magic parameter for passing to the constructor in tests. @@ -392,6 +395,10 @@ class QUIC_EXPORT_PRIVATE QuicCryptoServerConfig { rejection_observer_ = rejection_observer; } + ProofSource* proof_source() const; + + SSL_CTX* ssl_ctx() const; + private: friend class test::QuicCryptoServerConfigPeer; friend struct QuicSignedServerConfig; @@ -740,6 +747,9 @@ class QUIC_EXPORT_PRIVATE QuicCryptoServerConfig { // signatures. std::unique_ptr<ProofSource> proof_source_; + // ssl_ctx_ contains the server configuration for doing TLS handshakes. + bssl::UniquePtr<SSL_CTX> ssl_ctx_; + // ephemeral_key_source_ contains an object that caches ephemeral keys for a // short period of time. std::unique_ptr<EphemeralKeySource> ephemeral_key_source_; diff --git a/chromium/net/quic/core/crypto/quic_crypto_server_config_test.cc b/chromium/net/quic/core/crypto/quic_crypto_server_config_test.cc index 381c82b5cb8..437904eb824 100644 --- a/chromium/net/quic/core/crypto/quic_crypto_server_config_test.cc +++ b/chromium/net/quic/core/crypto/quic_crypto_server_config_test.cc @@ -15,6 +15,7 @@ #include "net/quic/core/crypto/crypto_server_config_protobuf.h" #include "net/quic/core/crypto/quic_random.h" #include "net/quic/core/quic_time.h" +#include "net/quic/core/tls_server_handshaker.h" #include "net/quic/platform/api/quic_socket_address.h" #include "net/quic/platform/api/quic_test.h" #include "net/quic/test_tools/crypto_test_utils.h" @@ -31,7 +32,8 @@ class QuicCryptoServerConfigTest : public QuicTest {}; TEST_F(QuicCryptoServerConfigTest, ServerConfig) { QuicRandom* rand = QuicRandom::GetInstance(); QuicCryptoServerConfig server(QuicCryptoServerConfig::TESTING, rand, - crypto_test_utils::ProofSourceForTesting()); + crypto_test_utils::ProofSourceForTesting(), + TlsServerHandshaker::CreateSslCtx()); MockClock clock; std::unique_ptr<CryptoHandshakeMessage> message(server.AddDefaultConfig( @@ -51,7 +53,8 @@ TEST_F(QuicCryptoServerConfigTest, CompressCerts) { QuicRandom* rand = QuicRandom::GetInstance(); QuicCryptoServerConfig server(QuicCryptoServerConfig::TESTING, rand, - crypto_test_utils::ProofSourceForTesting()); + crypto_test_utils::ProofSourceForTesting(), + TlsServerHandshaker::CreateSslCtx()); QuicCryptoServerConfigPeer peer(&server); std::vector<string> certs = {"testcert"}; @@ -70,7 +73,8 @@ TEST_F(QuicCryptoServerConfigTest, CompressSameCertsTwice) { QuicRandom* rand = QuicRandom::GetInstance(); QuicCryptoServerConfig server(QuicCryptoServerConfig::TESTING, rand, - crypto_test_utils::ProofSourceForTesting()); + crypto_test_utils::ProofSourceForTesting(), + TlsServerHandshaker::CreateSslCtx()); QuicCryptoServerConfigPeer peer(&server); // Compress the certs for the first time. @@ -99,7 +103,8 @@ TEST_F(QuicCryptoServerConfigTest, CompressDifferentCerts) { QuicRandom* rand = QuicRandom::GetInstance(); QuicCryptoServerConfig server(QuicCryptoServerConfig::TESTING, rand, - crypto_test_utils::ProofSourceForTesting()); + crypto_test_utils::ProofSourceForTesting(), + TlsServerHandshaker::CreateSslCtx()); QuicCryptoServerConfigPeer peer(&server); std::vector<string> certs = {"testcert"}; @@ -142,7 +147,8 @@ class SourceAddressTokenTest : public QuicTest { rand_(QuicRandom::GetInstance()), server_(QuicCryptoServerConfig::TESTING, rand_, - crypto_test_utils::ProofSourceForTesting()), + crypto_test_utils::ProofSourceForTesting(), + TlsServerHandshaker::CreateSslCtx()), peer_(&server_) { // Advance the clock to some non-zero time. clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1000000)); @@ -280,7 +286,8 @@ class CryptoServerConfigsTest : public QuicTest { : rand_(QuicRandom::GetInstance()), config_(QuicCryptoServerConfig::TESTING, rand_, - crypto_test_utils::ProofSourceForTesting()), + crypto_test_utils::ProofSourceForTesting(), + TlsServerHandshaker::CreateSslCtx()), test_peer_(&config_) {} void SetUp() override { diff --git a/chromium/net/quic/core/crypto/quic_decrypter.cc b/chromium/net/quic/core/crypto/quic_decrypter.cc index 99c2a814d8b..924b07c46b6 100644 --- a/chromium/net/quic/core/crypto/quic_decrypter.cc +++ b/chromium/net/quic/core/crypto/quic_decrypter.cc @@ -6,22 +6,25 @@ #include "crypto/hkdf.h" #include "net/quic/core/crypto/aes_128_gcm_12_decrypter.h" +#include "net/quic/core/crypto/aes_128_gcm_decrypter.h" +#include "net/quic/core/crypto/aes_256_gcm_decrypter.h" #include "net/quic/core/crypto/chacha20_poly1305_decrypter.h" +#include "net/quic/core/crypto/chacha20_poly1305_tls_decrypter.h" #include "net/quic/core/crypto/crypto_protocol.h" #include "net/quic/core/crypto/null_decrypter.h" +#include "net/quic/platform/api/quic_bug_tracker.h" #include "net/quic/platform/api/quic_logging.h" - -using std::string; +#include "third_party/boringssl/src/include/openssl/tls1.h" namespace net { // static -QuicDecrypter* QuicDecrypter::Create(QuicTag algorithm) { +std::unique_ptr<QuicDecrypter> QuicDecrypter::Create(QuicTag algorithm) { switch (algorithm) { case kAESG: - return new Aes128Gcm12Decrypter(); + return std::make_unique<Aes128Gcm12Decrypter>(); case kCC20: - return new ChaCha20Poly1305Decrypter(); + return std::make_unique<ChaCha20Poly1305Decrypter>(); default: QUIC_LOG(FATAL) << "Unsupported algorithm: " << algorithm; return nullptr; @@ -29,13 +32,33 @@ QuicDecrypter* QuicDecrypter::Create(QuicTag algorithm) { } // static +QuicDecrypter* QuicDecrypter::CreateFromCipherSuite(uint32_t cipher_suite) { + QuicDecrypter* decrypter; + switch (cipher_suite) { + case TLS1_CK_AES_128_GCM_SHA256: + decrypter = new Aes128GcmDecrypter(); + break; + case TLS1_CK_AES_256_GCM_SHA384: + decrypter = new Aes256GcmDecrypter(); + break; + case TLS1_CK_CHACHA20_POLY1305_SHA256: + decrypter = new ChaCha20Poly1305TlsDecrypter(); + break; + default: + QUIC_BUG << "TLS cipher suite is unknown to QUIC"; + return nullptr; + } + return decrypter; +} + +// static void QuicDecrypter::DiversifyPreliminaryKey(QuicStringPiece preliminary_key, QuicStringPiece nonce_prefix, const DiversificationNonce& nonce, size_t key_size, size_t nonce_prefix_size, - string* out_key, - string* out_nonce_prefix) { + std::string* out_key, + std::string* out_nonce_prefix) { crypto::HKDF hkdf(preliminary_key.as_string() + nonce_prefix.as_string(), QuicStringPiece(nonce.data(), nonce.size()), "QUIC key diversification", 0, key_size, 0, diff --git a/chromium/net/quic/core/crypto/quic_decrypter.h b/chromium/net/quic/core/crypto/quic_decrypter.h index 5b6258f85d1..a5059097ea6 100644 --- a/chromium/net/quic/core/crypto/quic_decrypter.h +++ b/chromium/net/quic/core/crypto/quic_decrypter.h @@ -7,6 +7,7 @@ #include <cstddef> #include <cstdint> +#include <memory> #include "net/quic/core/quic_packets.h" #include "net/quic/platform/api/quic_export.h" @@ -18,7 +19,12 @@ class QUIC_EXPORT_PRIVATE QuicDecrypter { public: virtual ~QuicDecrypter() {} - static QuicDecrypter* Create(QuicTag algorithm); + static std::unique_ptr<QuicDecrypter> Create(QuicTag algorithm); + + // Creates an IETF QuicDecrypter based on |cipher_suite| which must be an id + // returned by SSL_CIPHER_get_id. The caller is responsible for taking + // ownership of the new QuicDecrypter. + static QuicDecrypter* CreateFromCipherSuite(uint32_t cipher_suite); // Sets the encryption key. Returns true on success, false on failure. // @@ -102,6 +108,11 @@ class QUIC_EXPORT_PRIVATE QuicDecrypter { size_t* output_length, size_t max_output_length) = 0; + // Returns the size in bytes of a key for the algorithm. + virtual size_t GetKeySize() const = 0; + // Returns the size in bytes of an IV to use with the algorithm. + virtual size_t GetIVSize() const = 0; + // The ID of the cipher. Return 0x03000000 ORed with the 'cryptographic suite // selector'. virtual uint32_t cipher_id() const = 0; diff --git a/chromium/net/quic/core/crypto/quic_encrypter.cc b/chromium/net/quic/core/crypto/quic_encrypter.cc index 377720b9db9..ef78336035e 100644 --- a/chromium/net/quic/core/crypto/quic_encrypter.cc +++ b/chromium/net/quic/core/crypto/quic_encrypter.cc @@ -5,24 +5,49 @@ #include "net/quic/core/crypto/quic_encrypter.h" #include "net/quic/core/crypto/aes_128_gcm_12_encrypter.h" +#include "net/quic/core/crypto/aes_128_gcm_encrypter.h" +#include "net/quic/core/crypto/aes_256_gcm_encrypter.h" #include "net/quic/core/crypto/chacha20_poly1305_encrypter.h" +#include "net/quic/core/crypto/chacha20_poly1305_tls_encrypter.h" #include "net/quic/core/crypto/crypto_protocol.h" #include "net/quic/core/crypto/null_encrypter.h" +#include "net/quic/platform/api/quic_bug_tracker.h" #include "net/quic/platform/api/quic_logging.h" +#include "third_party/boringssl/src/include/openssl/tls1.h" namespace net { // static -QuicEncrypter* QuicEncrypter::Create(QuicTag algorithm) { +std::unique_ptr<QuicEncrypter> QuicEncrypter::Create(QuicTag algorithm) { switch (algorithm) { case kAESG: - return new Aes128Gcm12Encrypter(); + return std::make_unique<Aes128Gcm12Encrypter>(); case kCC20: - return new ChaCha20Poly1305Encrypter(); + return std::make_unique<ChaCha20Poly1305Encrypter>(); default: QUIC_LOG(FATAL) << "Unsupported algorithm: " << algorithm; return nullptr; } } +// static +QuicEncrypter* QuicEncrypter::CreateFromCipherSuite(uint32_t cipher_suite) { + QuicEncrypter* encrypter; + switch (cipher_suite) { + case TLS1_CK_AES_128_GCM_SHA256: + encrypter = new Aes128GcmEncrypter(); + break; + case TLS1_CK_AES_256_GCM_SHA384: + encrypter = new Aes256GcmEncrypter(); + break; + case TLS1_CK_CHACHA20_POLY1305_SHA256: + encrypter = new ChaCha20Poly1305TlsEncrypter(); + break; + default: + QUIC_BUG << "TLS cipher suite is unknown to QUIC"; + return nullptr; + } + return encrypter; +} + } // namespace net diff --git a/chromium/net/quic/core/crypto/quic_encrypter.h b/chromium/net/quic/core/crypto/quic_encrypter.h index c9e21f3a9b5..bc32213a1eb 100644 --- a/chromium/net/quic/core/crypto/quic_encrypter.h +++ b/chromium/net/quic/core/crypto/quic_encrypter.h @@ -6,6 +6,7 @@ #define NET_QUIC_CORE_CRYPTO_QUIC_ENCRYPTER_H_ #include <cstddef> +#include <memory> #include "net/quic/core/quic_packets.h" #include "net/quic/platform/api/quic_export.h" @@ -17,7 +18,12 @@ class QUIC_EXPORT_PRIVATE QuicEncrypter { public: virtual ~QuicEncrypter() {} - static QuicEncrypter* Create(QuicTag algorithm); + static std::unique_ptr<QuicEncrypter> Create(QuicTag algorithm); + + // Creates an IETF QuicEncrypter based on |cipher_suite| which must be an id + // returned by SSL_CIPHER_get_id. The caller is responsible for taking + // ownership of the new QuicEncrypter. + static QuicEncrypter* CreateFromCipherSuite(uint32_t cipher_suite); // Sets the encryption key. Returns true on success, false on failure. // @@ -95,6 +101,9 @@ class QUIC_EXPORT_PRIVATE QuicEncrypter { // Returns the size in bytes of the fixed initial part of the nonce. virtual size_t GetNoncePrefixSize() const = 0; + // Returns the size in bytes of an IV to use with the algorithm. + virtual size_t GetIVSize() const = 0; + // Returns the maximum length of plaintext that can be encrypted // to ciphertext no larger than |ciphertext_size|. virtual size_t GetMaxPlaintextSize(size_t ciphertext_size) const = 0; diff --git a/chromium/net/quic/core/crypto/quic_tls_adapter_test.cc b/chromium/net/quic/core/crypto/quic_tls_adapter_test.cc index 9a7c7cc32d8..614d14e8d05 100644 --- a/chromium/net/quic/core/crypto/quic_tls_adapter_test.cc +++ b/chromium/net/quic/core/crypto/quic_tls_adapter_test.cc @@ -6,6 +6,7 @@ #include <vector> +#include "net/quic/platform/api/quic_arraysize.h" #include "net/quic/platform/api/quic_test.h" #include "third_party/boringssl/src/include/openssl/bio.h" @@ -56,7 +57,7 @@ TEST_P(QuicTlsAdapterTest, ProcessInput) { char buf[4]; ASSERT_EQ(static_cast<int>(input.length()), - BIO_read(bio_, buf, arraysize(buf))); + BIO_read(bio_, buf, QUIC_ARRAYSIZE(buf))); EXPECT_EQ(input, string(buf, input.length())); } @@ -71,9 +72,9 @@ TEST_P(QuicTlsAdapterTest, BIORead) { // Test that a call to BIO_read for less than what is in |adapter_|'s buffer // still leaves more input remaining to read. char buf1[3]; - ASSERT_EQ(static_cast<int>(arraysize(buf1)), - BIO_read(bio_, buf1, arraysize(buf1))); - EXPECT_EQ("abc", string(buf1, arraysize(buf1))); + ASSERT_EQ(static_cast<int>(QUIC_ARRAYSIZE(buf1)), + BIO_read(bio_, buf1, QUIC_ARRAYSIZE(buf1))); + EXPECT_EQ("abc", string(buf1, QUIC_ARRAYSIZE(buf1))); EXPECT_EQ(1u, adapter_.InputBytesRemaining()); // Test that the bytes read by BIO_read can span input read in by @@ -82,9 +83,9 @@ TEST_P(QuicTlsAdapterTest, BIORead) { EXPECT_EQ(QUIC_NO_ERROR, adapter_.error()); EXPECT_EQ(2, visitor_.data_available_count()); char buf2[5]; - ASSERT_EQ(static_cast<int>(arraysize(buf2)), - BIO_read(bio_, buf2, arraysize(buf2))); - EXPECT_EQ("defgh", string(buf2, arraysize(buf2))); + ASSERT_EQ(static_cast<int>(QUIC_ARRAYSIZE(buf2)), + BIO_read(bio_, buf2, QUIC_ARRAYSIZE(buf2))); + EXPECT_EQ("defgh", string(buf2, QUIC_ARRAYSIZE(buf2))); EXPECT_EQ(0u, adapter_.InputBytesRemaining()); } diff --git a/chromium/net/quic/core/frames/quic_ack_frame.cc b/chromium/net/quic/core/frames/quic_ack_frame.cc index e1b95b95b55..6e22672f9c7 100644 --- a/chromium/net/quic/core/frames/quic_ack_frame.cc +++ b/chromium/net/quic/core/frames/quic_ack_frame.cc @@ -19,36 +19,6 @@ namespace { const QuicPacketNumber kMaxPrintRange = 128; } // namespace -PacketNumberQueue::const_iterator::const_iterator(const const_iterator& other) = - default; -PacketNumberQueue::const_iterator::const_iterator(const_iterator&& other) = - default; -PacketNumberQueue::const_iterator::~const_iterator() {} - -PacketNumberQueue::const_iterator::const_iterator( - typename QuicIntervalSet<QuicPacketNumber>::const_iterator it) - : vector_it_(it), use_deque_it_(false) {} - -PacketNumberQueue::const_reverse_iterator::const_reverse_iterator( - const const_reverse_iterator& other) = default; -PacketNumberQueue::const_reverse_iterator::const_reverse_iterator( - const_reverse_iterator&& other) = default; -PacketNumberQueue::const_reverse_iterator::~const_reverse_iterator() {} - -PacketNumberQueue::const_iterator::const_iterator( - typename QuicDeque<Interval<QuicPacketNumber>>::const_iterator it) - : deque_it_(it), use_deque_it_(true) {} - -PacketNumberQueue::const_reverse_iterator::const_reverse_iterator( - const typename QuicIntervalSet<QuicPacketNumber>::const_reverse_iterator& - it) - : vector_it_(it), use_deque_it_(false) {} - -PacketNumberQueue::const_reverse_iterator::const_reverse_iterator( - const typename QuicDeque< - Interval<QuicPacketNumber>>::const_reverse_iterator& it) - : deque_it_(it), use_deque_it_(true) {} - bool IsAwaitingPacket(const QuicAckFrame& ack_frame, QuicPacketNumber packet_number, QuicPacketNumber peer_least_packet_awaiting_ack) { @@ -57,8 +27,7 @@ bool IsAwaitingPacket(const QuicAckFrame& ack_frame, } QuicAckFrame::QuicAckFrame() - : deprecated_largest_observed(0), - ack_delay_time(QuicTime::Delta::Infinite()) {} + : largest_acked(0), ack_delay_time(QuicTime::Delta::Infinite()) {} QuicAckFrame::QuicAckFrame(const QuicAckFrame& other) = default; @@ -77,28 +46,7 @@ std::ostream& operator<<(std::ostream& os, const QuicAckFrame& ack_frame) { return os; } -QuicPacketNumber LargestAcked(const QuicAckFrame& frame) { - if (!FLAGS_quic_reloadable_flag_quic_deprecate_largest_observed) { - return frame.deprecated_largest_observed; - } - - if (!frame.packets.Empty() && - frame.packets.Max() != frame.deprecated_largest_observed) { - QUIC_BUG << "Peer last received packet: " << frame.packets.Max() - << " which is not equal to largest observed: " - << frame.deprecated_largest_observed; - } - - return frame.packets.Empty() ? 0 : frame.packets.Max(); -} - -PacketNumberQueue::PacketNumberQueue() - : use_deque_(FLAGS_quic_reloadable_flag_quic_frames_deque3) { - if (use_deque_) { - QUIC_FLAG_COUNT(quic_reloadable_flag_quic_frames_deque3); - } -} - +PacketNumberQueue::PacketNumberQueue() {} PacketNumberQueue::PacketNumberQueue(const PacketNumberQueue& other) = default; PacketNumberQueue::PacketNumberQueue(PacketNumberQueue&& other) = default; PacketNumberQueue::~PacketNumberQueue() {} @@ -109,80 +57,76 @@ PacketNumberQueue& PacketNumberQueue::operator=(PacketNumberQueue&& other) = default; void PacketNumberQueue::Add(QuicPacketNumber packet_number) { - if (use_deque_) { - // Check if the deque is empty - if (packet_number_deque_.empty()) { - packet_number_deque_.push_front( - Interval<QuicPacketNumber>(packet_number, packet_number + 1)); + // Check if the deque is empty + if (packet_number_deque_.empty()) { + packet_number_deque_.push_front( + Interval<QuicPacketNumber>(packet_number, packet_number + 1)); + return; + } + Interval<QuicPacketNumber> back = packet_number_deque_.back(); + + // Check for the typical case, + // when the next packet in order is acked + if (back.max() == packet_number) { + packet_number_deque_.back().SetMax(packet_number + 1); + return; + } + // Check if the next packet in order is skipped + if (back.max() < packet_number) { + packet_number_deque_.push_back( + Interval<QuicPacketNumber>(packet_number, packet_number + 1)); + return; + } + + Interval<QuicPacketNumber> front = packet_number_deque_.front(); + // Check if the packet can be popped on the front + if (front.min() > packet_number + 1) { + packet_number_deque_.push_front( + Interval<QuicPacketNumber>(packet_number, packet_number + 1)); + return; + } + if (front.min() == packet_number + 1) { + packet_number_deque_.front().SetMin(packet_number); + return; + } + + int i = packet_number_deque_.size() - 1; + // Iterating through the queue backwards + // to find a proper place for the packet + while (i >= 0) { + Interval<QuicPacketNumber> packet_interval = packet_number_deque_[i]; + DCHECK(packet_interval.min() < packet_interval.max()); + // Check if the packet is contained in an interval already + if (packet_interval.Contains(packet_number)) { return; } - Interval<QuicPacketNumber> back = packet_number_deque_.back(); - // Check for the typical case, - // when the next packet in order is acked - if (back.max() == packet_number) { - packet_number_deque_.back().SetMax(packet_number + 1); + // Check if the packet can extend an interval. + if (packet_interval.max() == packet_number) { + packet_number_deque_[i].SetMax(packet_number + 1); return; } - // Check if the next packet in order is skipped - if (back.max() < packet_number) { - packet_number_deque_.push_back( - Interval<QuicPacketNumber>(packet_number, packet_number + 1)); + // Check if the packet can extend an interval + // and merge two intervals if needed. + // There is no need to merge an interval in the previous + // if statement, as all merges will happen here. + if (packet_interval.min() == packet_number + 1) { + packet_number_deque_[i].SetMin(packet_number); + if (i > 0 && packet_number == packet_number_deque_[i - 1].max()) { + packet_number_deque_[i - 1].SetMax(packet_interval.max()); + packet_number_deque_.erase(packet_number_deque_.begin() + i); + } return; } - Interval<QuicPacketNumber> front = packet_number_deque_.front(); - // Check if the packet can be popped on the front - if (front.min() > packet_number + 1) { - packet_number_deque_.push_front( + // Check if we need to make a new interval for the packet + if (packet_interval.max() < packet_number + 1) { + packet_number_deque_.insert( + packet_number_deque_.begin() + i + 1, Interval<QuicPacketNumber>(packet_number, packet_number + 1)); return; } - if (front.min() == packet_number + 1) { - packet_number_deque_.front().SetMin(packet_number); - return; - } - - int i = packet_number_deque_.size() - 1; - // Iterating through the queue backwards - // to find a proper place for the packet - while (i >= 0) { - Interval<QuicPacketNumber> packet_interval = packet_number_deque_[i]; - DCHECK(packet_interval.min() < packet_interval.max()); - // Check if the packet is contained in an interval already - if (packet_interval.Contains(packet_number)) { - return; - } - - // Check if the packet can extend an interval. - if (packet_interval.max() == packet_number) { - packet_number_deque_[i].SetMax(packet_number + 1); - return; - } - // Check if the packet can extend an interval - // and merge two intervals if needed. - // There is no need to merge an interval in the previous - // if statement, as all merges will happen here. - if (packet_interval.min() == packet_number + 1) { - packet_number_deque_[i].SetMin(packet_number); - if (i > 0 && packet_number == packet_number_deque_[i - 1].max()) { - packet_number_deque_[i - 1].SetMax(packet_interval.max()); - packet_number_deque_.erase(packet_number_deque_.begin() + i); - } - return; - } - - // Check if we need to make a new interval for the packet - if (packet_interval.max() < packet_number + 1) { - packet_number_deque_.insert( - packet_number_deque_.begin() + i + 1, - Interval<QuicPacketNumber>(packet_number, packet_number + 1)); - return; - } - i--; - } - } else { - packet_number_intervals_.Add(packet_number, packet_number + 1); + i--; } } @@ -191,40 +135,34 @@ void PacketNumberQueue::AddRange(QuicPacketNumber lower, if (lower >= higher) { return; } - if (use_deque_) { - if (packet_number_deque_.empty()) { - packet_number_deque_.push_front( - Interval<QuicPacketNumber>(lower, higher)); - return; - } - Interval<QuicPacketNumber> back = packet_number_deque_.back(); + if (packet_number_deque_.empty()) { + packet_number_deque_.push_front(Interval<QuicPacketNumber>(lower, higher)); + return; + } + Interval<QuicPacketNumber> back = packet_number_deque_.back(); - if (back.max() == lower) { - // Check for the typical case, - // when the next packet in order is acked - packet_number_deque_.back().SetMax(higher); - return; - } - if (back.max() < lower) { - // Check if the next packet in order is skipped - packet_number_deque_.push_back(Interval<QuicPacketNumber>(lower, higher)); - return; - } - Interval<QuicPacketNumber> front = packet_number_deque_.front(); - // Check if the packets are being added in reverse order - if (front.min() == higher) { - packet_number_deque_.front().SetMin(lower); - } else if (front.min() > higher) { - packet_number_deque_.push_front( - Interval<QuicPacketNumber>(lower, higher)); + if (back.max() == lower) { + // Check for the typical case, + // when the next packet in order is acked + packet_number_deque_.back().SetMax(higher); + return; + } + if (back.max() < lower) { + // Check if the next packet in order is skipped + packet_number_deque_.push_back(Interval<QuicPacketNumber>(lower, higher)); + return; + } + Interval<QuicPacketNumber> front = packet_number_deque_.front(); + // Check if the packets are being added in reverse order + if (front.min() == higher) { + packet_number_deque_.front().SetMin(lower); + } else if (front.min() > higher) { + packet_number_deque_.push_front(Interval<QuicPacketNumber>(lower, higher)); - } else { - // Ranges must be above or below all existing ranges. - QUIC_BUG << "AddRange only supports adding packets above or below the " - << "current min:" << Min() << " and max:" << Max(); - } } else { - packet_number_intervals_.Add(lower, higher); + // Ranges must be above or below all existing ranges. + QUIC_BUG << "AddRange only supports adding packets above or below the " + << "current min:" << Min() << " and max:" << Max(); } } @@ -233,151 +171,92 @@ bool PacketNumberQueue::RemoveUpTo(QuicPacketNumber higher) { return false; } const QuicPacketNumber old_min = Min(); - if (use_deque_) { - while (!packet_number_deque_.empty()) { - Interval<QuicPacketNumber> front = packet_number_deque_.front(); - if (front.max() < higher) { + while (!packet_number_deque_.empty()) { + Interval<QuicPacketNumber> front = packet_number_deque_.front(); + if (front.max() < higher) { + packet_number_deque_.pop_front(); + } else if (front.min() < higher && front.max() >= higher) { + packet_number_deque_.front().SetMin(higher); + if (front.max() == higher) { packet_number_deque_.pop_front(); - } else if (front.min() < higher && front.max() >= higher) { - packet_number_deque_.front().SetMin(higher); - if (front.max() == higher) { - packet_number_deque_.pop_front(); - } - break; - } else { - break; } + break; + } else { + break; } - } else { - packet_number_intervals_.Difference(0, higher); } return Empty() || old_min != Min(); } void PacketNumberQueue::RemoveSmallestInterval() { - if (use_deque_) { - QUIC_BUG_IF(packet_number_deque_.size() < 2) - << (Empty() ? "No intervals to remove." - : "Can't remove the last interval."); - packet_number_deque_.pop_front(); - } else { - QUIC_BUG_IF(packet_number_intervals_.Size() < 2) - << (Empty() ? "No intervals to remove." - : "Can't remove the last interval."); - packet_number_intervals_.Difference(*packet_number_intervals_.begin()); - } + QUIC_BUG_IF(packet_number_deque_.size() < 2) + << (Empty() ? "No intervals to remove." + : "Can't remove the last interval."); + packet_number_deque_.pop_front(); } bool PacketNumberQueue::Contains(QuicPacketNumber packet_number) const { - if (use_deque_) { - if (packet_number_deque_.empty()) { - return false; - } - if (packet_number_deque_.front().min() > packet_number || - packet_number_deque_.back().max() <= packet_number) { - return false; - } - for (Interval<QuicPacketNumber> interval : packet_number_deque_) { - if (interval.Contains(packet_number)) { - return true; - } - } + if (packet_number_deque_.empty()) { return false; - } else { - return packet_number_intervals_.Contains(packet_number); } + if (packet_number_deque_.front().min() > packet_number || + packet_number_deque_.back().max() <= packet_number) { + return false; + } + for (Interval<QuicPacketNumber> interval : packet_number_deque_) { + if (interval.Contains(packet_number)) { + return true; + } + } + return false; } bool PacketNumberQueue::Empty() const { - if (use_deque_) { - return packet_number_deque_.empty(); - } else { - return packet_number_intervals_.Empty(); - } + return packet_number_deque_.empty(); } QuicPacketNumber PacketNumberQueue::Min() const { DCHECK(!Empty()); - if (use_deque_) { - return packet_number_deque_.front().min(); - } else { - return packet_number_intervals_.begin()->min(); - } + return packet_number_deque_.front().min(); } QuicPacketNumber PacketNumberQueue::Max() const { DCHECK(!Empty()); - if (use_deque_) { - return packet_number_deque_.back().max() - 1; - } else { - return packet_number_intervals_.rbegin()->max() - 1; - } + return packet_number_deque_.back().max() - 1; } size_t PacketNumberQueue::NumPacketsSlow() const { - if (use_deque_) { - int n_packets = 0; - for (Interval<QuicPacketNumber> interval : packet_number_deque_) { - n_packets += interval.Length(); - } - return n_packets; - } else { - size_t num_packets = 0; - for (const auto& interval : packet_number_intervals_) { - num_packets += interval.Length(); - } - return num_packets; + int n_packets = 0; + for (Interval<QuicPacketNumber> interval : packet_number_deque_) { + n_packets += interval.Length(); } + return n_packets; } size_t PacketNumberQueue::NumIntervals() const { - if (use_deque_) { - return packet_number_deque_.size(); - } else { - return packet_number_intervals_.Size(); - } + return packet_number_deque_.size(); } PacketNumberQueue::const_iterator PacketNumberQueue::begin() const { - if (use_deque_) { - return PacketNumberQueue::const_iterator(packet_number_deque_.begin()); - } else { - return PacketNumberQueue::const_iterator(packet_number_intervals_.begin()); - } + return packet_number_deque_.begin(); } PacketNumberQueue::const_iterator PacketNumberQueue::end() const { - if (use_deque_) { - return const_iterator(packet_number_deque_.end()); - } else { - return const_iterator(packet_number_intervals_.end()); - } + return packet_number_deque_.end(); } PacketNumberQueue::const_reverse_iterator PacketNumberQueue::rbegin() const { - if (use_deque_) { - return const_reverse_iterator(packet_number_deque_.rbegin()); - } else { - return const_reverse_iterator(packet_number_intervals_.rbegin()); - } + return packet_number_deque_.rbegin(); } PacketNumberQueue::const_reverse_iterator PacketNumberQueue::rend() const { - if (use_deque_) { - return const_reverse_iterator(packet_number_deque_.rend()); - } else { - return const_reverse_iterator(packet_number_intervals_.rend()); - } + return packet_number_deque_.rend(); } QuicPacketNumber PacketNumberQueue::LastIntervalLength() const { DCHECK(!Empty()); - if (use_deque_) { - return packet_number_deque_.back().Length(); - } else { - return packet_number_intervals_.rbegin()->Length(); - } + return packet_number_deque_.back().Length(); } // Largest min...max range for packet numbers where we print the numbers diff --git a/chromium/net/quic/core/frames/quic_ack_frame.h b/chromium/net/quic/core/frames/quic_ack_frame.h index c60610aacc9..98fe7012519 100644 --- a/chromium/net/quic/core/frames/quic_ack_frame.h +++ b/chromium/net/quic/core/frames/quic_ack_frame.h @@ -29,169 +29,9 @@ class QUIC_EXPORT_PRIVATE PacketNumberQueue { PacketNumberQueue& operator=(const PacketNumberQueue& other); PacketNumberQueue& operator=(PacketNumberQueue&& other); - class QUIC_EXPORT_PRIVATE const_iterator { - public: - const_iterator(const const_iterator& other); - const_iterator(const_iterator&& other); - ~const_iterator(); - - explicit const_iterator( - typename QuicIntervalSet<QuicPacketNumber>::const_iterator it); - - explicit const_iterator( - typename QuicDeque<Interval<QuicPacketNumber>>::const_iterator it); - - typedef std::input_iterator_tag iterator_category; - typedef Interval<QuicPacketNumber> value_type; - typedef value_type& reference; - typedef value_type* pointer; - typedef typename std::vector<value_type>::iterator::difference_type - difference_type; - - inline const Interval<QuicPacketNumber>& operator*() { - if (use_deque_it_) { - return *deque_it_; - } else { - return *vector_it_; - } - } - - inline const_iterator& operator++() { - if (use_deque_it_) { - deque_it_++; - } else { - vector_it_++; - } - return *this; - } - - inline const_iterator& operator--() { - if (use_deque_it_) { - deque_it_--; - } else { - vector_it_--; - } - return *this; - } - - inline const_iterator& operator++(int) { - if (use_deque_it_) { - ++deque_it_; - } else { - ++vector_it_; - } - return *this; - } - - inline bool operator==(const const_iterator& other) { - if (use_deque_it_ != other.use_deque_it_) { - return false; - } - - if (use_deque_it_) { - return deque_it_ == other.deque_it_; - } else { - return vector_it_ == other.vector_it_; - } - } - - inline bool operator!=(const const_iterator& other) { - return !(*this == other); - } - - private: - typename QuicIntervalSet<QuicPacketNumber>::const_iterator vector_it_; - typename QuicDeque<Interval<QuicPacketNumber>>::const_iterator deque_it_; - const bool use_deque_it_; - }; - - class QUIC_EXPORT_PRIVATE const_reverse_iterator { - public: - const_reverse_iterator(const const_reverse_iterator& other); - const_reverse_iterator(const_reverse_iterator&& other); - ~const_reverse_iterator(); - - explicit const_reverse_iterator( - const typename QuicIntervalSet< - QuicPacketNumber>::const_reverse_iterator& it); - - explicit const_reverse_iterator( - const typename QuicDeque< - Interval<QuicPacketNumber>>::const_reverse_iterator& it); - - typedef std::input_iterator_tag iterator_category; - typedef Interval<QuicPacketNumber> value_type; - typedef value_type& reference; - typedef value_type* pointer; - typedef typename std::vector<value_type>::iterator::difference_type - difference_type; - - inline const Interval<QuicPacketNumber>& operator*() { - if (use_deque_it_) { - return *deque_it_; - } else { - return *vector_it_; - } - } - - inline const Interval<QuicPacketNumber>* operator->() { - if (use_deque_it_) { - return &*deque_it_; - } else { - return &*vector_it_; - } - } - - inline const_reverse_iterator& operator++() { - if (use_deque_it_) { - deque_it_++; - } else { - vector_it_++; - } - return *this; - } - - inline const_reverse_iterator& operator--() { - if (use_deque_it_) { - deque_it_--; - } else { - vector_it_--; - } - return *this; - } - - inline const_reverse_iterator& operator++(int) { - if (use_deque_it_) { - ++deque_it_; - } else { - ++vector_it_; - } - return *this; - } - - inline bool operator==(const const_reverse_iterator& other) { - if (use_deque_it_ != other.use_deque_it_) { - return false; - } - - if (use_deque_it_) { - return deque_it_ == other.deque_it_; - } else { - return vector_it_ == other.vector_it_; - } - } - - inline bool operator!=(const const_reverse_iterator& other) { - return !(*this == other); - } - - private: - typename QuicIntervalSet<QuicPacketNumber>::const_reverse_iterator - vector_it_; - typename QuicDeque<Interval<QuicPacketNumber>>::const_reverse_iterator - deque_it_; - const bool use_deque_it_; - }; + typedef QuicDeque<Interval<QuicPacketNumber>>::const_iterator const_iterator; + typedef QuicDeque<Interval<QuicPacketNumber>>::const_reverse_iterator + const_reverse_iterator; // Adds |packet_number| to the set of packets in the queue. void Add(QuicPacketNumber packet_number); @@ -243,11 +83,7 @@ class QUIC_EXPORT_PRIVATE PacketNumberQueue { const PacketNumberQueue& q); private: - // TODO(lilika): Remove QuicIntervalSet<QuicPacketNumber> - // once FLAGS_quic_reloadable_flag_quic_frames_deque2 is removed - QuicIntervalSet<QuicPacketNumber> packet_number_intervals_; QuicDeque<Interval<QuicPacketNumber>> packet_number_deque_; - bool use_deque_; }; struct QUIC_EXPORT_PRIVATE QuicAckFrame { @@ -259,9 +95,10 @@ struct QUIC_EXPORT_PRIVATE QuicAckFrame { std::ostream& os, const QuicAckFrame& ack_frame); - // The highest packet number we've observed from the peer. - // This is being deprecated. - QuicPacketNumber deprecated_largest_observed; + // The highest packet number we've observed from the peer. When |packets| is + // not empty, it should always be equal to packets.Max(). The |LargestAcked| + // function ensures this invariant in debug mode. + QuicPacketNumber largest_acked; // Time elapsed since largest_observed() was received until this Ack frame was // sent. @@ -276,7 +113,11 @@ struct QUIC_EXPORT_PRIVATE QuicAckFrame { // The highest acked packet number we've observed from the peer. If no packets // have been observed, return 0. -QUIC_EXPORT_PRIVATE QuicPacketNumber LargestAcked(const QuicAckFrame& frame); +inline QUIC_EXPORT_PRIVATE QuicPacketNumber +LargestAcked(const QuicAckFrame& frame) { + DCHECK(frame.packets.Empty() || frame.packets.Max() == frame.largest_acked); + return frame.largest_acked; +} // True if the packet number is greater than largest_observed or is listed // as missing. diff --git a/chromium/net/quic/core/frames/quic_frame.cc b/chromium/net/quic/core/frames/quic_frame.cc index 6007cb3fa25..be96ff00450 100644 --- a/chromium/net/quic/core/frames/quic_frame.cc +++ b/chromium/net/quic/core/frames/quic_frame.cc @@ -153,6 +153,32 @@ void SetControlFrameId(QuicControlFrameId control_frame_id, QuicFrame* frame) { } } +QuicFrame CopyRetransmittableControlFrame(const QuicFrame& frame) { + QuicFrame copy; + switch (frame.type) { + case RST_STREAM_FRAME: + copy = QuicFrame(new QuicRstStreamFrame(*frame.rst_stream_frame)); + break; + case GOAWAY_FRAME: + copy = QuicFrame(new QuicGoAwayFrame(*frame.goaway_frame)); + break; + case WINDOW_UPDATE_FRAME: + copy = QuicFrame(new QuicWindowUpdateFrame(*frame.window_update_frame)); + break; + case BLOCKED_FRAME: + copy = QuicFrame(new QuicBlockedFrame(*frame.blocked_frame)); + break; + case PING_FRAME: + copy = QuicFrame(QuicPingFrame(frame.ping_frame.control_frame_id)); + break; + default: + QUIC_BUG << "Try to copy a non-retransmittable control frame: " << frame; + copy = QuicFrame(QuicPingFrame(kInvalidControlFrameId)); + break; + } + return copy; +} + std::ostream& operator<<(std::ostream& os, const QuicFrame& frame) { switch (frame.type) { case PADDING_FRAME: { diff --git a/chromium/net/quic/core/frames/quic_frame.h b/chromium/net/quic/core/frames/quic_frame.h index 49f81eee263..b02ceaefc84 100644 --- a/chromium/net/quic/core/frames/quic_frame.h +++ b/chromium/net/quic/core/frames/quic_frame.h @@ -89,6 +89,10 @@ GetControlFrameId(const QuicFrame& frame); QUIC_EXPORT_PRIVATE void SetControlFrameId(QuicControlFrameId control_frame_id, QuicFrame* frame); +// Returns a copy of |frame|. +QUIC_EXPORT_PRIVATE QuicFrame +CopyRetransmittableControlFrame(const QuicFrame& frame); + } // namespace net #endif // NET_QUIC_CORE_FRAMES_QUIC_FRAME_H_ diff --git a/chromium/net/quic/core/frames/quic_frames_test.cc b/chromium/net/quic/core/frames/quic_frames_test.cc index 87f9d2ad7d6..7e81b98d6da 100644 --- a/chromium/net/quic/core/frames/quic_frames_test.cc +++ b/chromium/net/quic/core/frames/quic_frames_test.cc @@ -25,7 +25,7 @@ class QuicFramesTest : public QuicTest {}; TEST_F(QuicFramesTest, AckFrameToString) { QuicAckFrame frame; - frame.deprecated_largest_observed = 5; + frame.largest_acked = 5; frame.ack_delay_time = QuicTime::Delta::FromMicroseconds(3); frame.packets.Add(4); frame.packets.Add(5); @@ -41,7 +41,7 @@ TEST_F(QuicFramesTest, AckFrameToString) { TEST_F(QuicFramesTest, BigAckFrameToString) { QuicAckFrame frame; - frame.deprecated_largest_observed = 500; + frame.largest_acked = 500; frame.ack_delay_time = QuicTime::Delta::FromMicroseconds(3); frame.packets.AddRange(4, 501); frame.received_packet_times = { @@ -159,7 +159,7 @@ TEST_F(QuicFramesTest, StopWaitingFrameToString) { TEST_F(QuicFramesTest, IsAwaitingPacket) { QuicAckFrame ack_frame1; - ack_frame1.deprecated_largest_observed = 10u; + ack_frame1.largest_acked = 10u; ack_frame1.packets.AddRange(1, 11); EXPECT_TRUE(IsAwaitingPacket(ack_frame1, 11u, 0u)); EXPECT_FALSE(IsAwaitingPacket(ack_frame1, 1u, 0u)); @@ -168,7 +168,7 @@ TEST_F(QuicFramesTest, IsAwaitingPacket) { EXPECT_TRUE(IsAwaitingPacket(ack_frame1, 11u, 0u)); QuicAckFrame ack_frame2; - ack_frame2.deprecated_largest_observed = 100u; + ack_frame2.largest_acked = 100u; ack_frame2.packets.AddRange(21, 100); EXPECT_FALSE(IsAwaitingPacket(ack_frame2, 11u, 20u)); EXPECT_FALSE(IsAwaitingPacket(ack_frame2, 80u, 20u)); @@ -266,78 +266,19 @@ TEST_F(QuicFramesTest, AddInterval) { EXPECT_EQ(expected_intervals, actual_intervals); - if (FLAGS_quic_reloadable_flag_quic_frames_deque3) { - // Ensure adding a range within the existing ranges fails. - EXPECT_QUIC_BUG(ack_frame1.packets.AddRange(20, 30), ""); - } else { - ack_frame1.packets.AddRange(20, 30); - } + // Ensure adding a range within the existing ranges fails. + EXPECT_QUIC_BUG(ack_frame1.packets.AddRange(20, 30), ""); const std::vector<Interval<QuicPacketNumber>> actual_intervals2( ack_frame1.packets.begin(), ack_frame1.packets.end()); std::vector<Interval<QuicPacketNumber>> expected_intervals2; expected_intervals2.emplace_back(Interval<QuicPacketNumber>(1, 10)); - if (!FLAGS_quic_reloadable_flag_quic_frames_deque3) { - expected_intervals2.emplace_back(Interval<QuicPacketNumber>(20, 30)); - } expected_intervals2.emplace_back(Interval<QuicPacketNumber>(50, 100)); EXPECT_EQ(expected_intervals2.size(), ack_frame1.packets.NumIntervals()); EXPECT_EQ(expected_intervals2, actual_intervals2); - if (!FLAGS_quic_reloadable_flag_quic_frames_deque3) { - ack_frame1.packets.AddRange(15, 20); - ack_frame1.packets.AddRange(30, 35); - - const std::vector<Interval<QuicPacketNumber>> actual_intervals3( - ack_frame1.packets.begin(), ack_frame1.packets.end()); - - std::vector<Interval<QuicPacketNumber>> expected_intervals3; - expected_intervals3.emplace_back(Interval<QuicPacketNumber>(1, 10)); - expected_intervals3.emplace_back(Interval<QuicPacketNumber>(15, 35)); - expected_intervals3.emplace_back(Interval<QuicPacketNumber>(50, 100)); - - EXPECT_EQ(expected_intervals3, actual_intervals3); - - ack_frame1.packets.AddRange(20, 35); - - const std::vector<Interval<QuicPacketNumber>> actual_intervals4( - ack_frame1.packets.begin(), ack_frame1.packets.end()); - - EXPECT_EQ(expected_intervals3, actual_intervals4); - ack_frame1.packets.AddRange(12, 20); - ack_frame1.packets.AddRange(30, 38); - - const std::vector<Interval<QuicPacketNumber>> actual_intervals5( - ack_frame1.packets.begin(), ack_frame1.packets.end()); - - std::vector<Interval<QuicPacketNumber>> expected_intervals5; - expected_intervals5.emplace_back(Interval<QuicPacketNumber>(1, 10)); - expected_intervals5.emplace_back(Interval<QuicPacketNumber>(12, 38)); - expected_intervals5.emplace_back(Interval<QuicPacketNumber>(50, 100)); - - EXPECT_EQ(expected_intervals5, actual_intervals5); - ack_frame1.packets.AddRange(8, 55); - - const std::vector<Interval<QuicPacketNumber>> actual_intervals6( - ack_frame1.packets.begin(), ack_frame1.packets.end()); - - std::vector<Interval<QuicPacketNumber>> expected_intervals6; - expected_intervals6.emplace_back(Interval<QuicPacketNumber>(1, 100)); - - EXPECT_EQ(expected_intervals6, actual_intervals6); - ack_frame1.packets.AddRange(0, 200); - - const std::vector<Interval<QuicPacketNumber>> actual_intervals7( - ack_frame1.packets.begin(), ack_frame1.packets.end()); - - std::vector<Interval<QuicPacketNumber>> expected_intervals7; - expected_intervals7.emplace_back(Interval<QuicPacketNumber>(0, 200)); - - EXPECT_EQ(expected_intervals7, actual_intervals7); - } - // Add ranges at both ends. QuicAckFrame ack_frame2; ack_frame2.packets.AddRange(20, 25); @@ -391,91 +332,9 @@ TEST_F(QuicFramesTest, AddAdjacentReverse) { EXPECT_EQ(expected_intervals, actual_intervals); } -TEST_F(QuicFramesTest, AddMerges) { - FLAGS_quic_reloadable_flag_quic_frames_deque3 = false; - QuicAckFrame ack_frame1; - ack_frame1.packets.AddRange(110, 112); - ack_frame1.packets.AddRange(106, 108); - ack_frame1.packets.AddRange(102, 104); - ack_frame1.packets.AddRange(1, 2); - ack_frame1.packets.AddRange(4, 7); - ack_frame1.packets.AddRange(10, 20); - ack_frame1.packets.AddRange(21, 30); - ack_frame1.packets.Add(20); - ack_frame1.packets.AddRange(40, 50); - ack_frame1.packets.AddRange(30, 35); - ack_frame1.packets.AddRange(35, 40); - ack_frame1.packets.AddRange(108, 110); - ack_frame1.packets.AddRange(50, 106); - ack_frame1.packets.AddRange(2, 4); - ack_frame1.packets.AddRange(7, 11); - std::vector<Interval<QuicPacketNumber>> expected_intervals; - expected_intervals.emplace_back(Interval<QuicPacketNumber>(1, 112)); - - const std::vector<Interval<QuicPacketNumber>> actual_intervals( - ack_frame1.packets.begin(), ack_frame1.packets.end()); - - EXPECT_EQ(expected_intervals, actual_intervals); -} - -TEST_F(QuicFramesTest, AddIntervalBig) { - FLAGS_quic_reloadable_flag_quic_frames_deque3 = false; - QuicAckFrame ack_frame1; - ack_frame1.packets.AddRange(20, 30); - ack_frame1.packets.AddRange(70, 100); - ack_frame1.packets.AddRange(56, 58); - ack_frame1.packets.AddRange(65, 69); - ack_frame1.packets.AddRange(59, 64); - ack_frame1.packets.AddRange(50, 55); - - std::vector<Interval<QuicPacketNumber>> expected_intervals; - expected_intervals.emplace_back(Interval<QuicPacketNumber>(20, 30)); - expected_intervals.emplace_back(Interval<QuicPacketNumber>(50, 55)); - expected_intervals.emplace_back(Interval<QuicPacketNumber>(56, 58)); - expected_intervals.emplace_back(Interval<QuicPacketNumber>(59, 64)); - expected_intervals.emplace_back(Interval<QuicPacketNumber>(65, 69)); - expected_intervals.emplace_back(Interval<QuicPacketNumber>(70, 100)); - - const std::vector<Interval<QuicPacketNumber>> actual_intervals( - ack_frame1.packets.begin(), ack_frame1.packets.end()); - - EXPECT_EQ(expected_intervals, actual_intervals); - ack_frame1.packets.AddRange(10, 60); - - std::vector<Interval<QuicPacketNumber>> expected_intervals2; - expected_intervals2.emplace_back(Interval<QuicPacketNumber>(10, 64)); - expected_intervals2.emplace_back(Interval<QuicPacketNumber>(65, 69)); - expected_intervals2.emplace_back(Interval<QuicPacketNumber>(70, 100)); - - const std::vector<Interval<QuicPacketNumber>> actual_intervals2( - ack_frame1.packets.begin(), ack_frame1.packets.end()); - - EXPECT_EQ(expected_intervals2, actual_intervals2); - - ack_frame1.packets.AddRange(68, 1000); - - std::vector<Interval<QuicPacketNumber>> expected_intervals3; - expected_intervals3.emplace_back(Interval<QuicPacketNumber>(10, 64)); - expected_intervals3.emplace_back(Interval<QuicPacketNumber>(65, 1000)); - - const std::vector<Interval<QuicPacketNumber>> actual_intervals3( - ack_frame1.packets.begin(), ack_frame1.packets.end()); - - EXPECT_EQ(expected_intervals3, actual_intervals3); - ack_frame1.packets.AddRange(0, 10000); - - std::vector<Interval<QuicPacketNumber>> expected_intervals4; - expected_intervals4.emplace_back(Interval<QuicPacketNumber>(0, 10000)); - - const std::vector<Interval<QuicPacketNumber>> actual_intervals4( - ack_frame1.packets.begin(), ack_frame1.packets.end()); - - EXPECT_EQ(expected_intervals4, actual_intervals4); -} - TEST_F(QuicFramesTest, RemoveSmallestInterval) { QuicAckFrame ack_frame1; - ack_frame1.deprecated_largest_observed = 100u; + ack_frame1.largest_acked = 100u; ack_frame1.packets.AddRange(51, 60); ack_frame1.packets.AddRange(71, 80); ack_frame1.packets.AddRange(91, 100); diff --git a/chromium/net/quic/core/quic_client_promised_info_test.cc b/chromium/net/quic/core/quic_client_promised_info_test.cc index 9d5d758cdaa..f8bed9edf80 100644 --- a/chromium/net/quic/core/quic_client_promised_info_test.cc +++ b/chromium/net/quic/core/quic_client_promised_info_test.cc @@ -8,6 +8,7 @@ #include "base/macros.h" #include "net/quic/core/spdy_utils.h" +#include "net/quic/core/tls_client_handshaker.h" #include "net/quic/platform/api/quic_logging.h" #include "net/quic/platform/api/quic_socket_address.h" #include "net/quic/platform/api/quic_test.h" @@ -35,7 +36,8 @@ class MockQuicSpdyClientSession : public QuicSpdyClientSession { QuicServerId("example.com", 443, PRIVACY_MODE_DISABLED), &crypto_config_, push_promise_index), - crypto_config_(crypto_test_utils::ProofVerifierForTesting()), + crypto_config_(crypto_test_utils::ProofVerifierForTesting(), + TlsClientHandshaker::CreateSslCtx()), authorized_(true) {} ~MockQuicSpdyClientSession() override {} diff --git a/chromium/net/quic/core/quic_client_push_promise_index_test.cc b/chromium/net/quic/core/quic_client_push_promise_index_test.cc index 9f980f14da5..3ab3a88e9f6 100644 --- a/chromium/net/quic/core/quic_client_push_promise_index_test.cc +++ b/chromium/net/quic/core/quic_client_push_promise_index_test.cc @@ -7,6 +7,7 @@ #include <string> #include "net/quic/core/spdy_utils.h" +#include "net/quic/core/tls_client_handshaker.h" #include "net/quic/platform/api/quic_test.h" #include "net/quic/test_tools/crypto_test_utils.h" #include "net/quic/test_tools/mock_quic_client_promised_info.h" @@ -34,7 +35,8 @@ class MockQuicSpdyClientSession : public QuicSpdyClientSession { QuicServerId("example.com", 443, PRIVACY_MODE_DISABLED), &crypto_config_, push_promise_index), - crypto_config_(crypto_test_utils::ProofVerifierForTesting()) {} + crypto_config_(crypto_test_utils::ProofVerifierForTesting(), + TlsClientHandshaker::CreateSslCtx()) {} ~MockQuicSpdyClientSession() override {} MOCK_METHOD1(CloseStream, void(QuicStreamId stream_id)); diff --git a/chromium/net/quic/core/quic_config.cc b/chromium/net/quic/core/quic_config.cc index 104333a48fe..593fb641391 100644 --- a/chromium/net/quic/core/quic_config.cc +++ b/chromium/net/quic/core/quic_config.cc @@ -668,7 +668,7 @@ void QuicConfig::SetDefaults() { SetInitialStreamFlowControlWindowToSend(kMinimumFlowControlSendWindow); SetInitialSessionFlowControlWindowToSend(kMinimumFlowControlSendWindow); - if (FLAGS_quic_reloadable_flag_quic_send_max_header_list_size) { + if (GetQuicReloadableFlag(quic_send_max_header_list_size)) { SetSupportMaxHeaderListSize(); } } diff --git a/chromium/net/quic/core/quic_connection.cc b/chromium/net/quic/core/quic_connection.cc index bbca3b58d57..027c90d35f5 100644 --- a/chromium/net/quic/core/quic_connection.cc +++ b/chromium/net/quic/core/quic_connection.cc @@ -178,12 +178,12 @@ QuicConnection::QuicConnection( QuicPacketWriter* writer, bool owns_writer, Perspective perspective, - const QuicTransportVersionVector& supported_versions) + const ParsedQuicVersionVector& supported_versions) : framer_(supported_versions, helper->GetClock()->ApproximateNow(), perspective), server_reply_to_connectivity_probes_( - FLAGS_quic_reloadable_flag_quic_server_reply_to_connectivity_probing), + GetQuicReloadableFlag(quic_server_reply_to_connectivity_probing)), current_packet_content_(NO_FRAMES_RECEIVED), current_peer_migration_type_(NO_CHANGE), helper_(helper), @@ -258,7 +258,7 @@ QuicConnection::QuicConnection( perspective, clock_, &stats_, - FLAGS_quic_reloadable_flag_quic_default_to_bbr ? kBBR : kCubicBytes, + GetQuicReloadableFlag(quic_default_to_bbr) ? kBBR : kCubicBytes, kNack), version_negotiation_state_(START_NEGOTIATION), perspective_(perspective), @@ -361,7 +361,7 @@ void QuicConnection::SetFromConfig(const QuicConfig& config) { if (config.HasClientSentConnectionOption(k5RTO, perspective_)) { close_connection_after_five_rtos_ = true; } - if (FLAGS_quic_reloadable_flag_quic_enable_3rtos && + if (GetQuicReloadableFlag(quic_enable_3rtos) && config.HasClientSentConnectionOption(k3RTO, perspective_)) { QUIC_FLAG_COUNT(quic_reloadable_flag_quic_enable_3rtos); close_connection_after_three_rtos_ = true; @@ -406,14 +406,14 @@ void QuicConnection::SetNumOpenStreams(size_t num_streams) { } bool QuicConnection::SelectMutualVersion( - const QuicTransportVersionVector& available_versions) { + const ParsedQuicVersionVector& available_versions) { // Try to find the highest mutual version by iterating over supported // versions, starting with the highest, and breaking out of the loop once we // find a matching version in the provided available_versions vector. - const QuicTransportVersionVector& supported_versions = + const ParsedQuicVersionVector& supported_versions = framer_.supported_versions(); for (size_t i = 0; i < supported_versions.size(); ++i) { - const QuicTransportVersion& version = supported_versions[i]; + const ParsedQuicVersion& version = supported_versions[i]; if (QuicContainsValue(available_versions, version)) { framer_.set_version(version); return true; @@ -452,9 +452,9 @@ void QuicConnection::OnPublicResetPacket(const QuicPublicResetPacket& packet) { } bool QuicConnection::OnProtocolVersionMismatch( - QuicTransportVersion received_version) { + ParsedQuicVersion received_version) { QUIC_DLOG(INFO) << ENDPOINT << "Received packet with mismatched version " - << received_version; + << ParsedQuicVersionToString(received_version); // TODO(satyamshekhar): Implement no server state in this mode. if (perspective_ == Perspective::IS_CLIENT) { const string error_details = "Protocol version mismatch."; @@ -463,7 +463,7 @@ bool QuicConnection::OnProtocolVersionMismatch( ConnectionCloseSource::FROM_SELF); return false; } - DCHECK_NE(transport_version(), received_version); + DCHECK_NE(version(), received_version); if (debug_visitor_ != nullptr) { debug_visitor_->OnProtocolVersionMismatch(received_version); @@ -495,11 +495,13 @@ bool QuicConnection::OnProtocolVersionMismatch( } version_negotiation_state_ = NEGOTIATED_VERSION; - visitor_->OnSuccessfulVersionNegotiation(received_version); + visitor_->OnSuccessfulVersionNegotiation(received_version.transport_version); if (debug_visitor_ != nullptr) { - debug_visitor_->OnSuccessfulVersionNegotiation(received_version); + debug_visitor_->OnSuccessfulVersionNegotiation( + received_version.transport_version); } - QUIC_DLOG(INFO) << ENDPOINT << "version negotiated " << received_version; + QUIC_DLOG(INFO) << ENDPOINT << "version negotiated " + << ParsedQuicVersionToString(received_version); // Store the new version. framer_.set_version(received_version); @@ -533,7 +535,7 @@ void QuicConnection::OnVersionNegotiationPacket( return; } - if (QuicContainsValue(packet.versions, transport_version())) { + if (QuicContainsValue(packet.versions, version())) { const string error_details = "Server already supports client's version and should have accepted the " "connection."; @@ -551,9 +553,9 @@ void QuicConnection::OnVersionNegotiationPacket( QUIC_INVALID_VERSION, QuicStrCat( "No common version found. Supported versions: {", - QuicTransportVersionVectorToString(framer_.supported_versions()), + ParsedQuicVersionVectorToString(framer_.supported_versions()), "}, peer supported versions: {", - QuicTransportVersionVectorToString(packet.versions), "}"), + ParsedQuicVersionVectorToString(packet.versions), "}"), ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); return; } @@ -859,14 +861,12 @@ const char* QuicConnection::ValidateAckFrame(const QuicAckFrame& incoming_ack) { return "Largest observed too low."; } - // TODO(wub): Remove this check along with - // FLAGS_quic_reloadable_flag_quic_deprecate_largest_observed. if (!incoming_ack.packets.Empty() && incoming_ack.packets.Max() != LargestAcked(incoming_ack)) { QUIC_BUG << ENDPOINT << "Peer last received packet: " << incoming_ack.packets.Max() << " which is not equal to largest observed: " - << incoming_ack.deprecated_largest_observed; + << incoming_ack.largest_acked; return "Last received packet not equal to largest observed."; } @@ -1161,7 +1161,7 @@ void QuicConnection::SendVersionNegotiationPacket() { return; } QUIC_DLOG(INFO) << ENDPOINT << "Sending version negotiation packet: {" - << QuicTransportVersionVectorToString( + << ParsedQuicVersionVectorToString( framer_.supported_versions()) << "}"; std::unique_ptr<QuicEncryptedPacket> version_packet( @@ -1219,10 +1219,7 @@ void QuicConnection::SendRstStream(QuicStreamId id, return; } // Flush stream frames of reset stream. - if (FLAGS_quic_reloadable_flag_quic_remove_on_stream_frame_discarded && - packet_generator_.HasPendingStreamFramesOfStream(id)) { - QUIC_FLAG_COUNT_N( - quic_reloadable_flag_quic_remove_on_stream_frame_discarded, 2, 2); + if (packet_generator_.HasPendingStreamFramesOfStream(id)) { packet_generator_.FlushAllQueuedFrames(); } @@ -1414,7 +1411,7 @@ bool QuicConnection::ProcessValidatedPacket(const QuicPacketHeader& header) { if (self_address_.port() != last_packet_destination_address_.port() || self_address_.host().Normalized() != last_packet_destination_address_.host().Normalized()) { - if (!FLAGS_quic_reloadable_flag_quic_allow_address_change_for_udp_proxy || + if (!GetQuicReloadableFlag(quic_allow_address_change_for_udp_proxy) || !visitor_->AllowSelfAddressChange()) { CloseConnection( QUIC_ERROR_MIGRATING_ADDRESS, @@ -1426,7 +1423,7 @@ bool QuicConnection::ProcessValidatedPacket(const QuicPacketHeader& header) { self_address_ = last_packet_destination_address_; } - if (FLAGS_quic_restart_flag_quic_enable_accept_random_ipn) { + if (GetQuicRestartFlag(quic_enable_accept_random_ipn)) { QUIC_FLAG_COUNT_N(quic_restart_flag_quic_enable_accept_random_ipn, 2, 2); // Configured to accept any packet number in range 1...0x7fffffff // as initial packet number. @@ -1488,7 +1485,7 @@ bool QuicConnection::ProcessValidatedPacket(const QuicPacketHeader& header) { ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); return false; } else { - DCHECK_EQ(header.version, transport_version()); + DCHECK_EQ(header.version, version()); version_negotiation_state_ = NEGOTIATED_VERSION; visitor_->OnSuccessfulVersionNegotiation(transport_version()); if (debug_visitor_ != nullptr) { @@ -2017,6 +2014,11 @@ void QuicConnection::SetDiversificationNonce( } void QuicConnection::SetDefaultEncryptionLevel(EncryptionLevel level) { + if (level != encryption_level_ && packet_generator_.HasQueuedFrames()) { + // Flush all queued frames when encryption level changes. + ScopedPacketFlusher flusher(this, NO_ACK); + packet_generator_.FlushAllQueuedFrames(); + } encryption_level_ = level; packet_generator_.set_encryption_level(level); } @@ -2250,7 +2252,7 @@ void QuicConnection::CheckForTimeout() { if (idle_duration >= idle_network_timeout_) { const string error_details = "No recent network activity."; QUIC_DVLOG(1) << ENDPOINT << error_details; - if (FLAGS_quic_reloadable_flag_quic_explicit_close_after_tlp && + if (GetQuicReloadableFlag(quic_explicit_close_after_tlp) && (sent_packet_manager_.GetConsecutiveTlpCount() > 0 || sent_packet_manager_.GetConsecutiveRtoCount() > 0 || visitor_->HasOpenDynamicStreams())) { @@ -2357,15 +2359,19 @@ QuicConnection::ScopedPacketFlusher::ScopedPacketFlusher( // If caller wants us to include an ack, check the delayed-ack timer to see if // there's ack info to be sent. if (ShouldSendAck(ack_mode)) { - QUIC_DVLOG(1) << "Bundling ack with outgoing packet."; - DCHECK(ack_mode == SEND_ACK || connection_->ack_frame_updated() || - connection_->stop_waiting_count_ > 1); - connection_->SendAck(); + if (!GetQuicReloadableFlag(quic_strict_ack_handling) || + !connection_->GetUpdatedAckFrame().ack_frame->packets.Empty()) { + QUIC_DVLOG(1) << "Bundling ack with outgoing packet."; + connection_->SendAck(); + } } } bool QuicConnection::ScopedPacketFlusher::ShouldSendAck( AckBundling ack_mode) const { + // If the ack alarm is set, make sure the ack has been updated. + DCHECK(!connection_->ack_alarm_->IsSet() || connection_->ack_frame_updated()) + << "ack_mode:" << ack_mode; switch (ack_mode) { case SEND_ACK: return true; @@ -2588,8 +2594,13 @@ void QuicConnection::StartPeerMigration( // TODO(jri): Move these calls to OnPeerMigrationValidated. Rename // OnConnectionMigration methods to OnPeerMigration. - visitor_->OnConnectionMigration(peer_migration_type); - sent_packet_manager_.OnConnectionMigration(peer_migration_type); + OnConnectionMigration(peer_migration_type); +} + +void QuicConnection::OnConnectionMigration( + PeerAddressChangeType addr_change_type) { + visitor_->OnConnectionMigration(addr_change_type); + sent_packet_manager_.OnConnectionMigration(addr_change_type); } bool QuicConnection::ack_frame_updated() const { @@ -2730,9 +2741,9 @@ void QuicConnection::UpdatePacketContent(PacketContent type) { current_peer_migration_type_ = NO_CHANGE; } -void QuicConnection::SetStreamNotifier( - StreamNotifierInterface* stream_notifier) { - sent_packet_manager_.SetStreamNotifier(stream_notifier); +void QuicConnection::SetSessionNotifier( + SessionNotifierInterface* session_notifier) { + sent_packet_manager_.SetSessionNotifier(session_notifier); } void QuicConnection::SetDataProducer( diff --git a/chromium/net/quic/core/quic_connection.h b/chromium/net/quic/core/quic_connection.h index f45293a71d2..bdb90a91516 100644 --- a/chromium/net/quic/core/quic_connection.h +++ b/chromium/net/quic/core/quic_connection.h @@ -26,6 +26,7 @@ #include "base/macros.h" #include "net/quic/core/crypto/quic_decrypter.h" +#include "net/quic/core/proto/cached_network_parameters.pb.h" #include "net/quic/core/quic_alarm.h" #include "net/quic/core/quic_alarm_factory.h" #include "net/quic/core/quic_blocked_writer_interface.h" @@ -55,7 +56,6 @@ class QuicEncrypter; class QuicRandom; namespace test { -class PacketSavingConnection; class QuicConnectionPeer; } // namespace test @@ -209,7 +209,7 @@ class QUIC_EXPORT_PRIVATE QuicConnectionDebugVisitor // Called when the protocol version on the received packet doensn't match // current protocol version of the connection. - virtual void OnProtocolVersionMismatch(QuicTransportVersion version) {} + virtual void OnProtocolVersionMismatch(ParsedQuicVersion version) {} // Called when the complete header of a packet has been parsed. virtual void OnPacketHeader(const QuicPacketHeader& header) {} @@ -265,7 +265,7 @@ class QUIC_EXPORT_PRIVATE QuicConnectionDebugVisitor virtual void OnSendConnectionState( const CachedNetworkParameters& cached_network_params) {} - // Called when a CachedNetworkParameters are recieved from the client. + // Called when a CachedNetworkParameters are received from the client. virtual void OnReceiveConnectionState( const CachedNetworkParameters& cached_network_params) {} @@ -325,7 +325,7 @@ class QUIC_EXPORT_PRIVATE QuicConnection QuicPacketWriter* writer, bool owns_writer, Perspective perspective, - const QuicTransportVersionVector& supported_versions); + const ParsedQuicVersionVector& supported_versions); ~QuicConnection() override; // Sets connection parameters from the supplied |config|. @@ -435,20 +435,16 @@ class QUIC_EXPORT_PRIVATE QuicConnection return framer_.transport_version(); } - // The QuicVersionLabel for the version this connection is using. - QuicVersionLabel version_label() const { - return framer_.last_version_label(); - } + ParsedQuicVersion version() const { return framer_.version(); } // The versions of the protocol that this connection supports. - const QuicTransportVersionVector& supported_versions() const { + const ParsedQuicVersionVector& supported_versions() const { return framer_.supported_versions(); } // From QuicFramerVisitorInterface void OnError(QuicFramer* framer) override; - bool OnProtocolVersionMismatch( - QuicTransportVersion received_version) override; + bool OnProtocolVersionMismatch(ParsedQuicVersion received_version) override; void OnPacket() override; void OnPublicResetPacket(const QuicPublicResetPacket& packet) override; void OnVersionNegotiationPacket( @@ -529,7 +525,7 @@ class QUIC_EXPORT_PRIVATE QuicConnection bool goaway_received() const { return goaway_received_; } // Must only be called on client connections. - const QuicTransportVersionVector& server_supported_versions() const { + const ParsedQuicVersionVector& server_supported_versions() const { DCHECK_EQ(Perspective::IS_CLIENT, perspective_); return server_supported_versions_; } @@ -683,8 +679,8 @@ class QUIC_EXPORT_PRIVATE QuicConnection // the MTU discovery alarm. void DiscoverMtu(); - // Sets the stream notifer on the SentPacketManager. - void SetStreamNotifier(StreamNotifierInterface* stream_notifier); + // Sets the session notifier on the SentPacketManager. + void SetSessionNotifier(SessionNotifierInterface* session_notifier); // Set data producer in framer. void SetDataProducer(QuicStreamFrameDataProducer* data_producer); @@ -751,8 +747,7 @@ class QUIC_EXPORT_PRIVATE QuicConnection // Selects and updates the version of the protocol being used by selecting a // version from |available_versions| which is also supported. Returns true if // such a version exists, false otherwise. - bool SelectMutualVersion( - const QuicTransportVersionVector& available_versions); + bool SelectMutualVersion(const ParsedQuicVersionVector& available_versions); // Returns the current per-packet options for the connection. PerPacketOptions* per_packet_options() { return per_packet_options_; } @@ -783,9 +778,12 @@ class QUIC_EXPORT_PRIVATE QuicConnection // Decides whether to send probing retransmissions, and does so if required. void MaybeSendProbingRetransmissions(); + // Notify various components(SendPacketManager, Session etc.) that this + // connection has been migrated. + void OnConnectionMigration(PeerAddressChangeType addr_change_type); + private: friend class test::QuicConnectionPeer; - friend class test::PacketSavingConnection; typedef std::list<SerializedPacket> QueuedPacketList; @@ -1113,7 +1111,7 @@ class QUIC_EXPORT_PRIVATE QuicConnection // If non-empty this contains the set of versions received in a // version negotiation packet. - QuicTransportVersionVector server_supported_versions_; + ParsedQuicVersionVector server_supported_versions_; // The size of the packet we are targeting while doing path MTU discovery. QuicByteCount mtu_discovery_target_; diff --git a/chromium/net/quic/core/quic_connection_test.cc b/chromium/net/quic/core/quic_connection_test.cc index 254eabe53b9..adf70273d05 100644 --- a/chromium/net/quic/core/quic_connection_test.cc +++ b/chromium/net/quic/core/quic_connection_test.cc @@ -117,6 +117,7 @@ class TaggingEncrypter : public QuicEncrypter { size_t GetKeySize() const override { return 0; } size_t GetNoncePrefixSize() const override { return 0; } + size_t GetIVSize() const override { return 0; } size_t GetMaxPlaintextSize(size_t ciphertext_size) const override { return ciphertext_size - kTagSize; @@ -180,6 +181,8 @@ class TaggingDecrypter : public QuicDecrypter { return true; } + size_t GetKeySize() const override { return 0; } + size_t GetIVSize() const override { return 0; } QuicStringPiece GetKey() const override { return QuicStringPiece(); } QuicStringPiece GetNoncePrefix() const override { return QuicStringPiece(); } // Use a distinct value starting with 0xFFFFFF, which is never used by TLS. @@ -277,9 +280,9 @@ class TestAlarmFactory : public QuicAlarmFactory { class TestPacketWriter : public QuicPacketWriter { public: - TestPacketWriter(QuicTransportVersion version, MockClock* clock) + TestPacketWriter(ParsedQuicVersion version, MockClock* clock) : version_(version), - framer_(SupportedTransportVersions(version_), Perspective::IS_SERVER), + framer_(SupportedVersions(version_), Perspective::IS_SERVER), last_packet_size_(0), write_blocked_(false), write_should_fail_(false), @@ -445,9 +448,8 @@ class TestPacketWriter : public QuicPacketWriter { void Reset() { framer_.Reset(); } - void SetSupportedTransportVersions( - const QuicTransportVersionVector& versions) { - framer_.SetSupportedTransportVersions(versions); + void SetSupportedVersions(const ParsedQuicVersionVector& versions) { + framer_.SetSupportedVersions(versions); } void set_max_packet_size(QuicByteCount max_packet_size) { @@ -455,7 +457,7 @@ class TestPacketWriter : public QuicPacketWriter { } private: - QuicTransportVersion version_; + ParsedQuicVersion version_; SimpleQuicFramer framer_; size_t last_packet_size_; QuicPacketHeader last_packet_header_; @@ -486,7 +488,7 @@ class TestConnection : public QuicConnection { TestAlarmFactory* alarm_factory, TestPacketWriter* writer, Perspective perspective, - QuicTransportVersion version) + ParsedQuicVersion version) : QuicConnection(connection_id, address, helper, @@ -494,7 +496,7 @@ class TestConnection : public QuicConnection { writer, /* owns_writer= */ false, perspective, - SupportedTransportVersions(version)) { + SupportedVersions(version)) { writer->set_perspective(perspective); SetEncrypter(ENCRYPTION_FORWARD_SECURE, new NullEncrypter(perspective)); SetDataProducer(&producer_); @@ -578,15 +580,13 @@ class TestConnection : public QuicConnection { return SendStreamDataWithString(kCryptoStreamId, "chlo", 0, NO_FIN); } - void set_version(QuicTransportVersion version) { + void set_version(ParsedQuicVersion version) { QuicConnectionPeer::GetFramer(this)->set_version(version); } - void SetSupportedTransportVersions( - const QuicTransportVersionVector& versions) { - QuicConnectionPeer::GetFramer(this)->SetSupportedTransportVersions( - versions); - writer()->SetSupportedTransportVersions(versions); + void SetSupportedVersions(const ParsedQuicVersionVector& versions) { + QuicConnectionPeer::GetFramer(this)->SetSupportedVersions(versions); + writer()->SetSupportedVersions(versions); } void set_perspective(Perspective perspective) { @@ -674,9 +674,9 @@ class TestConnection : public QuicConnection { enum class AckResponse { kDefer, kImmediate }; -// Run tests with combinations of {QuicTransportVersion, AckResponse}. +// Run tests with combinations of {ParsedQuicVersion, AckResponse}. struct TestParams { - TestParams(QuicTransportVersion version, + TestParams(ParsedQuicVersion version, AckResponse ack_response, bool no_stop_waiting) : version(version), @@ -684,14 +684,14 @@ struct TestParams { no_stop_waiting(no_stop_waiting) {} friend std::ostream& operator<<(std::ostream& os, const TestParams& p) { - os << "{ client_version: " << QuicVersionToString(p.version) + os << "{ client_version: " << ParsedQuicVersionToString(p.version) << " ack_response: " << (p.ack_response == AckResponse::kDefer ? "defer" : "immediate") << " no_stop_waiting: " << p.no_stop_waiting << " }"; return os; } - QuicTransportVersion version; + ParsedQuicVersion version; AckResponse ack_response; bool no_stop_waiting; }; @@ -699,8 +699,7 @@ struct TestParams { // Constructs various test permutations. std::vector<TestParams> GetTestParams() { std::vector<TestParams> params; - QuicTransportVersionVector all_supported_versions = - AllSupportedTransportVersions(); + ParsedQuicVersionVector all_supported_versions = AllSupportedVersions(); for (size_t i = 0; i < all_supported_versions.size(); ++i) { for (AckResponse ack_response : {AckResponse::kDefer, AckResponse::kImmediate}) { @@ -717,27 +716,27 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> { protected: QuicConnectionTest() : connection_id_(42), - framer_(SupportedTransportVersions(transport_version()), + framer_(SupportedVersions(version()), QuicTime::Zero(), Perspective::IS_CLIENT), send_algorithm_(new StrictMock<MockSendAlgorithm>), loss_algorithm_(new MockLossAlgorithm()), helper_(new TestConnectionHelper(&clock_, &random_generator_)), alarm_factory_(new TestAlarmFactory()), - peer_framer_(SupportedTransportVersions(transport_version()), + peer_framer_(SupportedVersions(version()), QuicTime::Zero(), Perspective::IS_SERVER), peer_creator_(connection_id_, &peer_framer_, /*delegate=*/nullptr), - writer_(new TestPacketWriter(transport_version(), &clock_)), + writer_(new TestPacketWriter(version(), &clock_)), connection_(connection_id_, kPeerAddress, helper_.get(), alarm_factory_.get(), writer_.get(), Perspective::IS_CLIENT, - transport_version()), + version()), creator_(QuicConnectionPeer::GetPacketCreator(&connection_)), generator_(QuicConnectionPeer::GetPacketGenerator(&connection_)), manager_(QuicConnectionPeer::GetSentPacketManager(&connection_)), @@ -782,7 +781,7 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> { .Times(AnyNumber()); } - QuicTransportVersion transport_version() { return GetParam().version; } + ParsedQuicVersion version() { return GetParam().version; } QuicAckFrame* outgoing_ack() { QuicFrame ack_frame = QuicConnectionPeer::GetUpdatedAckFrame(&connection_); @@ -862,7 +861,8 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> { const size_t encrypted_length = peer_framer_.EncryptInPlace( ENCRYPTION_NONE, header.packet_number, - GetStartOfEncryptedData(peer_framer_.transport_version(), header), + GetStartOfEncryptedData(peer_framer_.version().transport_version, + header), length, kMaxPacketSize, encrypted_buffer); DCHECK_GT(encrypted_length, 0u); @@ -1056,7 +1056,7 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> { ConnectionCloseSource::FROM_SELF)); // Call ProcessDataPacket rather than ProcessPacket, as we should not get a // packet call to the visitor. - if (FLAGS_quic_restart_flag_quic_enable_accept_random_ipn) { + if (GetQuicRestartFlag(quic_enable_accept_random_ipn)) { ProcessDataPacket(kMaxRandomInitialPacketNumber + 6000); } else { ProcessDataPacket(6000); @@ -1170,7 +1170,7 @@ TEST_P(QuicConnectionTest, SelfAddressChangeAtServer) { QuicIpAddress host; host.FromString("1.1.1.1"); QuicSocketAddress self_address(host, 123); - if (FLAGS_quic_reloadable_flag_quic_allow_address_change_for_udp_proxy) { + if (GetQuicReloadableFlag(quic_allow_address_change_for_udp_proxy)) { EXPECT_CALL(visitor_, AllowSelfAddressChange()).WillOnce(Return(false)); } EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_ERROR_MIGRATING_ADDRESS, _, _)); @@ -1306,7 +1306,7 @@ TEST_P(QuicConnectionTest, ReceiveConnectivityProbingAtServer) { kPeerAddress); EXPECT_EQ(kPeerAddress, connection_.peer_address()); - if (FLAGS_quic_reloadable_flag_quic_server_reply_to_connectivity_probing) { + if (GetQuicReloadableFlag(quic_server_reply_to_connectivity_probing)) { EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(0); EXPECT_CALL(visitor_, OnConnectivityProbeReceived(_, _)).Times(1); } else { @@ -1326,7 +1326,7 @@ TEST_P(QuicConnectionTest, ReceiveConnectivityProbingAtServer) { ConstructReceivedPacket(*probing_packet, clock_.Now())); ProcessReceivedPacket(kSelfAddress, kNewPeerAddress, *received); - if (FLAGS_quic_reloadable_flag_quic_server_reply_to_connectivity_probing) { + if (GetQuicReloadableFlag(quic_server_reply_to_connectivity_probing)) { EXPECT_EQ(kPeerAddress, connection_.peer_address()); } else { EXPECT_EQ(kNewPeerAddress, connection_.peer_address()); @@ -1355,7 +1355,7 @@ TEST_P(QuicConnectionTest, MigrateAfterProbingAtServer) { kPeerAddress); EXPECT_EQ(kPeerAddress, connection_.peer_address()); - if (FLAGS_quic_reloadable_flag_quic_server_reply_to_connectivity_probing) { + if (GetQuicReloadableFlag(quic_server_reply_to_connectivity_probing)) { EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(0); EXPECT_CALL(visitor_, OnConnectivityProbeReceived(_, _)).Times(1); } else { @@ -1373,7 +1373,7 @@ TEST_P(QuicConnectionTest, MigrateAfterProbingAtServer) { std::unique_ptr<QuicReceivedPacket> received( ConstructReceivedPacket(*probing_packet, clock_.Now())); ProcessReceivedPacket(kSelfAddress, kNewPeerAddress, *received); - if (FLAGS_quic_reloadable_flag_quic_server_reply_to_connectivity_probing) { + if (GetQuicReloadableFlag(quic_server_reply_to_connectivity_probing)) { EXPECT_EQ(kPeerAddress, connection_.peer_address()); } else { EXPECT_EQ(kNewPeerAddress, connection_.peer_address()); @@ -1381,7 +1381,7 @@ TEST_P(QuicConnectionTest, MigrateAfterProbingAtServer) { // Process another non-probing packet with the new peer address on server // side will start peer migration. - if (FLAGS_quic_reloadable_flag_quic_server_reply_to_connectivity_probing) { + if (GetQuicReloadableFlag(quic_server_reply_to_connectivity_probing)) { EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(1); } else { EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(0); @@ -1440,7 +1440,7 @@ TEST_P(QuicConnectionTest, ReceiveConnectivityProbingAtClient) { // Process a padded PING packet with a different self address on client side // is effectively receiving a connectivity probing. EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(0); - if (FLAGS_quic_reloadable_flag_quic_server_reply_to_connectivity_probing) { + if (GetQuicReloadableFlag(quic_server_reply_to_connectivity_probing)) { EXPECT_CALL(visitor_, OnConnectivityProbeReceived(_, _)).Times(1); } @@ -1491,7 +1491,7 @@ TEST_P(QuicConnectionTest, SmallerServerMaxPacketSize) { QuicConnectionId connection_id = 42; TestConnection connection(connection_id, kPeerAddress, helper_.get(), alarm_factory_.get(), writer_.get(), - Perspective::IS_SERVER, transport_version()); + Perspective::IS_SERVER, version()); EXPECT_EQ(Perspective::IS_SERVER, connection.perspective()); EXPECT_EQ(1000u, connection.max_packet_length()); } @@ -1517,7 +1517,7 @@ TEST_P(QuicConnectionTest, IncreaseServerMaxPacketSize) { ENCRYPTION_NONE, 12, *packet, buffer, kMaxPacketSize); EXPECT_EQ(kMaxPacketSize, encrypted_length); - framer_.set_version(transport_version()); + framer_.set_version(version()); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); connection_.ProcessUdpPacket( kSelfAddress, kPeerAddress, @@ -1550,7 +1550,7 @@ TEST_P(QuicConnectionTest, IncreaseServerMaxPacketSizeWhileWriterLimited) { ENCRYPTION_NONE, 12, *packet, buffer, kMaxPacketSize); EXPECT_EQ(kMaxPacketSize, encrypted_length); - framer_.set_version(transport_version()); + framer_.set_version(version()); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); connection_.ProcessUdpPacket( kSelfAddress, kPeerAddress, @@ -1578,7 +1578,7 @@ TEST_P(QuicConnectionTest, LimitMaxPacketSizeByWriterForNewConnection) { writer_->set_max_packet_size(lower_max_packet_size); TestConnection connection(connection_id, kPeerAddress, helper_.get(), alarm_factory_.get(), writer_.get(), - Perspective::IS_CLIENT, transport_version()); + Perspective::IS_CLIENT, version()); EXPECT_EQ(Perspective::IS_CLIENT, connection.perspective()); EXPECT_EQ(lower_max_packet_size, connection.max_packet_length()); } @@ -1670,7 +1670,7 @@ TEST_P(QuicConnectionTest, RejectPacketTooFarOut) { // Call ProcessDataPacket rather than ProcessPacket, as we should not get a // packet call to the visitor. - if (FLAGS_quic_restart_flag_quic_enable_accept_random_ipn) { + if (GetQuicRestartFlag(quic_enable_accept_random_ipn)) { ProcessDataPacket(kMaxRandomInitialPacketNumber + 6000); } else { ProcessDataPacket(6000); @@ -1793,7 +1793,7 @@ TEST_P(QuicConnectionTest, AckReceiptCausesAckSend) { } TEST_P(QuicConnectionTest, 20AcksCausesAckSend) { - if (connection_.transport_version() > QUIC_VERSION_38) { + if (connection_.version().transport_version > QUIC_VERSION_38) { return; } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); @@ -1815,7 +1815,7 @@ TEST_P(QuicConnectionTest, 20AcksCausesAckSend) { } TEST_P(QuicConnectionTest, AckNeedsRetransmittableFrames) { - if (connection_.transport_version() <= QUIC_VERSION_38) { + if (connection_.version().transport_version <= QUIC_VERSION_38) { return; } @@ -2085,7 +2085,10 @@ TEST_P(QuicConnectionTest, RecordSentTimeBeforePacketSent) { } TEST_P(QuicConnectionTest, FramePacking) { - // Send an ack and two stream frames in 1 packet by queueing them. + // Send two stream frames in 1 packet by queueing them. + // If quic_strict_ack_handling is false, the packet + // also bundles an empty ack frame and a stop_waiting frame. + connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); { QuicConnection::ScopedPacketFlusher flusher(&connection_, QuicConnection::SEND_ACK); @@ -2099,21 +2102,34 @@ TEST_P(QuicConnectionTest, FramePacking) { // Parse the last packet and ensure it's an ack and two stream frames from // two different streams. if (GetParam().no_stop_waiting) { - EXPECT_EQ(3u, writer_->frame_count()); + EXPECT_EQ(GetQuicReloadableFlag(quic_strict_ack_handling) ? 2u : 3u, + writer_->frame_count()); EXPECT_TRUE(writer_->stop_waiting_frames().empty()); } else { - EXPECT_EQ(4u, writer_->frame_count()); - EXPECT_FALSE(writer_->stop_waiting_frames().empty()); + EXPECT_EQ(GetQuicReloadableFlag(quic_strict_ack_handling) ? 2u : 4u, + writer_->frame_count()); + + if (GetQuicReloadableFlag(quic_strict_ack_handling)) { + EXPECT_TRUE(writer_->stop_waiting_frames().empty()); + } else { + EXPECT_FALSE(writer_->stop_waiting_frames().empty()); + } + } + + if (GetQuicReloadableFlag(quic_strict_ack_handling)) { + EXPECT_TRUE(writer_->ack_frames().empty()); + } else { + EXPECT_FALSE(writer_->ack_frames().empty()); } - EXPECT_FALSE(writer_->ack_frames().empty()); ASSERT_EQ(2u, writer_->stream_frames().size()); EXPECT_EQ(kClientDataStreamId1, writer_->stream_frames()[0]->stream_id); EXPECT_EQ(kClientDataStreamId2, writer_->stream_frames()[1]->stream_id); } TEST_P(QuicConnectionTest, FramePackingNonCryptoThenCrypto) { - // Send an ack and two stream frames (one non-crypto, then one crypto) in 2 - // packets by queueing them. + // Send two stream frames (one non-crypto, then one crypto) in 2 packets by + // queueing them. + connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); { EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2); QuicConnection::ScopedPacketFlusher flusher(&connection_, @@ -2132,8 +2148,8 @@ TEST_P(QuicConnectionTest, FramePackingNonCryptoThenCrypto) { } TEST_P(QuicConnectionTest, FramePackingCryptoThenNonCrypto) { - // Send an ack and two stream frames (one crypto, then one non-crypto) in 2 - // packets by queueing them. + // Send two stream frames (one crypto, then one non-crypto) in 2 packets by + // queueing them. { EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2); QuicConnection::ScopedPacketFlusher flusher(&connection_, @@ -3419,11 +3435,11 @@ TEST_P(QuicConnectionTest, MtuDiscoveryFailed) { mtu_discovery_packets.end()); ack.packets.AddRange(1, min_packet); ack.packets.AddRange(max_packet + 1, creator_->packet_number() + 1); - ack.deprecated_largest_observed = creator_->packet_number(); + ack.largest_acked = creator_->packet_number(); } else { ack.packets.AddRange(1, creator_->packet_number() + 1); - ack.deprecated_largest_observed = creator_->packet_number(); + ack.largest_acked = creator_->packet_number(); } ProcessAckPacket(&ack); @@ -3757,7 +3773,7 @@ TEST_P(QuicConnectionTest, NewTimeoutAfterSendSilentClose) { } TEST_P(QuicConnectionTest, TimeoutAfterSendSilentCloseAndTLP) { - FLAGS_quic_reloadable_flag_quic_explicit_close_after_tlp = true; + SetQuicReloadableFlag(quic_explicit_close_after_tlp, true); // Same test as above, but complete a handshake which enables silent close, // but sending TLPs causes the connection close to be sent. EXPECT_TRUE(connection_.connected()); @@ -3812,7 +3828,7 @@ TEST_P(QuicConnectionTest, TimeoutAfterSendSilentCloseAndTLP) { } TEST_P(QuicConnectionTest, TimeoutAfterSendSilentCloseWithOpenStreams) { - FLAGS_quic_reloadable_flag_quic_explicit_close_after_tlp = true; + SetQuicReloadableFlag(quic_explicit_close_after_tlp, true); // Same test as above, but complete a handshake which enables silent close, // but having open streams causes the connection close to be sent. EXPECT_TRUE(connection_.connected()); @@ -4000,7 +4016,7 @@ TEST_P(QuicConnectionTest, TimeoutAfter5ClientRTOs) { } TEST_P(QuicConnectionTest, TimeoutAfter3ClientRTOs) { - FLAGS_quic_reloadable_flag_quic_enable_3rtos = true; + SetQuicReloadableFlag(quic_enable_3rtos, true); connection_.SetMaxTailLossProbes(2); EXPECT_TRUE(connection_.connected()); EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); @@ -4065,7 +4081,7 @@ TEST_P(QuicConnectionTest, TestQueueLimitsOnSendStreamData) { // All packets carry version info till version is negotiated. size_t payload_length; size_t length = GetPacketLengthForOneStream( - connection_.transport_version(), kIncludeVersion, + connection_.version().transport_version, kIncludeVersion, !kIncludeDiversificationNonce, PACKET_8BYTE_CONNECTION_ID, PACKET_1BYTE_PACKET_NUMBER, &payload_length); connection_.SetMaxPacketLength(length); @@ -4088,7 +4104,7 @@ TEST_P(QuicConnectionTest, LoopThroughSendingPackets) { // stream frames with non-zero offets will fit within the packet length. size_t length = 2 + GetPacketLengthForOneStream( - connection_.transport_version(), kIncludeVersion, + connection_.version().transport_version, kIncludeVersion, !kIncludeDiversificationNonce, PACKET_8BYTE_CONNECTION_ID, PACKET_1BYTE_PACKET_NUMBER, &payload_length); connection_.SetMaxPacketLength(length); @@ -4927,9 +4943,10 @@ TEST_P(QuicConnectionTest, MissingPacketsBeforeLeastUnacked) { } TEST_P(QuicConnectionTest, ServerSendsVersionNegotiationPacket) { - connection_.SetSupportedTransportVersions(AllSupportedTransportVersions()); + connection_.SetSupportedVersions(AllSupportedVersions()); set_perspective(Perspective::IS_SERVER); - peer_framer_.set_version_for_tests(QUIC_VERSION_UNSUPPORTED); + peer_framer_.set_version_for_tests( + ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED)); QuicPacketHeader header; header.connection_id = connection_id_; @@ -4943,28 +4960,29 @@ TEST_P(QuicConnectionTest, ServerSendsVersionNegotiationPacket) { size_t encrypted_length = framer_.EncryptPayload(ENCRYPTION_NONE, 12, *packet, buffer, kMaxPacketSize); - framer_.set_version(transport_version()); + framer_.set_version(version()); connection_.ProcessUdpPacket( kSelfAddress, kPeerAddress, QuicReceivedPacket(buffer, encrypted_length, QuicTime::Zero(), false)); EXPECT_TRUE(writer_->version_negotiation_packet() != nullptr); - size_t num_versions = arraysize(kSupportedTransportVersions); - ASSERT_EQ(num_versions, + ParsedQuicVersionVector supported_versions = AllSupportedVersions(); + ASSERT_EQ(supported_versions.size(), writer_->version_negotiation_packet()->versions.size()); - // We expect all versions in kSupportedTransportVersions to be + // We expect all versions in supported_versions to be // included in the packet. - for (size_t i = 0; i < num_versions; ++i) { - EXPECT_EQ(kSupportedTransportVersions[i], + for (size_t i = 0; i < supported_versions.size(); ++i) { + EXPECT_EQ(supported_versions[i], writer_->version_negotiation_packet()->versions[i]); } } TEST_P(QuicConnectionTest, ServerSendsVersionNegotiationPacketSocketBlocked) { - connection_.SetSupportedTransportVersions(AllSupportedTransportVersions()); + connection_.SetSupportedVersions(AllSupportedVersions()); set_perspective(Perspective::IS_SERVER); - peer_framer_.set_version_for_tests(QUIC_VERSION_UNSUPPORTED); + peer_framer_.set_version_for_tests( + ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED)); QuicPacketHeader header; header.connection_id = connection_id_; @@ -4978,7 +4996,7 @@ TEST_P(QuicConnectionTest, ServerSendsVersionNegotiationPacketSocketBlocked) { size_t encrypted_length = framer_.EncryptPayload(ENCRYPTION_NONE, 12, *packet, buffer, kMaxPacketSize); - framer_.set_version(transport_version()); + framer_.set_version(version()); BlockOnNextWrite(); connection_.ProcessUdpPacket( kSelfAddress, kPeerAddress, @@ -4990,23 +5008,24 @@ TEST_P(QuicConnectionTest, ServerSendsVersionNegotiationPacketSocketBlocked) { connection_.OnCanWrite(); EXPECT_TRUE(writer_->version_negotiation_packet() != nullptr); - size_t num_versions = arraysize(kSupportedTransportVersions); - ASSERT_EQ(num_versions, + ParsedQuicVersionVector supported_versions = AllSupportedVersions(); + ASSERT_EQ(supported_versions.size(), writer_->version_negotiation_packet()->versions.size()); - // We expect all versions in kSupportedTransportVersions to be + // We expect all versions in supported_versions to be // included in the packet. - for (size_t i = 0; i < num_versions; ++i) { - EXPECT_EQ(kSupportedTransportVersions[i], + for (size_t i = 0; i < supported_versions.size(); ++i) { + EXPECT_EQ(supported_versions[i], writer_->version_negotiation_packet()->versions[i]); } } TEST_P(QuicConnectionTest, ServerSendsVersionNegotiationPacketSocketBlockedDataBuffered) { - connection_.SetSupportedTransportVersions(AllSupportedTransportVersions()); + connection_.SetSupportedVersions(AllSupportedVersions()); set_perspective(Perspective::IS_SERVER); - peer_framer_.set_version_for_tests(QUIC_VERSION_UNSUPPORTED); + peer_framer_.set_version_for_tests( + ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED)); QuicPacketHeader header; header.connection_id = connection_id_; @@ -5020,7 +5039,7 @@ TEST_P(QuicConnectionTest, size_t encryped_length = framer_.EncryptPayload(ENCRYPTION_NONE, 12, *packet, buffer, kMaxPacketSize); - framer_.set_version(transport_version()); + framer_.set_version(version()); set_perspective(Perspective::IS_SERVER); BlockOnNextWrite(); writer_->set_is_write_blocked_data_buffered(true); @@ -5034,12 +5053,13 @@ TEST_P(QuicConnectionTest, TEST_P(QuicConnectionTest, ClientHandlesVersionNegotiation) { // Start out with some unsupported version. QuicConnectionPeer::GetFramer(&connection_) - ->set_version_for_tests(QUIC_VERSION_UNSUPPORTED); + ->set_version_for_tests( + ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED)); // Send a version negotiation packet. std::unique_ptr<QuicEncryptedPacket> encrypted( - peer_framer_.BuildVersionNegotiationPacket( - connection_id_, AllSupportedTransportVersions())); + peer_framer_.BuildVersionNegotiationPacket(connection_id_, + AllSupportedVersions())); std::unique_ptr<QuicReceivedPacket> received( ConstructReceivedPacket(*encrypted, QuicTime::Zero())); connection_.ProcessUdpPacket(kSelfAddress, kPeerAddress, *received); @@ -5074,7 +5094,7 @@ TEST_P(QuicConnectionTest, BadVersionNegotiation) { ConnectionCloseSource::FROM_SELF)); std::unique_ptr<QuicEncryptedPacket> encrypted( framer_.BuildVersionNegotiationPacket(connection_id_, - AllSupportedTransportVersions())); + AllSupportedVersions())); std::unique_ptr<QuicReceivedPacket> received( ConstructReceivedPacket(*encrypted, QuicTime::Zero())); connection_.ProcessUdpPacket(kSelfAddress, kPeerAddress, *received); @@ -5156,32 +5176,29 @@ TEST_P(QuicConnectionTest, ProcessFramesIfPacketClosedConnection) { } TEST_P(QuicConnectionTest, SelectMutualVersion) { - connection_.SetSupportedTransportVersions(AllSupportedTransportVersions()); + connection_.SetSupportedVersions(AllSupportedVersions()); // Set the connection to speak the lowest quic version. connection_.set_version(QuicVersionMin()); - EXPECT_EQ(QuicVersionMin(), connection_.transport_version()); + EXPECT_EQ(QuicVersionMin(), connection_.version()); // Pass in available versions which includes a higher mutually supported // version. The higher mutually supported version should be selected. - QuicTransportVersionVector supported_versions; - for (size_t i = 0; i < arraysize(kSupportedTransportVersions); ++i) { - supported_versions.push_back(kSupportedTransportVersions[i]); - } + ParsedQuicVersionVector supported_versions = AllSupportedVersions(); EXPECT_TRUE(connection_.SelectMutualVersion(supported_versions)); - EXPECT_EQ(QuicVersionMax(), connection_.transport_version()); + EXPECT_EQ(QuicVersionMax(), connection_.version()); // Expect that the lowest version is selected. // Ensure the lowest supported version is less than the max, unless they're // the same. - EXPECT_LE(QuicVersionMin(), QuicVersionMax()); - QuicTransportVersionVector lowest_version_vector; + ParsedQuicVersionVector lowest_version_vector; lowest_version_vector.push_back(QuicVersionMin()); EXPECT_TRUE(connection_.SelectMutualVersion(lowest_version_vector)); - EXPECT_EQ(QuicVersionMin(), connection_.transport_version()); + EXPECT_EQ(QuicVersionMin(), connection_.version()); // Shouldn't be able to find a mutually supported version. - QuicTransportVersionVector unsupported_version; - unsupported_version.push_back(QUIC_VERSION_UNSUPPORTED); + ParsedQuicVersionVector unsupported_version; + unsupported_version.push_back( + ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED)); EXPECT_FALSE(connection_.SelectMutualVersion(unsupported_version)); } @@ -5229,10 +5246,10 @@ TEST_P(QuicConnectionTest, OnPacketHeaderDebugVisitor) { TEST_P(QuicConnectionTest, Pacing) { TestConnection server(connection_id_, kSelfAddress, helper_.get(), alarm_factory_.get(), writer_.get(), - Perspective::IS_SERVER, transport_version()); + Perspective::IS_SERVER, version()); TestConnection client(connection_id_, kPeerAddress, helper_.get(), alarm_factory_.get(), writer_.get(), - Perspective::IS_CLIENT, transport_version()); + Perspective::IS_CLIENT, version()); EXPECT_FALSE(QuicSentPacketManagerPeer::UsingPacing( static_cast<const QuicSentPacketManager*>( &client.sent_packet_manager()))); diff --git a/chromium/net/quic/core/quic_constants.h b/chromium/net/quic/core/quic_constants.h index bb643554f3e..49c3ead62df 100644 --- a/chromium/net/quic/core/quic_constants.h +++ b/chromium/net/quic/core/quic_constants.h @@ -113,6 +113,14 @@ const int64_t kMaximumIdleTimeoutSecs = 60 * 10; // 10 minutes. // The default timeout for a connection until the crypto handshake succeeds. const int64_t kMaxTimeForCryptoHandshakeSecs = 10; // 10 secs. +// The default maximum time QUIC session could be on non-default network before +// migrate back to default network. +const int64_t kMaxTimeOnNonDefaultNetworkSecs = 128; + +// The default maximum number of migrations to non default network on path +// degrading per network. +const int64_t kMaxMigrationsToNonDefaultNetworkOnPathDegrading = 5; + // Default limit on the number of undecryptable packets the connection buffers // before the CHLO/SHLO arrive. const size_t kDefaultMaxUndecryptablePackets = 10; @@ -195,6 +203,9 @@ const QuicPacketNumber kMaxRandomInitialPacketNumber = 0x7fffffff; // Used to represent an invalid or no control frame id. const QuicControlFrameId kInvalidControlFrameId = 0; +// The max length a stream can have. +const QuicByteCount kMaxStreamLength = (UINT64_C(1) << 62) - 1; + } // namespace net #endif // NET_QUIC_CORE_QUIC_CONSTANTS_H_ diff --git a/chromium/net/quic/core/quic_control_frame_manager.cc b/chromium/net/quic/core/quic_control_frame_manager.cc index 3e659983096..24f459ace35 100644 --- a/chromium/net/quic/core/quic_control_frame_manager.cc +++ b/chromium/net/quic/core/quic_control_frame_manager.cc @@ -28,31 +28,8 @@ void QuicControlFrameManager::OnControlFrameSent(const QuicFrame& frame) { } if (id == least_unacked_ + control_frames_.size()) { // This is a newly sent control frame. Save a copy of this frame. - switch (frame.type) { - case RST_STREAM_FRAME: - control_frames_.emplace_back( - QuicFrame(new QuicRstStreamFrame(*frame.rst_stream_frame))); - return; - case GOAWAY_FRAME: - control_frames_.emplace_back( - QuicFrame(new QuicGoAwayFrame(*frame.goaway_frame))); - return; - case WINDOW_UPDATE_FRAME: - control_frames_.emplace_back( - QuicFrame(new QuicWindowUpdateFrame(*frame.window_update_frame))); - return; - case BLOCKED_FRAME: - control_frames_.emplace_back( - QuicFrame(new QuicBlockedFrame(*frame.blocked_frame))); - return; - case PING_FRAME: - control_frames_.emplace_back( - QuicFrame(QuicPingFrame(frame.ping_frame.control_frame_id))); - return; - default: - DCHECK(false); - return; - } + control_frames_.emplace_back(CopyRetransmittableControlFrame(frame)); + return; } if (QuicContainsKey(pending_retransmissions_, id)) { // This is retransmitted control frame. diff --git a/chromium/net/quic/core/quic_crypto_client_handshaker.cc b/chromium/net/quic/core/quic_crypto_client_handshaker.cc index 418f9bd3fc6..5c59cc844bc 100644 --- a/chromium/net/quic/core/quic_crypto_client_handshaker.cc +++ b/chromium/net/quic/core/quic_crypto_client_handshaker.cc @@ -6,8 +6,8 @@ #include <memory> +#include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" -#include "base/metrics/sparse_histogram.h" #include "net/quic/core/crypto/crypto_protocol.h" #include "net/quic/core/crypto/crypto_utils.h" #include "net/quic/core/quic_session.h" @@ -318,7 +318,8 @@ void QuicCryptoClientHandshaker::DoSendCHLO( if (!cached->IsComplete(session()->connection()->clock()->WallNow())) { crypto_config_->FillInchoateClientHello( - server_id_, session()->connection()->supported_versions().front(), + server_id_, + session()->connection()->supported_versions().front().transport_version, cached, session()->connection()->random_generator(), /* demand_x509_proof= */ true, crypto_negotiated_params_, &out); // Pad the inchoate client hello to fill up a packet. @@ -350,7 +351,7 @@ void QuicCryptoClientHandshaker::DoSendCHLO( // If the server nonce is empty, copy over the server nonce from a previous // SREJ, if there is one. - if (FLAGS_quic_reloadable_flag_enable_quic_stateless_reject_support && + if (GetQuicReloadableFlag(enable_quic_stateless_reject_support) && crypto_negotiated_params_->server_nonce.empty() && cached->has_server_nonce()) { crypto_negotiated_params_->server_nonce = cached->GetNextServerNonce(); @@ -360,8 +361,8 @@ void QuicCryptoClientHandshaker::DoSendCHLO( string error_details; QuicErrorCode error = crypto_config_->FillClientHello( server_id_, session()->connection()->connection_id(), - session()->connection()->supported_versions().front(), cached, - session()->connection()->clock()->WallNow(), + session()->connection()->supported_versions().front().transport_version, + cached, session()->connection()->clock()->WallNow(), session()->connection()->random_generator(), channel_id_key_.get(), crypto_negotiated_params_, &out, &error_details); if (error != QUIC_NO_ERROR) { @@ -426,16 +427,16 @@ void QuicCryptoClientHandshaker::DoReceiveREJ( } DVLOG(1) << "Reasons for rejection: " << packed_error; if (num_client_hellos_ == QuicCryptoClientStream::kMaxClientHellos) { - UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicClientHelloRejectReasons.TooMany", - packed_error); + base::UmaHistogramSparse("Net.QuicClientHelloRejectReasons.TooMany", + packed_error); } - UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicClientHelloRejectReasons.Secure", - packed_error); + base::UmaHistogramSparse("Net.QuicClientHelloRejectReasons.Secure", + packed_error); } // Receipt of a REJ message means that the server received the CHLO // so we can cancel and retransmissions. - session()->connection()->NeuterUnencryptedPackets(); + session()->NeuterUnencryptedData(); stateless_reject_received_ = in->tag() == kSREJ; string error_details; @@ -619,8 +620,9 @@ void QuicCryptoClientHandshaker::DoReceiveSHLO( QuicErrorCode error = crypto_config_->ProcessServerHello( *in, session()->connection()->connection_id(), session()->connection()->transport_version(), - session()->connection()->server_supported_versions(), cached, - crypto_negotiated_params_, &error_details); + ParsedVersionsToTransportVersions( + session()->connection()->server_supported_versions()), + cached, crypto_negotiated_params_, &error_details); if (error != QUIC_NO_ERROR) { stream_->CloseConnectionWithDetails( diff --git a/chromium/net/quic/core/quic_crypto_client_stream.cc b/chromium/net/quic/core/quic_crypto_client_stream.cc index 1599716cac8..a81670125f0 100644 --- a/chromium/net/quic/core/quic_crypto_client_stream.cc +++ b/chromium/net/quic/core/quic_crypto_client_stream.cc @@ -15,8 +15,10 @@ #include "net/quic/core/quic_packets.h" #include "net/quic/core/quic_session.h" #include "net/quic/core/quic_utils.h" +#include "net/quic/core/tls_client_handshaker.h" #include "net/quic/platform/api/quic_flags.h" #include "net/quic/platform/api/quic_logging.h" +#include "net/quic/platform/api/quic_ptr_util.h" #include "net/quic/platform/api/quic_str_cat.h" using std::string; @@ -36,8 +38,21 @@ QuicCryptoClientStream::QuicCryptoClientStream( ProofHandler* proof_handler) : QuicCryptoClientStreamBase(session) { DCHECK_EQ(Perspective::IS_CLIENT, session->connection()->perspective()); - handshaker_.reset(new QuicCryptoClientHandshaker( - server_id, this, session, verify_context, crypto_config, proof_handler)); + switch (session->connection()->version().handshake_protocol) { + case PROTOCOL_QUIC_CRYPTO: + handshaker_ = QuicMakeUnique<QuicCryptoClientHandshaker>( + server_id, this, session, verify_context, crypto_config, + proof_handler); + break; + case PROTOCOL_TLS1_3: + handshaker_ = QuicMakeUnique<TlsClientHandshaker>( + this, session, server_id, crypto_config->proof_verifier(), + crypto_config->ssl_ctx(), verify_context); + break; + case PROTOCOL_UNSUPPORTED: + QUIC_BUG << "Attempting to create QuicCryptoClientStream for unknown " + "handshake protocol"; + } } QuicCryptoClientStream::~QuicCryptoClientStream() {} diff --git a/chromium/net/quic/core/quic_crypto_client_stream_test.cc b/chromium/net/quic/core/quic_crypto_client_stream_test.cc index ab338189342..499520608ae 100644 --- a/chromium/net/quic/core/quic_crypto_client_stream_test.cc +++ b/chromium/net/quic/core/quic_crypto_client_stream_test.cc @@ -12,6 +12,9 @@ #include "net/quic/core/quic_packets.h" #include "net/quic/core/quic_server_id.h" #include "net/quic/core/quic_utils.h" +#include "net/quic/core/tls_client_handshaker.h" +#include "net/quic/core/tls_server_handshaker.h" +#include "net/quic/platform/api/quic_arraysize.h" #include "net/quic/platform/api/quic_flags.h" #include "net/quic/platform/api/quic_test.h" #include "net/quic/test_tools/crypto_test_utils.h" @@ -34,14 +37,17 @@ const uint16_t kServerPort = 443; class QuicCryptoClientStreamTest : public QuicTest { public: QuicCryptoClientStreamTest() - : server_id_(kServerHostname, kServerPort, PRIVACY_MODE_DISABLED), - crypto_config_(crypto_test_utils::ProofVerifierForTesting()) { + : supported_versions_(AllSupportedVersions()), + server_id_(kServerHostname, kServerPort, PRIVACY_MODE_DISABLED), + crypto_config_(crypto_test_utils::ProofVerifierForTesting(), + TlsClientHandshaker::CreateSslCtx()) { CreateConnection(); } void CreateConnection() { - connection_ = new PacketSavingConnection(&client_helper_, &alarm_factory_, - Perspective::IS_CLIENT); + connection_ = + new PacketSavingConnection(&client_helper_, &alarm_factory_, + Perspective::IS_CLIENT, supported_versions_); // Advance the time, because timers do not like uninitialized times. connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1)); @@ -50,7 +56,9 @@ class QuicCryptoClientStreamTest : public QuicTest { } void CompleteCryptoHandshake() { - EXPECT_CALL(*session_, OnProofValid(testing::_)); + if (stream()->handshake_protocol() != PROTOCOL_TLS1_3) { + EXPECT_CALL(*session_, OnProofValid(testing::_)); + } EXPECT_CALL(*session_, OnProofVerifyDetailsAvailable(testing::_)) .Times(testing::AnyNumber()); stream()->CryptoConnect(); @@ -68,6 +76,7 @@ class QuicCryptoClientStreamTest : public QuicTest { MockQuicConnectionHelper client_helper_; MockAlarmFactory alarm_factory_; PacketSavingConnection* connection_; + ParsedQuicVersionVector supported_versions_; std::unique_ptr<TestQuicSpdyClientSession> session_; QuicServerId server_id_; CryptoHandshakeMessage message_; @@ -86,6 +95,21 @@ TEST_F(QuicCryptoClientStreamTest, ConnectedAfterSHLO) { EXPECT_TRUE(stream()->handshake_confirmed()); } +TEST_F(QuicCryptoClientStreamTest, ConnectedAfterTlsHandshake) { + FLAGS_quic_supports_tls_handshake = true; + supported_versions_.clear(); + for (QuicTransportVersion transport_version : + AllSupportedTransportVersions()) { + supported_versions_.push_back( + ParsedQuicVersion(PROTOCOL_TLS1_3, transport_version)); + } + CreateConnection(); + CompleteCryptoHandshake(); + EXPECT_EQ(PROTOCOL_TLS1_3, stream()->handshake_protocol()); + EXPECT_TRUE(stream()->encryption_established()); + EXPECT_TRUE(stream()->handshake_confirmed()); +} + TEST_F(QuicCryptoClientStreamTest, MessageAfterHandshake) { CompleteCryptoHandshake(); @@ -222,7 +246,7 @@ TEST_F(QuicCryptoClientStreamTest, ServerConfigUpdate) { const string& cached_scfg = state->server_config(); test::CompareCharArraysWithHexError( "scfg", cached_scfg.data(), cached_scfg.length(), - reinterpret_cast<char*>(scfg), arraysize(scfg)); + reinterpret_cast<char*>(scfg), QUIC_ARRAYSIZE(scfg)); QuicStreamSequencer* sequencer = QuicStreamPeer::sequencer(stream()); EXPECT_FALSE(QuicStreamSequencerPeer::IsUnderlyingBufferAllocated(sequencer)); @@ -236,7 +260,8 @@ TEST_F(QuicCryptoClientStreamTest, ServerConfigUpdateWithCert) { // Build a server config update message with certificates QuicCryptoServerConfig crypto_config( QuicCryptoServerConfig::TESTING, QuicRandom::GetInstance(), - crypto_test_utils::ProofSourceForTesting()); + crypto_test_utils::ProofSourceForTesting(), + TlsServerHandshaker::CreateSslCtx()); crypto_test_utils::FakeServerOptions options; crypto_test_utils::SetupCryptoServerConfigForTest( connection_->clock(), QuicRandom::GetInstance(), &crypto_config, options); @@ -355,10 +380,12 @@ TEST_F(QuicCryptoClientStreamTest, NoTokenBindingInPrivacyMode) { class QuicCryptoClientStreamStatelessTest : public QuicTest { public: QuicCryptoClientStreamStatelessTest() - : client_crypto_config_(crypto_test_utils::ProofVerifierForTesting()), + : client_crypto_config_(crypto_test_utils::ProofVerifierForTesting(), + TlsClientHandshaker::CreateSslCtx()), server_crypto_config_(QuicCryptoServerConfig::TESTING, QuicRandom::GetInstance(), - crypto_test_utils::ProofSourceForTesting()), + crypto_test_utils::ProofSourceForTesting(), + TlsServerHandshaker::CreateSslCtx()), server_compressed_certs_cache_( QuicCompressedCertsCache::kQuicCompressedCertsCacheSize), server_id_(kServerHostname, kServerPort, PRIVACY_MODE_DISABLED) { @@ -366,7 +393,7 @@ class QuicCryptoClientStreamStatelessTest : public QuicTest { CreateClientSessionForTest(server_id_, /* supports_stateless_rejects= */ true, QuicTime::Delta::FromSeconds(100000), - AllSupportedTransportVersions(), &helper_, + AllSupportedVersions(), &helper_, &alarm_factory_, &client_crypto_config_, &client_connection_, &client_session); CHECK(client_session); @@ -392,7 +419,7 @@ class QuicCryptoClientStreamStatelessTest : public QuicTest { void InitializeFakeStatelessRejectServer() { TestQuicSpdyServerSession* server_session = nullptr; CreateServerSessionForTest(server_id_, QuicTime::Delta::FromSeconds(100000), - AllSupportedTransportVersions(), &helper_, + AllSupportedVersions(), &helper_, &alarm_factory_, &server_crypto_config_, &server_compressed_certs_cache_, &server_connection_, &server_session); @@ -402,7 +429,7 @@ class QuicCryptoClientStreamStatelessTest : public QuicTest { crypto_test_utils::SetupCryptoServerConfigForTest( server_connection_->clock(), server_connection_->random_generator(), &server_crypto_config_, options); - FLAGS_quic_reloadable_flag_enable_quic_stateless_reject_support = true; + SetQuicReloadableFlag(enable_quic_stateless_reject_support, true); } MockQuicConnectionHelper helper_; @@ -422,7 +449,7 @@ class QuicCryptoClientStreamStatelessTest : public QuicTest { }; TEST_F(QuicCryptoClientStreamStatelessTest, StatelessReject) { - FLAGS_quic_reloadable_flag_enable_quic_stateless_reject_support = true; + SetQuicReloadableFlag(enable_quic_stateless_reject_support, true); QuicCryptoClientConfig::CachedState* client_state = client_crypto_config_.LookupOrCreate(server_id_); diff --git a/chromium/net/quic/core/quic_crypto_handshaker.cc b/chromium/net/quic/core/quic_crypto_handshaker.cc index 39a9a4e9c9b..7455afd6d71 100644 --- a/chromium/net/quic/core/quic_crypto_handshaker.cc +++ b/chromium/net/quic/core/quic_crypto_handshaker.cc @@ -25,7 +25,7 @@ void QuicCryptoHandshaker::SendHandshakeMessage( const CryptoHandshakeMessage& message) { QUIC_DVLOG(1) << ENDPOINT << "Sending " << message.DebugString(session()->perspective()); - session()->connection()->NeuterUnencryptedPackets(); + session()->NeuterUnencryptedData(); session()->OnCryptoHandshakeMessageSent(message); const QuicData& data = message.GetSerialized(session()->perspective()); stream_->WriteOrBufferData(QuicStringPiece(data.data(), data.length()), false, diff --git a/chromium/net/quic/core/quic_crypto_server_handshaker.cc b/chromium/net/quic/core/quic_crypto_server_handshaker.cc index b89934621fb..99164153b7e 100644 --- a/chromium/net/quic/core/quic_crypto_server_handshaker.cc +++ b/chromium/net/quic/core/quic_crypto_server_handshaker.cc @@ -6,6 +6,7 @@ #include <memory> +#include "net/quic/platform/api/quic_arraysize.h" #include "net/quic/platform/api/quic_text_utils.h" #include "third_party/boringssl/src/include/openssl/sha.h" @@ -375,7 +376,7 @@ bool QuicCryptoServerHandshaker::GetBase64SHA256ClientChannelID( SHA256(reinterpret_cast<const uint8_t*>(channel_id.data()), channel_id.size(), digest); - QuicTextUtils::Base64Encode(digest, arraysize(digest), output); + QuicTextUtils::Base64Encode(digest, QUIC_ARRAYSIZE(digest), output); return true; } @@ -435,10 +436,10 @@ void QuicCryptoServerHandshaker::ProcessClientHello( crypto_config_->ProcessClientHello( result, /*reject_only=*/false, connection->connection_id(), connection->self_address(), GetClientAddress(), transport_version(), - connection->supported_versions(), use_stateless_rejects_in_crypto_config, - server_designated_connection_id, connection->clock(), - connection->random_generator(), compressed_certs_cache_, - crypto_negotiated_params_, signed_config_, + ParsedVersionsToTransportVersions(connection->supported_versions()), + use_stateless_rejects_in_crypto_config, server_designated_connection_id, + connection->clock(), connection->random_generator(), + compressed_certs_cache_, crypto_negotiated_params_, signed_config_, QuicCryptoStream::CryptoMessageFramingOverhead(transport_version()), chlo_packet_size_, std::move(done_cb)); } diff --git a/chromium/net/quic/core/quic_crypto_server_handshaker.h b/chromium/net/quic/core/quic_crypto_server_handshaker.h index 5b5d0f838ac..dbdd94c09cf 100644 --- a/chromium/net/quic/core/quic_crypto_server_handshaker.h +++ b/chromium/net/quic/core/quic_crypto_server_handshaker.h @@ -5,6 +5,8 @@ #ifndef NET_QUIC_CORE_QUIC_CRYPTO_SERVER_HANDSHAKER_H_ #define NET_QUIC_CORE_QUIC_CRYPTO_SERVER_HANDSHAKER_H_ +#include "net/quic/core/proto/cached_network_parameters.pb.h" +#include "net/quic/core/proto/source_address_token.pb.h" #include "net/quic/core/quic_crypto_handshaker.h" #include "net/quic/core/quic_crypto_server_stream.h" #include "net/quic/core/quic_session.h" diff --git a/chromium/net/quic/core/quic_crypto_server_stream.cc b/chromium/net/quic/core/quic_crypto_server_stream.cc index d9d2c83cb33..65b4300212d 100644 --- a/chromium/net/quic/core/quic_crypto_server_stream.cc +++ b/chromium/net/quic/core/quic_crypto_server_stream.cc @@ -15,8 +15,10 @@ #include "net/quic/core/quic_crypto_server_handshaker.h" #include "net/quic/core/quic_packets.h" #include "net/quic/core/quic_session.h" +#include "net/quic/core/tls_server_handshaker.h" #include "net/quic/platform/api/quic_flags.h" #include "net/quic/platform/api/quic_logging.h" +#include "net/quic/platform/api/quic_ptr_util.h" #include "net/quic/platform/api/quic_string_piece.h" using std::string; @@ -52,9 +54,21 @@ QuicCryptoServerStream::QuicCryptoServerStream( Helper* helper) : QuicCryptoServerStreamBase(session) { DCHECK_EQ(Perspective::IS_SERVER, session->connection()->perspective()); - handshaker_.reset(new QuicCryptoServerHandshaker( - crypto_config, this, compressed_certs_cache, - use_stateless_rejects_if_peer_supported, session, helper)); + switch (session->connection()->version().handshake_protocol) { + case PROTOCOL_QUIC_CRYPTO: + handshaker_ = QuicMakeUnique<QuicCryptoServerHandshaker>( + crypto_config, this, compressed_certs_cache, + use_stateless_rejects_if_peer_supported, session, helper); + break; + case PROTOCOL_TLS1_3: + handshaker_ = QuicMakeUnique<TlsServerHandshaker>( + this, session, crypto_config->ssl_ctx(), + crypto_config->proof_source()); + break; + case PROTOCOL_UNSUPPORTED: + QUIC_BUG << "Attempting to create QuicCryptoServerStream for unknown " + "handshake protocol"; + } } QuicCryptoServerStream::~QuicCryptoServerStream() {} diff --git a/chromium/net/quic/core/quic_crypto_server_stream.h b/chromium/net/quic/core/quic_crypto_server_stream.h index 625f2fed0b2..8df4fc536dd 100644 --- a/chromium/net/quic/core/quic_crypto_server_stream.h +++ b/chromium/net/quic/core/quic_crypto_server_stream.h @@ -13,7 +13,6 @@ #include "net/quic/core/crypto/crypto_handshake.h" #include "net/quic/core/crypto/quic_compressed_certs_cache.h" #include "net/quic/core/crypto/quic_crypto_server_config.h" -#include "net/quic/core/proto/source_address_token.pb.h" #include "net/quic/core/quic_config.h" #include "net/quic/core/quic_crypto_handshaker.h" #include "net/quic/core/quic_crypto_stream.h" diff --git a/chromium/net/quic/core/quic_crypto_server_stream_test.cc b/chromium/net/quic/core/quic_crypto_server_stream_test.cc index f49b5f6a9fc..69cbea3183d 100644 --- a/chromium/net/quic/core/quic_crypto_server_stream_test.cc +++ b/chromium/net/quic/core/quic_crypto_server_stream_test.cc @@ -20,6 +20,8 @@ #include "net/quic/core/quic_crypto_client_stream.h" #include "net/quic/core/quic_packets.h" #include "net/quic/core/quic_session.h" +#include "net/quic/core/tls_client_handshaker.h" +#include "net/quic/core/tls_server_handshaker.h" #include "net/quic/platform/api/quic_flags.h" #include "net/quic/platform/api/quic_logging.h" #include "net/quic/platform/api/quic_ptr_util.h" @@ -66,12 +68,14 @@ class QuicCryptoServerStreamTest : public QuicTestWithParam<bool> { explicit QuicCryptoServerStreamTest(std::unique_ptr<ProofSource> proof_source) : server_crypto_config_(QuicCryptoServerConfig::TESTING, QuicRandom::GetInstance(), - std::move(proof_source)), + std::move(proof_source), + TlsServerHandshaker::CreateSslCtx()), server_compressed_certs_cache_( QuicCompressedCertsCache::kQuicCompressedCertsCacheSize), server_id_(kServerHostname, kServerPort, PRIVACY_MODE_DISABLED), - client_crypto_config_(crypto_test_utils::ProofVerifierForTesting()) { - FLAGS_quic_reloadable_flag_enable_quic_stateless_reject_support = false; + client_crypto_config_(crypto_test_utils::ProofVerifierForTesting(), + TlsClientHandshaker::CreateSslCtx()) { + SetQuicReloadableFlag(enable_quic_stateless_reject_support, false); } void Initialize() { InitializeServer(); } @@ -180,8 +184,7 @@ class QuicCryptoServerStreamTest : public QuicTestWithParam<bool> { crypto_test_utils::FakeClientOptions client_options_; // Which QUIC versions the client and server support. - QuicTransportVersionVector supported_versions_ = - AllSupportedTransportVersions(); + ParsedQuicVersionVector supported_versions_ = AllSupportedVersions(); }; INSTANTIATE_TEST_CASE_P(Tests, QuicCryptoServerStreamTest, testing::Bool()); @@ -209,6 +212,22 @@ TEST_P(QuicCryptoServerStreamTest, ConnectedAfterCHLO) { EXPECT_TRUE(server_stream()->handshake_confirmed()); } +TEST_P(QuicCryptoServerStreamTest, ConnectedAfterTlsHandshake) { + FLAGS_quic_supports_tls_handshake = true; + client_options_.only_tls_versions = true; + supported_versions_.clear(); + for (QuicTransportVersion transport_version : + AllSupportedTransportVersions()) { + supported_versions_.push_back( + ParsedQuicVersion(PROTOCOL_TLS1_3, transport_version)); + } + Initialize(); + CompleteCryptoHandshake(); + EXPECT_EQ(PROTOCOL_TLS1_3, server_stream()->handshake_protocol()); + EXPECT_TRUE(server_stream()->encryption_established()); + EXPECT_TRUE(server_stream()->handshake_confirmed()); +} + TEST_P(QuicCryptoServerStreamTest, ForwardSecureAfterCHLO) { Initialize(); InitializeFakeClient(/* supports_stateless_rejects= */ false); @@ -231,7 +250,7 @@ TEST_P(QuicCryptoServerStreamTest, ForwardSecureAfterCHLO) { } TEST_P(QuicCryptoServerStreamTest, StatelessRejectAfterCHLO) { - FLAGS_quic_reloadable_flag_enable_quic_stateless_reject_support = true; + SetQuicReloadableFlag(enable_quic_stateless_reject_support, true); Initialize(); InitializeFakeClient(/* supports_stateless_rejects= */ true); @@ -265,7 +284,7 @@ TEST_P(QuicCryptoServerStreamTest, StatelessRejectAfterCHLO) { } TEST_P(QuicCryptoServerStreamTest, ConnectedAfterStatelessHandshake) { - FLAGS_quic_reloadable_flag_enable_quic_stateless_reject_support = true; + SetQuicReloadableFlag(enable_quic_stateless_reject_support, true); Initialize(); InitializeFakeClient(/* supports_stateless_rejects= */ true); @@ -312,7 +331,7 @@ TEST_P(QuicCryptoServerStreamTest, ConnectedAfterStatelessHandshake) { } TEST_P(QuicCryptoServerStreamTest, NoStatelessRejectIfNoClientSupport) { - FLAGS_quic_reloadable_flag_enable_quic_stateless_reject_support = true; + SetQuicReloadableFlag(enable_quic_stateless_reject_support, true); Initialize(); // The server is configured to use stateless rejects, but the client does not @@ -435,7 +454,7 @@ TEST_P(QuicCryptoServerStreamTest, SendSCUPAfterHandshakeComplete) { // crypto_test_utils::MovePackets stops processing parsing following packets. // Actually, crypto stream test should use QuicSession instead of // QuicSpdySession (b/32366134). - FLAGS_quic_reloadable_flag_quic_send_max_header_list_size = false; + SetQuicReloadableFlag(quic_send_max_header_list_size, false); Initialize(); InitializeFakeClient(/* supports_stateless_rejects= */ false); diff --git a/chromium/net/quic/core/quic_crypto_stream.cc b/chromium/net/quic/core/quic_crypto_stream.cc index a60e30fc84b..9bd4a47ac06 100644 --- a/chromium/net/quic/core/quic_crypto_stream.cc +++ b/chromium/net/quic/core/quic_crypto_stream.cc @@ -97,4 +97,65 @@ void QuicCryptoStream::WriteCryptoData(const QuicStringPiece& data) { WriteOrBufferData(data, /* fin */ false, /* ack_listener */ nullptr); } +void QuicCryptoStream::NeuterUnencryptedStreamData() { + for (const auto& interval : bytes_consumed_[ENCRYPTION_NONE]) { + QuicByteCount newly_acked_length = 0; + send_buffer().OnStreamDataAcked( + interval.min(), interval.max() - interval.min(), &newly_acked_length); + } +} + +void QuicCryptoStream::OnStreamDataConsumed(size_t bytes_consumed) { + if (bytes_consumed > 0) { + bytes_consumed_[session()->connection()->encryption_level()].Add( + stream_bytes_written(), stream_bytes_written() + bytes_consumed); + } + QuicStream::OnStreamDataConsumed(bytes_consumed); +} + +void QuicCryptoStream::WritePendingRetransmission() { + while (HasPendingRetransmission()) { + StreamPendingRetransmission pending = + send_buffer().NextPendingRetransmission(); + QuicIntervalSet<QuicStreamOffset> retransmission( + pending.offset, pending.offset + pending.length); + EncryptionLevel retransmission_encryption_level = ENCRYPTION_NONE; + // Determine the encryption level to write the retransmission + // at. The retransmission should be written at the same encryption level + // as the original transmission. + for (size_t i = 0; i < NUM_ENCRYPTION_LEVELS; ++i) { + if (retransmission.Intersects(bytes_consumed_[i])) { + retransmission_encryption_level = static_cast<EncryptionLevel>(i); + retransmission.Intersection(bytes_consumed_[i]); + break; + } + } + pending.offset = retransmission.begin()->min(); + pending.length = + retransmission.begin()->max() - retransmission.begin()->min(); + EncryptionLevel current_encryption_level = + session()->connection()->encryption_level(); + // Set appropriate encryption level. + session()->connection()->SetDefaultEncryptionLevel( + retransmission_encryption_level); + QuicConsumedData consumed = session()->WritevData( + this, id(), pending.length, pending.offset, NO_FIN); + QUIC_DVLOG(1) << ENDPOINT << "stream " << id() + << " tries to retransmit stream data [" << pending.offset + << ", " << pending.offset + pending.length + << ") with encryption level: " + << retransmission_encryption_level + << ", consumed: " << consumed; + OnStreamFrameRetransmitted(pending.offset, consumed.bytes_consumed, + consumed.fin_consumed); + // Restore encryption level. + session()->connection()->SetDefaultEncryptionLevel( + current_encryption_level); + if (consumed.bytes_consumed < pending.length) { + // The connection is write blocked. + break; + } + } +} + } // namespace net diff --git a/chromium/net/quic/core/quic_crypto_stream.h b/chromium/net/quic/core/quic_crypto_stream.h index ef6856360ac..695e1e57897 100644 --- a/chromium/net/quic/core/quic_crypto_stream.h +++ b/chromium/net/quic/core/quic_crypto_stream.h @@ -79,7 +79,22 @@ class QUIC_EXPORT_PRIVATE QuicCryptoStream : public QuicStream { // Provides the message parser to use when data is received on this stream. virtual CryptoMessageParser* crypto_message_parser() = 0; + // Called to cancel retransmission of unencrypted crypto stream data. + void NeuterUnencryptedStreamData(); + + // Override to record the encryption level of consumed data. + void OnStreamDataConsumed(size_t bytes_consumed) override; + + // Override to retransmit lost crypto data with the appropriate encryption + // level. + void WritePendingRetransmission() override; + private: + // Consumed data according to encryption levels. + // TODO(fayang): This is not needed once switching from QUIC crypto to + // TLS 1.3, which never encrypts crypto data. + QuicIntervalSet<QuicStreamOffset> bytes_consumed_[NUM_ENCRYPTION_LEVELS]; + DISALLOW_COPY_AND_ASSIGN(QuicCryptoStream); }; diff --git a/chromium/net/quic/core/quic_crypto_stream_test.cc b/chromium/net/quic/core/quic_crypto_stream_test.cc index bf29b6c64f3..59726408615 100644 --- a/chromium/net/quic/core/quic_crypto_stream_test.cc +++ b/chromium/net/quic/core/quic_crypto_stream_test.cc @@ -20,6 +20,10 @@ using std::string; +using testing::_; +using testing::InSequence; +using testing::Invoke; + namespace net { namespace test { namespace { @@ -125,6 +129,79 @@ TEST_F(QuicCryptoStreamTest, NoConnectionLevelFlowControl) { QuicStreamPeer::StreamContributesToConnectionFlowControl(&stream_)); } +TEST_F(QuicCryptoStreamTest, RetransmitCryptoData) { + if (!FLAGS_quic_reloadable_flag_quic_allow_multiple_acks_for_data2) { + return; + } + InSequence s; + // Send [0, 1350) in ENCRYPTION_NONE. + EXPECT_EQ(ENCRYPTION_NONE, connection_->encryption_level()); + string data(1350, 'a'); + EXPECT_CALL(session_, WritevData(_, kCryptoStreamId, 1350, 0, _)) + .WillOnce(Invoke(MockQuicSession::ConsumeData)); + stream_.WriteOrBufferData(data, false, nullptr); + // Send [1350, 2700) in ENCRYPTION_INITIAL. + connection_->SetDefaultEncryptionLevel(ENCRYPTION_INITIAL); + EXPECT_EQ(ENCRYPTION_INITIAL, connection_->encryption_level()); + EXPECT_CALL(session_, WritevData(_, kCryptoStreamId, 1350, 1350, _)) + .WillOnce(Invoke(MockQuicSession::ConsumeData)); + stream_.WriteOrBufferData(data, false, nullptr); + connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); + EXPECT_EQ(ENCRYPTION_FORWARD_SECURE, connection_->encryption_level()); + + // Lost [0, 1000). + stream_.OnStreamFrameLost(0, 1000, false); + EXPECT_TRUE(stream_.HasPendingRetransmission()); + // Lost [1200, 2000). + stream_.OnStreamFrameLost(1200, 800, false); + EXPECT_CALL(session_, WritevData(_, kCryptoStreamId, 1000, 0, _)) + .WillOnce(Invoke(MockQuicSession::ConsumeData)); + // Verify [1200, 2000) are sent in [1200, 1350) and [1350, 2000) because of + // they are in different encryption levels. + EXPECT_CALL(session_, WritevData(_, kCryptoStreamId, 150, 1200, _)) + .WillOnce(Invoke(MockQuicSession::ConsumeData)); + EXPECT_CALL(session_, WritevData(_, kCryptoStreamId, 650, 1350, _)) + .WillOnce(Invoke(MockQuicSession::ConsumeData)); + stream_.OnCanWrite(); + EXPECT_FALSE(stream_.HasPendingRetransmission()); + // Verify connection's encryption level has restored. + EXPECT_EQ(ENCRYPTION_FORWARD_SECURE, connection_->encryption_level()); +} + +TEST_F(QuicCryptoStreamTest, NeuterUnencryptedStreamData) { + if (!FLAGS_quic_reloadable_flag_quic_allow_multiple_acks_for_data2) { + return; + } + // Send [0, 1350) in ENCRYPTION_NONE. + EXPECT_EQ(ENCRYPTION_NONE, connection_->encryption_level()); + string data(1350, 'a'); + EXPECT_CALL(session_, WritevData(_, kCryptoStreamId, 1350, 0, _)) + .WillOnce(Invoke(MockQuicSession::ConsumeData)); + stream_.WriteOrBufferData(data, false, nullptr); + // Send [1350, 2700) in ENCRYPTION_INITIAL. + connection_->SetDefaultEncryptionLevel(ENCRYPTION_INITIAL); + EXPECT_EQ(ENCRYPTION_INITIAL, connection_->encryption_level()); + EXPECT_CALL(session_, WritevData(_, kCryptoStreamId, 1350, 1350, _)) + .WillOnce(Invoke(MockQuicSession::ConsumeData)); + stream_.WriteOrBufferData(data, false, nullptr); + + // Lost [0, 1350). + stream_.OnStreamFrameLost(0, 1350, false); + EXPECT_TRUE(stream_.HasPendingRetransmission()); + // Neuters [0, 1350). + stream_.NeuterUnencryptedStreamData(); + EXPECT_FALSE(stream_.HasPendingRetransmission()); + // Lost [0, 1350) again. + stream_.OnStreamFrameLost(0, 1350, false); + EXPECT_FALSE(stream_.HasPendingRetransmission()); + + // Lost [1350, 2000). + stream_.OnStreamFrameLost(1350, 650, false); + EXPECT_TRUE(stream_.HasPendingRetransmission()); + stream_.NeuterUnencryptedStreamData(); + EXPECT_TRUE(stream_.HasPendingRetransmission()); +} + } // namespace } // namespace test } // namespace net diff --git a/chromium/net/quic/core/quic_data_writer_test.cc b/chromium/net/quic/core/quic_data_writer_test.cc index 2217ed1cbc6..bc59ba4004f 100644 --- a/chromium/net/quic/core/quic_data_writer_test.cc +++ b/chromium/net/quic/core/quic_data_writer_test.cc @@ -8,6 +8,7 @@ #include "net/quic/core/quic_data_reader.h" #include "net/quic/core/quic_utils.h" +#include "net/quic/platform/api/quic_arraysize.h" #include "net/quic/platform/api/quic_flags.h" #include "net/quic/platform/api/quic_test.h" #include "net/quic/test_tools/quic_test_utils.h" @@ -558,22 +559,22 @@ TEST_P(QuicDataWriterTest, WriteIntegers) { TEST_P(QuicDataWriterTest, WriteBytes) { char bytes[] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; - char buf[arraysize(bytes)]; - QuicDataWriter writer(arraysize(buf), buf, GetParam().endianness); - EXPECT_TRUE(writer.WriteBytes(bytes, arraysize(bytes))); - for (unsigned int i = 0; i < arraysize(bytes); ++i) { + char buf[QUIC_ARRAYSIZE(bytes)]; + QuicDataWriter writer(QUIC_ARRAYSIZE(buf), buf, GetParam().endianness); + EXPECT_TRUE(writer.WriteBytes(bytes, QUIC_ARRAYSIZE(bytes))); + for (unsigned int i = 0; i < QUIC_ARRAYSIZE(bytes); ++i) { EXPECT_EQ(bytes[i], buf[i]); } } TEST_P(QuicDataWriterTest, WriteUInt8AtOffset) { char bytes[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'}; - char buf[arraysize(bytes)]; - for (unsigned int i = 0; i < arraysize(bytes); ++i) { - QuicDataWriter writer(arraysize(buf), buf, GetParam().endianness); - EXPECT_TRUE(writer.WriteBytes(bytes, arraysize(bytes))); + char buf[QUIC_ARRAYSIZE(bytes)]; + for (unsigned int i = 0; i < QUIC_ARRAYSIZE(bytes); ++i) { + QuicDataWriter writer(QUIC_ARRAYSIZE(buf), buf, GetParam().endianness); + EXPECT_TRUE(writer.WriteBytes(bytes, QUIC_ARRAYSIZE(bytes))); EXPECT_TRUE(writer.WriteUInt8AtOffset('I', i)); - for (unsigned int j = 0; j < arraysize(bytes); ++j) { + for (unsigned int j = 0; j < QUIC_ARRAYSIZE(bytes); ++j) { if (j == i) { EXPECT_EQ('I', buf[j]); } else { diff --git a/chromium/net/quic/core/quic_error_codes.cc b/chromium/net/quic/core/quic_error_codes.cc index 2f734e524b0..3bdd84ca971 100644 --- a/chromium/net/quic/core/quic_error_codes.cc +++ b/chromium/net/quic/core/quic_error_codes.cc @@ -128,9 +128,10 @@ const char* QuicErrorCodeToString(QuicErrorCode error) { RETURN_STRING_LITERAL(QUIC_CRYPTO_CHLO_TOO_LARGE); RETURN_STRING_LITERAL(QUIC_MULTIPATH_PATH_DOES_NOT_EXIST); RETURN_STRING_LITERAL(QUIC_MULTIPATH_PATH_NOT_ACTIVE); - RETURN_STRING_LITERAL(QUIC_TOO_MANY_FRAME_GAPS); + RETURN_STRING_LITERAL(QUIC_TOO_MANY_STREAM_DATA_INTERVALS); RETURN_STRING_LITERAL(QUIC_STREAM_SEQUENCER_INVALID_STATE); RETURN_STRING_LITERAL(QUIC_TOO_MANY_SESSIONS_ON_SERVER); + RETURN_STRING_LITERAL(QUIC_STREAM_LENGTH_OVERFLOW); RETURN_STRING_LITERAL(QUIC_LAST_ERROR); // Intentionally have no default case, so we'll break the build // if we add errors and don't put them here. diff --git a/chromium/net/quic/core/quic_error_codes.h b/chromium/net/quic/core/quic_error_codes.h index 2a6f335bb45..f5d94ee2e5c 100644 --- a/chromium/net/quic/core/quic_error_codes.h +++ b/chromium/net/quic/core/quic_error_codes.h @@ -263,8 +263,8 @@ enum QuicErrorCode { QUIC_CONNECTION_MIGRATION_NON_MIGRATABLE_STREAM = 84, // Stream frames arrived too discontiguously so that stream sequencer buffer - // maintains too many gaps. - QUIC_TOO_MANY_FRAME_GAPS = 93, + // maintains too many intervals. + QUIC_TOO_MANY_STREAM_DATA_INTERVALS = 93, // Sequencer buffer get into weird state where continuing read/write will lead // to crash. @@ -273,8 +273,11 @@ enum QuicErrorCode { // Connection closed because of server hits max number of sessions allowed. QUIC_TOO_MANY_SESSIONS_ON_SERVER = 96, + // Receive a RST_STREAM with offset larger than kMaxStreamLength. + QUIC_STREAM_LENGTH_OVERFLOW = 98, + // No error. Used as bound while iterating. - QUIC_LAST_ERROR = 98, + QUIC_LAST_ERROR = 99, }; // QuicErrorCodes is encoded as a single octet on-the-wire. static_assert(static_cast<int>(QUIC_LAST_ERROR) <= diff --git a/chromium/net/quic/core/quic_flags_list.h b/chromium/net/quic/core/quic_flags_list.h index bcd204f9e70..c5f8d924722 100644 --- a/chromium/net/quic/core/quic_flags_list.h +++ b/chromium/net/quic/core/quic_flags_list.h @@ -67,13 +67,6 @@ QUIC_FLAG(double, FLAGS_quic_bbr_cwnd_gain, 2.0f) // Add the equivalent number of bytes as 3 TCP TSO segments to QUIC's BBR CWND. QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_bbr_add_tso_cwnd, false) -// If true, enable version 38 which supports new PADDING frame and respects NSTP -// connection option. -QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_enable_version_38, true) - -// If true, enable QUIC v39. -QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_enable_version_39, true) - // Simplify QUIC\'s adaptive time loss detection to measure the necessary // reordering window for every spurious retransmit. QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_fix_adaptive_time_loss, false) @@ -92,10 +85,6 @@ QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_default_to_bbr, false) // option. QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_bbr_rate_recovery, false) -// Adds a QuicPacketNumberQueue that is based on a deque and does not support -// costly AddRange arguments. -QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_frames_deque3, true) - // If true, enable QUIC v42. QUIC_FLAG(bool, FLAGS_quic_enable_version_42, false) @@ -110,10 +99,6 @@ QUIC_FLAG(uint32_t, FLAGS_quic_send_buffer_max_data_slice_size, 4096u) // protocol. QUIC_FLAG(bool, FLAGS_quic_supports_tls_handshake, false) -// If true, QUIC v40 is enabled which includes changes to RST_STREAM, ACK -// and STREAM frames match IETF format. -QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_enable_version_41, true) - // If true, QUIC can take ownership of data provided in a reference counted // memory to avoid data copy. QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_use_mem_slices, false) @@ -121,64 +106,17 @@ QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_use_mem_slices, false) // Allow QUIC to accept initial packet numbers that are random, not 1. QUIC_FLAG(bool, FLAGS_quic_restart_flag_quic_enable_accept_random_ipn, false) -// Report the more analogous TLS 1.3 cipher suites rather than TLS 1.2 ECDHE_RSA -// ciphers in QuicDecrypters. -QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_use_tls13_cipher_suites, true) - -// If true, read and write QUIC version labels in network byte order. -QUIC_FLAG(bool, - FLAGS_quic_reloadable_flag_quic_use_net_byte_order_version_label, - true) - -// If true, send stateless reset token in SHLO. This token is used in IETF -// public reset packet. -QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_send_reset_token_in_shlo, true) - -// Default enable all cubic fixes in QUIC Cubic by default. -QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_enable_cubic_fixes, true) - // If true, enable QUIC v43. QUIC_FLAG(bool, FLAGS_quic_enable_version_43, false) // If true, allows one address change when UDP proxying. QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_allow_address_change_for_udp_proxy, - false) - -// If true, allow a new BBR connection option to use a slower STARTUP once loss -// occurs -QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_bbr_slower_startup, true) - -// Deprecate QuicAckFrame.largest_observed since it is redundant. -QUIC_FLAG(bool, - FLAGS_quic_reloadable_flag_quic_deprecate_largest_observed, true) -// Fully drain the queue in QUIC BBR at least once per cycle(8 rounds) when -// activated by the BBR3 connection option. -QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_bbr_fully_drain_queue, true) - -// When true, allows connection options to be sent to completely disable packet -// conservation in QUIC BBR STARTUP or make it more aggressive. -QUIC_FLAG(bool, - FLAGS_quic_reloadable_flag_quic_bbr_conservation_in_startup, - false) - -// Allows increasing the length of time ack aggregation is windowed for to 20 -// and 40 RTTs. -QUIC_FLAG(bool, - FLAGS_quic_reloadable_flag_quic_bbr_ack_aggregation_window, - false) - -// If true, OnStreamFrameDiscarded is not called on stream cancellation, and -// canceled stream is immediately closed. -QUIC_FLAG(bool, - FLAGS_quic_reloadable_flag_quic_remove_on_stream_frame_discarded, - false) - // Explicitly send a connection close if the TLP count is greater than 0 when // idle timeout occurs. -QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_explicit_close_after_tlp, false) +QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_explicit_close_after_tlp, true) // Enables 3 new connection options to make PROBE_RTT more aggressive QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_bbr_less_probe_rtt, false) @@ -190,10 +128,6 @@ QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_server_reply_to_connectivity_probing, true) -// If true, truncates QUIC error strings to 256 characters before writing them -// to the wire. -QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_truncate_long_details, true) - // If true, allow stream data and control frames to be acked multiple times. QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_allow_multiple_acks_for_data2, @@ -203,7 +137,34 @@ QUIC_FLAG(bool, // guaranteed to be 2048. QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_fix_sequencer_buffer_block_count2, - false) + true) // If true, use deframer from net/quic/http instead of net/http2. -QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_enable_hq_deframer, false) +QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_enable_hq_deframer, true) + +// If true, then 1) at sender, avoid sending empty acks, 2) at receiver, close +// connection when a ack frame\'s first block length is 0, unless the ack is +// completely empty. +QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_strict_ack_handling, false) + +// If true, fixes for the two bugs described in crbug.com/723604 will be +// enabled. +QUIC_FLAG(bool, + FLAGS_quic_reloadable_flag_quic_2rtt_drop_client_cached_certs, + false) + +// If true, limit quic stream length to be below 2^62. +QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_stream_too_long, false) + +// When true, enables the 1TLP connection option to configure QUIC to send one +// TLP instead of 2. +QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_one_tlp, false) + +// If true, stream sequencer buffer allows receiving overlapping stream data. +QUIC_FLAG(bool, + FLAGS_quic_reloadable_flag_quic_allow_receiving_overlapping_data, + false) + +// If true, QuicStreamSendBuffer keeps track of the slice which next write +// should get data from if writing new data. +QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_use_write_index, false) diff --git a/chromium/net/quic/core/quic_framer.cc b/chromium/net/quic/core/quic_framer.cc index ef3607dffb8..624f1f691ec 100644 --- a/chromium/net/quic/core/quic_framer.cc +++ b/chromium/net/quic/core/quic_framer.cc @@ -28,6 +28,7 @@ #include "net/quic/platform/api/quic_map_util.h" #include "net/quic/platform/api/quic_ptr_util.h" #include "net/quic/platform/api/quic_str_cat.h" +#include "net/quic/platform/api/quic_text_utils.h" using std::string; @@ -157,7 +158,7 @@ QuicPacketNumberLength ReadAckPacketNumberLength(QuicTransportVersion version, } // namespace -QuicFramer::QuicFramer(const QuicTransportVersionVector& supported_versions, +QuicFramer::QuicFramer(const ParsedQuicVersionVector& supported_versions, QuicTime creation_time, Perspective perspective) : visitor_(nullptr), @@ -165,6 +166,7 @@ QuicFramer::QuicFramer(const QuicTransportVersionVector& supported_versions, largest_packet_number_(0), last_serialized_connection_id_(0), last_version_label_(0), + version_(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED), supported_versions_(supported_versions), decrypter_level_(ENCRYPTION_NONE), alternative_decrypter_level_(ENCRYPTION_NONE), @@ -175,7 +177,7 @@ QuicFramer::QuicFramer(const QuicTransportVersionVector& supported_versions, last_timestamp_(QuicTime::Delta::Zero()), data_producer_(nullptr) { DCHECK(!supported_versions.empty()); - transport_version_ = supported_versions_[0]; + version_ = supported_versions_[0]; decrypter_ = QuicMakeUnique<NullDecrypter>(perspective); encrypter_[ENCRYPTION_NONE] = QuicMakeUnique<NullEncrypter>(perspective); } @@ -285,9 +287,20 @@ size_t QuicFramer::GetVersionNegotiationPacketSize(size_t number_versions) { number_versions * kQuicVersionSize; } -bool QuicFramer::IsSupportedVersion(const QuicTransportVersion version) const { - for (size_t i = 0; i < supported_versions_.size(); ++i) { - if (version == supported_versions_[i]) { +// TODO(nharper): Change this method to take a ParsedQuicVersion. +bool QuicFramer::IsSupportedTransportVersion( + const QuicTransportVersion version) const { + for (ParsedQuicVersion supported_version : supported_versions_) { + if (version == supported_version.transport_version) { + return true; + } + } + return false; +} + +bool QuicFramer::IsSupportedVersion(const ParsedQuicVersion version) const { + for (ParsedQuicVersion supported_version : supported_versions_) { + if (version == supported_version) { return true; } } @@ -337,8 +350,8 @@ size_t QuicFramer::GetSerializedFrameLength( } bool can_truncate = frame.type == ACK_FRAME && - free_bytes >= - GetMinAckFrameSize(transport_version_, PACKET_6BYTE_PACKET_NUMBER); + free_bytes >= GetMinAckFrameSize(version_.transport_version, + PACKET_6BYTE_PACKET_NUMBER); if (can_truncate) { // Truncate the frame so the packet will not exceed kMaxPacketSize. // Note that we may not use every byte of the writer in this case. @@ -531,7 +544,7 @@ std::unique_ptr<QuicEncryptedPacket> QuicFramer::BuildPublicResetPacket( // static std::unique_ptr<QuicEncryptedPacket> QuicFramer::BuildVersionNegotiationPacket( QuicConnectionId connection_id, - const QuicTransportVersionVector& versions) { + const ParsedQuicVersionVector& versions) { DCHECK(!versions.empty()); size_t len = GetVersionNegotiationPacketSize(versions.size()); std::unique_ptr<char[]> buffer(new char[len]); @@ -551,20 +564,12 @@ std::unique_ptr<QuicEncryptedPacket> QuicFramer::BuildVersionNegotiationPacket( return nullptr; } - for (QuicTransportVersion version : versions) { - if (FLAGS_quic_reloadable_flag_quic_use_net_byte_order_version_label) { - QUIC_FLAG_COUNT_N( - quic_reloadable_flag_quic_use_net_byte_order_version_label, 3, 10); - // TODO(rch): Use WriteUInt32() once QUIC_VERSION_38 and earlier - // are removed. - if (!writer.WriteTag(QuicEndian::HostToNet32( - QuicVersionToQuicVersionLabel(version)))) { - return nullptr; - } - } else { - if (!writer.WriteTag(QuicVersionToQuicVersionLabel(version))) { - return nullptr; - } + for (ParsedQuicVersion version : versions) { + // TODO(rch): Use WriteUInt32() once QUIC_VERSION_38 and earlier + // are removed. + if (!writer.WriteTag( + QuicEndian::HostToNet32(CreateQuicVersionLabel(version)))) { + return nullptr; } } @@ -591,7 +596,7 @@ bool QuicFramer::ProcessPacket(const QuicEncryptedPacket& packet) { } if (perspective_ == Perspective::IS_SERVER && header.version_flag && - header.version != transport_version_) { + header.version != version_) { if (!visitor_->OnProtocolVersionMismatch(header.version)) { return true; } @@ -634,14 +639,10 @@ bool QuicFramer::ProcessVersionNegotiationPacket( set_detailed_error("Unable to read supported version in negotiation."); return RaiseError(QUIC_INVALID_VERSION_NEGOTIATION_PACKET); } - if (FLAGS_quic_reloadable_flag_quic_use_net_byte_order_version_label) { - QUIC_FLAG_COUNT_N( - quic_reloadable_flag_quic_use_net_byte_order_version_label, 4, 10); - // TODO(rch): Use ReadUInt32() once QUIC_VERSION_38 and earlier - // are removed. - version_label = QuicEndian::NetToHost32(version_label); - } - packet.versions.push_back(QuicVersionLabelToQuicVersion(version_label)); + // TODO(rch): Use ReadUInt32() once QUIC_VERSION_38 and earlier + // are removed. + version_label = QuicEndian::NetToHost32(version_label); + packet.versions.push_back(ParseQuicVersionLabel(version_label)); } while (!reader->IsDoneReading()); visitor_->OnVersionNegotiationPacket(packet); @@ -775,25 +776,15 @@ bool QuicFramer::AppendPacketHeader(const QuicPacketHeader& header, if (header.version_flag) { DCHECK_EQ(Perspective::IS_CLIENT, perspective_); - QuicVersionLabel version_label = - QuicVersionToQuicVersionLabel(transport_version_); - if (FLAGS_quic_reloadable_flag_quic_use_net_byte_order_version_label) { - QUIC_FLAG_COUNT_N( - quic_reloadable_flag_quic_use_net_byte_order_version_label, 5, 10); - // TODO(rch): Use WriteUInt32() once QUIC_VERSION_38 and earlier - // are removed. - if (!writer->WriteTag(QuicEndian::NetToHost32(version_label))) { - return false; - } - } else { - if (!writer->WriteTag(version_label)) { - return false; - } + QuicVersionLabel version_label = CreateQuicVersionLabel(version_); + // TODO(rch): Use WriteUInt32() once QUIC_VERSION_38 and earlier + // are removed. + if (!writer->WriteTag(QuicEndian::NetToHost32(version_label))) { + return false; } - QUIC_DVLOG(1) << ENDPOINT << "version = " << transport_version_ - << ", label = '" << QuicVersionLabelToString(version_label) - << "'"; + QUIC_DVLOG(1) << ENDPOINT << "label = '" + << QuicVersionLabelToString(version_label) << "'"; } if (header.nonce != nullptr && @@ -903,21 +894,16 @@ bool QuicFramer::ProcessPublicHeader(QuicDataReader* reader, set_detailed_error("Unable to read protocol version."); return false; } - if (FLAGS_quic_reloadable_flag_quic_use_net_byte_order_version_label) { - QUIC_FLAG_COUNT_N( - quic_reloadable_flag_quic_use_net_byte_order_version_label, 6, 10); - // TODO(rch): Use ReadUInt32() once QUIC_VERSION_38 and earlier - // are removed. - version_label = QuicEndian::NetToHost32(version_label); - } + // TODO(rch): Use ReadUInt32() once QUIC_VERSION_38 and earlier + // are removed. + version_label = QuicEndian::NetToHost32(version_label); // If the version from the new packet is the same as the version of this // framer, then the public flags should be set to something we understand. // If not, this raises an error. last_version_label_ = version_label; - QuicTransportVersion version = QuicVersionLabelToQuicVersion(version_label); - if (version == transport_version_ && - public_flags > PACKET_PUBLIC_FLAGS_MAX) { + ParsedQuicVersion version = ParseQuicVersionLabel(version_label); + if (version == version_ && public_flags > PACKET_PUBLIC_FLAGS_MAX) { set_detailed_error("Illegal public flags value."); return false; } @@ -1067,9 +1053,9 @@ bool QuicFramer::ProcessFrameData(QuicDataReader* reader, if (frame_type & kQuicFrameTypeSpecialMask) { // Stream Frame - if ((transport_version_ < QUIC_VERSION_41 && + if ((version_.transport_version < QUIC_VERSION_41 && (frame_type & kQuicFrameTypeStreamMask_Pre40)) || - (transport_version_ >= QUIC_VERSION_41 && + (version_.transport_version >= QUIC_VERSION_41 && ((frame_type & kQuicFrameTypeStreamMask) == kQuicFrameTypeStreamMask))) { QuicStreamFrame frame; @@ -1086,9 +1072,9 @@ bool QuicFramer::ProcessFrameData(QuicDataReader* reader, } // Ack Frame - if ((transport_version_ < QUIC_VERSION_41 && + if ((version_.transport_version < QUIC_VERSION_41 && (frame_type & kQuicFrameTypeAckMask_Pre40)) || - (transport_version_ >= QUIC_VERSION_41 && + (version_.transport_version >= QUIC_VERSION_41 && ((frame_type & kQuicFrameTypeSpecialMask) == kQuicFrameTypeAckMask))) { QuicAckFrame frame; @@ -1266,7 +1252,7 @@ bool QuicFramer::ProcessStreamFrame(QuicDataReader* reader, uint8_t stream_id_length = 0; uint8_t offset_length = 4; bool has_data_length = true; - if (transport_version_ < QUIC_VERSION_41) { + if (version_.transport_version < QUIC_VERSION_41) { stream_flags &= ~kQuicFrameTypeStreamMask_Pre40; // Read from right to left: StreamID, Offset, Data Length, Fin. @@ -1340,12 +1326,12 @@ bool QuicFramer::ProcessAckFrame(QuicDataReader* reader, uint8_t frame_type, QuicAckFrame* ack_frame) { bool has_ack_blocks = - ExtractBit(frame_type, transport_version_ < QUIC_VERSION_41 + ExtractBit(frame_type, version_.transport_version < QUIC_VERSION_41 ? kQuicHasMultipleAckBlocksOffset_Pre40 : kQuicHasMultipleAckBlocksOffset); uint8_t num_ack_blocks = 0; uint8_t num_received_packets = 0; - if (transport_version_ > QUIC_VERSION_39) { + if (version_.transport_version > QUIC_VERSION_39) { if (has_ack_blocks && !reader->ReadUInt8(&num_ack_blocks)) { set_detailed_error("Unable to read num of ack blocks."); return false; @@ -1359,11 +1345,11 @@ bool QuicFramer::ProcessAckFrame(QuicDataReader* reader, // Determine the two lengths from the frame type: largest acked length, // ack block length. const QuicPacketNumberLength ack_block_length = ReadAckPacketNumberLength( - transport_version_, + version_.transport_version, ExtractBits(frame_type, kQuicSequenceNumberLengthNumBits, kActBlockLengthOffset)); const QuicPacketNumberLength largest_acked_length = ReadAckPacketNumberLength( - transport_version_, + version_.transport_version, ExtractBits(frame_type, kQuicSequenceNumberLengthNumBits, kLargestAckedOffset)); @@ -1387,7 +1373,7 @@ bool QuicFramer::ProcessAckFrame(QuicDataReader* reader, } if (has_ack_blocks) { - if (transport_version_ <= QUIC_VERSION_39 && + if (version_.transport_version <= QUIC_VERSION_39 && !reader->ReadUInt8(&num_ack_blocks)) { set_detailed_error("Unable to read num of ack blocks."); return false; @@ -1400,16 +1386,31 @@ bool QuicFramer::ProcessAckFrame(QuicDataReader* reader, return false; } + if (GetQuicReloadableFlag(quic_strict_ack_handling) && + first_block_length == 0) { + QUIC_FLAG_COUNT(quic_reloadable_flag_quic_strict_ack_handling); + // For non-empty ACKs, the first block length must be non-zero. + if (largest_acked != 0 || num_ack_blocks != 0) { + set_detailed_error( + QuicStrCat("First block length is zero but ACK is " + "not empty. largest acked is ", + largest_acked, ", num ack blocks is ", + QuicTextUtils::Uint64ToString(num_ack_blocks), ".") + .c_str()); + return false; + } + } + if (first_block_length > largest_acked + 1) { set_detailed_error(QuicStrCat("Underflow with first ack block length ", first_block_length, " largest acked is ", - largest_acked + 1, ".") + largest_acked, ".") .c_str()); return false; } QuicPacketNumber first_received = largest_acked + 1 - first_block_length; - ack_frame->deprecated_largest_observed = largest_acked; + ack_frame->largest_acked = largest_acked; ack_frame->packets.AddRange(first_received, largest_acked + 1); if (num_ack_blocks > 0) { @@ -1440,7 +1441,7 @@ bool QuicFramer::ProcessAckFrame(QuicDataReader* reader, } } - if (transport_version_ <= QUIC_VERSION_39 && + if (version_.transport_version <= QUIC_VERSION_39 && !reader->ReadUInt8(&num_received_packets)) { set_detailed_error("Unable to read num received packets."); return false; @@ -1528,7 +1529,7 @@ bool QuicFramer::ProcessRstStreamFrame(QuicDataReader* reader, return false; } - if (transport_version_ <= QUIC_VERSION_39) { + if (version_.transport_version <= QUIC_VERSION_39) { if (!reader->ReadUInt64(&frame->byte_offset)) { set_detailed_error("Unable to read rst stream sent byte offset."); return false; @@ -1548,7 +1549,7 @@ bool QuicFramer::ProcessRstStreamFrame(QuicDataReader* reader, frame->error_code = static_cast<QuicRstStreamErrorCode>(error_code); - if (transport_version_ > QUIC_VERSION_39) { + if (version_.transport_version > QUIC_VERSION_39) { if (!reader->ReadUInt64(&frame->byte_offset)) { set_detailed_error("Unable to read rst stream sent byte offset."); return false; @@ -1641,7 +1642,7 @@ bool QuicFramer::ProcessBlockedFrame(QuicDataReader* reader, void QuicFramer::ProcessPaddingFrame(QuicDataReader* reader, QuicPaddingFrame* frame) { - if (transport_version_ <= QUIC_VERSION_37) { + if (version_.transport_version <= QUIC_VERSION_37) { frame->num_padding_bytes = reader->BytesRemaining() + 1; reader->ReadRemainingPayload(); return; @@ -1709,7 +1710,7 @@ size_t QuicFramer::EncryptInPlace(EncryptionLevel level, char* buffer) { size_t output_length = 0; if (!encrypter_[level]->EncryptPacket( - transport_version_, packet_number, + version_.transport_version, packet_number, QuicStringPiece(buffer, ad_len), // Associated data QuicStringPiece(buffer + ad_len, total_len - ad_len), // Plaintext buffer + ad_len, // Destination buffer @@ -1728,7 +1729,8 @@ size_t QuicFramer::EncryptPayload(EncryptionLevel level, size_t buffer_len) { DCHECK(encrypter_[level] != nullptr); - QuicStringPiece associated_data = packet.AssociatedData(transport_version_); + QuicStringPiece associated_data = + packet.AssociatedData(version_.transport_version); // Copy in the header, because the encrypter only populates the encrypted // plaintext content. const size_t ad_len = associated_data.length(); @@ -1736,9 +1738,9 @@ size_t QuicFramer::EncryptPayload(EncryptionLevel level, // Encrypt the plaintext into the buffer. size_t output_length = 0; if (!encrypter_[level]->EncryptPacket( - transport_version_, packet_number, associated_data, - packet.Plaintext(transport_version_), buffer + ad_len, &output_length, - buffer_len - ad_len)) { + version_.transport_version, packet_number, associated_data, + packet.Plaintext(version_.transport_version), buffer + ad_len, + &output_length, buffer_len - ad_len)) { RaiseError(QUIC_ENCRYPTION_FAILURE); return 0; } @@ -1772,13 +1774,13 @@ bool QuicFramer::DecryptPayload(QuicDataReader* encrypted_reader, QuicStringPiece encrypted = encrypted_reader->ReadRemainingPayload(); DCHECK(decrypter_ != nullptr); QuicStringPiece associated_data = GetAssociatedDataFromEncryptedPacket( - transport_version_, packet, header.connection_id_length, + version_.transport_version, packet, header.connection_id_length, header.version_flag, header.nonce != nullptr, header.packet_number_length); bool success = decrypter_->DecryptPacket( - transport_version_, header.packet_number, associated_data, encrypted, - decrypted_buffer, decrypted_length, buffer_length); + version_.transport_version, header.packet_number, associated_data, + encrypted, decrypted_buffer, decrypted_length, buffer_length); if (success) { visitor_->OnDecryptedPacket(decrypter_level_); } else if (alternative_decrypter_ != nullptr) { @@ -1800,8 +1802,8 @@ bool QuicFramer::DecryptPayload(QuicDataReader* encrypted_reader, if (try_alternative_decryption) { success = alternative_decrypter_->DecryptPacket( - transport_version_, header.packet_number, associated_data, encrypted, - decrypted_buffer, decrypted_length, buffer_length); + version_.transport_version, header.packet_number, associated_data, + encrypted, decrypted_buffer, decrypted_length, buffer_length); } if (success) { visitor_->OnDecryptedPacket(alternative_decrypter_level_); @@ -1845,11 +1847,12 @@ size_t QuicFramer::GetAckFrameSize( AckFrameInfo ack_info = GetAckFrameInfo(ack); QuicPacketNumberLength largest_acked_length = - GetMinPacketNumberLength(transport_version_, LargestAcked(ack)); - QuicPacketNumberLength ack_block_length = - GetMinPacketNumberLength(transport_version_, ack_info.max_block_length); + GetMinPacketNumberLength(version_.transport_version, LargestAcked(ack)); + QuicPacketNumberLength ack_block_length = GetMinPacketNumberLength( + version_.transport_version, ack_info.max_block_length); - ack_size = GetMinAckFrameSize(transport_version_, largest_acked_length); + ack_size = + GetMinAckFrameSize(version_.transport_version, largest_acked_length); // First ack block length. ack_size += ack_block_length; if (ack_info.num_ack_blocks != 0) { @@ -1871,14 +1874,15 @@ size_t QuicFramer::ComputeFrameLength( switch (frame.type) { case STREAM_FRAME: return GetMinStreamFrameSize( - transport_version_, frame.stream_frame->stream_id, + version_.transport_version, frame.stream_frame->stream_id, frame.stream_frame->offset, last_frame_in_packet) + frame.stream_frame->data_length; case ACK_FRAME: { return GetAckFrameSize(*frame.ack_frame, packet_number_length); } case STOP_WAITING_FRAME: - return GetStopWaitingFrameSize(transport_version_, packet_number_length); + return GetStopWaitingFrameSize(version_.transport_version, + packet_number_length); case MTU_DISCOVERY_FRAME: // MTU discovery frames are serialized as ping frames. case PING_FRAME: @@ -1919,7 +1923,7 @@ bool QuicFramer::AppendTypeByte(const QuicFrame& frame, if (frame.stream_frame == nullptr) { QUIC_BUG << "Failed to append STREAM frame with no stream_frame."; } - if (transport_version_ < QUIC_VERSION_41) { + if (version_.transport_version < QUIC_VERSION_41) { // Fin bit. type_byte |= frame.stream_frame->fin ? kQuicStreamFinMask_Pre40 : 0; @@ -1930,8 +1934,8 @@ bool QuicFramer::AppendTypeByte(const QuicFrame& frame, // Offset 3 bits. type_byte <<= kQuicStreamShift_Pre40; - const size_t offset_len = - GetStreamOffsetSize(transport_version_, frame.stream_frame->offset); + const size_t offset_len = GetStreamOffsetSize( + version_.transport_version, frame.stream_frame->offset); if (offset_len > 0) { type_byte |= offset_len - 1; } @@ -1950,7 +1954,7 @@ bool QuicFramer::AppendTypeByte(const QuicFrame& frame, // Offset 2 bits. uint8_t offset_len_encode = 3; - switch (GetStreamOffsetSize(transport_version_, + switch (GetStreamOffsetSize(version_.transport_version, frame.stream_frame->offset)) { case 0: offset_len_encode = 0; @@ -2042,8 +2046,9 @@ bool QuicFramer::AppendStreamFrame(const QuicStreamFrame& frame, QUIC_BUG << "Writing stream id size failed."; return false; } - if (!AppendStreamOffset(GetStreamOffsetSize(transport_version_, frame.offset), - frame.offset, writer)) { + if (!AppendStreamOffset( + GetStreamOffsetSize(version_.transport_version, frame.offset), + frame.offset, writer)) { QUIC_BUG << "Writing offset size failed."; return false; } @@ -2075,9 +2080,9 @@ bool QuicFramer::AppendStreamFrame(const QuicStreamFrame& frame, return true; } -void QuicFramer::set_version(const QuicTransportVersion version) { - DCHECK(IsSupportedVersion(version)) << QuicVersionToString(version); - transport_version_ = version; +void QuicFramer::set_version(const ParsedQuicVersion version) { + DCHECK(IsSupportedVersion(version)) << ParsedQuicVersionToString(version); + version_ = version; } bool QuicFramer::AppendAckFrameAndTypeByte(const QuicAckFrame& frame, @@ -2085,13 +2090,13 @@ bool QuicFramer::AppendAckFrameAndTypeByte(const QuicAckFrame& frame, const AckFrameInfo new_ack_info = GetAckFrameInfo(frame); QuicPacketNumber largest_acked = LargestAcked(frame); QuicPacketNumberLength largest_acked_length = - GetMinPacketNumberLength(transport_version_, largest_acked); + GetMinPacketNumberLength(version_.transport_version, largest_acked); QuicPacketNumberLength ack_block_length = GetMinPacketNumberLength( - transport_version_, new_ack_info.max_block_length); + version_.transport_version, new_ack_info.max_block_length); // Calculate available bytes for timestamps and ack blocks. int32_t available_timestamp_and_ack_block_bytes = writer->capacity() - writer->length() - ack_block_length - - GetMinAckFrameSize(transport_version_, largest_acked_length) - + GetMinAckFrameSize(version_.transport_version, largest_acked_length) - (new_ack_info.num_ack_blocks != 0 ? kNumberOfAckBlocksSize : 0); DCHECK_LE(0, available_timestamp_and_ack_block_bytes); @@ -2100,7 +2105,7 @@ bool QuicFramer::AppendAckFrameAndTypeByte(const QuicAckFrame& frame, // Whether there are multiple ack blocks. uint8_t type_byte = 0; SetBit(&type_byte, new_ack_info.num_ack_blocks != 0, - transport_version_ < QUIC_VERSION_41 + version_.transport_version < QUIC_VERSION_41 ? kQuicHasMultipleAckBlocksOffset_Pre40 : kQuicHasMultipleAckBlocksOffset); @@ -2110,7 +2115,7 @@ bool QuicFramer::AppendAckFrameAndTypeByte(const QuicAckFrame& frame, SetBits(&type_byte, GetPacketNumberFlags(ack_block_length), kQuicSequenceNumberLengthNumBits, kActBlockLengthOffset); - if (transport_version_ < QUIC_VERSION_41) { + if (version_.transport_version < QUIC_VERSION_41) { type_byte |= kQuicFrameTypeAckMask_Pre40; } else { type_byte |= kQuicFrameTypeAckMask; @@ -2131,7 +2136,7 @@ bool QuicFramer::AppendAckFrameAndTypeByte(const QuicAckFrame& frame, num_ack_blocks = std::numeric_limits<uint8_t>::max(); } - if (transport_version_ > QUIC_VERSION_39) { + if (version_.transport_version > QUIC_VERSION_39) { if (num_ack_blocks > 0 && !writer->WriteBytes(&num_ack_blocks, 1)) { return false; } @@ -2160,7 +2165,7 @@ bool QuicFramer::AppendAckFrameAndTypeByte(const QuicAckFrame& frame, return false; } - if (transport_version_ <= QUIC_VERSION_39) { + if (version_.transport_version <= QUIC_VERSION_39) { if (num_ack_blocks > 0) { if (!writer->WriteBytes(&num_ack_blocks, 1)) { return false; @@ -2260,7 +2265,7 @@ bool QuicFramer::AppendTimestampsToAckFrame(const QuicAckFrame& frame, } uint8_t num_received_packets = frame.received_packet_times.size(); - if (transport_version_ <= QUIC_VERSION_39) { + if (version_.transport_version <= QUIC_VERSION_39) { if (!writer->WriteBytes(&num_received_packets, 1)) { return false; } @@ -2333,7 +2338,7 @@ bool QuicFramer::AppendStopWaitingFrame(const QuicPacketHeader& header, << " is too small for least_unacked_delta: " << least_unacked_delta << " packet_number:" << header.packet_number << " least_unacked:" << frame.least_unacked - << " version:" << transport_version_; + << " version:" << version_.transport_version; return false; } if (!AppendPacketNumber(header.packet_number_length, least_unacked_delta, @@ -2351,7 +2356,7 @@ bool QuicFramer::AppendRstStreamFrame(const QuicRstStreamFrame& frame, return false; } - if (transport_version_ <= QUIC_VERSION_39) { + if (version_.transport_version <= QUIC_VERSION_39) { if (!writer->WriteUInt64(frame.byte_offset)) { return false; } @@ -2362,7 +2367,7 @@ bool QuicFramer::AppendRstStreamFrame(const QuicRstStreamFrame& frame, return false; } - if (transport_version_ > QUIC_VERSION_39) { + if (version_.transport_version > QUIC_VERSION_39) { if (!writer->WriteUInt64(frame.byte_offset)) { return false; } @@ -2423,7 +2428,7 @@ bool QuicFramer::AppendBlockedFrame(const QuicBlockedFrame& frame, bool QuicFramer::AppendPaddingFrame(const QuicPaddingFrame& frame, QuicDataWriter* writer) { - if (transport_version_ <= QUIC_VERSION_37) { + if (version_.transport_version <= QUIC_VERSION_37) { writer->WritePadding(); return true; } @@ -2449,8 +2454,8 @@ bool QuicFramer::RaiseError(QuicErrorCode error) { } Endianness QuicFramer::endianness() const { - return transport_version_ > QUIC_VERSION_38 ? NETWORK_BYTE_ORDER - : HOST_BYTE_ORDER; + return version_.transport_version > QUIC_VERSION_38 ? NETWORK_BYTE_ORDER + : HOST_BYTE_ORDER; } bool QuicFramer::StartsWithChlo(QuicStreamId id, @@ -2472,11 +2477,9 @@ bool QuicFramer::StartsWithChlo(QuicStreamId id, } QuicStringPiece QuicFramer::TruncateErrorString(QuicStringPiece error) { - if (error.length() <= kMaxErrorStringLength || - !FLAGS_quic_reloadable_flag_quic_truncate_long_details) { + if (error.length() <= kMaxErrorStringLength) { return error; } - QUIC_FLAG_COUNT(quic_reloadable_flag_quic_truncate_long_details); return QuicStringPiece(error.data(), kMaxErrorStringLength); } diff --git a/chromium/net/quic/core/quic_framer.h b/chromium/net/quic/core/quic_framer.h index f1d4603595f..abea88ffef2 100644 --- a/chromium/net/quic/core/quic_framer.h +++ b/chromium/net/quic/core/quic_framer.h @@ -72,7 +72,7 @@ class QUIC_EXPORT_PRIVATE QuicFramerVisitorInterface { // version of the |framer_| to |received_version| or false to stop processing // this packet. virtual bool OnProtocolVersionMismatch( - QuicTransportVersion received_version) = 0; + ParsedQuicVersion received_version) = 0; // Called when a new packet has been received, before it // has been validated or processed. @@ -150,14 +150,17 @@ class QUIC_EXPORT_PRIVATE QuicFramer { // QuicDecrypter for level ENCRYPTION_NONE. |supported_versions| specifies the // list of supported QUIC versions. |quic_version_| is set to the maximum // version in |supported_versions|. - QuicFramer(const QuicTransportVersionVector& supported_versions, + QuicFramer(const ParsedQuicVersionVector& supported_versions, QuicTime creation_time, Perspective perspective); virtual ~QuicFramer(); + // Returns true if |version| is a supported transport version. + bool IsSupportedTransportVersion(const QuicTransportVersion version) const; + // Returns true if |version| is a supported protocol version. - bool IsSupportedVersion(const QuicTransportVersion version) const; + bool IsSupportedVersion(const ParsedQuicVersion version) const; // Set callbacks to be called from the framer. A visitor must be set, or // else the framer will likely crash. It is acceptable for the visitor @@ -165,18 +168,22 @@ class QUIC_EXPORT_PRIVATE QuicFramer { // will be used. void set_visitor(QuicFramerVisitorInterface* visitor) { visitor_ = visitor; } - const QuicTransportVersionVector& supported_versions() const { + const ParsedQuicVersionVector& supported_versions() const { return supported_versions_; } - QuicTransportVersion transport_version() const { return transport_version_; } + QuicTransportVersion transport_version() const { + return version_.transport_version; + } + + ParsedQuicVersion version() const { return version_; } - void set_version(const QuicTransportVersion version); + void set_version(const ParsedQuicVersion version); // Does not DCHECK for supported version. Used by tests to set unsupported // version to trigger version negotiation. - void set_version_for_tests(const QuicTransportVersion version) { - transport_version_ = version; + void set_version_for_tests(const ParsedQuicVersion version) { + version_ = version; } QuicErrorCode error() const { return error_; } @@ -261,10 +268,10 @@ class QUIC_EXPORT_PRIVATE QuicFramer { // Returns a new version negotiation packet. static std::unique_ptr<QuicEncryptedPacket> BuildVersionNegotiationPacket( QuicConnectionId connection_id, - const QuicTransportVersionVector& versions); + const ParsedQuicVersionVector& versions); // If header.version_flag is set, the version in the - // packet will be set -- but it will be set from transport_version_ not + // packet will be set -- but it will be set from version_ not // header.versions. bool AppendPacketHeader(const QuicPacketHeader& header, QuicDataWriter* writer); @@ -328,10 +335,9 @@ class QUIC_EXPORT_PRIVATE QuicFramer { QuicTransportVersion version, QuicPacketNumber packet_number); - void SetSupportedTransportVersions( - const QuicTransportVersionVector& versions) { + void SetSupportedVersions(const ParsedQuicVersionVector& versions) { supported_versions_ = versions; - transport_version_ = versions[0]; + version_ = versions[0]; } // Returns true if data with |offset| of stream |id| starts with 'CHLO'. @@ -513,12 +519,12 @@ class QUIC_EXPORT_PRIVATE QuicFramer { // The last QUIC version label received. QuicVersionLabel last_version_label_; // Version of the protocol being used. - QuicTransportVersion transport_version_; + ParsedQuicVersion version_; // This vector contains QUIC 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). - QuicTransportVersionVector supported_versions_; + ParsedQuicVersionVector supported_versions_; // Primary decrypter used to decrypt packets during parsing. std::unique_ptr<QuicDecrypter> decrypter_; // Alternative decrypter that can also be used to decrypt packets. diff --git a/chromium/net/quic/core/quic_framer_test.cc b/chromium/net/quic/core/quic_framer_test.cc index 95bd03b40ae..055af34165b 100644 --- a/chromium/net/quic/core/quic_framer_test.cc +++ b/chromium/net/quic/core/quic_framer_test.cc @@ -17,6 +17,7 @@ #include "net/quic/core/crypto/quic_encrypter.h" #include "net/quic/core/quic_packets.h" #include "net/quic/core/quic_utils.h" +#include "net/quic/platform/api/quic_arraysize.h" #include "net/quic/platform/api/quic_flags.h" #include "net/quic/platform/api/quic_logging.h" #include "net/quic/platform/api/quic_ptr_util.h" @@ -71,6 +72,7 @@ class TestEncrypter : public QuicEncrypter { } size_t GetKeySize() const override { return 0; } size_t GetNoncePrefixSize() const override { return 0; } + size_t GetIVSize() const override { return 0; } size_t GetMaxPlaintextSize(size_t ciphertext_size) const override { return ciphertext_size; } @@ -114,6 +116,8 @@ class TestDecrypter : public QuicDecrypter { *output_length = ciphertext.length(); return true; } + size_t GetKeySize() const override { return 0; } + size_t GetIVSize() const override { return 0; } QuicStringPiece GetKey() const override { return QuicStringPiece(); } QuicStringPiece GetNoncePrefix() const override { return QuicStringPiece(); } // Use a distinct value starting with 0xFFFFFF, which is never used by TLS. @@ -154,7 +158,7 @@ class TestQuicVisitor : public QuicFramerVisitorInterface { version_negotiation_packet_.reset(new QuicVersionNegotiationPacket(packet)); } - bool OnProtocolVersionMismatch(QuicTransportVersion version) override { + bool OnProtocolVersionMismatch(ParsedQuicVersion version) override { QUIC_DLOG(INFO) << "QuicFramer Version Mismatch, version: " << version; ++version_mismatch_; return true; @@ -271,16 +275,14 @@ struct PacketFragment { using PacketFragments = std::vector<struct PacketFragment>; -class QuicFramerTest : public QuicTestWithParam<QuicTransportVersion> { +class QuicFramerTest : public QuicTestWithParam<ParsedQuicVersion> { public: QuicFramerTest() : encrypter_(new test::TestEncrypter()), decrypter_(new test::TestDecrypter()), + version_(GetParam()), start_(QuicTime::Zero() + QuicTime::Delta::FromMicroseconds(0x10)), - framer_(AllSupportedTransportVersions(), - start_, - Perspective::IS_SERVER) { - version_ = GetParam(); + framer_(AllSupportedVersions(), start_, Perspective::IS_SERVER) { framer_.set_version(version_); framer_.SetDecrypter(ENCRYPTION_NONE, decrypter_); framer_.SetEncrypter(ENCRYPTION_NONE, encrypter_); @@ -290,17 +292,17 @@ class QuicFramerTest : public QuicTestWithParam<QuicTransportVersion> { // Helper function to get unsigned char representation of digit in the // units place of the current QUIC version number. unsigned char GetQuicVersionDigitOnes() { - return static_cast<unsigned char>('0' + version_ % 10); + return CreateQuicVersionLabel(version_) & 0xff; } // Helper function to get unsigned char representation of digit in the // tens place of the current QUIC version number. unsigned char GetQuicVersionDigitTens() { - return static_cast<unsigned char>('0' + (version_ / 10) % 10); + return (CreateQuicVersionLabel(version_) >> 8) & 0xff; } bool CheckEncryption(QuicPacketNumber packet_number, QuicPacket* packet) { - EXPECT_EQ(version_, encrypter_->version_); + EXPECT_EQ(version_.transport_version, encrypter_->version_); if (packet_number != encrypter_->packet_number_) { QUIC_LOG(ERROR) << "Encrypted incorrect packet number. expected " << packet_number @@ -327,7 +329,7 @@ class QuicFramerTest : public QuicTestWithParam<QuicTransportVersion> { bool CheckDecryption(const QuicEncryptedPacket& encrypted, bool includes_version, bool includes_diversification_nonce) { - EXPECT_EQ(version_, decrypter_->version_); + EXPECT_EQ(version_.transport_version, decrypter_->version_); if (visitor_.header_->packet_number != decrypter_->packet_number_) { QUIC_LOG(ERROR) << "Decrypted incorrect packet number. expected " << visitor_.header_->packet_number @@ -448,7 +450,7 @@ class QuicFramerTest : public QuicTestWithParam<QuicTransportVersion> { test::TestEncrypter* encrypter_; test::TestDecrypter* decrypter_; - QuicTransportVersion version_; + ParsedQuicVersion version_; QuicTime start_; QuicFramer framer_; test::TestQuicVisitor visitor_; @@ -457,7 +459,7 @@ class QuicFramerTest : public QuicTestWithParam<QuicTransportVersion> { // Run all framer tests with all supported versions of QUIC. INSTANTIATE_TEST_CASE_P(QuicFramerTests, QuicFramerTest, - ::testing::ValuesIn(kSupportedTransportVersions)); + ::testing::ValuesIn(AllSupportedVersions())); TEST_P(QuicFramerTest, CalculatePacketNumberFromWireNearEpochStart) { // A few quick manual sanity checks. @@ -587,7 +589,7 @@ TEST_P(QuicFramerTest, LargePacket) { memset(packet + header_size, 0, kMaxPacketSize - header_size); - QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); + QuicEncryptedPacket encrypted(AsChars(packet), QUIC_ARRAYSIZE(packet), false); EXPECT_QUIC_BUG(framer_.ProcessPacket(encrypted), "Packet too large:1"); ASSERT_TRUE(visitor_.header_.get()); @@ -953,7 +955,7 @@ TEST_P(QuicFramerTest, PacketWithDiversificationNonce) { QuicEncryptedPacket encrypted( AsChars(framer_.transport_version() <= QUIC_VERSION_38 ? packet : packet39), - arraysize(packet), false); + QUIC_ARRAYSIZE(packet), false); QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); ASSERT_TRUE(visitor_.header_->nonce != nullptr); @@ -1002,7 +1004,7 @@ TEST_P(QuicFramerTest, LargePublicFlagWithMismatchedVersions) { QuicEncryptedPacket encrypted( AsChars(framer_.transport_version() <= QUIC_VERSION_38 ? packet : packet39), - arraysize(packet), false); + QUIC_ARRAYSIZE(packet), false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); ASSERT_TRUE(visitor_.header_.get()); @@ -1046,7 +1048,7 @@ TEST_P(QuicFramerTest, PaddingFrame) { return; } - QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); + QuicEncryptedPacket encrypted(AsChars(packet), QUIC_ARRAYSIZE(packet), false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); ASSERT_TRUE(visitor_.header_.get()); @@ -1164,7 +1166,7 @@ TEST_P(QuicFramerTest, NewPaddingFrame) { p = packet39; } - QuicEncryptedPacket encrypted(AsChars(p), arraysize(packet), false); + QuicEncryptedPacket encrypted(AsChars(p), QUIC_ARRAYSIZE(packet), false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); ASSERT_TRUE(visitor_.header_.get()); @@ -1387,7 +1389,7 @@ TEST_P(QuicFramerTest, MissingDiversificationNonce) { } else if (framer_.transport_version() > QUIC_VERSION_38) { p = packet39; } - QuicEncryptedPacket encrypted(AsChars(p), arraysize(packet), false); + QuicEncryptedPacket encrypted(AsChars(p), QUIC_ARRAYSIZE(packet), false); EXPECT_FALSE(framer_.ProcessPacket(encrypted)); EXPECT_EQ(QUIC_DECRYPTION_FAILURE, framer_.error()); } @@ -1960,7 +1962,7 @@ TEST_P(QuicFramerTest, RejectPacket) { } else if (framer_.transport_version() > QUIC_VERSION_38) { p = packet39; } - QuicEncryptedPacket encrypted(AsChars(p), arraysize(packet), false); + QuicEncryptedPacket encrypted(AsChars(p), QUIC_ARRAYSIZE(packet), false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); @@ -1984,7 +1986,7 @@ TEST_P(QuicFramerTest, RejectPublicHeader) { }; // clang-format on - QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); + QuicEncryptedPacket encrypted(AsChars(packet), QUIC_ARRAYSIZE(packet), false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); @@ -2126,7 +2128,7 @@ TEST_P(QuicFramerTest, FirstAckFrameUnderflow) { {"Unable to read first ack block length.", {0x88, 0x88}}, // num timestamps. - {"Underflow with first ack block length 34952 largest acked is 4661.", + {"Underflow with first ack block length 34952 largest acked is 4660.", {0x00}} }; @@ -2154,7 +2156,7 @@ TEST_P(QuicFramerTest, FirstAckFrameUnderflow) { {"Unable to read first ack block length.", {0x88, 0x88}}, // num timestamps. - {"Underflow with first ack block length 34952 largest acked is 4661.", + {"Underflow with first ack block length 34952 largest acked is 4660.", {0x00}} }; @@ -2196,6 +2198,155 @@ TEST_P(QuicFramerTest, FirstAckFrameUnderflow) { CheckFramingBoundaries(fragments, QUIC_INVALID_ACK_DATA); } +TEST_P(QuicFramerTest, AckFrameFirstAckBlockLengthZero) { + SetQuicReloadableFlag(quic_strict_ack_handling, + true); + + // clang-format off + PacketFragments packet = { + // public flags (8 byte connection_id) + {"", + { 0x3C }}, + // connection_id + {"", + { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 }}, + // packet number + {"", + { 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12 }}, + + // frame type (ack frame) + // (more than one ack block, 2 byte largest observed, 2 byte block length) + {"", + { 0x65 }}, + // largest acked + {"Unable to read largest acked.", + { 0x34, 0x12 }}, + // Zero delta time. + {"Unable to read ack delay time.", + { 0x00, 0x00 }}, + // num ack blocks ranges. + {"Unable to read num of ack blocks.", + { 0x01 }}, + // first ack block length. + {"Unable to read first ack block length.", + { 0x00, 0x00 }}, + // gap to next block. + { "First block length is zero but ACK is not empty. " + "largest acked is 4660, num ack blocks is 1.", + { 0x01 }}, + // ack block length. + { "First block length is zero but ACK is not empty. " + "largest acked is 4660, num ack blocks is 1.", + { 0xaf, 0x0e }}, + // Number of timestamps. + { "First block length is zero but ACK is not empty. " + "largest acked is 4660, num ack blocks is 1.", + { 0x00 }}, + }; + + PacketFragments packet39 = { + // public flags (8 byte connection_id) + {"", + { 0x3C }}, + // connection_id + {"", + { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 }}, + // packet number + {"", + { 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC }}, + + // frame type (ack frame) + // (more than one ack block, 2 byte largest observed, 2 byte block length) + {"", + { 0x65 }}, + // largest acked + {"Unable to read largest acked.", + { 0x12, 0x34 }}, + // Zero delta time. + {"Unable to read ack delay time.", + { 0x00, 0x00 }}, + // num ack blocks ranges. + {"Unable to read num of ack blocks.", + { 0x01 }}, + // first ack block length. + {"Unable to read first ack block length.", + { 0x00, 0x00 }}, + // gap to next block. + { "First block length is zero but ACK is not empty. " + "largest acked is 4660, num ack blocks is 1.", + { 0x01 }}, + // ack block length. + { "First block length is zero but ACK is not empty. " + "largest acked is 4660, num ack blocks is 1.", + { 0x0e, 0xaf }}, + // Number of timestamps. + { "First block length is zero but ACK is not empty. " + "largest acked is 4660, num ack blocks is 1.", + { 0x00 }}, + }; + + PacketFragments packet41 = { + // public flags (8 byte connection_id) + {"", + { 0x3C }}, + // connection_id + {"", + { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 }}, + // packet number + {"", + { 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC }}, + + // frame type (ack frame) + // (more than one ack block, 2 byte largest observed, 2 byte block length) + {"", + { 0xB5 }}, + // num ack blocks ranges. + {"Unable to read num of ack blocks.", + { 0x01 }}, + // Number of timestamps. + { "Unable to read num received packets.", + { 0x00 }}, + // largest acked + {"Unable to read largest acked.", + { 0x12, 0x34 }}, + // Zero delta time. + {"Unable to read ack delay time.", + { 0x00, 0x00 }}, + // first ack block length. + {"Unable to read first ack block length.", + { 0x00, 0x00 }}, + // gap to next block. + { "First block length is zero but ACK is not empty. " + "largest acked is 4660, num ack blocks is 1.", + { 0x01 }}, + // ack block length. + { "First block length is zero but ACK is not empty. " + "largest acked is 4660, num ack blocks is 1.", + { 0x0e, 0xaf }}, + }; + + // clang-format on + PacketFragments& fragments = + framer_.transport_version() > QUIC_VERSION_39 + ? packet41 + : (framer_.transport_version() > QUIC_VERSION_38 ? packet39 : packet); + + std::unique_ptr<QuicEncryptedPacket> encrypted( + AssemblePacketFromFragments(fragments)); + + EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); + EXPECT_EQ(QUIC_INVALID_ACK_DATA, framer_.error()); + + ASSERT_TRUE(visitor_.header_.get()); + EXPECT_TRUE(CheckDecryption(*encrypted, !kIncludeVersion, + !kIncludeDiversificationNonce)); + + EXPECT_EQ(0u, visitor_.stream_frames_.size()); + ASSERT_EQ(0u, visitor_.ack_frames_.size()); + + CheckFramingBoundaries(fragments, QUIC_INVALID_ACK_DATA); +} + TEST_P(QuicFramerTest, AckFrameOneAckBlockMaxLength) { // clang-format off PacketFragments packet = { @@ -2633,7 +2784,7 @@ TEST_P(QuicFramerTest, InvalidNewStopWaitingFrame) { QuicEncryptedPacket encrypted( AsChars(framer_.transport_version() <= QUIC_VERSION_38 ? packet : packet39), - arraysize(packet), false); + QUIC_ARRAYSIZE(packet), false); EXPECT_FALSE(framer_.ProcessPacket(encrypted)); EXPECT_EQ(QUIC_INVALID_STOP_WAITING_DATA, framer_.error()); EXPECT_EQ("Invalid unacked delta.", framer_.detailed_error()); @@ -3051,7 +3202,7 @@ TEST_P(QuicFramerTest, PingFrame) { QuicEncryptedPacket encrypted( AsChars(framer_.transport_version() <= QUIC_VERSION_38 ? packet : packet39), - arraysize(packet), false); + QUIC_ARRAYSIZE(packet), false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); @@ -3192,7 +3343,7 @@ TEST_P(QuicFramerTest, PublicResetPacketWithTrailingJunk) { }; // clang-format on - QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); + QuicEncryptedPacket encrypted(AsChars(packet), QUIC_ARRAYSIZE(packet), false); EXPECT_FALSE(framer_.ProcessPacket(encrypted)); ASSERT_EQ(QUIC_INVALID_PUBLIC_RST_PACKET, framer_.error()); EXPECT_EQ("Unable to read reset message.", framer_.detailed_error()); @@ -3377,7 +3528,7 @@ TEST_P(QuicFramerTest, BuildPaddingFramePacket) { "constructed packet", data->data(), data->length(), AsChars(framer_.transport_version() <= QUIC_VERSION_38 ? packet : packet39), - arraysize(packet)); + QUIC_ARRAYSIZE(packet)); } TEST_P(QuicFramerTest, BuildStreamFramePacketWithNewPaddingFrame) { @@ -3491,11 +3642,11 @@ TEST_P(QuicFramerTest, BuildStreamFramePacketWithNewPaddingFrame) { } else if (framer_.transport_version() > QUIC_VERSION_38) { p = packet39; } - QuicEncryptedPacket encrypted(AsChars(p), arraysize(packet), false); + QuicEncryptedPacket encrypted(AsChars(p), QUIC_ARRAYSIZE(packet), false); test::CompareCharArraysWithHexError("constructed packet", data->data(), data->length(), AsChars(p), - arraysize(packet)); + QUIC_ARRAYSIZE(packet)); } TEST_P(QuicFramerTest, Build4ByteSequenceNumberPaddingFramePacket) { @@ -3550,7 +3701,7 @@ TEST_P(QuicFramerTest, Build4ByteSequenceNumberPaddingFramePacket) { "constructed packet", data->data(), data->length(), AsChars(framer_.transport_version() <= QUIC_VERSION_38 ? packet : packet39), - arraysize(packet)); + QUIC_ARRAYSIZE(packet)); } TEST_P(QuicFramerTest, Build2ByteSequenceNumberPaddingFramePacket) { @@ -3605,7 +3756,7 @@ TEST_P(QuicFramerTest, Build2ByteSequenceNumberPaddingFramePacket) { "constructed packet", data->data(), data->length(), AsChars(framer_.transport_version() <= QUIC_VERSION_38 ? packet : packet39), - arraysize(packet)); + QUIC_ARRAYSIZE(packet)); } TEST_P(QuicFramerTest, Build1ByteSequenceNumberPaddingFramePacket) { @@ -3643,7 +3794,7 @@ TEST_P(QuicFramerTest, Build1ByteSequenceNumberPaddingFramePacket) { test::CompareCharArraysWithHexError("constructed packet", data->data(), data->length(), AsChars(packet), - arraysize(packet)); + QUIC_ARRAYSIZE(packet)); } TEST_P(QuicFramerTest, BuildStreamFramePacket) { @@ -3737,7 +3888,7 @@ TEST_P(QuicFramerTest, BuildStreamFramePacket) { } test::CompareCharArraysWithHexError("constructed packet", data->data(), data->length(), AsChars(p), - arraysize(packet)); + QUIC_ARRAYSIZE(packet)); } TEST_P(QuicFramerTest, BuildStreamFramePacketWithVersionFlag) { @@ -3825,7 +3976,7 @@ TEST_P(QuicFramerTest, BuildStreamFramePacketWithVersionFlag) { } test::CompareCharArraysWithHexError("constructed packet", data->data(), data->length(), AsChars(p), - arraysize(packet)); + QUIC_ARRAYSIZE(packet)); } TEST_P(QuicFramerTest, BuildVersionNegotiationPacket) { @@ -3842,11 +3993,11 @@ TEST_P(QuicFramerTest, BuildVersionNegotiationPacket) { QuicConnectionId connection_id = kConnectionId; std::unique_ptr<QuicEncryptedPacket> data( - framer_.BuildVersionNegotiationPacket( - connection_id, SupportedTransportVersions(GetParam()))); + framer_.BuildVersionNegotiationPacket(connection_id, + SupportedVersions(GetParam()))); test::CompareCharArraysWithHexError("constructed packet", data->data(), data->length(), AsChars(packet), - arraysize(packet)); + QUIC_ARRAYSIZE(packet)); } TEST_P(QuicFramerTest, BuildAckFramePacketOneAckBlock) { @@ -3937,7 +4088,7 @@ TEST_P(QuicFramerTest, BuildAckFramePacketOneAckBlock) { ASSERT_TRUE(data != nullptr); test::CompareCharArraysWithHexError("constructed packet", data->data(), data->length(), AsChars(p), - arraysize(packet)); + QUIC_ARRAYSIZE(packet)); } TEST_P(QuicFramerTest, BuildAckFramePacketOneAckBlockMaxLength) { @@ -3948,7 +4099,6 @@ TEST_P(QuicFramerTest, BuildAckFramePacketOneAckBlockMaxLength) { header.packet_number = kPacketNumber; QuicAckFrame ack_frame = InitAckFrame(kPacketNumber); - FLAGS_quic_reloadable_flag_quic_frames_deque3 = true; ack_frame.ack_delay_time = QuicTime::Delta::Zero(); QuicFrames frames = {QuicFrame(&ack_frame)}; @@ -4018,13 +4168,13 @@ TEST_P(QuicFramerTest, BuildAckFramePacketOneAckBlockMaxLength) { }; // clang-format on unsigned char* p = packet; - size_t packet_size = arraysize(packet); + size_t packet_size = QUIC_ARRAYSIZE(packet); if (framer_.transport_version() > QUIC_VERSION_39) { p = packet41; - packet_size = arraysize(packet41); + packet_size = QUIC_ARRAYSIZE(packet41); } else if (framer_.transport_version() > QUIC_VERSION_38) { p = packet39; - packet_size = arraysize(packet39); + packet_size = QUIC_ARRAYSIZE(packet39); } std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); @@ -4180,7 +4330,7 @@ TEST_P(QuicFramerTest, BuildAckFramePacketMultipleAckBlocks) { test::CompareCharArraysWithHexError("constructed packet", data->data(), data->length(), AsChars(p), - arraysize(packet)); + QUIC_ARRAYSIZE(packet)); } TEST_P(QuicFramerTest, BuildAckFramePacketMaxAckBlocks) { @@ -4192,7 +4342,7 @@ TEST_P(QuicFramerTest, BuildAckFramePacketMaxAckBlocks) { // Use kSmallLargestObservedto make this test finished in a short time. QuicAckFrame ack_frame; - ack_frame.deprecated_largest_observed = kSmallLargestObserved; + ack_frame.largest_acked = kSmallLargestObserved; ack_frame.ack_delay_time = QuicTime::Delta::Zero(); // 300 ack blocks. for (size_t i = 2; i < 2 * 300; i += 2) { @@ -4494,7 +4644,7 @@ TEST_P(QuicFramerTest, BuildAckFramePacketMaxAckBlocks) { test::CompareCharArraysWithHexError("constructed packet", data->data(), data->length(), AsChars(p), - arraysize(packet)); + QUIC_ARRAYSIZE(packet)); } TEST_P(QuicFramerTest, BuildNewStopWaitingPacket) { @@ -4548,7 +4698,7 @@ TEST_P(QuicFramerTest, BuildNewStopWaitingPacket) { "constructed packet", data->data(), data->length(), AsChars(framer_.transport_version() <= QUIC_VERSION_38 ? packet : packet39), - arraysize(packet)); + QUIC_ARRAYSIZE(packet)); } TEST_P(QuicFramerTest, BuildRstFramePacketQuic) { @@ -4636,11 +4786,11 @@ TEST_P(QuicFramerTest, BuildRstFramePacketQuic) { } else if (framer_.transport_version() > QUIC_VERSION_38) { p = packet39; } - QuicEncryptedPacket encrypted(AsChars(p), arraysize(packet), false); + QuicEncryptedPacket encrypted(AsChars(p), QUIC_ARRAYSIZE(packet), false); test::CompareCharArraysWithHexError("constructed packet", data->data(), data->length(), AsChars(p), - arraysize(packet)); + QUIC_ARRAYSIZE(packet)); } TEST_P(QuicFramerTest, BuildCloseFramePacket) { @@ -4709,11 +4859,10 @@ TEST_P(QuicFramerTest, BuildCloseFramePacket) { "constructed packet", data->data(), data->length(), AsChars(framer_.transport_version() <= QUIC_VERSION_38 ? packet : packet39), - arraysize(packet)); + QUIC_ARRAYSIZE(packet)); } TEST_P(QuicFramerTest, BuildTruncatedCloseFramePacket) { - FLAGS_quic_reloadable_flag_quic_truncate_long_details = true; QuicPacketHeader header; header.connection_id = kConnectionId; header.reset_flag = false; @@ -4829,10 +4978,10 @@ TEST_P(QuicFramerTest, BuildTruncatedCloseFramePacket) { // clang-format on unsigned char* p = packet; - size_t packet_size = arraysize(packet); + size_t packet_size = QUIC_ARRAYSIZE(packet); if (framer_.transport_version() > QUIC_VERSION_38) { p = packet39; - packet_size = arraysize(packet39); + packet_size = QUIC_ARRAYSIZE(packet39); } std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); @@ -4913,11 +5062,10 @@ TEST_P(QuicFramerTest, BuildGoAwayPacket) { "constructed packet", data->data(), data->length(), AsChars(framer_.transport_version() <= QUIC_VERSION_38 ? packet : packet39), - arraysize(packet)); + QUIC_ARRAYSIZE(packet)); } TEST_P(QuicFramerTest, BuildTruncatedGoAwayPacket) { - FLAGS_quic_reloadable_flag_quic_truncate_long_details = true; QuicPacketHeader header; header.connection_id = kConnectionId; header.reset_flag = false; @@ -5038,10 +5186,10 @@ TEST_P(QuicFramerTest, BuildTruncatedGoAwayPacket) { // clang-format on unsigned char* p = packet; - size_t packet_size = arraysize(packet); + size_t packet_size = QUIC_ARRAYSIZE(packet); if (framer_.transport_version() > QUIC_VERSION_38) { p = packet39; - packet_size = arraysize(packet39); + packet_size = QUIC_ARRAYSIZE(packet39); } std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); @@ -5109,7 +5257,7 @@ TEST_P(QuicFramerTest, BuildWindowUpdatePacket) { "constructed packet", data->data(), data->length(), AsChars(framer_.transport_version() <= QUIC_VERSION_38 ? packet : packet39), - arraysize(packet)); + QUIC_ARRAYSIZE(packet)); } TEST_P(QuicFramerTest, BuildBlockedPacket) { @@ -5163,7 +5311,7 @@ TEST_P(QuicFramerTest, BuildBlockedPacket) { "constructed packet", data->data(), data->length(), AsChars(framer_.transport_version() <= QUIC_VERSION_38 ? packet : packet39), - arraysize(packet)); + QUIC_ARRAYSIZE(packet)); } TEST_P(QuicFramerTest, BuildPingPacket) { @@ -5210,7 +5358,7 @@ TEST_P(QuicFramerTest, BuildPingPacket) { "constructed packet", data->data(), data->length(), AsChars(framer_.transport_version() <= QUIC_VERSION_38 ? packet : packet39), - arraysize(packet)); + QUIC_ARRAYSIZE(packet)); } // Test that the connectivity probing packet is serialized correctly as a @@ -5257,10 +5405,10 @@ TEST_P(QuicFramerTest, BuildConnectivityProbingPacket) { // clang-format on unsigned char* p = packet; - size_t packet_size = arraysize(packet); + size_t packet_size = QUIC_ARRAYSIZE(packet); if (framer_.transport_version() > QUIC_VERSION_38) { p = packet39; - packet_size = arraysize(packet39); + packet_size = QUIC_ARRAYSIZE(packet39); } std::unique_ptr<char[]> buffer(new char[kMaxPacketSize]); @@ -5277,7 +5425,7 @@ TEST_P(QuicFramerTest, BuildConnectivityProbingPacket) { "constructed packet", data.data(), data.length(), AsChars(framer_.transport_version() <= QUIC_VERSION_38 ? packet : packet39), - arraysize(packet)); + QUIC_ARRAYSIZE(packet)); } // Test that the MTU discovery packet is serialized correctly as a PING packet. @@ -5325,7 +5473,7 @@ TEST_P(QuicFramerTest, BuildMtuDiscoveryPacket) { "constructed packet", data->data(), data->length(), AsChars(framer_.transport_version() <= QUIC_VERSION_38 ? packet : packet39), - arraysize(packet)); + QUIC_ARRAYSIZE(packet)); } TEST_P(QuicFramerTest, BuildPublicResetPacket) { @@ -5358,7 +5506,7 @@ TEST_P(QuicFramerTest, BuildPublicResetPacket) { ASSERT_TRUE(data != nullptr); test::CompareCharArraysWithHexError("constructed packet", data->data(), data->length(), AsChars(packet), - arraysize(packet)); + QUIC_ARRAYSIZE(packet)); } TEST_P(QuicFramerTest, BuildPublicResetPacketWithClientAddress) { @@ -5403,7 +5551,7 @@ TEST_P(QuicFramerTest, BuildPublicResetPacketWithClientAddress) { test::CompareCharArraysWithHexError("constructed packet", data->data(), data->length(), AsChars(packet), - arraysize(packet)); + QUIC_ARRAYSIZE(packet)); } TEST_P(QuicFramerTest, EncryptPacket) { @@ -5445,8 +5593,9 @@ TEST_P(QuicFramerTest, EncryptPacket) { std::unique_ptr<QuicPacket> raw(new QuicPacket( AsChars(framer_.transport_version() <= QUIC_VERSION_38 ? packet : packet39), - arraysize(packet), false, PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, - !kIncludeDiversificationNonce, PACKET_6BYTE_PACKET_NUMBER)); + QUIC_ARRAYSIZE(packet), false, PACKET_8BYTE_CONNECTION_ID, + !kIncludeVersion, !kIncludeDiversificationNonce, + PACKET_6BYTE_PACKET_NUMBER)); char buffer[kMaxPacketSize]; size_t encrypted_length = framer_.EncryptPayload( ENCRYPTION_NONE, packet_number, *raw, buffer, kMaxPacketSize); @@ -5498,8 +5647,9 @@ TEST_P(QuicFramerTest, EncryptPacketWithVersionFlag) { std::unique_ptr<QuicPacket> raw(new QuicPacket( AsChars(framer_.transport_version() <= QUIC_VERSION_38 ? packet : packet39), - arraysize(packet), false, PACKET_8BYTE_CONNECTION_ID, kIncludeVersion, - !kIncludeDiversificationNonce, PACKET_6BYTE_PACKET_NUMBER)); + QUIC_ARRAYSIZE(packet), false, PACKET_8BYTE_CONNECTION_ID, + kIncludeVersion, !kIncludeDiversificationNonce, + PACKET_6BYTE_PACKET_NUMBER)); char buffer[kMaxPacketSize]; size_t encrypted_length = framer_.EncryptPayload( ENCRYPTION_NONE, packet_number, *raw, buffer, kMaxPacketSize); @@ -5743,7 +5893,7 @@ TEST_P(QuicFramerTest, StopPacketProcessing) { } else if (framer_.transport_version() > QUIC_VERSION_38) { p = packet39; } - QuicEncryptedPacket encrypted(AsChars(p), arraysize(packet), false); + QuicEncryptedPacket encrypted(AsChars(p), QUIC_ARRAYSIZE(packet), false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); } @@ -5767,8 +5917,8 @@ TEST_P(QuicFramerTest, ConstructEncryptedPacket) { new NullDecrypter(framer_.perspective())); framer_.SetEncrypter(ENCRYPTION_NONE, new NullEncrypter(framer_.perspective())); - QuicTransportVersionVector versions; - versions.push_back(framer_.transport_version()); + ParsedQuicVersionVector versions; + versions.push_back(framer_.version()); std::unique_ptr<QuicEncryptedPacket> packet(ConstructEncryptedPacket( 42, false, false, kTestQuicStreamId, kTestString, PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER, &versions)); @@ -5803,8 +5953,8 @@ TEST_P(QuicFramerTest, ConstructMisFramedEncryptedPacket) { new NullDecrypter(framer_.perspective())); framer_.SetEncrypter(ENCRYPTION_NONE, new NullEncrypter(framer_.perspective())); - QuicTransportVersionVector versions; - versions.push_back(framer_.transport_version()); + ParsedQuicVersionVector versions; + versions.push_back(framer_.version()); std::unique_ptr<QuicEncryptedPacket> packet(ConstructMisFramedEncryptedPacket( 42, false, false, kTestQuicStreamId, kTestString, PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER, &versions, @@ -5838,7 +5988,7 @@ extern "C" { // target function to be fuzzed by Dr. Fuzz void QuicFramerFuzzFunc(unsigned char* data, size_t size) { - QuicFramer framer(AllSupportedTransportVersions(), QuicTime::Zero(), + QuicFramer framer(AllSupportedVersions(), QuicTime::Zero(), Perspective::IS_SERVER); const char* const packet_bytes = reinterpret_cast<const char*>(data); @@ -5945,7 +6095,7 @@ TEST_P(QuicFramerTest, FramerFuzzTest) { } else if (framer_.transport_version() > QUIC_VERSION_38) { p = packet39; } - QuicFramerFuzzFunc(p, arraysize(packet)); + QuicFramerFuzzFunc(p, QUIC_ARRAYSIZE(packet)); } TEST_P(QuicFramerTest, StartsWithChlo) { diff --git a/chromium/net/quic/core/quic_headers_stream.cc b/chromium/net/quic/core/quic_headers_stream.cc index 68e2b5a6fd4..5f7276d4b8e 100644 --- a/chromium/net/quic/core/quic_headers_stream.cc +++ b/chromium/net/quic/core/quic_headers_stream.cc @@ -5,6 +5,7 @@ #include "net/quic/core/quic_headers_stream.h" #include "net/quic/core/quic_spdy_session.h" +#include "net/quic/platform/api/quic_arraysize.h" #include "net/quic/platform/api/quic_flag_utils.h" #include "net/quic/platform/api/quic_flags.h" @@ -38,7 +39,7 @@ void QuicHeadersStream::OnDataAvailable() { QuicTime timestamp(QuicTime::Zero()); while (true) { iov.iov_base = buffer; - iov.iov_len = arraysize(buffer); + iov.iov_len = QUIC_ARRAYSIZE(buffer); if (!sequencer()->GetReadableRegion(&iov, ×tamp)) { // No more data to read. break; @@ -111,7 +112,8 @@ void QuicHeadersStream::OnStreamFrameAcked(QuicStreamOffset offset, } void QuicHeadersStream::OnStreamFrameRetransmitted(QuicStreamOffset offset, - QuicByteCount data_length) { + QuicByteCount data_length, + bool /*fin_retransmitted*/) { for (CompressedHeaderInfo& header : unacked_headers_) { if (offset < header.headers_stream_offset) { // This header frame offset belongs to headers with smaller offset, stop diff --git a/chromium/net/quic/core/quic_headers_stream.h b/chromium/net/quic/core/quic_headers_stream.h index 9d6df38a51b..4892b0e85dc 100644 --- a/chromium/net/quic/core/quic_headers_stream.h +++ b/chromium/net/quic/core/quic_headers_stream.h @@ -44,7 +44,8 @@ class QUIC_EXPORT_PRIVATE QuicHeadersStream : public QuicStream { QuicTime::Delta ack_delay_time) override; void OnStreamFrameRetransmitted(QuicStreamOffset offset, - QuicByteCount data_length) override; + QuicByteCount data_length, + bool fin_retransmitted) override; private: friend class test::QuicHeadersStreamPeer; diff --git a/chromium/net/quic/core/quic_headers_stream_test.cc b/chromium/net/quic/core/quic_headers_stream_test.cc index 616c8368d9b..cc5ca02babe 100644 --- a/chromium/net/quic/core/quic_headers_stream_test.cc +++ b/chromium/net/quic/core/quic_headers_stream_test.cc @@ -133,28 +133,36 @@ class ForceHolAckListener : public QuicAckListenerInterface { DISALLOW_COPY_AND_ASSIGN(ForceHolAckListener); }; -typedef testing::tuple<QuicTransportVersion, Perspective> TestParamsTuple; - struct TestParams { - explicit TestParams(TestParamsTuple params) - : version(testing::get<0>(params)), perspective(testing::get<1>(params)) { - QUIC_LOG(INFO) << "TestParams: version: " << QuicVersionToString(version) + TestParams(const ParsedQuicVersion& version, Perspective perspective) + : version(version), perspective(perspective) { + QUIC_LOG(INFO) << "TestParams: version: " + << ParsedQuicVersionToString(version) << ", perspective: " << perspective; } - QuicTransportVersion version; + TestParams(const TestParams& other) + : version(other.version), perspective(other.perspective) {} + + ParsedQuicVersion version; Perspective perspective; }; -class QuicHeadersStreamTest : public QuicTestWithParam<TestParamsTuple> { +std::vector<TestParams> GetTestParams() { + std::vector<TestParams> params; + ParsedQuicVersionVector all_supported_versions = AllSupportedVersions(); + for (size_t i = 0; i < all_supported_versions.size(); ++i) { + for (Perspective p : {Perspective::IS_SERVER, Perspective::IS_CLIENT}) { + params.emplace_back(all_supported_versions[i], p); + } + } + return params; +} + +class QuicHeadersStreamTest : public QuicTestWithParam<TestParams> { public: - // Constructing the test_params_ object will set the necessary flags before - // the MockQuicConnection is constructed, which we need because the latter - // will construct a SpdyFramer that will use those flags to decide whether - // to construct a decoder adapter. QuicHeadersStreamTest() - : test_params_(GetParam()), - connection_(new StrictMock<MockQuicConnection>(&helper_, + : connection_(new StrictMock<MockQuicConnection>(&helper_, &alarm_factory_, perspective(), GetVersion())), @@ -250,8 +258,9 @@ class QuicHeadersStreamTest : public QuicTestWithParam<TestParamsTuple> { EXPECT_CALL(session_, WritevData(headers_stream_, kHeadersStreamId, _, _, NO_FIN)) .WillOnce(WithArgs<2>(Invoke(this, &QuicHeadersStreamTest::SaveIov))); - QuicSpdySessionPeer::WriteHeadersImpl( - &session_, stream_id, headers_.Clone(), fin, priority, nullptr); + QuicSpdySessionPeer::WriteHeadersImpl(&session_, stream_id, + headers_.Clone(), fin, priority, 0, + false, nullptr); // Parse the outgoing data and check that it matches was was written. if (is_request) { @@ -288,15 +297,15 @@ class QuicHeadersStreamTest : public QuicTestWithParam<TestParamsTuple> { headers_handler_.reset(); } - Perspective perspective() const { return test_params_.perspective; } + Perspective perspective() const { return GetParam().perspective; } QuicTransportVersion transport_version() const { - return test_params_.version; + return GetParam().version.transport_version; } - QuicTransportVersionVector GetVersion() { - QuicTransportVersionVector versions; - versions.push_back(transport_version()); + ParsedQuicVersionVector GetVersion() { + ParsedQuicVersionVector versions; + versions.push_back(GetParam().version); return versions; } @@ -311,7 +320,6 @@ class QuicHeadersStreamTest : public QuicTestWithParam<TestParamsTuple> { static const bool kFrameComplete = true; static const bool kHasPriority = true; - const TestParams test_params_; MockQuicConnectionHelper helper_; MockAlarmFactory alarm_factory_; StrictMock<MockQuicConnection>* connection_; @@ -335,12 +343,9 @@ class QuicHeadersStreamTest : public QuicTestWithParam<TestParamsTuple> { }; // Run all tests with each version, perspective (client or server).. -INSTANTIATE_TEST_CASE_P( - Tests, - QuicHeadersStreamTest, - ::testing::Combine(::testing::ValuesIn(AllSupportedTransportVersions()), - ::testing::Values(Perspective::IS_CLIENT, - Perspective::IS_SERVER))); +INSTANTIATE_TEST_CASE_P(Tests, + QuicHeadersStreamTest, + ::testing::ValuesIn(GetTestParams())); TEST_P(QuicHeadersStreamTest, StreamId) { EXPECT_EQ(3u, headers_stream_->id()); @@ -460,7 +465,7 @@ TEST_P(QuicHeadersStreamTest, ProcessPushPromise) { } TEST_P(QuicHeadersStreamTest, ProcessPushPromiseDisabledSetting) { - FLAGS_quic_reloadable_flag_quic_respect_http2_settings_frame = true; + SetQuicReloadableFlag(quic_respect_http2_settings_frame, true); session_.OnConfigNegotiated(); SpdySettingsIR data; // Respect supported settings frames SETTINGS_ENABLE_PUSH. @@ -629,7 +634,7 @@ TEST_P(QuicHeadersStreamTest, ProcessSpdyRstStreamFrame) { } TEST_P(QuicHeadersStreamTest, ProcessSpdySettingsFrame) { - FLAGS_quic_reloadable_flag_quic_respect_http2_settings_frame = false; + SetQuicReloadableFlag(quic_respect_http2_settings_frame, false); SpdySettingsIR data; data.AddSetting(SETTINGS_HEADER_TABLE_SIZE, 0); SpdySerializedFrame frame(framer_->SerializeFrame(data)); @@ -643,8 +648,8 @@ TEST_P(QuicHeadersStreamTest, ProcessSpdySettingsFrame) { } TEST_P(QuicHeadersStreamTest, RespectHttp2SettingsFrameSupportedFields) { - FLAGS_quic_reloadable_flag_quic_respect_http2_settings_frame = true; - FLAGS_quic_reloadable_flag_quic_send_max_header_list_size = true; + SetQuicReloadableFlag(quic_respect_http2_settings_frame, true); + SetQuicReloadableFlag(quic_send_max_header_list_size, true); const uint32_t kTestHeaderTableSize = 1000; SpdySettingsIR data; // Respect supported settings frames SETTINGS_HEADER_TABLE_SIZE, @@ -660,8 +665,8 @@ TEST_P(QuicHeadersStreamTest, RespectHttp2SettingsFrameSupportedFields) { } TEST_P(QuicHeadersStreamTest, RespectHttp2SettingsFrameUnsupportedFields) { - FLAGS_quic_reloadable_flag_quic_respect_http2_settings_frame = true; - FLAGS_quic_reloadable_flag_quic_send_max_header_list_size = true; + SetQuicReloadableFlag(quic_respect_http2_settings_frame, true); + SetQuicReloadableFlag(quic_send_max_header_list_size, true); SpdySettingsIR data; // Does not support SETTINGS_MAX_CONCURRENT_STREAMS, // SETTINGS_INITIAL_WINDOW_SIZE, SETTINGS_ENABLE_PUSH and @@ -835,8 +840,8 @@ TEST_P(QuicHeadersStreamTest, HpackEncoderDebugVisitor) { TEST_P(QuicHeadersStreamTest, AckSentData) { EXPECT_CALL(session_, WritevData(headers_stream_, kHeadersStreamId, _, _, NO_FIN)) - .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData)); - if (!FLAGS_quic_reloadable_flag_quic_allow_multiple_acks_for_data2) { + .WillRepeatedly(Invoke(MockQuicSession::ConsumeData)); + if (!GetQuicReloadableFlag(quic_allow_multiple_acks_for_data2)) { EXPECT_CALL(*connection_, CloseConnection(QUIC_INTERNAL_ERROR, _, _)); } InSequence s; @@ -862,8 +867,8 @@ TEST_P(QuicHeadersStreamTest, AckSentData) { // Packet 2 gets retransmitted. EXPECT_CALL(*ack_listener3, OnPacketRetransmitted(7)).Times(1); EXPECT_CALL(*ack_listener2, OnPacketRetransmitted(7)).Times(1); - headers_stream_->OnStreamFrameRetransmitted(21, 7); - headers_stream_->OnStreamFrameRetransmitted(28, 7); + headers_stream_->OnStreamFrameRetransmitted(21, 7, false); + headers_stream_->OnStreamFrameRetransmitted(28, 7, false); // Packets are acked in order: 2, 3, 1. EXPECT_CALL(*ack_listener3, OnPacketAcked(7, _)); @@ -880,7 +885,7 @@ TEST_P(QuicHeadersStreamTest, AckSentData) { headers_stream_->OnStreamFrameAcked(7, 7, false, QuicTime::Delta::Zero()); // Unsent data is acked. EXPECT_CALL(*ack_listener2, OnPacketAcked(7, _)); - if (FLAGS_quic_reloadable_flag_quic_allow_multiple_acks_for_data2) { + if (GetQuicReloadableFlag(quic_allow_multiple_acks_for_data2)) { headers_stream_->OnStreamFrameAcked(14, 10, false, QuicTime::Delta::Zero()); } else { EXPECT_QUIC_BUG(headers_stream_->OnStreamFrameAcked( @@ -893,7 +898,7 @@ TEST_P(QuicHeadersStreamTest, FrameContainsMultipleHeaders) { // In this test, a stream frame can contain multiple headers. EXPECT_CALL(session_, WritevData(headers_stream_, kHeadersStreamId, _, _, NO_FIN)) - .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData)); + .WillRepeatedly(Invoke(MockQuicSession::ConsumeData)); InSequence s; QuicReferenceCountedPointer<MockAckListener> ack_listener1( new MockAckListener()); @@ -912,7 +917,7 @@ TEST_P(QuicHeadersStreamTest, FrameContainsMultipleHeaders) { // Frame 1 is retransmitted. EXPECT_CALL(*ack_listener1, OnPacketRetransmitted(14)); EXPECT_CALL(*ack_listener2, OnPacketRetransmitted(3)); - headers_stream_->OnStreamFrameRetransmitted(0, 17); + headers_stream_->OnStreamFrameRetransmitted(0, 17, false); // Frames are acked in order: 2, 3, 1. EXPECT_CALL(*ack_listener2, OnPacketAcked(4, _)); @@ -930,12 +935,12 @@ TEST_P(QuicHeadersStreamTest, FrameContainsMultipleHeaders) { } TEST_P(QuicHeadersStreamTest, HeadersGetAckedMultipleTimes) { - if (!FLAGS_quic_reloadable_flag_quic_allow_multiple_acks_for_data2) { + if (!GetQuicReloadableFlag(quic_allow_multiple_acks_for_data2)) { return; } EXPECT_CALL(session_, WritevData(headers_stream_, kHeadersStreamId, _, _, NO_FIN)) - .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData)); + .WillRepeatedly(Invoke(MockQuicSession::ConsumeData)); InSequence s; QuicReferenceCountedPointer<MockAckListener> ack_listener1( new MockAckListener()); diff --git a/chromium/net/quic/core/quic_packet_creator.cc b/chromium/net/quic/core/quic_packet_creator.cc index a9056cf03c4..bc52f7dd25f 100644 --- a/chromium/net/quic/core/quic_packet_creator.cc +++ b/chromium/net/quic/core/quic_packet_creator.cc @@ -12,6 +12,7 @@ #include "net/quic/core/quic_data_writer.h" #include "net/quic/core/quic_utils.h" #include "net/quic/platform/api/quic_aligned.h" +#include "net/quic/platform/api/quic_arraysize.h" #include "net/quic/platform/api/quic_bug_tracker.h" #include "net/quic/platform/api/quic_flag_utils.h" #include "net/quic/platform/api/quic_flags.h" @@ -302,7 +303,7 @@ void QuicPacketCreator::CreateAndSerializeStreamFrame( QuicPacketHeader header; FillPacketHeader(&header); QUIC_CACHELINE_ALIGNED char encrypted_buffer[kMaxPacketSize]; - QuicDataWriter writer(arraysize(encrypted_buffer), encrypted_buffer, + QuicDataWriter writer(QUIC_ARRAYSIZE(encrypted_buffer), encrypted_buffer, framer_->endianness()); if (!framer_->AppendPacketHeader(header, &writer)) { QUIC_BUG << "AppendPacketHeader failed"; @@ -343,7 +344,7 @@ void QuicPacketCreator::CreateAndSerializeStreamFrame( size_t encrypted_length = framer_->EncryptInPlace( packet_.encryption_level, packet_.packet_number, GetStartOfEncryptedData(framer_->transport_version(), header), - writer.length(), arraysize(encrypted_buffer), encrypted_buffer); + writer.length(), QUIC_ARRAYSIZE(encrypted_buffer), encrypted_buffer); if (encrypted_length == 0) { QUIC_BUG << "Failed to encrypt packet number " << header.packet_number; return; @@ -462,7 +463,7 @@ void QuicPacketCreator::SerializePacket(char* encrypted_buffer, std::unique_ptr<QuicEncryptedPacket> QuicPacketCreator::SerializeVersionNegotiationPacket( - const QuicTransportVersionVector& supported_versions) { + const ParsedQuicVersionVector& supported_versions) { DCHECK_EQ(Perspective::IS_SERVER, framer_->perspective()); std::unique_ptr<QuicEncryptedPacket> encrypted = QuicFramer::BuildVersionNegotiationPacket(connection_id_, @@ -480,7 +481,7 @@ QuicPacketCreator::SerializeConnectivityProbingPacket() { std::unique_ptr<char[]> buffer(new char[kMaxPacketSize]); size_t length = framer_->BuildConnectivityProbingPacket(header, buffer.get(), - max_packet_length_); + max_plaintext_size_); DCHECK(length); const size_t encrypted_length = framer_->EncryptInPlace( diff --git a/chromium/net/quic/core/quic_packet_creator.h b/chromium/net/quic/core/quic_packet_creator.h index 8888e749906..c73cbd8efab 100644 --- a/chromium/net/quic/core/quic_packet_creator.h +++ b/chromium/net/quic/core/quic_packet_creator.h @@ -154,7 +154,7 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { // Creates a version negotiation packet which supports |supported_versions|. std::unique_ptr<QuicEncryptedPacket> SerializeVersionNegotiationPacket( - const QuicTransportVersionVector& supported_versions); + const ParsedQuicVersionVector& supported_versions); // Creates a connectivity probing packet. std::unique_ptr<QuicEncryptedPacket> SerializeConnectivityProbingPacket(); diff --git a/chromium/net/quic/core/quic_packet_creator_test.cc b/chromium/net/quic/core/quic_packet_creator_test.cc index 543d088da70..e8a6d6afa7b 100644 --- a/chromium/net/quic/core/quic_packet_creator_test.cc +++ b/chromium/net/quic/core/quic_packet_creator_test.cc @@ -39,27 +39,26 @@ namespace { const QuicStreamId kGetNthClientInitiatedStreamId1 = kHeadersStreamId + 2; -// Run tests with combinations of {QuicTransportVersion, +// Run tests with combinations of {ParsedQuicVersion, // ToggleVersionSerialization}. struct TestParams { - TestParams(QuicTransportVersion version, bool version_serialization) + TestParams(ParsedQuicVersion version, bool version_serialization) : version(version), version_serialization(version_serialization) {} friend std::ostream& operator<<(std::ostream& os, const TestParams& p) { - os << "{ version: " << QuicVersionToString(p.version) + os << "{ version: " << ParsedQuicVersionToString(p.version) << " include version: " << p.version_serialization << " }"; return os; } - QuicTransportVersion version; + ParsedQuicVersion version; bool version_serialization; }; // Constructs various test permutations. std::vector<TestParams> GetTestParams() { std::vector<TestParams> params; - QuicTransportVersionVector all_supported_versions = - AllSupportedTransportVersions(); + ParsedQuicVersionVector all_supported_versions = AllSupportedVersions(); for (size_t i = 0; i < all_supported_versions.size(); ++i) { params.push_back(TestParams(all_supported_versions[i], true)); params.push_back(TestParams(all_supported_versions[i], false)); @@ -127,18 +126,15 @@ class QuicPacketCreatorTest : public QuicTestWithParam<TestParams> { protected: QuicPacketCreatorTest() - : server_framer_(SupportedTransportVersions(GetParam().version), + : server_framer_(SupportedVersions(GetParam().version), QuicTime::Zero(), Perspective::IS_SERVER), - client_framer_(SupportedTransportVersions(GetParam().version), + client_framer_(SupportedVersions(GetParam().version), QuicTime::Zero(), Perspective::IS_CLIENT), connection_id_(2), data_("foo"), - creator_(connection_id_, - &client_framer_, - &delegate_, - &producer_), + creator_(connection_id_, &client_framer_, &delegate_, &producer_), serialized_packet_(creator_.NoPacket()) { creator_.SetEncrypter(ENCRYPTION_INITIAL, new NullEncrypter(Perspective::IS_CLIENT)); @@ -663,7 +659,7 @@ TEST_P(QuicPacketCreatorTest, NonCryptoStreamFramePacketNonPadding) { TEST_P(QuicPacketCreatorTest, SerializeVersionNegotiationPacket) { QuicFramerPeer::SetPerspective(&client_framer_, Perspective::IS_SERVER); - QuicTransportVersionVector versions; + ParsedQuicVersionVector versions; versions.push_back(test::QuicVersionMax()); std::unique_ptr<QuicEncryptedPacket> encrypted( creator_.SerializeVersionNegotiationPacket(versions)); @@ -724,7 +720,7 @@ TEST_P(QuicPacketCreatorTest, UpdatePacketSequenceNumberLengthLeastAwaiting) { QuicPacketCreatorPeer::SetPacketNumber(&creator_, UINT64_C(64) * 256 * 256 * 256 * 256); creator_.UpdatePacketNumberLength(2, 10000 / kDefaultMaxPacketSize); - if (GetParam().version <= QUIC_VERSION_39) { + if (GetParam().version.transport_version <= QUIC_VERSION_39) { EXPECT_EQ(PACKET_6BYTE_PACKET_NUMBER, QuicPacketCreatorPeer::GetPacketNumberLength(&creator_)); } else { @@ -752,7 +748,7 @@ TEST_P(QuicPacketCreatorTest, UpdatePacketSequenceNumberLengthCwnd) { creator_.UpdatePacketNumberLength( 1, UINT64_C(1000) * 256 * 256 * 256 * 256 / kDefaultMaxPacketSize); - if (GetParam().version <= QUIC_VERSION_39) { + if (GetParam().version.transport_version <= QUIC_VERSION_39) { EXPECT_EQ(PACKET_6BYTE_PACKET_NUMBER, QuicPacketCreatorPeer::GetPacketNumberLength(&creator_)); } else { diff --git a/chromium/net/quic/core/quic_packet_generator.cc b/chromium/net/quic/core/quic_packet_generator.cc index e74edcf71ef..2274d32f111 100644 --- a/chromium/net/quic/core/quic_packet_generator.cc +++ b/chromium/net/quic/core/quic_packet_generator.cc @@ -309,7 +309,7 @@ void QuicPacketGenerator::SetMaxPacketLength(QuicByteCount length) { std::unique_ptr<QuicEncryptedPacket> QuicPacketGenerator::SerializeVersionNegotiationPacket( - const QuicTransportVersionVector& supported_versions) { + const ParsedQuicVersionVector& supported_versions) { return packet_creator_.SerializeVersionNegotiationPacket(supported_versions); } diff --git a/chromium/net/quic/core/quic_packet_generator.h b/chromium/net/quic/core/quic_packet_generator.h index 74a3d9c70be..d3f1473a95a 100644 --- a/chromium/net/quic/core/quic_packet_generator.h +++ b/chromium/net/quic/core/quic_packet_generator.h @@ -137,7 +137,7 @@ class QUIC_EXPORT_PRIVATE QuicPacketGenerator { // Creates a version negotiation packet which supports |supported_versions|. std::unique_ptr<QuicEncryptedPacket> SerializeVersionNegotiationPacket( - const QuicTransportVersionVector& supported_versions); + const ParsedQuicVersionVector& supported_versions); // Creates a connectivity probing packet. std::unique_ptr<QuicEncryptedPacket> SerializeConnectivityProbingPacket(); diff --git a/chromium/net/quic/core/quic_packet_generator_test.cc b/chromium/net/quic/core/quic_packet_generator_test.cc index 8cc2be7b10c..e24df72a8d3 100644 --- a/chromium/net/quic/core/quic_packet_generator_test.cc +++ b/chromium/net/quic/core/quic_packet_generator_test.cc @@ -149,14 +149,10 @@ class TestPacketGenerator : public QuicPacketGenerator { class QuicPacketGeneratorTest : public QuicTest { public: QuicPacketGeneratorTest() - : framer_(AllSupportedTransportVersions(), + : framer_(AllSupportedVersions(), QuicTime::Zero(), Perspective::IS_CLIENT), - generator_(42, - &framer_, - &random_generator_, - &delegate_, - &producer_), + generator_(42, &framer_, &random_generator_, &delegate_, &producer_), creator_(QuicPacketGeneratorPeer::GetPacketCreator(&generator_)) { creator_->SetEncrypter(ENCRYPTION_FORWARD_SECURE, new NullEncrypter(Perspective::IS_CLIENT)); @@ -1074,14 +1070,7 @@ TEST_F(QuicPacketGeneratorTest, ConnectionCloseFrameLargerThanPacketSize) { char buf[2000] = {}; QuicStringPiece error_details(buf, 2000); frame->error_details = error_details.as_string(); - if (FLAGS_quic_reloadable_flag_quic_truncate_long_details) { - generator_.AddControlFrame(QuicFrame(frame)); - } else { - EXPECT_CALL(delegate_, OnUnrecoverableError( - QUIC_FAILED_TO_SERIALIZE_PACKET, - "Single frame cannot fit into a packet", _)); - EXPECT_QUIC_BUG(generator_.AddControlFrame(QuicFrame(frame)), ""); - } + generator_.AddControlFrame(QuicFrame(frame)); EXPECT_TRUE(generator_.HasQueuedFrames()); EXPECT_TRUE(generator_.HasRetransmittableFrames()); } diff --git a/chromium/net/quic/core/quic_packets.cc b/chromium/net/quic/core/quic_packets.cc index 2dbbedea60c..35013e0fadc 100644 --- a/chromium/net/quic/core/quic_packets.cc +++ b/chromium/net/quic/core/quic_packets.cc @@ -54,7 +54,8 @@ QuicPacketHeader::QuicPacketHeader() reset_flag(false), version_flag(false), packet_number_length(PACKET_6BYTE_PACKET_NUMBER), - version(QUIC_VERSION_UNSUPPORTED), + version( + ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED)), nonce(nullptr), packet_number(0) {} @@ -87,7 +88,7 @@ std::ostream& operator<<(std::ostream& os, const QuicPacketHeader& header) { << ", reset_flag: " << header.reset_flag << ", version_flag: " << header.version_flag; if (header.version_flag) { - os << ", version: " << QuicVersionToString(header.version); + os << ", version: " << ParsedQuicVersionToString(header.version); } if (header.nonce != nullptr) { os << ", diversification_nonce: " diff --git a/chromium/net/quic/core/quic_packets.h b/chromium/net/quic/core/quic_packets.h index df73ad88fa2..3ee5a6bd470 100644 --- a/chromium/net/quic/core/quic_packets.h +++ b/chromium/net/quic/core/quic_packets.h @@ -72,7 +72,7 @@ struct QUIC_EXPORT_PRIVATE QuicPacketHeader { bool reset_flag; bool version_flag; QuicPacketNumberLength packet_number_length; - QuicTransportVersion version; + ParsedQuicVersion version; // nonce contains an optional, 32-byte nonce value. If not included in the // packet, |nonce| will be empty. DiversificationNonce* nonce; @@ -95,7 +95,7 @@ struct QUIC_EXPORT_PRIVATE QuicVersionNegotiationPacket { ~QuicVersionNegotiationPacket(); QuicConnectionId connection_id; - QuicTransportVersionVector versions; + ParsedQuicVersionVector versions; }; class QUIC_EXPORT_PRIVATE QuicData { diff --git a/chromium/net/quic/core/quic_received_packet_manager.cc b/chromium/net/quic/core/quic_received_packet_manager.cc index b2a6cc1e653..2f01d30f944 100644 --- a/chromium/net/quic/core/quic_received_packet_manager.cc +++ b/chromium/net/quic/core/quic_received_packet_manager.cc @@ -55,7 +55,7 @@ void QuicReceivedPacketManager::RecordPacketReceived( std::max(stats_->max_time_reordering_us, reordering_time_us); } if (packet_number > LargestAcked(ack_frame_)) { - ack_frame_.deprecated_largest_observed = packet_number; + ack_frame_.largest_acked = packet_number; time_largest_observed_ = receipt_time; } ack_frame_.packets.Add(packet_number); diff --git a/chromium/net/quic/core/quic_sent_packet_manager.cc b/chromium/net/quic/core/quic_sent_packet_manager.cc index db69f08b48a..26411993fdd 100644 --- a/chromium/net/quic/core/quic_sent_packet_manager.cc +++ b/chromium/net/quic/core/quic_sent_packet_manager.cc @@ -111,11 +111,11 @@ void QuicSentPacketManager::SetFromConfig(const QuicConfig& config) { if (config.HasClientRequestedIndependentOption(kRENO, perspective_)) { SetSendAlgorithm(kRenoBytes); } else if (config.HasClientRequestedIndependentOption(kBYTE, perspective_) || - (FLAGS_quic_reloadable_flag_quic_default_to_bbr && + (GetQuicReloadableFlag(quic_default_to_bbr) && config.HasClientRequestedIndependentOption(kQBIC, perspective_))) { SetSendAlgorithm(kCubicBytes); - } else if (FLAGS_quic_reloadable_flag_quic_enable_pcc && + } else if (GetQuicReloadableFlag(quic_enable_pcc) && config.HasClientRequestedIndependentOption(kTPCC, perspective_)) { SetSendAlgorithm(kPCC); } @@ -131,6 +131,11 @@ void QuicSentPacketManager::SetFromConfig(const QuicConfig& config) { if (config.HasClientSentConnectionOption(kNTLP, perspective_)) { max_tail_loss_probes_ = 0; } + if (GetQuicReloadableFlag(quic_one_tlp) && + config.HasClientSentConnectionOption(k1TLP, perspective_)) { + QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_one_tlp, 1, 2); + max_tail_loss_probes_ = 1; + } if (config.HasClientSentConnectionOption(kTLPR, perspective_)) { enable_half_rtt_tail_loss_probe_ = true; } @@ -450,7 +455,7 @@ void QuicSentPacketManager::MarkPacketHandled(QuicPacketNumber packet_number, pending_retransmissions_.erase(newest_transmission); if (newest_transmission == packet_number) { - unacked_packets_.NotifyStreamFramesAcked(*info, ack_delay_time); + unacked_packets_.NotifyFramesAcked(*info, ack_delay_time); } else { RecordSpuriousRetransmissions(*info, packet_number); // Remove the most recent packet from flight if it's a crypto handshake @@ -461,8 +466,8 @@ void QuicSentPacketManager::MarkPacketHandled(QuicPacketNumber packet_number, // only handle nullptr encrypted packets in a special way. const QuicTransmissionInfo& newest_transmission_info = unacked_packets_.GetTransmissionInfo(newest_transmission); - unacked_packets_.NotifyStreamFramesAcked(newest_transmission_info, - ack_delay_time); + unacked_packets_.NotifyFramesAcked(newest_transmission_info, + ack_delay_time); if (HasCryptoHandshake(newest_transmission_info)) { unacked_packets_.RemoveFromInFlight(newest_transmission); } @@ -949,9 +954,9 @@ const SendAlgorithmInterface* QuicSentPacketManager::GetSendAlgorithm() const { return send_algorithm_.get(); } -void QuicSentPacketManager::SetStreamNotifier( - StreamNotifierInterface* stream_notifier) { - unacked_packets_.SetStreamNotifier(stream_notifier); +void QuicSentPacketManager::SetSessionNotifier( + SessionNotifierInterface* session_notifier) { + unacked_packets_.SetSessionNotifier(session_notifier); } } // namespace net diff --git a/chromium/net/quic/core/quic_sent_packet_manager.h b/chromium/net/quic/core/quic_sent_packet_manager.h index 673982370da..b0c974ce8ec 100644 --- a/chromium/net/quic/core/quic_sent_packet_manager.h +++ b/chromium/net/quic/core/quic_sent_packet_manager.h @@ -229,7 +229,7 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager { const SendAlgorithmInterface* GetSendAlgorithm() const; - void SetStreamNotifier(StreamNotifierInterface* stream_notifier); + void SetSessionNotifier(SessionNotifierInterface* session_notifier); QuicPacketNumber largest_packet_peer_knows_is_acked() const { return largest_packet_peer_knows_is_acked_; diff --git a/chromium/net/quic/core/quic_sent_packet_manager_test.cc b/chromium/net/quic/core/quic_sent_packet_manager_test.cc index 25e7a78fc47..8b7071714f7 100644 --- a/chromium/net/quic/core/quic_sent_packet_manager_test.cc +++ b/chromium/net/quic/core/quic_sent_packet_manager_test.cc @@ -7,6 +7,7 @@ #include <memory> #include "net/quic/core/quic_pending_retransmission.h" +#include "net/quic/platform/api/quic_arraysize.h" #include "net/quic/platform/api/quic_flags.h" #include "net/quic/platform/api/quic_ptr_util.h" #include "net/quic/platform/api/quic_string_piece.h" @@ -255,9 +256,10 @@ TEST_F(QuicSentPacketManagerTest, IsUnacked) { SendDataPacket(1); QuicPacketNumber unacked[] = {1}; - VerifyUnackedPackets(unacked, arraysize(unacked)); + VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); QuicPacketNumber retransmittable[] = {1}; - VerifyRetransmittablePackets(retransmittable, arraysize(retransmittable)); + VerifyRetransmittablePackets(retransmittable, + QUIC_ARRAYSIZE(retransmittable)); } TEST_F(QuicSentPacketManagerTest, IsUnAckedRetransmit) { @@ -266,9 +268,10 @@ TEST_F(QuicSentPacketManagerTest, IsUnAckedRetransmit) { EXPECT_TRUE(QuicSentPacketManagerPeer::IsRetransmission(&manager_, 2)); QuicPacketNumber unacked[] = {1, 2}; - VerifyUnackedPackets(unacked, arraysize(unacked)); + VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); QuicPacketNumber retransmittable[] = {2}; - VerifyRetransmittablePackets(retransmittable, arraysize(retransmittable)); + VerifyRetransmittablePackets(retransmittable, + QUIC_ARRAYSIZE(retransmittable)); } TEST_F(QuicSentPacketManagerTest, RetransmitThenAck) { @@ -283,7 +286,7 @@ TEST_F(QuicSentPacketManagerTest, RetransmitThenAck) { // Packet 1 is unacked, pending, but not retransmittable. QuicPacketNumber unacked[] = {1}; - VerifyUnackedPackets(unacked, arraysize(unacked)); + VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); EXPECT_TRUE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_)); VerifyRetransmittablePackets(nullptr, 0); } @@ -320,7 +323,7 @@ TEST_F(QuicSentPacketManagerTest, RetransmitThenStopRetransmittingBeforeSend) { EXPECT_FALSE(manager_.HasPendingRetransmissions()); QuicPacketNumber unacked[] = {1}; - VerifyUnackedPackets(unacked, arraysize(unacked)); + VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); VerifyRetransmittablePackets(nullptr, 0); EXPECT_EQ(0u, stats_.packets_spuriously_retransmitted); } @@ -338,7 +341,7 @@ TEST_F(QuicSentPacketManagerTest, RetransmitThenAckPrevious) { // 2 remains unacked, but no packets have retransmittable data. QuicPacketNumber unacked[] = {2}; - VerifyUnackedPackets(unacked, arraysize(unacked)); + VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); EXPECT_TRUE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_)); VerifyRetransmittablePackets(nullptr, 0); @@ -406,7 +409,7 @@ TEST_F(QuicSentPacketManagerTest, // Since 2 was marked for retransmit, when 1 is acked, 2 is kept for RTT. QuicPacketNumber unacked[] = {2}; - VerifyUnackedPackets(unacked, arraysize(unacked)); + VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); EXPECT_FALSE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_)); VerifyRetransmittablePackets(nullptr, 0); @@ -435,7 +438,7 @@ TEST_F(QuicSentPacketManagerTest, RetransmitTwiceThenAckFirst) { // 2 and 3 remain unacked, but no packets have retransmittable data. QuicPacketNumber unacked[] = {2, 3}; - VerifyUnackedPackets(unacked, arraysize(unacked)); + VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); EXPECT_TRUE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_)); VerifyRetransmittablePackets(nullptr, 0); @@ -443,11 +446,11 @@ TEST_F(QuicSentPacketManagerTest, RetransmitTwiceThenAckFirst) { SendDataPacket(4); ack_frame = InitAckFrame({{1, 2}, {3, 5}}); QuicPacketNumber acked[] = {3, 4}; - ExpectAcksAndLosses(true, acked, arraysize(acked), nullptr, 0); + ExpectAcksAndLosses(true, acked, QUIC_ARRAYSIZE(acked), nullptr, 0); manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow()); QuicPacketNumber unacked2[] = {2}; - VerifyUnackedPackets(unacked2, arraysize(unacked2)); + VerifyUnackedPackets(unacked2, QUIC_ARRAYSIZE(unacked2)); EXPECT_TRUE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_)); SendDataPacket(5); @@ -628,7 +631,8 @@ TEST_F(QuicSentPacketManagerTest, TailLossProbeTimeout) { ack_frame = InitAckFrame({{3, 6}}); QuicPacketNumber acked[] = {4, 5}; QuicPacketNumber lost[] = {1, 2}; - ExpectAcksAndLosses(true, acked, arraysize(acked), lost, arraysize(lost)); + ExpectAcksAndLosses(true, acked, QUIC_ARRAYSIZE(acked), lost, + QUIC_ARRAYSIZE(lost)); manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow()); EXPECT_FALSE(manager_.HasPendingRetransmissions()); @@ -732,7 +736,7 @@ TEST_F(QuicSentPacketManagerTest, CryptoHandshakeTimeout) { // Now ack the two crypto packets and the speculatively encrypted request, // and ensure the first four crypto packets get abandoned, but not lost. QuicPacketNumber acked[] = {3, 4, 5, 8, 9}; - ExpectAcksAndLosses(true, acked, arraysize(acked), nullptr, 0); + ExpectAcksAndLosses(true, acked, QUIC_ARRAYSIZE(acked), nullptr, 0); QuicAckFrame ack_frame = InitAckFrame({{3, 6}, {8, 10}}); manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow()); @@ -780,7 +784,7 @@ TEST_F(QuicSentPacketManagerTest, CryptoHandshakeTimeoutVersionNegotiation) { // Least unacked isn't raised until an ack is received, so ack the // crypto packets. QuicPacketNumber acked[] = {8, 9}; - ExpectAcksAndLosses(true, acked, arraysize(acked), nullptr, 0); + ExpectAcksAndLosses(true, acked, QUIC_ARRAYSIZE(acked), nullptr, 0); QuicAckFrame ack_frame = InitAckFrame({{8, 10}}); manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow()); EXPECT_EQ(10u, manager_.GetLeastUnacked()); @@ -807,7 +811,7 @@ TEST_F(QuicSentPacketManagerTest, CryptoHandshakeSpuriousRetransmission) { EXPECT_FALSE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_)); QuicPacketNumber unacked[] = {3}; - VerifyUnackedPackets(unacked, arraysize(unacked)); + VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); } TEST_F(QuicSentPacketManagerTest, CryptoHandshakeTimeoutUnsentDataPacket) { @@ -841,7 +845,7 @@ TEST_F(QuicSentPacketManagerTest, // version negotiation. manager_.RetransmitUnackedPackets(ALL_UNACKED_RETRANSMISSION); QuicPacketNumber unacked[] = {1, 2}; - VerifyUnackedPackets(unacked, arraysize(unacked)); + VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); EXPECT_TRUE(manager_.HasPendingRetransmissions()); EXPECT_TRUE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_)); EXPECT_FALSE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_)); @@ -868,7 +872,7 @@ TEST_F(QuicSentPacketManagerTest, manager_.NeuterUnencryptedPackets(); EXPECT_FALSE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_)); QuicPacketNumber unacked[] = {1, 2, 3}; - VerifyUnackedPackets(unacked, arraysize(unacked)); + VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); VerifyRetransmittablePackets(nullptr, 0); EXPECT_FALSE(manager_.HasPendingRetransmissions()); EXPECT_FALSE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_)); @@ -1467,6 +1471,33 @@ TEST_F(QuicSentPacketManagerTest, NegotiateNoTLPFromOptionsAtClient) { EXPECT_EQ(0u, QuicSentPacketManagerPeer::GetMaxTailLossProbes(&manager_)); } +TEST_F(QuicSentPacketManagerTest, Negotiate1TLPFromOptionsAtServer) { + SetQuicReloadableFlag(quic_one_tlp, true); + QuicConfig config; + QuicTagVector options; + + options.push_back(k1TLP); + QuicConfigPeer::SetReceivedConnectionOptions(&config, options); + EXPECT_CALL(*network_change_visitor_, OnCongestionChange()); + EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); + manager_.SetFromConfig(config); + EXPECT_EQ(1u, QuicSentPacketManagerPeer::GetMaxTailLossProbes(&manager_)); +} + +TEST_F(QuicSentPacketManagerTest, Negotiate1TLPFromOptionsAtClient) { + SetQuicReloadableFlag(quic_one_tlp, true); + QuicConfig client_config; + QuicTagVector options; + + options.push_back(k1TLP); + QuicSentPacketManagerPeer::SetPerspective(&manager_, Perspective::IS_CLIENT); + client_config.SetConnectionOptionsToSend(options); + EXPECT_CALL(*network_change_visitor_, OnCongestionChange()); + EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); + manager_.SetFromConfig(client_config); + EXPECT_EQ(1u, QuicSentPacketManagerPeer::GetMaxTailLossProbes(&manager_)); +} + TEST_F(QuicSentPacketManagerTest, NegotiateTLPRttFromOptionsAtServer) { QuicConfig config; QuicTagVector options; diff --git a/chromium/net/quic/core/quic_server_id.h b/chromium/net/quic/core/quic_server_id.h index 880afd2be9d..d7cb609b2f2 100644 --- a/chromium/net/quic/core/quic_server_id.h +++ b/chromium/net/quic/core/quic_server_id.h @@ -5,8 +5,7 @@ #ifndef NET_QUIC_CORE_QUIC_SERVER_ID_H_ #define NET_QUIC_CORE_QUIC_SERVER_ID_H_ -#include <stdint.h> - +#include <cstdint> #include <string> #include "net/base/host_port_pair.h" diff --git a/chromium/net/quic/core/quic_server_id_test.cc b/chromium/net/quic/core/quic_server_id_test.cc index abf05a3edd4..be8eeb1e79b 100644 --- a/chromium/net/quic/core/quic_server_id_test.cc +++ b/chromium/net/quic/core/quic_server_id_test.cc @@ -4,6 +4,7 @@ #include "net/quic/core/quic_server_id.h" +#include "net/quic/platform/api/quic_estimate_memory_usage.h" #include "net/quic/platform/api/quic_test.h" using std::string; @@ -26,6 +27,16 @@ TEST_F(QuicServerIdTest, ToString) { EXPECT_EQ("https://google.com:10/private", private_server_id_str); } +TEST_F(QuicServerIdTest, HostPortPair) { + HostPortPair google_host_port_pair("google.com", 10); + + QuicServerId google_server_id(google_host_port_pair, PRIVACY_MODE_DISABLED); + EXPECT_TRUE(google_host_port_pair.Equals(google_server_id.host_port_pair())); + + QuicServerId private_server_id(google_host_port_pair, PRIVACY_MODE_ENABLED); + EXPECT_TRUE(google_host_port_pair.Equals(private_server_id.host_port_pair())); +} + TEST_F(QuicServerIdTest, LessThan) { QuicServerId a_10_https(HostPortPair("a.com", 10), PRIVACY_MODE_DISABLED); QuicServerId a_11_https(HostPortPair("a.com", 11), PRIVACY_MODE_DISABLED); @@ -142,6 +153,13 @@ TEST_F(QuicServerIdTest, Equals) { EXPECT_FALSE(new_a_10_https_no_private == a_10_https_private); } +TEST_F(QuicServerIdTest, EstimateMemoryUsage) { + HostPortPair host_port_pair("this is a rather very quite long hostname", 10); + QuicServerId server_id(host_port_pair, PRIVACY_MODE_ENABLED); + EXPECT_EQ(QuicEstimateMemoryUsage(host_port_pair), + QuicEstimateMemoryUsage(server_id)); +} + } // namespace } // namespace net diff --git a/chromium/net/quic/core/quic_server_session_base_test.cc b/chromium/net/quic/core/quic_server_session_base_test.cc index 3eefabe3bb6..e91fa773588 100644 --- a/chromium/net/quic/core/quic_server_session_base_test.cc +++ b/chromium/net/quic/core/quic_server_session_base_test.cc @@ -14,6 +14,7 @@ #include "net/quic/core/quic_connection.h" #include "net/quic/core/quic_crypto_server_stream.h" #include "net/quic/core/quic_utils.h" +#include "net/quic/core/tls_server_handshaker.h" #include "net/quic/platform/api/quic_flags.h" #include "net/quic/platform/api/quic_ptr_util.h" #include "net/quic/platform/api/quic_socket_address.h" @@ -106,7 +107,7 @@ class TestServerSession : public QuicServerSessionBase { QuicCompressedCertsCache* compressed_certs_cache) override { return new QuicCryptoServerStream( crypto_config, compressed_certs_cache, - FLAGS_quic_reloadable_flag_enable_quic_stateless_reject_support, this, + GetQuicReloadableFlag(enable_quic_stateless_reject_support), this, stream_helper()); } @@ -116,8 +117,7 @@ class TestServerSession : public QuicServerSessionBase { const size_t kMaxStreamsForTest = 10; -class QuicServerSessionBaseTest - : public QuicTestWithParam<QuicTransportVersion> { +class QuicServerSessionBaseTest : public QuicTestWithParam<ParsedQuicVersion> { protected: QuicServerSessionBaseTest() : QuicServerSessionBaseTest(crypto_test_utils::ProofSourceForTesting()) {} @@ -125,7 +125,8 @@ class QuicServerSessionBaseTest explicit QuicServerSessionBaseTest(std::unique_ptr<ProofSource> proof_source) : crypto_config_(QuicCryptoServerConfig::TESTING, QuicRandom::GetInstance(), - std::move(proof_source)), + std::move(proof_source), + TlsServerHandshaker::CreateSslCtx()), compressed_certs_cache_( QuicCompressedCertsCache::kQuicCompressedCertsCacheSize) { config_.SetMaxStreamsPerConnection(kMaxStreamsForTest, kMaxStreamsForTest); @@ -139,7 +140,7 @@ class QuicServerSessionBaseTest connection_ = new StrictMock<MockQuicConnection>( &helper_, &alarm_factory_, Perspective::IS_SERVER, - SupportedTransportVersions(GetParam())); + SupportedVersions(GetParam())); session_.reset(new TestServerSession( config_, connection_, &owner_, &stream_helper_, &crypto_config_, &compressed_certs_cache_, &response_cache_)); @@ -191,7 +192,7 @@ MATCHER_P(EqualsProto, network_params, "") { INSTANTIATE_TEST_CASE_P(Tests, QuicServerSessionBaseTest, - ::testing::ValuesIn(AllSupportedTransportVersions())); + ::testing::ValuesIn(AllSupportedVersions())); TEST_P(QuicServerSessionBaseTest, CloseStreamDueToReset) { // Open a stream, then reset it. // Send two bytes of payload to open it. @@ -366,7 +367,7 @@ class MockQuicCryptoServerStream : public QuicCryptoServerStream { : QuicCryptoServerStream( crypto_config, compressed_certs_cache, - FLAGS_quic_reloadable_flag_enable_quic_stateless_reject_support, + GetQuicReloadableFlag(enable_quic_stateless_reject_support), session, helper) {} ~MockQuicCryptoServerStream() override {} @@ -570,21 +571,21 @@ class StreamMemberLifetimeTest : public QuicServerSessionBaseTest { INSTANTIATE_TEST_CASE_P(StreamMemberLifetimeTests, StreamMemberLifetimeTest, - ::testing::ValuesIn(AllSupportedTransportVersions())); + ::testing::ValuesIn(AllSupportedVersions())); // Trigger an operation which causes an async invocation of // ProofSource::GetProof. Delay the completion of the operation until after the // stream has been destroyed, and verify that there are no memory bugs. TEST_P(StreamMemberLifetimeTest, Basic) { - FLAGS_quic_reloadable_flag_enable_quic_stateless_reject_support = true; - FLAGS_quic_reloadable_flag_quic_use_cheap_stateless_rejects = true; + SetQuicReloadableFlag(enable_quic_stateless_reject_support, true); + SetQuicReloadableFlag(quic_use_cheap_stateless_rejects, true); const QuicClock* clock = helper_.GetClock(); - QuicTransportVersion version = AllSupportedTransportVersions().front(); + ParsedQuicVersion version = AllSupportedVersions().front(); CryptoHandshakeMessage chlo = crypto_test_utils::GenerateDefaultInchoateCHLO( - clock, version, &crypto_config_); + clock, version.transport_version, &crypto_config_); chlo.SetVector(kCOPT, QuicTagVector{kSREJ}); - std::vector<QuicTransportVersion> packet_version_list = {version}; + std::vector<ParsedQuicVersion> packet_version_list = {version}; std::unique_ptr<QuicEncryptedPacket> packet(ConstructEncryptedPacket( 1, true, false, 1, string(chlo.GetSerialized(Perspective::IS_CLIENT) diff --git a/chromium/net/quic/core/quic_session.cc b/chromium/net/quic/core/quic_session.cc index 9d2e6ace311..b53709c0393 100644 --- a/chromium/net/quic/core/quic_session.cc +++ b/chromium/net/quic/core/quic_session.cc @@ -54,9 +54,9 @@ QuicSession::QuicSession(QuicConnection* connection, perspective() == Perspective::IS_SERVER, nullptr), currently_writing_stream_id_(0), - can_use_slices_(FLAGS_quic_reloadable_flag_quic_use_mem_slices), + can_use_slices_(GetQuicReloadableFlag(quic_use_mem_slices)), allow_multiple_acks_for_data_( - FLAGS_quic_reloadable_flag_quic_allow_multiple_acks_for_data2) { + GetQuicReloadableFlag(quic_allow_multiple_acks_for_data2)) { if (allow_multiple_acks_for_data_) { QUIC_FLAG_COUNT(quic_reloadable_flag_quic_allow_multiple_acks_for_data2); } @@ -64,7 +64,7 @@ QuicSession::QuicSession(QuicConnection* connection, void QuicSession::Initialize() { connection_->set_visitor(this); - connection_->SetStreamNotifier(this); + connection_->SetSessionNotifier(this); connection_->SetDataProducer(this); connection_->SetFromConfig(config_); @@ -265,6 +265,11 @@ bool QuicSession::CheckStreamNotBusyLooping(QuicStream* stream, } void QuicSession::OnCanWrite() { + if (!RetransmitLostStreamData()) { + // Cannot finish retransmitting lost data, connection is write blocked. + return; + } + // We limit the number of writes to the number of pending streams. If more // streams become pending, WillingAndAbleToWrite will be true, which will // cause the connection to request resumption before yielding to other @@ -319,17 +324,21 @@ void QuicSession::OnCanWrite() { } bool QuicSession::WillingAndAbleToWrite() const { - // If the crypto or headers streams are blocked, we want to schedule a write - - // they don't get blocked by connection level flow control. Otherwise only - // schedule a write if we are not flow control blocked at the connection - // level. - return write_blocked_streams_.HasWriteBlockedCryptoOrHeadersStream() || + // Schedule a write when: + // 1) any stream has pending retransmissions, or + // 2) If the crypto or headers streams are blocked, or + // 3) connection is not flow control blocked and there are write blocked + // streams. + return !streams_with_pending_retransmission_.empty() || + write_blocked_streams_.HasWriteBlockedCryptoOrHeadersStream() || (!flow_controller_.IsBlocked() && write_blocked_streams_.HasWriteBlockedDataStreams()); } bool QuicSession::HasPendingHandshake() const { - return write_blocked_streams_.crypto_stream_blocked(); + return QuicContainsKey(streams_with_pending_retransmission_, + kCryptoStreamId) || + write_blocked_streams_.crypto_stream_blocked(); } bool QuicSession::HasOpenDynamicStreams() const { @@ -368,7 +377,10 @@ QuicConsumedData QuicSession::WritevData(QuicStream* stream, } QuicConsumedData data = connection_->SendStreamData(id, write_length, offset, state); - write_blocked_streams_.UpdateBytesForStream(id, data.bytes_consumed); + if (offset >= stream->stream_bytes_written()) { + // This is new stream data. + write_blocked_streams_.UpdateBytesForStream(id, data.bytes_consumed); + } return data; } @@ -430,6 +442,8 @@ void QuicSession::CloseStreamInner(QuicStreamId stream_id, bool locally_reset) { zombie_streams_[stream->id()] = std::move(it->second); } else { closed_streams_.push_back(std::move(it->second)); + // Do not retransmit data of a closed stream. + streams_with_pending_retransmission_.erase(stream_id); } // If we haven't received a FIN or RST for this stream, we need to keep track @@ -526,10 +540,7 @@ void QuicSession::OnConfigNegotiated() { } } - if (FLAGS_quic_reloadable_flag_quic_send_reset_token_in_shlo) { - QUIC_FLAG_COUNT(quic_reloadable_flag_quic_send_reset_token_in_shlo); - config_.SetStatelessResetTokenToSend(GetStatelessResetToken()); - } + config_.SetStatelessResetTokenToSend(GetStatelessResetToken()); } // A small number of additional incoming streams beyond the limit should be @@ -763,6 +774,14 @@ bool QuicSession::ShouldYield(QuicStreamId stream_id) { return write_blocked_streams()->ShouldYield(stream_id); } +void QuicSession::NeuterUnencryptedStreamData() { + QuicCryptoStream* crypto_stream = GetMutableCryptoStream(); + crypto_stream->NeuterUnencryptedStreamData(); + if (!crypto_stream->HasPendingRetransmission()) { + streams_with_pending_retransmission_.erase(kCryptoStreamId); + } +} + QuicStream* QuicSession::GetOrCreateDynamicStream( const QuicStreamId stream_id) { DCHECK(!QuicContainsKey(static_stream_map_, stream_id)) @@ -941,6 +960,8 @@ void QuicSession::OnStreamDoneWaitingForAcks(QuicStreamId id) { closed_streams_.push_back(std::move(it->second)); zombie_streams_.erase(it); + // Do not retransmit data of a closed stream. + streams_with_pending_retransmission_.erase(id); } QuicStream* QuicSession::GetStream(QuicStreamId id) const { @@ -959,13 +980,20 @@ QuicStream* QuicSession::GetStream(QuicStreamId id) const { return nullptr; } -void QuicSession::OnStreamFrameAcked(const QuicStreamFrame& frame, - QuicTime::Delta ack_delay_time) { - QuicStream* stream = GetStream(frame.stream_id); +void QuicSession::OnFrameAcked(const QuicFrame& frame, + QuicTime::Delta ack_delay_time) { + if (frame.type != STREAM_FRAME) { + return; + } + QuicStream* stream = GetStream(frame.stream_frame->stream_id); // Stream can already be reset when sent frame gets acked. if (stream != nullptr) { - stream->OnStreamFrameAcked(frame.offset, frame.data_length, frame.fin, - ack_delay_time); + stream->OnStreamFrameAcked(frame.stream_frame->offset, + frame.stream_frame->data_length, + frame.stream_frame->fin, ack_delay_time); + if (!stream->HasPendingRetransmission()) { + streams_with_pending_retransmission_.erase(stream->id()); + } } } @@ -979,20 +1007,27 @@ void QuicSession::OnStreamFrameRetransmitted(const QuicStreamFrame& frame) { ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); return; } - stream->OnStreamFrameRetransmitted(frame.offset, frame.data_length); + stream->OnStreamFrameRetransmitted(frame.offset, frame.data_length, + frame.fin); } -void QuicSession::OnStreamFrameDiscarded(const QuicStreamFrame& frame) { - QuicStream* stream = GetStream(frame.stream_id); +void QuicSession::OnFrameLost(const QuicFrame& frame) { + if (frame.type != STREAM_FRAME) { + return; + } + QuicStream* stream = GetStream(frame.stream_frame->stream_id); if (stream == nullptr) { - QUIC_BUG << "Stream: " << frame.stream_id << " is closed when " << frame - << " is discarded."; - connection()->CloseConnection( - QUIC_INTERNAL_ERROR, "Attempt to discard frame of a closed stream", - ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); return; } - stream->OnStreamFrameDiscarded(frame.offset, frame.data_length, frame.fin); + stream->OnStreamFrameLost(frame.stream_frame->offset, + frame.stream_frame->data_length, + frame.stream_frame->fin); + if (stream->HasPendingRetransmission() && + !QuicContainsKey(streams_with_pending_retransmission_, + frame.stream_frame->stream_id)) { + streams_with_pending_retransmission_.insert( + std::make_pair(frame.stream_frame->stream_id, true)); + } } bool QuicSession::WriteStreamData(QuicStreamId id, @@ -1013,4 +1048,48 @@ uint128 QuicSession::GetStatelessResetToken() const { return kStatelessResetToken; } +bool QuicSession::RetransmitLostStreamData() { + QuicConnection::ScopedPacketFlusher retransmission_flusher( + connection_, QuicConnection::SEND_ACK_IF_QUEUED); + while (!streams_with_pending_retransmission_.empty()) { + if (!connection_->CanWriteStreamData()) { + break; + } + if (QuicContainsKey(streams_with_pending_retransmission_, + kCryptoStreamId)) { + // Retransmit crypto data first. + QuicStream* crypto_stream = GetStream(kCryptoStreamId); + crypto_stream->OnCanWrite(); + if (crypto_stream->HasPendingRetransmission()) { + // Connection is write blocked. + break; + } else { + streams_with_pending_retransmission_.erase(kCryptoStreamId); + } + continue; + } + // Retransmit lost data on headers and data streams. + QuicStream* stream = + GetStream(streams_with_pending_retransmission_.begin()->first); + if (stream != nullptr) { + stream->OnCanWrite(); + if (stream->HasPendingRetransmission()) { + // Connection is write blocked. + break; + } else { + streams_with_pending_retransmission_.pop_front(); + } + } else { + QUIC_BUG << "Try to retransmit data of a closed stream"; + streams_with_pending_retransmission_.pop_front(); + } + } + + return streams_with_pending_retransmission_.empty(); +} + +void QuicSession::NeuterUnencryptedData() { + connection_->NeuterUnencryptedPackets(); +} + } // namespace net diff --git a/chromium/net/quic/core/quic_session.h b/chromium/net/quic/core/quic_session.h index 6387eadba0a..35981f07e42 100644 --- a/chromium/net/quic/core/quic_session.h +++ b/chromium/net/quic/core/quic_session.h @@ -23,7 +23,7 @@ #include "net/quic/core/quic_stream.h" #include "net/quic/core/quic_stream_frame_data_producer.h" #include "net/quic/core/quic_write_blocked_list.h" -#include "net/quic/core/stream_notifier_interface.h" +#include "net/quic/core/session_notifier_interface.h" #include "net/quic/platform/api/quic_containers.h" #include "net/quic/platform/api/quic_export.h" #include "net/quic/platform/api/quic_socket_address.h" @@ -39,7 +39,7 @@ class QuicSessionPeer; } // namespace test class QUIC_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface, - public StreamNotifierInterface, + public SessionNotifierInterface, public QuicStreamFrameDataProducer { public: // An interface from the session to the entity owning the session. @@ -122,11 +122,11 @@ class QUIC_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface, QuicByteCount data_length, QuicDataWriter* writer) override; - // StreamNotifierInterface methods: - void OnStreamFrameAcked(const QuicStreamFrame& frame, - QuicTime::Delta ack_delay_time) override; + // SessionNotifierInterface methods: + void OnFrameAcked(const QuicFrame& frame, + QuicTime::Delta ack_delay_time) override; void OnStreamFrameRetransmitted(const QuicStreamFrame& frame) override; - void OnStreamFrameDiscarded(const QuicStreamFrame& frame) override; + void OnFrameLost(const QuicFrame& frame) override; // Called on every incoming packet. Passes |packet| through to |connection_|. virtual void ProcessUdpPacket(const QuicSocketAddress& self_address, @@ -233,6 +233,9 @@ class QUIC_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface, // a stream is reset because of an error). void OnStreamDoneWaitingForAcks(QuicStreamId id); + // Called to cancel retransmission of unencypted crypto stream data. + void NeuterUnencryptedData(); + // Returns true if the session has data to be sent, either queued in the // connection, or in a write-blocked stream. bool HasDataToWrite() const; @@ -275,6 +278,9 @@ class QUIC_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface, // Returns true if this stream should yield writes to another blocked stream. bool ShouldYield(QuicStreamId stream_id); + // Called to cancel retransmission of unencrypted stream data. + void NeuterUnencryptedStreamData(); + bool can_use_slices() const { return can_use_slices_; } bool allow_multiple_acks_for_data() const { @@ -424,6 +430,10 @@ class QUIC_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface, // closed. QuicStream* GetStream(QuicStreamId id) const; + // Let streams retransmit lost data, returns true if all lost data is + // retransmitted. Returns false otherwise. + bool RetransmitLostStreamData(); + // Keep track of highest received byte offset of locally closed streams, while // waiting for a definitive final highest offset from the peer. std::map<QuicStreamId, QuicStreamOffset> @@ -499,6 +509,11 @@ class QUIC_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface, // Latched value of quic_reloadable_flag_quic_allow_multiple_acks_for_data2. const bool allow_multiple_acks_for_data_; + // TODO(fayang): switch to linked_hash_set when chromium supports it. The bool + // is not used here. + // List of streams with pending retransmissions. + QuicLinkedHashMap<QuicStreamId, bool> streams_with_pending_retransmission_; + DISALLOW_COPY_AND_ASSIGN(QuicSession); }; diff --git a/chromium/net/quic/core/quic_session_test.cc b/chromium/net/quic/core/quic_session_test.cc index d401957bf60..734e2a82711 100644 --- a/chromium/net/quic/core/quic_session_test.cc +++ b/chromium/net/quic/core/quic_session_test.cc @@ -92,6 +92,8 @@ class TestCryptoStream : public QuicCryptoStream, public QuicCryptoHandshaker { MOCK_METHOD0(OnCanWrite, void()); + MOCK_CONST_METHOD0(HasPendingRetransmission, bool()); + private: using QuicCryptoStream::session; @@ -118,6 +120,8 @@ class TestStream : public QuicSpdyStream { void OnDataAvailable() override {} MOCK_METHOD0(OnCanWrite, void()); + + MOCK_CONST_METHOD0(HasPendingRetransmission, bool()); }; // Poor man's functor for use as callback in a mock. @@ -241,14 +245,14 @@ class TestSession : public QuicSpdySession { bool writev_consumes_all_data_; }; -class QuicSessionTestBase : public QuicTestWithParam<QuicTransportVersion> { +class QuicSessionTestBase : public QuicTestWithParam<ParsedQuicVersion> { protected: explicit QuicSessionTestBase(Perspective perspective) - : connection_(new StrictMock<MockQuicConnection>( - &helper_, - &alarm_factory_, - perspective, - SupportedTransportVersions(GetParam()))), + : connection_( + new StrictMock<MockQuicConnection>(&helper_, + &alarm_factory_, + perspective, + SupportedVersions(GetParam()))), session_(connection_) { session_.config()->SetInitialStreamFlowControlWindowToSend( kInitialStreamFlowControlWindowForTest); @@ -329,7 +333,7 @@ class QuicSessionTestServer : public QuicSessionTestBase { INSTANTIATE_TEST_CASE_P(Tests, QuicSessionTestServer, - ::testing::ValuesIn(AllSupportedTransportVersions())); + ::testing::ValuesIn(AllSupportedVersions())); TEST_P(QuicSessionTestServer, PeerAddress) { EXPECT_EQ(QuicSocketAddress(QuicIpAddress::Loopback4(), kTestPort), @@ -562,7 +566,7 @@ TEST_P(QuicSessionTestServer, OnCanWriteBundlesStreams) { CryptoHandshakeMessage msg; MockPacketWriter* writer = static_cast<MockPacketWriter*>( QuicConnectionPeer::GetWriter(session_.connection())); - if (FLAGS_quic_reloadable_flag_quic_send_max_header_list_size) { + if (GetQuicReloadableFlag(quic_send_max_header_list_size)) { EXPECT_CALL(*writer, WritePacket(_, _, _, _, _)) .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 0))); } @@ -827,7 +831,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, ServerReplyToConnecitivityProbe) { - if (!FLAGS_quic_reloadable_flag_quic_server_reply_to_connectivity_probing) { + if (!GetQuicReloadableFlag(quic_server_reply_to_connectivity_probing)) { return; } QuicSocketAddress old_peer_address = @@ -837,7 +841,7 @@ TEST_P(QuicSessionTestServer, ServerReplyToConnecitivityProbe) { QuicSocketAddress new_peer_address = QuicSocketAddress(QuicIpAddress::Loopback4(), kTestPort + 1); - if (FLAGS_quic_reloadable_flag_quic_server_reply_to_connectivity_probing) { + if (GetQuicReloadableFlag(quic_server_reply_to_connectivity_probing)) { MockPacketWriter* writer = static_cast<MockPacketWriter*>( QuicConnectionPeer::GetWriter(session_.connection())); EXPECT_CALL(*writer, WritePacket(_, _, _, new_peer_address, _)) @@ -850,7 +854,7 @@ TEST_P(QuicSessionTestServer, ServerReplyToConnecitivityProbe) { } session_.OnConnectivityProbeReceived(session_.self_address(), new_peer_address); - if (FLAGS_quic_reloadable_flag_quic_server_reply_to_connectivity_probing) { + if (GetQuicReloadableFlag(quic_server_reply_to_connectivity_probing)) { EXPECT_EQ(old_peer_address, session_.peer_address()); } else { EXPECT_EQ(new_peer_address, session_.peer_address()); @@ -1340,7 +1344,7 @@ class QuicSessionTestClient : public QuicSessionTestBase { INSTANTIATE_TEST_CASE_P(Tests, QuicSessionTestClient, - ::testing::ValuesIn(AllSupportedTransportVersions())); + ::testing::ValuesIn(AllSupportedVersions())); TEST_P(QuicSessionTestClient, AvailableStreamsClient) { ASSERT_TRUE(session_.GetOrCreateDynamicStream(6) != nullptr); @@ -1423,6 +1427,104 @@ TEST_P(QuicSessionTestServer, ZombieStreams) { EXPECT_EQ(2u, session_.closed_streams()->front()->id()); } +TEST_P(QuicSessionTestServer, OnStreamFrameLost) { + InSequence s; + + // Drive congestion control manually. + MockSendAlgorithm* send_algorithm = new StrictMock<MockSendAlgorithm>; + QuicConnectionPeer::SetSendAlgorithm(session_.connection(), send_algorithm); + + TestCryptoStream* crypto_stream = session_.GetMutableCryptoStream(); + TestStream* stream2 = session_.CreateOutgoingDynamicStream(); + TestStream* stream4 = session_.CreateOutgoingDynamicStream(); + + QuicStreamFrame frame1(kCryptoStreamId, false, 0, 1300); + QuicStreamFrame frame2(stream2->id(), false, 0, 9); + QuicStreamFrame frame3(stream4->id(), false, 0, 9); + + // Lost data on cryption stream, streams 2 and 4. + EXPECT_CALL(*stream4, HasPendingRetransmission()).WillOnce(Return(true)); + EXPECT_CALL(*crypto_stream, HasPendingRetransmission()) + .WillOnce(Return(true)); + EXPECT_CALL(*stream2, HasPendingRetransmission()).WillOnce(Return(true)); + session_.OnFrameLost(QuicFrame(&frame3)); + session_.OnFrameLost(QuicFrame(&frame1)); + session_.OnFrameLost(QuicFrame(&frame2)); + EXPECT_TRUE(session_.WillingAndAbleToWrite()); + + // Mark streams 2 and 4 write blocked. + session_.MarkConnectionLevelWriteBlocked(stream2->id()); + session_.MarkConnectionLevelWriteBlocked(stream4->id()); + + // Lost data is retransmitted before new data, and retransmissions for crypto + // stream go first. + // Do not check congestion window when crypto stream has lost data. + EXPECT_CALL(*send_algorithm, CanSend(_)).Times(0); + EXPECT_CALL(*crypto_stream, OnCanWrite()); + EXPECT_CALL(*crypto_stream, HasPendingRetransmission()) + .WillOnce(Return(false)); + // Check congestion window for non crypto streams. + EXPECT_CALL(*send_algorithm, CanSend(_)).WillOnce(Return(true)); + EXPECT_CALL(*stream4, OnCanWrite()); + EXPECT_CALL(*stream4, HasPendingRetransmission()).WillOnce(Return(false)); + // Connection is blocked. + EXPECT_CALL(*send_algorithm, CanSend(_)).WillRepeatedly(Return(false)); + + session_.OnCanWrite(); + EXPECT_TRUE(session_.WillingAndAbleToWrite()); + + // Unblock connection. + // Stream 2 retransmits lost data. + EXPECT_CALL(*send_algorithm, CanSend(_)).WillOnce(Return(true)); + EXPECT_CALL(*stream2, OnCanWrite()); + EXPECT_CALL(*stream2, HasPendingRetransmission()).WillOnce(Return(false)); + EXPECT_CALL(*send_algorithm, CanSend(_)).WillOnce(Return(true)); + // Stream 2 sends new data. + EXPECT_CALL(*stream2, OnCanWrite()); + EXPECT_CALL(*send_algorithm, CanSend(_)).WillOnce(Return(true)); + EXPECT_CALL(*stream4, OnCanWrite()); + EXPECT_CALL(*send_algorithm, OnApplicationLimited(_)); + + session_.OnCanWrite(); + EXPECT_FALSE(session_.WillingAndAbleToWrite()); +} + +TEST_P(QuicSessionTestServer, DonotRetransmitDataOfClosedStreams) { + InSequence s; + + TestStream* stream2 = session_.CreateOutgoingDynamicStream(); + TestStream* stream4 = session_.CreateOutgoingDynamicStream(); + TestStream* stream6 = session_.CreateOutgoingDynamicStream(); + + QuicStreamFrame frame1(stream2->id(), false, 0, 9); + QuicStreamFrame frame2(stream4->id(), false, 0, 9); + QuicStreamFrame frame3(stream6->id(), false, 0, 9); + + EXPECT_CALL(*stream6, HasPendingRetransmission()).WillOnce(Return(true)); + EXPECT_CALL(*stream4, HasPendingRetransmission()).WillOnce(Return(true)); + EXPECT_CALL(*stream2, HasPendingRetransmission()).WillOnce(Return(true)); + session_.OnFrameLost(QuicFrame(&frame3)); + session_.OnFrameLost(QuicFrame(&frame2)); + session_.OnFrameLost(QuicFrame(&frame1)); + + session_.MarkConnectionLevelWriteBlocked(stream2->id()); + session_.MarkConnectionLevelWriteBlocked(stream4->id()); + session_.MarkConnectionLevelWriteBlocked(stream6->id()); + + // Reset stream 4 locally. + EXPECT_CALL(*connection_, SendRstStream(stream4->id(), _, _)); + stream4->Reset(QUIC_STREAM_CANCELLED); + + // Verify stream 4 is removed from streams with lost data list. + EXPECT_CALL(*stream6, OnCanWrite()); + EXPECT_CALL(*stream6, HasPendingRetransmission()).WillOnce(Return(false)); + EXPECT_CALL(*stream2, OnCanWrite()); + EXPECT_CALL(*stream2, HasPendingRetransmission()).WillOnce(Return(false)); + EXPECT_CALL(*stream2, OnCanWrite()); + EXPECT_CALL(*stream6, OnCanWrite()); + session_.OnCanWrite(); +} + } // namespace } // namespace test } // namespace net diff --git a/chromium/net/quic/core/quic_socket_address_coder_test.cc b/chromium/net/quic/core/quic_socket_address_coder_test.cc index ce2032fb93b..c538a443d91 100644 --- a/chromium/net/quic/core/quic_socket_address_coder_test.cc +++ b/chromium/net/quic/core/quic_socket_address_coder_test.cc @@ -4,6 +4,7 @@ #include "net/quic/core/quic_socket_address_coder.h" +#include "net/quic/platform/api/quic_arraysize.h" #include "net/quic/platform/api/quic_test.h" using std::string; @@ -110,7 +111,7 @@ TEST_F(QuicSocketAddressCoderTest, EncodeAndDecode) { {"::1", 65534}, }; - for (size_t i = 0; i < arraysize(test_case); i++) { + for (size_t i = 0; i < QUIC_ARRAYSIZE(test_case); i++) { QuicIpAddress ip; ASSERT_TRUE(ip.FromString(test_case[i].ip_literal)); QuicSocketAddressCoder encoder(QuicSocketAddress(ip, test_case[i].port)); diff --git a/chromium/net/quic/core/quic_spdy_session.cc b/chromium/net/quic/core/quic_spdy_session.cc index 6679b105561..47bf470407c 100644 --- a/chromium/net/quic/core/quic_spdy_session.cc +++ b/chromium/net/quic/core/quic_spdy_session.cc @@ -121,7 +121,7 @@ class QuicSpdySession::SpdyFramerVisitor } void OnSetting(SpdySettingsIds id, uint32_t value) override { - if (!FLAGS_quic_reloadable_flag_quic_respect_http2_settings_frame) { + if (!GetQuicReloadableFlag(quic_respect_http2_settings_frame)) { CloseConnection("SPDY SETTINGS frame received.", QUIC_INVALID_HEADERS_STREAM_DATA); return; @@ -150,7 +150,7 @@ class QuicSpdySession::SpdyFramerVisitor // TODO(fayang): Need to support SETTINGS_MAX_HEADER_LIST_SIZE when // clients are actually sending it. case SETTINGS_MAX_HEADER_LIST_SIZE: - if (FLAGS_quic_reloadable_flag_quic_send_max_header_list_size) { + if (GetQuicReloadableFlag(quic_send_max_header_list_size)) { break; } default: @@ -161,14 +161,14 @@ class QuicSpdySession::SpdyFramerVisitor } void OnSettingsAck() override { - if (!FLAGS_quic_reloadable_flag_quic_respect_http2_settings_frame) { + if (!GetQuicReloadableFlag(quic_respect_http2_settings_frame)) { CloseConnection("SPDY SETTINGS frame received.", QUIC_INVALID_HEADERS_STREAM_DATA); } } void OnSettingsEnd() override { - if (!FLAGS_quic_reloadable_flag_quic_respect_http2_settings_frame) { + if (!GetQuicReloadableFlag(quic_respect_http2_settings_frame)) { CloseConnection("SPDY SETTINGS frame received.", QUIC_INVALID_HEADERS_STREAM_DATA); } @@ -296,10 +296,11 @@ QuicSpdySession::QuicSpdySession(QuicConnection* connection, supports_push_promise_(perspective() == Perspective::IS_CLIENT), cur_max_timestamp_(QuicTime::Zero()), prev_max_timestamp_(QuicTime::Zero()), - use_hq_deframer_(FLAGS_quic_reloadable_flag_quic_enable_hq_deframer), + use_hq_deframer_(GetQuicReloadableFlag(quic_enable_hq_deframer)), spdy_framer_(SpdyFramer::ENABLE_COMPRESSION), spdy_framer_visitor_(new SpdyFramerVisitor(this)) { if (use_hq_deframer_) { + QUIC_FLAG_COUNT(quic_reloadable_flag_quic_enable_hq_deframer); hq_deframer_.set_visitor(spdy_framer_visitor_.get()); hq_deframer_.set_debug_visitor(spdy_framer_visitor_.get()); } else { @@ -399,10 +400,21 @@ size_t QuicSpdySession::WriteHeaders( SpdyHeaderBlock headers, bool fin, SpdyPriority priority, - QuicReferenceCountedPointer<QuicAckListenerInterface> - ack_notifier_delegate) { + QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) { + return WriteHeadersImpl(id, std::move(headers), fin, priority, 0, false, + std::move(ack_listener)); +} + +size_t QuicSpdySession::WriteHeaders( + QuicStreamId id, + SpdyHeaderBlock headers, + bool fin, + SpdyPriority priority, + QuicStreamId parent_stream_id, + bool exclusive, + QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) { return WriteHeadersImpl(id, std::move(headers), fin, priority, - std::move(ack_notifier_delegate)); + parent_stream_id, exclusive, std::move(ack_listener)); } size_t QuicSpdySession::WriteHeadersImpl( @@ -410,18 +422,32 @@ size_t QuicSpdySession::WriteHeadersImpl( SpdyHeaderBlock headers, bool fin, SpdyPriority priority, - QuicReferenceCountedPointer<QuicAckListenerInterface> - ack_notifier_delegate) { + QuicStreamId parent_stream_id, + bool exclusive, + QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) { SpdyHeadersIR headers_frame(id, std::move(headers)); headers_frame.set_fin(fin); if (perspective() == Perspective::IS_CLIENT) { headers_frame.set_has_priority(true); headers_frame.set_weight(Spdy3PriorityToHttp2Weight(priority)); + headers_frame.set_parent_stream_id(parent_stream_id); + headers_frame.set_exclusive(exclusive); } SpdySerializedFrame frame(spdy_framer_.SerializeFrame(headers_frame)); headers_stream_->WriteOrBufferData( QuicStringPiece(frame.data(), frame.size()), false, - std::move(ack_notifier_delegate)); + std::move(ack_listener)); + return frame.size(); +} + +size_t QuicSpdySession::WritePriority(QuicStreamId id, + QuicStreamId parent_stream_id, + int weight, + bool exclusive) { + SpdyPriorityIR priority_frame(id, parent_stream_id, weight, exclusive); + SpdySerializedFrame frame(spdy_framer_.SerializeFrame(priority_frame)); + headers_stream_->WriteOrBufferData( + QuicStringPiece(frame.data(), frame.size()), false, nullptr); return frame.size(); } @@ -480,7 +506,7 @@ QuicSpdyStream* QuicSpdySession::GetSpdyDataStream( void QuicSpdySession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) { QuicSession::OnCryptoHandshakeEvent(event); - if (FLAGS_quic_reloadable_flag_quic_send_max_header_list_size && + if (GetQuicReloadableFlag(quic_send_max_header_list_size) && event == HANDSHAKE_CONFIRMED && config()->SupportMaxHeaderListSize()) { SendMaxHeaderListSize(max_inbound_header_list_size_); } diff --git a/chromium/net/quic/core/quic_spdy_session.h b/chromium/net/quic/core/quic_spdy_session.h index a2a4c3ce345..f8a2d5c73bf 100644 --- a/chromium/net/quic/core/quic_spdy_session.h +++ b/chromium/net/quic/core/quic_spdy_session.h @@ -92,6 +92,23 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession : public QuicSession { SpdyPriority priority, QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener); + // |parent_stream_id| and |exclusive| are HTTP2 stream dependency info. + virtual size_t WriteHeaders( + QuicStreamId id, + SpdyHeaderBlock headers, + bool fin, + SpdyPriority priority, + QuicStreamId parent_stream_id, + bool exclusive, + QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener); + + // Writes a PRIORITY frame the to peer. Returns the size in bytes of the + // resulting PRIORITY frame. + size_t WritePriority(QuicStreamId id, + QuicStreamId parent_stream_id, + int weight, + bool exclusive); + // Write |headers| for |promised_stream_id| on |original_stream_id| in a // PUSH_PROMISE frame to peer. // Return the size, in bytes, of the resulting PUSH_PROMISE frame. @@ -109,13 +126,13 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession : public QuicSession { virtual void OnHeadersHeadOfLineBlocking(QuicTime::Delta delta); // Called by the stream on creation to set priority in the write blocked list. - void RegisterStreamPriority(QuicStreamId id, SpdyPriority priority); + virtual void RegisterStreamPriority(QuicStreamId id, SpdyPriority priority); // Called by the stream on deletion to clear priority crom the write blocked // list. - void UnregisterStreamPriority(QuicStreamId id); + virtual void UnregisterStreamPriority(QuicStreamId id); // Called by the stream on SetPriority to update priority on the write blocked // list. - void UpdateStreamPriority(QuicStreamId id, SpdyPriority new_priority); + virtual void UpdateStreamPriority(QuicStreamId id, SpdyPriority new_priority); void OnConfigNegotiated() override; @@ -226,6 +243,8 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession : public QuicSession { SpdyHeaderBlock headers, bool fin, SpdyPriority priority, + QuicStreamId parent_stream_id, + bool exclusive, QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener); std::unique_ptr<QuicHeadersStream> headers_stream_; diff --git a/chromium/net/quic/core/quic_spdy_stream_test.cc b/chromium/net/quic/core/quic_spdy_stream_test.cc index 04543f69b6d..3e2c4cb765e 100644 --- a/chromium/net/quic/core/quic_spdy_stream_test.cc +++ b/chromium/net/quic/core/quic_spdy_stream_test.cc @@ -11,6 +11,7 @@ #include "net/quic/core/quic_utils.h" #include "net/quic/core/quic_write_blocked_list.h" #include "net/quic/core/spdy_utils.h" +#include "net/quic/platform/api/quic_arraysize.h" #include "net/quic/platform/api/quic_map_util.h" #include "net/quic/platform/api/quic_ptr_util.h" #include "net/quic/platform/api/quic_string_piece.h" @@ -50,7 +51,7 @@ class TestStream : public QuicSpdyStream { char buffer[2048]; struct iovec vec; vec.iov_base = buffer; - vec.iov_len = arraysize(buffer); + vec.iov_len = QUIC_ARRAYSIZE(buffer); size_t bytes_read = Readv(&vec, 1); data_ += string(buffer, bytes_read); } @@ -66,7 +67,7 @@ class TestStream : public QuicSpdyStream { string data_; }; -class QuicSpdyStreamTest : public QuicTestWithParam<QuicTransportVersion> { +class QuicSpdyStreamTest : public QuicTestWithParam<ParsedQuicVersion> { public: QuicSpdyStreamTest() { headers_[":host"] = "www.google.com"; @@ -101,7 +102,7 @@ class QuicSpdyStreamTest : public QuicTestWithParam<QuicTransportVersion> { void Initialize(bool stream_should_process_data) { connection_ = new testing::StrictMock<MockQuicConnection>( &helper_, &alarm_factory_, Perspective::IS_SERVER, - SupportedTransportVersions(GetParam())); + SupportedVersions(GetParam())); session_.reset(new testing::StrictMock<MockQuicSpdySession>(connection_)); stream_ = new TestStream(GetNthClientInitiatedId(0), session_.get(), stream_should_process_data); @@ -136,7 +137,7 @@ class QuicSpdyStreamTest : public QuicTestWithParam<QuicTransportVersion> { INSTANTIATE_TEST_CASE_P(Tests, QuicSpdyStreamTest, - ::testing::ValuesIn(AllSupportedTransportVersions())); + ::testing::ValuesIn(AllSupportedVersions())); TEST_P(QuicSpdyStreamTest, ProcessHeaderList) { Initialize(kShouldProcessData); @@ -318,10 +319,10 @@ TEST_P(QuicSpdyStreamTest, ProcessHeadersAndBodyReadv) { stream_->ConsumeHeaderList(); char buffer[2048]; - ASSERT_LT(body.length(), arraysize(buffer)); + ASSERT_LT(body.length(), QUIC_ARRAYSIZE(buffer)); struct iovec vec; vec.iov_base = buffer; - vec.iov_len = arraysize(buffer); + vec.iov_len = QUIC_ARRAYSIZE(buffer); size_t bytes_read = stream_->Readv(&vec, 1); EXPECT_EQ(body.length(), bytes_read); @@ -362,7 +363,7 @@ TEST_P(QuicSpdyStreamTest, ProcessHeadersAndBodyIncrementalReadv) { char buffer[1]; struct iovec vec; vec.iov_base = buffer; - vec.iov_len = arraysize(buffer); + vec.iov_len = QUIC_ARRAYSIZE(buffer); for (size_t i = 0; i < body.length(); ++i) { size_t bytes_read = stream_->Readv(&vec, 1); @@ -385,9 +386,9 @@ TEST_P(QuicSpdyStreamTest, ProcessHeadersUsingReadvWithMultipleIovecs) { char buffer2[1]; struct iovec vec[2]; vec[0].iov_base = buffer1; - vec[0].iov_len = arraysize(buffer1); + vec[0].iov_len = QUIC_ARRAYSIZE(buffer1); vec[1].iov_base = buffer2; - vec[1].iov_len = arraysize(buffer2); + vec[1].iov_len = QUIC_ARRAYSIZE(buffer2); for (size_t i = 0; i < body.length(); i += 2) { size_t bytes_read = stream_->Readv(vec, 2); @@ -844,7 +845,7 @@ TEST_P(QuicSpdyStreamTest, WritingTrailersSendsAFin) { Initialize(kShouldProcessData); EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) .Times(AnyNumber()) - .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData)); + .WillRepeatedly(Invoke(MockQuicSession::ConsumeData)); // Write the initial headers, without a FIN. EXPECT_CALL(*session_, WriteHeadersMock(_, _, _, _, _)); @@ -864,7 +865,7 @@ TEST_P(QuicSpdyStreamTest, WritingTrailersFinalOffset) { Initialize(kShouldProcessData); EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) .Times(AnyNumber()) - .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData)); + .WillRepeatedly(Invoke(MockQuicSession::ConsumeData)); // Write the initial headers. EXPECT_CALL(*session_, WriteHeadersMock(_, _, _, _, _)); @@ -892,7 +893,7 @@ TEST_P(QuicSpdyStreamTest, WritingTrailersClosesWriteSide) { Initialize(kShouldProcessData); EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) .Times(AnyNumber()) - .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData)); + .WillRepeatedly(Invoke(MockQuicSession::ConsumeData)); // Write the initial headers. EXPECT_CALL(*session_, WriteHeadersMock(_, _, _, _, _)); @@ -916,7 +917,7 @@ TEST_P(QuicSpdyStreamTest, WritingTrailersWithQueuedBytes) { Initialize(kShouldProcessData); EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) .Times(AnyNumber()) - .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData)); + .WillRepeatedly(Invoke(MockQuicSession::ConsumeData)); // Write the initial headers. EXPECT_CALL(*session_, WriteHeadersMock(_, _, _, _, _)); @@ -948,7 +949,7 @@ TEST_P(QuicSpdyStreamTest, WritingTrailersAfterFIN) { Initialize(kShouldProcessData); EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) .Times(AnyNumber()) - .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData)); + .WillRepeatedly(Invoke(MockQuicSession::ConsumeData)); // Write the initial headers, with a FIN. EXPECT_CALL(*session_, WriteHeadersMock(_, _, _, _, _)); @@ -965,7 +966,7 @@ TEST_P(QuicSpdyStreamTest, HeaderStreamNotiferCorrespondingSpdyStream) { Initialize(kShouldProcessData); EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) .Times(AnyNumber()) - .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData)); + .WillRepeatedly(Invoke(MockQuicSession::ConsumeData)); testing::InSequence s; QuicReferenceCountedPointer<MockAckListener> ack_listener1( new MockAckListener()); @@ -991,20 +992,20 @@ TEST_P(QuicSpdyStreamTest, HeaderStreamNotiferCorrespondingSpdyStream) { session_->OnStreamFrameRetransmitted(frame1); EXPECT_CALL(*ack_listener1, OnPacketAcked(7, _)); - session_->OnStreamFrameAcked(frame1, QuicTime::Delta::Zero()); + session_->OnFrameAcked(QuicFrame(&frame1), QuicTime::Delta::Zero()); EXPECT_CALL(*ack_listener1, OnPacketAcked(5, _)); - session_->OnStreamFrameAcked(frame2, QuicTime::Delta::Zero()); + session_->OnFrameAcked(QuicFrame(&frame2), QuicTime::Delta::Zero()); EXPECT_CALL(*ack_listener2, OnPacketAcked(7, _)); - session_->OnStreamFrameAcked(frame3, QuicTime::Delta::Zero()); + session_->OnFrameAcked(QuicFrame(&frame3), QuicTime::Delta::Zero()); EXPECT_CALL(*ack_listener2, OnPacketAcked(5, _)); - session_->OnStreamFrameAcked(frame4, QuicTime::Delta::Zero()); + session_->OnFrameAcked(QuicFrame(&frame4), QuicTime::Delta::Zero()); } TEST_P(QuicSpdyStreamTest, StreamBecomesZombieWithWriteThatCloses) { Initialize(kShouldProcessData); EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) .Times(AnyNumber()) - .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData)); + .WillRepeatedly(Invoke(MockQuicSession::ConsumeData)); QuicStreamPeer::CloseReadSide(stream_); // This write causes stream to be closed. stream_->WriteOrBufferData("Test1", true, nullptr); diff --git a/chromium/net/quic/core/quic_stream.cc b/chromium/net/quic/core/quic_stream.cc index 00806bed866..53fae6107c5 100644 --- a/chromium/net/quic/core/quic_stream.cc +++ b/chromium/net/quic/core/quic_stream.cc @@ -10,6 +10,7 @@ #include "net/quic/platform/api/quic_flag_utils.h" #include "net/quic/platform/api/quic_flags.h" #include "net/quic/platform/api/quic_logging.h" +#include "net/quic/platform/api/quic_str_cat.h" using std::string; @@ -52,6 +53,7 @@ QuicStream::QuicStream(QuicStreamId id, QuicSession* session) fin_buffered_(false), fin_sent_(false), fin_outstanding_(false), + fin_lost_(false), fin_received_(false), rst_sent_(false), rst_received_(false), @@ -71,9 +73,8 @@ QuicStream::QuicStream(QuicStreamId id, QuicSession* session) send_buffer_( session->connection()->helper()->GetStreamSendBufferAllocator(), session->allow_multiple_acks_for_data()), - buffered_data_threshold_(GetQuicFlag(FLAGS_quic_buffered_data_threshold)), - remove_on_stream_frame_discarded_( - FLAGS_quic_reloadable_flag_quic_remove_on_stream_frame_discarded) { + buffered_data_threshold_( + GetQuicFlag(FLAGS_quic_buffered_data_threshold)) { SetFromConfig(); } @@ -94,6 +95,20 @@ void QuicStream::OnStreamFrame(const QuicStreamFrame& frame) { DCHECK(!(read_side_closed_ && write_side_closed_)); + bool is_stream_too_long = + (frame.offset > kMaxStreamLength) || + (kMaxStreamLength - frame.offset < frame.data_length); + if (GetQuicReloadableFlag(quic_stream_too_long) && is_stream_too_long) { + // Close connection if stream becomes too long. + QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_stream_too_long, 4, 5); + QUIC_PEER_BUG + << "Receive stream frame reaches max stream length. frame offset " + << frame.offset << " length " << frame.data_length; + CloseConnectionWithDetails( + QUIC_STREAM_LENGTH_OVERFLOW, + "Peer sends more data than allowed on this stream."); + return; + } if (frame.fin) { fin_received_ = true; if (fin_sent_) { @@ -141,6 +156,14 @@ int QuicStream::num_duplicate_frames_received() const { void QuicStream::OnStreamReset(const QuicRstStreamFrame& frame) { rst_received_ = true; + if (GetQuicReloadableFlag(quic_stream_too_long) && + frame.byte_offset > kMaxStreamLength) { + QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_stream_too_long, 5, 5); + // Peer are not suppose to write bytes more than maxium allowed. + CloseConnectionWithDetails(QUIC_STREAM_LENGTH_OVERFLOW, + "Reset frame stream offset overflow."); + return; + } MaybeIncreaseHighestReceivedOffset(frame.byte_offset); if (flow_controller_.FlowControlViolation() || connection_flow_controller_->FlowControlViolation()) { @@ -221,6 +244,15 @@ void QuicStream::WriteOrBufferData( if (data.length() > 0) { struct iovec iov(MakeIovec(data)); QuicStreamOffset offset = send_buffer_.stream_offset(); + if (GetQuicReloadableFlag(quic_stream_too_long) && + kMaxStreamLength - offset < data.length()) { + QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_stream_too_long, 1, 5); + QUIC_BUG << "Write too many data via stream " << id_; + CloseConnectionWithDetails( + QUIC_STREAM_LENGTH_OVERFLOW, + QuicStrCat("Write too many data via stream ", id_)); + return; + } send_buffer_.SaveStreamData(&iov, 1, 0, data.length()); OnDataBuffered(offset, data.length(), ack_listener); } @@ -231,9 +263,17 @@ void QuicStream::WriteOrBufferData( } void QuicStream::OnCanWrite() { + if (HasPendingRetransmission()) { + // Exit early to allow other streams to write pending retransmissions if + // any. + WritePendingRetransmission(); + return; + } + if (write_side_closed_) { - QUIC_DLOG(ERROR) << ENDPOINT << "Stream " << id() - << "attempting to write when the write side is closed"; + QUIC_DLOG(ERROR) + << ENDPOINT << "Stream " << id() + << " attempting to write new data when the write side is closed"; return; } if (HasBufferedData() || (fin_buffered_ && !fin_sent_)) { @@ -285,6 +325,16 @@ QuicConsumedData QuicStream::WritevData(const struct iovec* iov, return consumed_data; } + if (GetQuicReloadableFlag(quic_stream_too_long) && + kMaxStreamLength - send_buffer_.stream_offset() < write_length) { + QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_stream_too_long, 2, 5); + QUIC_BUG << "Write too many data via stream " << id_; + CloseConnectionWithDetails( + QUIC_STREAM_LENGTH_OVERFLOW, + QuicStrCat("Write too many data via stream ", id_)); + return consumed_data; + } + bool had_buffered_data = HasBufferedData(); if (CanWriteNewData()) { // Save all data if buffered data size is below low water mark. @@ -334,6 +384,16 @@ QuicConsumedData QuicStream::WriteMemSlices(QuicMemSliceSpan span, bool fin) { QuicStreamOffset offset = send_buffer_.stream_offset(); consumed_data.bytes_consumed = span.SaveMemSlicesInSendBuffer(&send_buffer_); + if (GetQuicReloadableFlag(quic_stream_too_long) && + (offset > send_buffer_.stream_offset() || + kMaxStreamLength < send_buffer_.stream_offset())) { + QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_stream_too_long, 3, 5); + QUIC_BUG << "Write too many data via stream " << id_; + CloseConnectionWithDetails( + QUIC_STREAM_LENGTH_OVERFLOW, + QuicStrCat("Write too many data via stream ", id_)); + return consumed_data; + } OnDataBuffered(offset, consumed_data.bytes_consumed, nullptr); } } @@ -347,6 +407,17 @@ QuicConsumedData QuicStream::WriteMemSlices(QuicMemSliceSpan span, bool fin) { return consumed_data; } +bool QuicStream::HasPendingRetransmission() const { + return send_buffer_.HasPendingRetransmission() || fin_lost_; +} + +bool QuicStream::IsStreamFrameOutstanding(QuicStreamOffset offset, + QuicByteCount data_length, + bool fin) const { + return send_buffer_.IsStreamDataOutstanding(offset, data_length) || + (fin && fin_outstanding_); +} + QuicConsumedData QuicStream::WritevDataInner(size_t write_length, QuicStreamOffset offset, bool fin) { @@ -394,6 +465,10 @@ QuicTransportVersion QuicStream::transport_version() const { return session_->connection()->transport_version(); } +HandshakeProtocol QuicStream::handshake_protocol() const { + return session_->connection()->version().handshake_protocol; +} + void QuicStream::StopReading() { QUIC_DLOG(INFO) << ENDPOINT << "Stop reading from stream " << id(); sequencer_.StopReading(); @@ -511,6 +586,7 @@ void QuicStream::OnStreamFrameAcked(QuicStreamOffset offset, (fin_acked && fin_outstanding_); if (fin_acked) { fin_outstanding_ = false; + fin_lost_ = false; } if (!IsWaitingForAcks()) { session_->OnStreamDoneWaitingForAcks(id_); @@ -520,48 +596,31 @@ void QuicStream::OnStreamFrameAcked(QuicStreamOffset offset, } } -void QuicStream::OnStreamFrameRetransmitted(QuicStreamOffset /*offset*/, - QuicByteCount data_length) { +void QuicStream::OnStreamFrameRetransmitted(QuicStreamOffset offset, + QuicByteCount data_length, + bool fin_retransmitted) { + send_buffer_.OnStreamDataRetransmitted(offset, data_length); + if (fin_retransmitted) { + fin_lost_ = false; + } if (ack_listener_ != nullptr) { ack_listener_->OnPacketRetransmitted(data_length); } } -void QuicStream::OnStreamFrameDiscarded(QuicStreamOffset offset, - QuicByteCount data_length, - bool fin_discarded) { - if (remove_on_stream_frame_discarded_) { - // TODO(fayang): Remove OnStreamFrameDiscarded from StreamNotifierInterface - // when deprecating - // quic_reloadable_flag_quic_remove_on_stream_frame_discarded. - QUIC_FLAG_COUNT_N( - quic_reloadable_flag_quic_remove_on_stream_frame_discarded, 1, 2); - return; - } - - QuicByteCount newly_acked_length = 0; - if (!send_buffer_.OnStreamDataAcked(offset, data_length, - &newly_acked_length)) { - CloseConnectionWithDetails(QUIC_INTERNAL_ERROR, - "Trying to discard unsent data."); - return; - } - if (!fin_sent_ && fin_discarded) { - CloseConnectionWithDetails(QUIC_INTERNAL_ERROR, - "Trying to discard unsent fin."); - return; +void QuicStream::OnStreamFrameLost(QuicStreamOffset offset, + QuicByteCount data_length, + bool fin_lost) { + if (data_length > 0) { + send_buffer_.OnStreamDataLost(offset, data_length); } - if (fin_discarded) { - fin_outstanding_ = false; - } - if (!IsWaitingForAcks()) { - session_->OnStreamDoneWaitingForAcks(id_); + if (fin_lost && fin_outstanding_) { + fin_lost_ = true; } } bool QuicStream::IsWaitingForAcks() const { - return (!remove_on_stream_frame_discarded_ || !rst_sent_ || - stream_error_ == QUIC_STREAM_NO_ERROR) && + return (!rst_sent_ || stream_error_ == QUIC_STREAM_NO_ERROR) && (send_buffer_.stream_bytes_outstanding() || fin_outstanding_); } @@ -569,6 +628,8 @@ bool QuicStream::WriteStreamData(QuicStreamOffset offset, QuicByteCount data_length, QuicDataWriter* writer) { DCHECK_LT(0u, data_length); + QUIC_DVLOG(2) << ENDPOINT << "Write stream " << id_ << " data from offset " + << offset << " length " << data_length; return send_buffer_.WriteStreamData(offset, data_length, writer); } @@ -614,7 +675,7 @@ void QuicStream::WriteBufferedData() { QuicConsumedData consumed_data = WritevDataInner(write_length, stream_bytes_written(), fin); - send_buffer_.OnStreamDataConsumed(consumed_data.bytes_consumed); + OnStreamDataConsumed(consumed_data.bytes_consumed); AddBytesSent(consumed_data.bytes_consumed); QUIC_DVLOG(1) << ENDPOINT << "stream " << id_ << " sends " @@ -668,4 +729,47 @@ const QuicIntervalSet<QuicStreamOffset>& QuicStream::bytes_acked() const { return send_buffer_.bytes_acked(); } +void QuicStream::OnStreamDataConsumed(size_t bytes_consumed) { + send_buffer_.OnStreamDataConsumed(bytes_consumed); +} + +void QuicStream::WritePendingRetransmission() { + while (HasPendingRetransmission()) { + QuicConsumedData consumed(0, false); + if (!send_buffer_.HasPendingRetransmission()) { + QUIC_DVLOG(1) << ENDPOINT << "stream " << id_ + << " retransmits fin only frame."; + consumed = + session()->WritevData(this, id_, 0, stream_bytes_written(), FIN); + fin_lost_ = !consumed.fin_consumed; + if (fin_lost_) { + // Connection is write blocked. + return; + } + } else { + StreamPendingRetransmission pending = + send_buffer_.NextPendingRetransmission(); + // Determine whether the lost fin can be bundled with the data. + const bool can_bundle_fin = + fin_lost_ && + (pending.offset + pending.length == stream_bytes_written()); + consumed = + session()->WritevData(this, id_, pending.length, pending.offset, + can_bundle_fin ? FIN : NO_FIN); + QUIC_DVLOG(1) << ENDPOINT << "stream " << id_ + << " tries to retransmit stream data [" << pending.offset + << ", " << pending.offset + pending.length + << ") and fin: " << can_bundle_fin + << ", consumed: " << consumed; + OnStreamFrameRetransmitted(pending.offset, consumed.bytes_consumed, + consumed.fin_consumed); + if (consumed.bytes_consumed < pending.length || + (can_bundle_fin && !consumed.fin_consumed)) { + // Connection is write blocked. + return; + } + } + } +} + } // namespace net diff --git a/chromium/net/quic/core/quic_stream.h b/chromium/net/quic/core/quic_stream.h index 31670e6ec28..52bd18f7330 100644 --- a/chromium/net/quic/core/quic_stream.h +++ b/chromium/net/quic/core/quic_stream.h @@ -29,7 +29,7 @@ #include "net/quic/core/quic_stream_send_buffer.h" #include "net/quic/core/quic_stream_sequencer.h" #include "net/quic/core/quic_types.h" -#include "net/quic/core/stream_notifier_interface.h" +#include "net/quic/core/session_notifier_interface.h" #include "net/quic/platform/api/quic_export.h" #include "net/quic/platform/api/quic_mem_slice_span.h" #include "net/quic/platform/api/quic_reference_counted.h" @@ -168,6 +168,10 @@ class QUIC_EXPORT_PRIVATE QuicStream { // Returns the version of QUIC being used for this stream. QuicTransportVersion transport_version() const; + // Returns the crypto handshake protocol that was used on this stream's + // connection. + HandshakeProtocol handshake_protocol() const; + bool fin_received() const { return fin_received_; } // Sets the sequencer to consume all incoming data itself and not call @@ -205,21 +209,33 @@ class QUIC_EXPORT_PRIVATE QuicStream { bool fin_acked, QuicTime::Delta ack_delay_time); - // Called when data [offset, offset + data_length) gets retransmitted. + // Called when data [offset, offset + data_length) was retransmitted. + // |fin_retransmitted| indicates whether fin was retransmitted. virtual void OnStreamFrameRetransmitted(QuicStreamOffset offset, - QuicByteCount data_length); + QuicByteCount data_length, + bool fin_retransmitted); - // Called when data [offset, offset + data_length) gets discarded because - // stream is cancelled. |fin_discarded| indicates whether the fin is - // discarded. - void OnStreamFrameDiscarded(QuicStreamOffset offset, - QuicByteCount data_length, - bool fin_discarded); + // Called when data [offset, offset + data_length) is considered as lost. + // |fin_lost| inidacates whether the fin is considered as lost. + void OnStreamFrameLost(QuicStreamOffset offset, + QuicByteCount data_length, + bool fin_lost); // Same as WritevData except data is provided in reference counted memory so // that data copy is avoided. QuicConsumedData WriteMemSlices(QuicMemSliceSpan span, bool fin); + // Returns true if any stream data is lost (including fin) and needs to be + // retransmitted. + virtual bool HasPendingRetransmission() const; + + // Returns true if any portion of data [offset, offset + data_length) is + // outstanding or fin is outstanding (if |fin| is true). Returns false + // otherwise. + bool IsStreamFrameOutstanding(QuicStreamOffset offset, + QuicByteCount data_length, + bool fin) const; + protected: // Sends as many bytes in the first |count| buffers of |iov| to the connection // as the connection will consume. If FIN is consumed, the write side is @@ -262,6 +278,12 @@ class QUIC_EXPORT_PRIVATE QuicStream { // Called when upper layer can write new data. virtual void OnCanWriteNewData() {} + // Called when |bytes_consumed| bytes has been consumed. + virtual void OnStreamDataConsumed(size_t bytes_consumed); + + // Writes pending retransmissions if any. + virtual void WritePendingRetransmission(); + bool fin_buffered() const { return fin_buffered_; } const QuicSession* session() const { return session_; } @@ -281,6 +303,10 @@ class QUIC_EXPORT_PRIVATE QuicStream { const QuicIntervalSet<QuicStreamOffset>& bytes_acked() const; + const QuicStreamSendBuffer& send_buffer() const { return send_buffer_; } + + QuicStreamSendBuffer& send_buffer() { return send_buffer_; } + private: friend class test::QuicStreamPeer; friend class QuicStreamUtils; @@ -326,6 +352,8 @@ class QUIC_EXPORT_PRIVATE QuicStream { bool fin_sent_; // True if a FIN is waiting to be acked. bool fin_outstanding_; + // True if a FIN is lost. + bool fin_lost_; // True if this stream has received (and the sequencer has accepted) a // StreamFrame with the FIN set. @@ -372,10 +400,6 @@ class QUIC_EXPORT_PRIVATE QuicStream { // Latched value of FLAGS_quic_buffered_data_threshold. const QuicByteCount buffered_data_threshold_; - // Latched value of - // FLAGS_quic_reloadable_flag_quic_remove_on_stream_frame_discarded. - const bool remove_on_stream_frame_discarded_; - DISALLOW_COPY_AND_ASSIGN(QuicStream); }; diff --git a/chromium/net/quic/core/quic_stream_send_buffer.cc b/chromium/net/quic/core/quic_stream_send_buffer.cc index 5b1fbaaea83..7671245c376 100644 --- a/chromium/net/quic/core/quic_stream_send_buffer.cc +++ b/chromium/net/quic/core/quic_stream_send_buffer.cc @@ -26,13 +26,21 @@ BufferedSlice& BufferedSlice::operator=(BufferedSlice&& other) = default; BufferedSlice::~BufferedSlice() {} +bool StreamPendingRetransmission::operator==( + const StreamPendingRetransmission& other) const { + return offset == other.offset && length == other.length; +} + QuicStreamSendBuffer::QuicStreamSendBuffer(QuicBufferAllocator* allocator, bool allow_multiple_acks_for_data) : stream_offset_(0), allocator_(allocator), stream_bytes_written_(0), stream_bytes_outstanding_(0), - allow_multiple_acks_for_data_(allow_multiple_acks_for_data) {} + allow_multiple_acks_for_data_(allow_multiple_acks_for_data), + write_index_(-1), + use_write_index_(allow_multiple_acks_for_data_ && + GetQuicReloadableFlag(quic_use_write_index)) {} QuicStreamSendBuffer::~QuicStreamSendBuffer() {} @@ -56,12 +64,17 @@ void QuicStreamSendBuffer::SaveStreamData(const struct iovec* iov, } void QuicStreamSendBuffer::SaveMemSlice(QuicMemSlice slice) { + QUIC_DVLOG(2) << "Save slice offset " << stream_offset_ << " length " + << slice.length(); if (slice.empty()) { QUIC_BUG << "Try to save empty MemSlice to send buffer."; return; } size_t length = slice.length(); buffered_slices_.emplace_back(std::move(slice), stream_offset_); + if (write_index_ == -1) { + write_index_ = buffered_slices_.size() - 1; + } stream_offset_ += length; } @@ -73,8 +86,11 @@ void QuicStreamSendBuffer::OnStreamDataConsumed(size_t bytes_consumed) { bool QuicStreamSendBuffer::WriteStreamData(QuicStreamOffset offset, QuicByteCount data_length, QuicDataWriter* writer) { + if (use_write_index_) { + return WriteStreamDataWithIndex(offset, data_length, writer); + } for (const BufferedSlice& slice : buffered_slices_) { - if (offset < slice.offset) { + if (data_length == 0 || offset < slice.offset) { break; } if (offset >= slice.offset + slice.slice.length()) { @@ -93,6 +109,66 @@ bool QuicStreamSendBuffer::WriteStreamData(QuicStreamOffset offset, return data_length == 0; } +bool QuicStreamSendBuffer::WriteStreamDataWithIndex(QuicStreamOffset offset, + QuicByteCount data_length, + QuicDataWriter* writer) { + bool write_index_hit = false; + QuicDeque<BufferedSlice>::iterator slice_it = + write_index_ == -1 + ? buffered_slices_.begin() + // Assume with write_index, write mostly starts from indexed slice. + : buffered_slices_.begin() + write_index_; + if (write_index_ != -1) { + if (offset >= slice_it->offset + slice_it->slice.length()) { + QUIC_BUG << "Tried to write data out of sequence."; + return false; + } + // Determine if write actually happens at indexed slice. + if (offset >= slice_it->offset) { + write_index_hit = true; + QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_use_write_index, 1, 2); + } else { + // Write index missed, move iterator to the beginning. + slice_it = buffered_slices_.begin(); + } + } + + for (; slice_it != buffered_slices_.end(); ++slice_it) { + if (data_length == 0 || offset < slice_it->offset) { + break; + } + if (offset >= slice_it->offset + slice_it->slice.length()) { + continue; + } + QuicByteCount slice_offset = offset - slice_it->offset; + QuicByteCount available_bytes_in_slice = + slice_it->slice.length() - slice_offset; + QuicByteCount copy_length = std::min(data_length, available_bytes_in_slice); + if (!writer->WriteBytes(slice_it->slice.data() + slice_offset, + copy_length)) { + QUIC_BUG << "Writer fails to write."; + return false; + } + offset += copy_length; + data_length -= copy_length; + + if (write_index_hit && copy_length == available_bytes_in_slice) { + // Finished writing all data in current slice, advance write index for + // next write. + ++write_index_; + } + } + + if (write_index_hit && + static_cast<size_t>(write_index_) == buffered_slices_.size()) { + // Already write to the end off buffer. + DVLOG(2) << "Finish writing out all buffered data."; + write_index_ = -1; + } + + return data_length == 0; +} + bool QuicStreamSendBuffer::OnStreamDataAcked( QuicStreamOffset offset, QuicByteCount data_length, @@ -114,12 +190,27 @@ bool QuicStreamSendBuffer::OnStreamDataAcked( stream_bytes_outstanding_ -= *newly_acked_length; if (allow_multiple_acks_for_data_) { bytes_acked_.Add(offset, offset + data_length); + pending_retransmissions_.Difference(offset, offset + data_length); while (!buffered_slices_.empty() && bytes_acked_.Contains(buffered_slices_.front().offset, buffered_slices_.front().offset + buffered_slices_.front().slice.length())) { // Remove data which stops waiting for acks. Please note, data can be // acked out of order, but send buffer is cleaned up in order. + if (use_write_index_) { + QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_use_write_index, 2, 2); + QUIC_BUG_IF(write_index_ == 0) + << "Fail to advance current_write_slice_. It points to the slice " + "whose data has all be written and ACK'ed or ignored. " + "current_write_slice_ offset " + << buffered_slices_[write_index_].offset << " length " + << buffered_slices_[write_index_].slice.length(); + if (write_index_ > 0) { + // If write index is pointing to any slice, reduce the index as the + // slices are all shifted to the left by one. + --write_index_; + } + } buffered_slices_.pop_front(); } return true; @@ -150,6 +241,52 @@ bool QuicStreamSendBuffer::OnStreamDataAcked( return true; } +void QuicStreamSendBuffer::OnStreamDataLost(QuicStreamOffset offset, + QuicByteCount data_length) { + if (data_length == 0) { + return; + } + QuicIntervalSet<QuicStreamOffset> bytes_lost(offset, offset + data_length); + bytes_lost.Difference(bytes_acked_); + if (bytes_lost.Empty()) { + return; + } + for (const auto& lost : bytes_lost) { + pending_retransmissions_.Add(lost.min(), lost.max()); + } +} + +void QuicStreamSendBuffer::OnStreamDataRetransmitted( + QuicStreamOffset offset, + QuicByteCount data_length) { + if (data_length == 0) { + return; + } + pending_retransmissions_.Difference(offset, offset + data_length); +} + +bool QuicStreamSendBuffer::HasPendingRetransmission() const { + return !pending_retransmissions_.Empty(); +} + +StreamPendingRetransmission QuicStreamSendBuffer::NextPendingRetransmission() + const { + if (HasPendingRetransmission()) { + const auto pending = pending_retransmissions_.begin(); + return {pending->min(), pending->max() - pending->min()}; + } + QUIC_BUG << "NextPendingRetransmission is called unexpected with no " + "pending retransmissions."; + return {0, 0}; +} + +bool QuicStreamSendBuffer::IsStreamDataOutstanding( + QuicStreamOffset offset, + QuicByteCount data_length) const { + return data_length > 0 && + !bytes_acked_.Contains(offset, offset + data_length); +} + size_t QuicStreamSendBuffer::size() const { return buffered_slices_.size(); } diff --git a/chromium/net/quic/core/quic_stream_send_buffer.h b/chromium/net/quic/core/quic_stream_send_buffer.h index 79eafccc2dd..c9a7b4aa523 100644 --- a/chromium/net/quic/core/quic_stream_send_buffer.h +++ b/chromium/net/quic/core/quic_stream_send_buffer.h @@ -42,6 +42,19 @@ struct BufferedSlice { QuicByteCount outstanding_data_length; }; +struct StreamPendingRetransmission { + StreamPendingRetransmission(QuicStreamOffset offset, QuicByteCount length) + : offset(offset), length(length) {} + + // Starting offset of this pending retransmission. + QuicStreamOffset offset; + // Length of this pending retransmission. + QuicByteCount length; + + QUIC_EXPORT_PRIVATE bool operator==( + const StreamPendingRetransmission& other) const; +}; + // QuicStreamSendBuffer contains a list of QuicStreamDataSlices. New data slices // are added to the tail of the list. Data slices are removed from the head of // the list when they get fully acked. Stream data can be retrieved and acked @@ -78,6 +91,24 @@ class QUIC_EXPORT_PRIVATE QuicStreamSendBuffer { QuicByteCount data_length, QuicByteCount* newly_acked_length); + // Called when data [offset, offset + data_length) is considered as lost. + void OnStreamDataLost(QuicStreamOffset offset, QuicByteCount data_length); + + // Called when data [offset, offset + length) was retransmitted. + void OnStreamDataRetransmitted(QuicStreamOffset offset, + QuicByteCount data_length); + + // Returns true if there is pending retransmissions. + bool HasPendingRetransmission() const; + + // Returns next pending retransmissions. + StreamPendingRetransmission NextPendingRetransmission() const; + + // Returns true if data [offset, offset + data_length) is outstanding and + // waiting to be acked. Returns false otherwise. + bool IsStreamDataOutstanding(QuicStreamOffset offset, + QuicByteCount data_length) const; + // Number of data slices in send buffer. size_t size() const; @@ -97,6 +128,15 @@ class QUIC_EXPORT_PRIVATE QuicStreamSendBuffer { friend class test::QuicStreamSendBufferPeer; friend class test::QuicStreamPeer; + // Another version of WriteStreamData() to be able to start writing from + // write_index_ points to instead of searching through the slices to find the + // place to write. + // TODO(danzh): inline this method into WriteStreamData() after + // quic_reloadable_flag_quic_use_write_index is deprecated. + bool WriteStreamDataWithIndex(QuicStreamOffset offset, + QuicByteCount data_length, + QuicDataWriter* writer); + QuicDeque<BufferedSlice> buffered_slices_; // Offset of next inserted byte. @@ -115,6 +155,17 @@ class QUIC_EXPORT_PRIVATE QuicStreamSendBuffer { // Latch value for quic_reloadable_flag_quic_allow_multiple_acks_for_data2. const bool allow_multiple_acks_for_data_; + + // Data considered as lost and needs to be retransmitted. + QuicIntervalSet<QuicStreamOffset> pending_retransmissions_; + + // Index of slice which contains data waiting to be written for the first + // time. -1 if send buffer is empty or all data has been written. + int32_t write_index_; + + // True if quic_reloadable_flag_quic_stream_send_buffer_write_index and + // allow_multiple_acks_for_data_ are both true. + const bool use_write_index_; }; } // namespace net diff --git a/chromium/net/quic/core/quic_stream_send_buffer_test.cc b/chromium/net/quic/core/quic_stream_send_buffer_test.cc index d2770244731..f4e092f2714 100644 --- a/chromium/net/quic/core/quic_stream_send_buffer_test.cc +++ b/chromium/net/quic/core/quic_stream_send_buffer_test.cc @@ -9,6 +9,7 @@ #include "net/quic/core/quic_utils.h" #include "net/quic/platform/api/quic_flags.h" #include "net/quic/platform/api/quic_test.h" +#include "net/quic/test_tools/quic_stream_send_buffer_peer.h" #include "net/quic/test_tools/quic_test_utils.h" using std::string; @@ -28,7 +29,7 @@ class QuicStreamSendBufferTest : public QuicTest { QuicStreamSendBufferTest() : send_buffer_( &allocator_, - FLAGS_quic_reloadable_flag_quic_allow_multiple_acks_for_data2) { + GetQuicReloadableFlag(quic_allow_multiple_acks_for_data2)) { EXPECT_EQ(0u, send_buffer_.size()); EXPECT_EQ(0u, send_buffer_.stream_bytes_written()); EXPECT_EQ(0u, send_buffer_.stream_bytes_outstanding()); @@ -41,7 +42,11 @@ class QuicStreamSendBufferTest : public QuicTest { QuicMemSlice slice1(&allocator_, 1024); memset(const_cast<char*>(slice1.data()), 'c', 1024); QuicMemSlice slice2(&allocator_, 768); - memset(const_cast<char*>(slice2.data()), 'c', 768); + memset(const_cast<char*>(slice2.data()), 'd', 768); + + // Index starts from not pointing to any slice. + EXPECT_EQ(nullptr, + QuicStreamSendBufferPeer::CurrentWriteSlice(&send_buffer_)); // Save all data. SetQuicFlag(&FLAGS_quic_send_buffer_max_data_slice_size, 1024); @@ -50,12 +55,22 @@ class QuicStreamSendBufferTest : public QuicTest { EXPECT_TRUE(slice1.empty()); send_buffer_.SaveMemSlice(std::move(slice2)); EXPECT_TRUE(slice2.empty()); + + EXPECT_EQ(4u, send_buffer_.size()); + // At this point, the whole buffer looks like: + // | a * 1536 |b * 256| c * 1280 | d * 768 | + // | slice1 | slice2 | slice3 | slice4 | + } + + void WriteAllData() { // Write all data. - send_buffer_.OnStreamDataConsumed(3840); + char buf[4000]; + QuicDataWriter writer(4000, buf, HOST_BYTE_ORDER); + send_buffer_.WriteStreamData(0, 3840u, &writer); + + send_buffer_.OnStreamDataConsumed(3840u); EXPECT_EQ(3840u, send_buffer_.stream_bytes_written()); EXPECT_EQ(3840u, send_buffer_.stream_bytes_outstanding()); - - EXPECT_EQ(4u, send_buffer_.size()); } SimpleBufferAllocator allocator_; @@ -68,7 +83,7 @@ TEST_F(QuicStreamSendBufferTest, CopyDataToBuffer) { string copy1(1024, 'a'); string copy2 = string(512, 'a') + string(256, 'b') + string(256, 'c'); string copy3(1024, 'c'); - string copy4(768, 'c'); + string copy4(768, 'd'); ASSERT_TRUE(send_buffer_.WriteStreamData(0, 1024, &writer)); EXPECT_EQ(copy1, QuicStringPiece(buf, 1024)); @@ -76,7 +91,7 @@ TEST_F(QuicStreamSendBufferTest, CopyDataToBuffer) { EXPECT_EQ(copy2, QuicStringPiece(buf + 1024, 1024)); ASSERT_TRUE(send_buffer_.WriteStreamData(2048, 1024, &writer)); EXPECT_EQ(copy3, QuicStringPiece(buf + 2048, 1024)); - ASSERT_TRUE(send_buffer_.WriteStreamData(2048, 768, &writer)); + ASSERT_TRUE(send_buffer_.WriteStreamData(3072, 768, &writer)); EXPECT_EQ(copy4, QuicStringPiece(buf + 3072, 768)); // Test data piece across boundries. @@ -85,15 +100,28 @@ TEST_F(QuicStreamSendBufferTest, CopyDataToBuffer) { ASSERT_TRUE(send_buffer_.WriteStreamData(1000, 1024, &writer2)); EXPECT_EQ(copy5, QuicStringPiece(buf, 1024)); ASSERT_TRUE(send_buffer_.WriteStreamData(2500, 1024, &writer2)); - EXPECT_EQ(copy3, QuicStringPiece(buf + 1024, 1024)); + string copy6 = string(572, 'c') + string(452, 'd'); + EXPECT_EQ(copy6, QuicStringPiece(buf + 1024, 1024)); // Invalid data copy. QuicDataWriter writer3(4000, buf, HOST_BYTE_ORDER); EXPECT_FALSE(send_buffer_.WriteStreamData(3000, 1024, &writer3)); - EXPECT_FALSE(send_buffer_.WriteStreamData(0, 4000, &writer3)); + if (GetQuicReloadableFlag(quic_use_write_index) && + GetQuicReloadableFlag(quic_allow_multiple_acks_for_data2)) { + EXPECT_DFATAL(send_buffer_.WriteStreamData(0, 4000, &writer3), + "Writer fails to write."); + } else { + EXPECT_FALSE(send_buffer_.WriteStreamData(0, 4000, &writer3)); + } + + send_buffer_.OnStreamDataConsumed(3840); + EXPECT_EQ(3840u, send_buffer_.stream_bytes_written()); + EXPECT_EQ(3840u, send_buffer_.stream_bytes_outstanding()); } TEST_F(QuicStreamSendBufferTest, RemoveStreamFrame) { + WriteAllData(); + QuicByteCount newly_acked_length; EXPECT_TRUE(send_buffer_.OnStreamDataAcked(1024, 1024, &newly_acked_length)); EXPECT_EQ(1024u, newly_acked_length); @@ -114,6 +142,8 @@ TEST_F(QuicStreamSendBufferTest, RemoveStreamFrame) { } TEST_F(QuicStreamSendBufferTest, RemoveStreamFrameAcrossBoundries) { + WriteAllData(); + QuicByteCount newly_acked_length; EXPECT_TRUE(send_buffer_.OnStreamDataAcked(2024, 576, &newly_acked_length)); EXPECT_EQ(576u, newly_acked_length); @@ -138,9 +168,10 @@ TEST_F(QuicStreamSendBufferTest, RemoveStreamFrameAcrossBoundries) { } TEST_F(QuicStreamSendBufferTest, AckStreamDataMultipleTimes) { - if (!FLAGS_quic_reloadable_flag_quic_allow_multiple_acks_for_data2) { + if (!GetQuicReloadableFlag(quic_allow_multiple_acks_for_data2)) { return; } + WriteAllData(); QuicByteCount newly_acked_length; EXPECT_TRUE(send_buffer_.OnStreamDataAcked(100, 1500, &newly_acked_length)); EXPECT_EQ(1500u, newly_acked_length); @@ -162,6 +193,89 @@ TEST_F(QuicStreamSendBufferTest, AckStreamDataMultipleTimes) { EXPECT_FALSE(send_buffer_.OnStreamDataAcked(4000, 100, &newly_acked_length)); } +TEST_F(QuicStreamSendBufferTest, PendingRetransmission) { + if (!FLAGS_quic_reloadable_flag_quic_allow_multiple_acks_for_data2) { + return; + } + WriteAllData(); + EXPECT_TRUE(send_buffer_.IsStreamDataOutstanding(0, 3840)); + EXPECT_FALSE(send_buffer_.HasPendingRetransmission()); + // Lost data [0, 1200). + send_buffer_.OnStreamDataLost(0, 1200); + // Lost data [1500, 2000). + send_buffer_.OnStreamDataLost(1500, 500); + EXPECT_TRUE(send_buffer_.HasPendingRetransmission()); + + EXPECT_EQ(StreamPendingRetransmission(0, 1200), + send_buffer_.NextPendingRetransmission()); + // Retransmit data [0, 500). + send_buffer_.OnStreamDataRetransmitted(0, 500); + EXPECT_TRUE(send_buffer_.IsStreamDataOutstanding(0, 500)); + EXPECT_EQ(StreamPendingRetransmission(500, 700), + send_buffer_.NextPendingRetransmission()); + // Ack data [500, 1200). + QuicByteCount newly_acked_length = 0; + EXPECT_TRUE(send_buffer_.OnStreamDataAcked(500, 700, &newly_acked_length)); + EXPECT_FALSE(send_buffer_.IsStreamDataOutstanding(500, 700)); + EXPECT_TRUE(send_buffer_.HasPendingRetransmission()); + EXPECT_EQ(StreamPendingRetransmission(1500, 500), + send_buffer_.NextPendingRetransmission()); + // Retransmit data [1500, 2000). + send_buffer_.OnStreamDataRetransmitted(1500, 500); + EXPECT_FALSE(send_buffer_.HasPendingRetransmission()); + + // Lost [200, 800). + send_buffer_.OnStreamDataLost(200, 600); + EXPECT_TRUE(send_buffer_.HasPendingRetransmission()); + // Verify [200, 500) is considered as lost, as [500, 800) has been acked. + EXPECT_EQ(StreamPendingRetransmission(200, 300), + send_buffer_.NextPendingRetransmission()); + + // Verify 0 length data is not outstanding. + EXPECT_FALSE(send_buffer_.IsStreamDataOutstanding(100, 0)); + // Verify partially acked data is outstanding. + EXPECT_TRUE(send_buffer_.IsStreamDataOutstanding(400, 800)); +} + +TEST_F(QuicStreamSendBufferTest, CurrentWriteIndex) { + if (!GetQuicReloadableFlag(quic_use_write_index) || + !GetQuicReloadableFlag(quic_allow_multiple_acks_for_data2)) { + return; + } + char buf[4000]; + QuicDataWriter writer(4000, buf, HOST_BYTE_ORDER); + // With data buffered, index points to the 1st slice of data. + EXPECT_EQ(0u, + QuicStreamSendBufferPeer::CurrentWriteSlice(&send_buffer_)->offset); + ASSERT_TRUE(send_buffer_.WriteStreamData(0, 1024, &writer)); + // Wrote all data on 1st slice, index points to next slice. + EXPECT_EQ(1024u, + QuicStreamSendBufferPeer::CurrentWriteSlice(&send_buffer_)->offset); + ASSERT_TRUE(send_buffer_.WriteStreamData(1024, 512, &writer)); + // Last write didn't finish a whole slice. Index remains. + EXPECT_EQ(1024u, + QuicStreamSendBufferPeer::CurrentWriteSlice(&send_buffer_)->offset); + send_buffer_.OnStreamDataConsumed(1024); + + // If data in 1st slice gets ACK'ed, it shouldn't change the indexed slice + QuicByteCount newly_acked_length; + EXPECT_TRUE(send_buffer_.OnStreamDataAcked(0, 1024, &newly_acked_length)); + EXPECT_EQ(1024u, + QuicStreamSendBufferPeer::CurrentWriteSlice(&send_buffer_)->offset); + + ASSERT_TRUE( + send_buffer_.WriteStreamData(1024 + 512, 3840 - 1024 - 512, &writer)); + // After writing all buffered data, index become invalid again. + EXPECT_EQ(nullptr, + QuicStreamSendBufferPeer::CurrentWriteSlice(&send_buffer_)); + QuicMemSlice slice(&allocator_, 60); + memset(const_cast<char*>(slice.data()), 'e', 60); + send_buffer_.SaveMemSlice(std::move(slice)); + // With new data, index points to the new data. + EXPECT_EQ(3840u, + QuicStreamSendBufferPeer::CurrentWriteSlice(&send_buffer_)->offset); +} + } // namespace } // namespace test } // namespace net diff --git a/chromium/net/quic/core/quic_stream_sequencer.cc b/chromium/net/quic/core/quic_stream_sequencer.cc index d272910c300..b235e53588d 100644 --- a/chromium/net/quic/core/quic_stream_sequencer.cc +++ b/chromium/net/quic/core/quic_stream_sequencer.cc @@ -47,6 +47,7 @@ void QuicStreamSequencer::OnStreamFrame(const QuicStreamFrame& frame) { return; } } + const size_t previous_readable_bytes = buffered_frames_.ReadableBytes(); size_t bytes_written; string error_details; QuicErrorCode result = buffered_frames_.OnStreamData( @@ -73,7 +74,12 @@ void QuicStreamSequencer::OnStreamFrame(const QuicStreamFrame& frame) { return; } - if (byte_offset == buffered_frames_.BytesConsumed()) { + bool can_continue_read = byte_offset == buffered_frames_.BytesConsumed(); + if (buffered_frames_.allow_overlapping_data()) { + can_continue_read = + previous_readable_bytes == 0 && buffered_frames_.ReadableBytes() > 0; + } + if (can_continue_read) { if (ignore_read_data_) { FlushBufferedFrames(); } else { diff --git a/chromium/net/quic/core/quic_stream_sequencer_buffer.cc b/chromium/net/quic/core/quic_stream_sequencer_buffer.cc index 01d75d556ac..04984afbf8c 100644 --- a/chromium/net/quic/core/quic_stream_sequencer_buffer.cc +++ b/chromium/net/quic/core/quic_stream_sequencer_buffer.cc @@ -18,7 +18,7 @@ namespace net { namespace { size_t CalculateBlockCount(size_t max_capacity_bytes) { - if (FLAGS_quic_reloadable_flag_quic_fix_sequencer_buffer_block_count2) { + if (GetQuicReloadableFlag(quic_fix_sequencer_buffer_block_count2)) { QUIC_FLAG_COUNT( quic_reloadable_flag_quic_fix_sequencer_buffer_block_count2); return (max_capacity_bytes + QuicStreamSequencerBuffer::kBlockSizeBytes - @@ -32,6 +32,8 @@ size_t CalculateBlockCount(size_t max_capacity_bytes) { // Upper limit of how many gaps allowed in buffer, which ensures a reasonable // number of iterations needed to find the right gap to fill when a frame // arrives. +// TODO(fayang): Rename kMaxNumGapsAllowed to kMaxNumDataIntervalsAllowed when +// deprecating quic_reloadable_flag_quic_allow_receiving_overlapping_data. const size_t kMaxNumGapsAllowed = 2 * kMaxPacketGap; } // namespace @@ -52,7 +54,12 @@ QuicStreamSequencerBuffer::QuicStreamSequencerBuffer(size_t max_capacity_bytes) blocks_count_(CalculateBlockCount(max_capacity_bytes)), total_bytes_read_(0), blocks_(nullptr), - destruction_indicator_(123456) { + destruction_indicator_(123456), + allow_overlapping_data_( + GetQuicReloadableFlag(quic_allow_receiving_overlapping_data)) { + if (allow_overlapping_data_) { + QUIC_FLAG_COUNT(quic_reloadable_flag_quic_allow_receiving_overlapping_data); + } CHECK_GT(blocks_count_, 1u) << "blocks_count_ = " << blocks_count_ << ", max_buffer_capacity_bytes_ = " << max_buffer_capacity_bytes_; @@ -73,11 +80,18 @@ void QuicStreamSequencerBuffer::Clear() { } } num_bytes_buffered_ = 0; - // Reset gaps_ so that buffer is in a state as if all data before - // total_bytes_read_ has been consumed, and those after total_bytes_read_ - // has never arrived. - gaps_ = std::list<Gap>( - 1, Gap(total_bytes_read_, std::numeric_limits<QuicStreamOffset>::max())); + if (allow_overlapping_data_) { + bytes_received_.Clear(); + bytes_received_.Add(0, total_bytes_read_); + } else { + // Reset gaps_ so that buffer is in a state as if all data before + // total_bytes_read_ has been consumed, and those after total_bytes_read_ + // has never arrived. + gaps_ = std::list<Gap>( + 1, + Gap(total_bytes_read_, std::numeric_limits<QuicStreamOffset>::max())); + } + frame_arrival_time_map_.clear(); } @@ -106,6 +120,45 @@ QuicErrorCode QuicStreamSequencerBuffer::OnStreamData( *error_details = "Received empty stream frame without FIN."; return QUIC_EMPTY_STREAM_FRAME_NO_FIN; } + if (allow_overlapping_data_) { + // Write beyond the current range this buffer is covering. + if (starting_offset + size > + total_bytes_read_ + max_buffer_capacity_bytes_ || + starting_offset + size < starting_offset) { + *error_details = "Received data beyond available range."; + return QUIC_INTERNAL_ERROR; + } + + QuicIntervalSet<QuicStreamOffset> newly_received(starting_offset, + starting_offset + size); + newly_received.Difference(bytes_received_); + if (newly_received.Empty()) { + return QUIC_NO_ERROR; + } + bytes_received_.Add(starting_offset, starting_offset + size); + if (bytes_received_.Size() >= kMaxNumGapsAllowed) { + // This frame is going to create more intervals than allowed. Stop + // processing. + *error_details = "Too many data intervals received for this stream."; + return QUIC_TOO_MANY_STREAM_DATA_INTERVALS; + } + for (const auto& interval : newly_received) { + const QuicStreamOffset copy_offset = interval.min(); + const QuicByteCount copy_length = interval.max() - interval.min(); + size_t bytes_copy = 0; + if (!CopyStreamData( + copy_offset, + data.substr(copy_offset - starting_offset, copy_length), + &bytes_copy, error_details)) { + return QUIC_STREAM_SEQUENCER_INVALID_STATE; + } + *bytes_buffered += bytes_copy; + frame_arrival_time_map_.insert( + std::make_pair(copy_offset, FrameInfo(copy_length, timestamp))); + } + num_bytes_buffered_ += *bytes_buffered; + return QUIC_NO_ERROR; + } // Find the first gap not ending before |offset|. This gap maybe the gap to // fill if the arriving frame doesn't overlaps with previous ones. @@ -165,7 +218,7 @@ QuicErrorCode QuicStreamSequencerBuffer::OnStreamData( // This frame is going to create one more gap which exceeds max number of // gaps allowed. Stop processing. *error_details = "Too many gaps created for this stream."; - return QUIC_TOO_MANY_FRAME_GAPS; + return QUIC_TOO_MANY_STREAM_DATA_INTERVALS; } if (!CopyStreamData(offset, data, bytes_buffered, error_details)) { @@ -366,7 +419,7 @@ int QuicStreamSequencerBuffer::GetReadableRegions(struct iovec* iov, } size_t start_block_idx = NextBlockToRead(); - QuicStreamOffset readable_offset_end = gaps_.front().begin_offset - 1; + QuicStreamOffset readable_offset_end = FirstMissingByte() - 1; DCHECK_GE(readable_offset_end + 1, total_bytes_read_); size_t end_block_offset = GetInBlockOffset(readable_offset_end); size_t end_block_idx = GetBlockIndex(readable_offset_end); @@ -483,7 +536,7 @@ bool QuicStreamSequencerBuffer::MarkConsumed(size_t bytes_used) { size_t QuicStreamSequencerBuffer::FlushBufferedFrames() { size_t prev_total_bytes_read = total_bytes_read_; - total_bytes_read_ = gaps_.back().begin_offset; + total_bytes_read_ = NextExpectedByte(); Clear(); return total_bytes_read_ - prev_total_bytes_read; } @@ -494,7 +547,7 @@ void QuicStreamSequencerBuffer::ReleaseWholeBuffer() { } size_t QuicStreamSequencerBuffer::ReadableBytes() const { - return gaps_.front().begin_offset - total_bytes_read_; + return FirstMissingByte() - total_bytes_read_; } bool QuicStreamSequencerBuffer::HasBytesToRead() const { @@ -537,27 +590,46 @@ bool QuicStreamSequencerBuffer::RetireBlockIfEmpty(size_t block_index) { // Check where the logical end of this buffer is. // Not empty if the end of circular buffer has been wrapped to this block. - if (GetBlockIndex(gaps_.back().begin_offset - 1) == block_index) { + if (GetBlockIndex(NextExpectedByte() - 1) == block_index) { return true; } // Read index remains in this block, which means a gap has been reached. if (NextBlockToRead() == block_index) { - Gap first_gap = gaps_.front(); - DCHECK(first_gap.begin_offset == total_bytes_read_); - // Check where the next piece data is. - // Not empty if next piece of data is still in this chunk. - bool gap_ends_in_this_block = - (GetBlockIndex(first_gap.end_offset) == block_index); - if (gap_ends_in_this_block) { - return true; + if (allow_overlapping_data_) { + if (bytes_received_.Size() > 1) { + auto it = bytes_received_.begin(); + ++it; + if (GetBlockIndex(it->min()) == block_index) { + // Do not retire the block if next data interval is in this block. + return true; + } + } else { + QUIC_BUG << "Read stopped at where it shouldn't."; + return false; + } + } else { + Gap first_gap = gaps_.front(); + DCHECK(first_gap.begin_offset == total_bytes_read_); + // Check where the next piece data is. + // Not empty if next piece of data is still in this chunk. + bool gap_ends_in_this_block = + (GetBlockIndex(first_gap.end_offset) == block_index); + if (gap_ends_in_this_block) { + return true; + } } } return RetireBlock(block_index); } bool QuicStreamSequencerBuffer::Empty() const { - return gaps_.size() == 1 && gaps_.front().begin_offset == total_bytes_read_; + if (!allow_overlapping_data_) { + return gaps_.size() == 1 && gaps_.front().begin_offset == total_bytes_read_; + } + return bytes_received_.Empty() || + (bytes_received_.Size() == 1 && total_bytes_read_ > 0 && + bytes_received_.begin()->max() == total_bytes_read_); } size_t QuicStreamSequencerBuffer::GetBlockCapacity(size_t block_index) const { @@ -596,6 +668,9 @@ void QuicStreamSequencerBuffer::UpdateFrameArrivalMap(QuicStreamOffset offset) { } string QuicStreamSequencerBuffer::GapsDebugString() { + if (allow_overlapping_data_) { + return bytes_received_.ToString(); + } string current_gaps_string; for (const Gap& gap : gaps_) { QuicStreamOffset current_gap_begin = gap.begin_offset; @@ -619,4 +694,25 @@ string QuicStreamSequencerBuffer::ReceivedFramesDebugString() { return current_frames_string; } +QuicStreamOffset QuicStreamSequencerBuffer::FirstMissingByte() const { + if (allow_overlapping_data_) { + if (bytes_received_.Empty() || bytes_received_.begin()->min() > 0) { + // Offset 0 is not received yet. + return 0; + } + return bytes_received_.begin()->max(); + } + return gaps_.front().begin_offset; +} + +QuicStreamOffset QuicStreamSequencerBuffer::NextExpectedByte() const { + if (allow_overlapping_data_) { + if (bytes_received_.Empty()) { + return 0; + } + return bytes_received_.rbegin()->max(); + } + return gaps_.back().begin_offset; +} + } // namespace net diff --git a/chromium/net/quic/core/quic_stream_sequencer_buffer.h b/chromium/net/quic/core/quic_stream_sequencer_buffer.h index 439965d5311..9a65dd6b247 100644 --- a/chromium/net/quic/core/quic_stream_sequencer_buffer.h +++ b/chromium/net/quic/core/quic_stream_sequencer_buffer.h @@ -7,8 +7,8 @@ // QuicStreamSequencerBuffer is a circular stream buffer with random write and // in-sequence read. It consists of a vector of pointers pointing -// to memory blocks created as needed and a list of Gaps to indicate -// the missing data between the data already written into the buffer. +// to memory blocks created as needed and an interval set recording received +// data. // - Data are written in with offset indicating where it should be in the // stream, and the buffer grown as needed (up to the maximum buffer capacity), // without expensive copying (extra blocks are allocated). @@ -167,6 +167,11 @@ class QUIC_EXPORT_PRIVATE QuicStreamSequencerBuffer { // Count how many bytes are in buffer at this moment. size_t BytesBuffered() const; + // Returns number of bytes available to be read out. + size_t ReadableBytes() const; + + bool allow_overlapping_data() const { return allow_overlapping_data_; } + private: friend class test::QuicStreamSequencerBufferPeer; @@ -184,7 +189,7 @@ class QUIC_EXPORT_PRIVATE QuicStreamSequencerBuffer { bool RetireBlock(size_t index); // Should only be called after the indexed block is read till the end of the - // block or a gap has been reached. + // block or missing data has been reached. // If the block at |block_index| contains no buffered data, the block // should be retired. // Return false on success, or false otherwise. @@ -192,6 +197,8 @@ class QUIC_EXPORT_PRIVATE QuicStreamSequencerBuffer { // Called within OnStreamData() to update the gap OnStreamData() writes into // (remove, split or change begin/end offset). + // TODO(fayang): Remove this when deprecating + // quic_reloadable_flag_quic_allow_receiving_overlapping_data. void UpdateGapList(std::list<Gap>::iterator gap_with_new_data_written, QuicStreamOffset start_offset, size_t bytes_written); @@ -214,8 +221,11 @@ class QUIC_EXPORT_PRIVATE QuicStreamSequencerBuffer { // Get the index of the logical 1st block to start next read. size_t NextBlockToRead() const; - // Returns number of bytes available to be read out. - size_t ReadableBytes() const; + // Returns offset of first missing byte. + QuicStreamOffset FirstMissingByte() const; + + // Returns offset of highest received byte + 1. + QuicStreamOffset NextExpectedByte() const; // Called after Readv() and MarkConsumed() to keep frame_arrival_time_map_ // up to date. @@ -239,6 +249,8 @@ class QUIC_EXPORT_PRIVATE QuicStreamSequencerBuffer { QuicStreamOffset total_bytes_read_; // Contains Gaps which represents currently missing data. + // TODO(fayang): Remove list of gaps when deprecating + // quic_reloadable_flag_quic_allow_receiving_overlapping_data. std::list<Gap> gaps_; // An ordered, variable-length list of blocks, with the length limited @@ -250,6 +262,8 @@ class QUIC_EXPORT_PRIVATE QuicStreamSequencerBuffer { size_t num_bytes_buffered_; // Stores all the buffered frames' start offset, length and arrival time. + // TODO(fayang): Remove this when deprecating + // quic_reloadable_flag_quic_allow_receiving_overlapping_data. std::map<QuicStreamOffset, FrameInfo> frame_arrival_time_map_; // For debugging use after free, assigned to 123456 in constructor and 654321 @@ -257,6 +271,13 @@ class QUIC_EXPORT_PRIVATE QuicStreamSequencerBuffer { // or memory corruption. int32_t destruction_indicator_; + // Currently received data. + QuicIntervalSet<QuicStreamOffset> bytes_received_; + + // Latched value of + // quic_reloadable_flag_quic_allow_receiving_overlapping_data. + const bool allow_overlapping_data_; + DISALLOW_COPY_AND_ASSIGN(QuicStreamSequencerBuffer); }; } // namespace net diff --git a/chromium/net/quic/core/quic_stream_sequencer_buffer_test.cc b/chromium/net/quic/core/quic_stream_sequencer_buffer_test.cc index 168debd538d..9ca1e8264c7 100644 --- a/chromium/net/quic/core/quic_stream_sequencer_buffer_test.cc +++ b/chromium/net/quic/core/quic_stream_sequencer_buffer_test.cc @@ -84,7 +84,7 @@ class QuicStreamSequencerBufferTest : public testing::Test { }; TEST_F(QuicStreamSequencerBufferTest, InitializeWithMaxRecvWindowSize) { - if (!FLAGS_quic_reloadable_flag_quic_fix_sequencer_buffer_block_count2) { + if (!GetQuicReloadableFlag(quic_fix_sequencer_buffer_block_count2)) { return; } ResetMaxCapacityBytes(16 * 1024 * 1024); // 16MB @@ -132,9 +132,16 @@ TEST_F(QuicStreamSequencerBufferTest, OnStreamDataWithinBlock) { ASSERT_EQ('a', block_ptr->buffer[helper_->GetInBlockOffset(800) + i]); } EXPECT_EQ(2, helper_->GapSize()); - std::list<Gap> gaps = helper_->GetGaps(); - EXPECT_EQ(800u, gaps.front().end_offset); - EXPECT_EQ(1824u, gaps.back().begin_offset); + EXPECT_EQ(0u, helper_->ReadableBytes()); + if (helper_->allow_overlapping_data()) { + EXPECT_EQ(1u, helper_->bytes_received().Size()); + EXPECT_EQ(800u, helper_->bytes_received().begin()->min()); + EXPECT_EQ(1824u, helper_->bytes_received().begin()->max()); + } else { + std::list<Gap> gaps = helper_->GetGaps(); + EXPECT_EQ(800u, gaps.front().end_offset); + EXPECT_EQ(1824u, gaps.back().begin_offset); + } auto* frame_map = helper_->frame_arrival_time_map(); EXPECT_EQ(1u, frame_map->size()); EXPECT_EQ(800u, frame_map->begin()->first); @@ -167,14 +174,25 @@ TEST_F(QuicStreamSequencerBufferTest, OnStreamDataWithOverlap) { EXPECT_EQ(QUIC_NO_ERROR, buffer_->OnStreamData(800, source, t1, &written, &error_details_)); // Try to write to [0, 1024) and [1024, 2048). - // But no byte will be written since overlap. clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1)); QuicTime t2 = clock_.ApproximateNow(); + auto* frame_map = helper_->frame_arrival_time_map(); + if (helper_->allow_overlapping_data()) { + EXPECT_EQ(QUIC_NO_ERROR, + buffer_->OnStreamData(0, source, t2, &written, &error_details_)); + EXPECT_EQ(QUIC_NO_ERROR, buffer_->OnStreamData(1024, source, t2, &written, + &error_details_)); + EXPECT_EQ(3u, frame_map->size()); + EXPECT_EQ(t1, (*frame_map)[800].timestamp); + EXPECT_EQ(t2, (*frame_map)[0].timestamp); + EXPECT_EQ(t2, (*frame_map)[1824].timestamp); + return; + } + // But no byte will be written since overlap. EXPECT_EQ(QUIC_OVERLAPPING_STREAM_DATA, buffer_->OnStreamData(0, source, t2, &written, &error_details_)); EXPECT_EQ(QUIC_OVERLAPPING_STREAM_DATA, buffer_->OnStreamData(1024, source, t2, &written, &error_details_)); - auto* frame_map = helper_->frame_arrival_time_map(); EXPECT_EQ(1u, frame_map->size()); EXPECT_EQ(t1, (*frame_map)[800].timestamp); } @@ -187,6 +205,31 @@ TEST_F(QuicStreamSequencerBufferTest, buffer_->OnStreamData(800, source, clock_.ApproximateNow(), &written, &error_details_); source = string(800, 'b'); + string one_byte = "c"; + auto* frame_map = helper_->frame_arrival_time_map(); + if (helper_->allow_overlapping_data()) { + // Write [1, 801). + EXPECT_EQ(QUIC_NO_ERROR, + buffer_->OnStreamData(1, source, clock_.ApproximateNow(), + &written, &error_details_)); + // Write [0, 800). + EXPECT_EQ(QUIC_NO_ERROR, + buffer_->OnStreamData(0, source, clock_.ApproximateNow(), + &written, &error_details_)); + // Write [1823, 1824). + EXPECT_EQ(QUIC_NO_ERROR, + buffer_->OnStreamData(1823, one_byte, clock_.ApproximateNow(), + &written, &error_details_)); + EXPECT_EQ(0u, written); + // write one byte to [1824, 1825) + EXPECT_EQ(QUIC_NO_ERROR, + buffer_->OnStreamData(1824, one_byte, clock_.ApproximateNow(), + &written, &error_details_)); + EXPECT_EQ(4u, frame_map->size()); + EXPECT_TRUE(helper_->CheckBufferInvariants()); + return; + } + // Try to write to [1, 801), but should fail due to overlapping EXPECT_EQ(QUIC_OVERLAPPING_STREAM_DATA, buffer_->OnStreamData(1, source, clock_.ApproximateNow(), &written, @@ -196,7 +239,6 @@ TEST_F(QuicStreamSequencerBufferTest, buffer_->OnStreamData(0, source, clock_.ApproximateNow(), &written, &error_details_)); // Try to write one byte to [1823, 1824), but should count as duplicate - string one_byte = "c"; EXPECT_EQ(QUIC_NO_ERROR, buffer_->OnStreamData(1823, one_byte, clock_.ApproximateNow(), &written, &error_details_)); @@ -205,7 +247,6 @@ TEST_F(QuicStreamSequencerBufferTest, EXPECT_EQ(QUIC_NO_ERROR, buffer_->OnStreamData(1824, one_byte, clock_.ApproximateNow(), &written, &error_details_)); - auto* frame_map = helper_->frame_arrival_time_map(); EXPECT_EQ(3u, frame_map->size()); EXPECT_TRUE(helper_->CheckBufferInvariants()); } @@ -232,8 +273,13 @@ TEST_F(QuicStreamSequencerBufferTest, OnStreamDataInLongStreamWithOverlap) { // Assume a stream has already buffered almost 4GB. uint64_t total_bytes_read = pow(2, 32) - 1; helper_->set_total_bytes_read(total_bytes_read); - helper_->set_gaps(std::list<Gap>( - 1, Gap(total_bytes_read, std::numeric_limits<QuicStreamOffset>::max()))); + if (helper_->allow_overlapping_data()) { + helper_->AddBytesReceived(0, total_bytes_read); + } else { + helper_->set_gaps(std::list<Gap>( + 1, + Gap(total_bytes_read, std::numeric_limits<QuicStreamOffset>::max()))); + } // Three new out of order frames arrive. const size_t kBytesToWrite = 100; @@ -817,8 +863,13 @@ TEST_F(QuicStreamSequencerBufferTest, TooManyGaps) { QuicStreamOffset last_straw = 2 * kMaxNumGapsAllowed - 1; if (begin == last_straw) { - EXPECT_EQ(QUIC_TOO_MANY_FRAME_GAPS, rs); - EXPECT_EQ("Too many gaps created for this stream.", error_details_); + EXPECT_EQ(QUIC_TOO_MANY_STREAM_DATA_INTERVALS, rs); + if (GetQuicReloadableFlag(quic_allow_receiving_overlapping_data)) { + EXPECT_EQ("Too many data intervals received for this stream.", + error_details_); + } else { + EXPECT_EQ("Too many gaps created for this stream.", error_details_); + } break; } } diff --git a/chromium/net/quic/core/quic_stream_sequencer_test.cc b/chromium/net/quic/core/quic_stream_sequencer_test.cc index 8ca75ff1656..c14e77d65ad 100644 --- a/chromium/net/quic/core/quic_stream_sequencer_test.cc +++ b/chromium/net/quic/core/quic_stream_sequencer_test.cc @@ -12,6 +12,7 @@ #include "net/quic/core/quic_stream.h" #include "net/quic/core/quic_utils.h" +#include "net/quic/platform/api/quic_arraysize.h" #include "net/quic/platform/api/quic_logging.h" #include "net/quic/platform/api/quic_string_piece.h" #include "net/quic/platform/api/quic_test.h" @@ -60,7 +61,7 @@ class QuicStreamSequencerTest : public QuicTest { public: void ConsumeData(size_t num_bytes) { char buffer[1024]; - ASSERT_GT(arraysize(buffer), num_bytes); + ASSERT_GT(QUIC_ARRAYSIZE(buffer), num_bytes); struct iovec iov; iov.iov_base = buffer; iov.iov_len = num_bytes; @@ -90,7 +91,7 @@ class QuicStreamSequencerTest : public QuicTest { bool VerifyReadableRegions(const std::vector<string>& expected) { iovec iovecs[5]; size_t num_iovecs = - sequencer_->GetReadableRegions(iovecs, arraysize(iovecs)); + sequencer_->GetReadableRegions(iovecs, QUIC_ARRAYSIZE(iovecs)); return VerifyReadableRegion(expected) && VerifyIovecs(iovecs, num_iovecs, expected); } @@ -384,7 +385,7 @@ class QuicSequencerRandomTest : public QuicStreamSequencerTest { typedef std::vector<Frame> FrameList; void CreateFrames() { - int payload_size = arraysize(kPayload) - 1; + int payload_size = QUIC_ARRAYSIZE(kPayload) - 1; int remaining_payload = payload_size; while (remaining_payload != 0) { int size = std::min(OneToN(6), remaining_payload); @@ -406,10 +407,10 @@ class QuicSequencerRandomTest : public QuicStreamSequencerTest { void ReadAvailableData() { // Read all available data - char output[arraysize(kPayload) + 1]; + char output[QUIC_ARRAYSIZE(kPayload) + 1]; iovec iov; iov.iov_base = output; - iov.iov_len = arraysize(output); + iov.iov_len = QUIC_ARRAYSIZE(output); int bytes_read = sequencer_->Readv(&iov, 1); EXPECT_NE(0, bytes_read); output_.append(output, bytes_read); @@ -439,7 +440,7 @@ TEST_F(QuicSequencerRandomTest, RandomFramesNoDroppingNoBackup) { list_.erase(list_.begin() + index); } - ASSERT_EQ(arraysize(kPayload) - 1, output_.size()); + ASSERT_EQ(QUIC_ARRAYSIZE(kPayload) - 1, output_.size()); EXPECT_EQ(kPayload, output_); } @@ -453,7 +454,7 @@ TEST_F(QuicSequencerRandomTest, RandomFramesNoDroppingBackup) { EXPECT_CALL(stream_, OnDataAvailable()).Times(AnyNumber()); - while (output_.size() != arraysize(kPayload) - 1) { + while (output_.size() != QUIC_ARRAYSIZE(kPayload) - 1) { if (!list_.empty() && OneToN(2) == 1) { // Send data int index = OneToN(list_.size()) - 1; OnFrame(list_[index].first, list_[index].second.data()); @@ -470,7 +471,7 @@ TEST_F(QuicSequencerRandomTest, RandomFramesNoDroppingBackup) { ASSERT_EQ(0, iovs_peeked); ASSERT_FALSE(sequencer_->GetReadableRegion(peek_iov, ×tamp)); } - int total_bytes_to_peek = arraysize(buffer); + int total_bytes_to_peek = QUIC_ARRAYSIZE(buffer); for (int i = 0; i < iovs_peeked; ++i) { int bytes_to_peek = std::min<int>(peek_iov[i].iov_len, total_bytes_to_peek); @@ -564,7 +565,7 @@ TEST_F(QuicStreamSequencerTest, MarkConsumedWithMissingPacket) { sequencer_->MarkConsumed(6); } -TEST_F(QuicStreamSequencerTest, DontAcceptOverlappingFrames) { +TEST_F(QuicStreamSequencerTest, OverlappingFramesReceived) { // The peer should never send us non-identical stream frames which contain // overlapping byte ranges - if they do, we close the connection. QuicStreamId id = @@ -574,10 +575,59 @@ TEST_F(QuicStreamSequencerTest, DontAcceptOverlappingFrames) { sequencer_->OnStreamFrame(frame1); QuicStreamFrame frame2(id, false, 2, QuicStringPiece("hello")); - EXPECT_CALL(stream_, - CloseConnectionWithDetails(QUIC_OVERLAPPING_STREAM_DATA, _)) - .Times(1); + if (GetQuicReloadableFlag(quic_allow_receiving_overlapping_data)) { + EXPECT_CALL(stream_, + CloseConnectionWithDetails(QUIC_OVERLAPPING_STREAM_DATA, _)) + .Times(0); + } else { + EXPECT_CALL(stream_, + CloseConnectionWithDetails(QUIC_OVERLAPPING_STREAM_DATA, _)) + .Times(1); + } + sequencer_->OnStreamFrame(frame2); +} + +TEST_F(QuicStreamSequencerTest, DataAvailableOnOverlappingFrames) { + if (!GetQuicReloadableFlag(quic_allow_receiving_overlapping_data)) { + return; + } + QuicStreamId id = + QuicSpdySessionPeer::GetNthClientInitiatedStreamId(session_, 0); + const string data(1000, '.'); + + // Received [0, 1000). + QuicStreamFrame frame1(id, false, 0, data); + EXPECT_CALL(stream_, OnDataAvailable()); + sequencer_->OnStreamFrame(frame1); + // Consume [0, 500). + QuicStreamSequencerTest::ConsumeData(500); + EXPECT_EQ(500u, sequencer_->NumBytesConsumed()); + EXPECT_EQ(500u, sequencer_->NumBytesBuffered()); + + // Received [500, 1500). + QuicStreamFrame frame2(id, false, 500, data); + // Do not call OnDataAvailable as there are readable bytes left in the buffer. + EXPECT_CALL(stream_, OnDataAvailable()).Times(0); sequencer_->OnStreamFrame(frame2); + // Consume [1000, 1500). + QuicStreamSequencerTest::ConsumeData(1000); + EXPECT_EQ(1500u, sequencer_->NumBytesConsumed()); + EXPECT_EQ(0u, sequencer_->NumBytesBuffered()); + + // Received [1498, 1503). + QuicStreamFrame frame3(id, false, 1498, QuicStringPiece("hello")); + EXPECT_CALL(stream_, OnDataAvailable()); + sequencer_->OnStreamFrame(frame3); + QuicStreamSequencerTest::ConsumeData(3); + EXPECT_EQ(1503u, sequencer_->NumBytesConsumed()); + EXPECT_EQ(0u, sequencer_->NumBytesBuffered()); + + // Received [1000, 1005). + QuicStreamFrame frame4(id, false, 1000, QuicStringPiece("hello")); + EXPECT_CALL(stream_, OnDataAvailable()).Times(0); + sequencer_->OnStreamFrame(frame4); + EXPECT_EQ(1503u, sequencer_->NumBytesConsumed()); + EXPECT_EQ(0u, sequencer_->NumBytesBuffered()); } TEST_F(QuicStreamSequencerTest, InOrderTimestamps) { diff --git a/chromium/net/quic/core/quic_stream_test.cc b/chromium/net/quic/core/quic_stream_test.cc index 9fc0291473d..ef3667af3b0 100644 --- a/chromium/net/quic/core/quic_stream_test.cc +++ b/chromium/net/quic/core/quic_stream_test.cc @@ -10,6 +10,7 @@ #include "net/quic/core/quic_utils.h" #include "net/quic/core/quic_write_blocked_list.h" #include "net/quic/core/spdy_utils.h" +#include "net/quic/platform/api/quic_arraysize.h" #include "net/quic/platform/api/quic_flags.h" #include "net/quic/platform/api/quic_logging.h" #include "net/quic/platform/api/quic_ptr_util.h" @@ -20,18 +21,20 @@ #include "net/quic/test_tools/quic_flow_controller_peer.h" #include "net/quic/test_tools/quic_session_peer.h" #include "net/quic/test_tools/quic_stream_peer.h" +#include "net/quic/test_tools/quic_stream_sequencer_peer.h" #include "net/quic/test_tools/quic_test_utils.h" #include "net/test/gtest_util.h" #include "testing/gmock_mutant.h" using std::string; +using testing::_; using testing::AnyNumber; using testing::AtLeast; using testing::InSequence; using testing::Invoke; +using testing::InvokeWithoutArgs; using testing::Return; using testing::StrictMock; -using testing::_; namespace net { namespace test { @@ -70,7 +73,7 @@ class QuicStreamTest : public QuicTestWithParam<bool> { QuicStreamTest() : initial_flow_control_window_bytes_(kMaxPacketSize), zero_(QuicTime::Delta::Zero()), - supported_versions_(AllSupportedTransportVersions()) { + supported_versions_(AllSupportedVersions()) { headers_[":host"] = "www.google.com"; headers_[":path"] = "/index.hml"; headers_[":scheme"] = "https"; @@ -153,7 +156,7 @@ class QuicStreamTest : public QuicTestWithParam<bool> { QuicWriteBlockedList* write_blocked_list_; uint32_t initial_flow_control_window_bytes_; QuicTime::Delta zero_; - QuicTransportVersionVector supported_versions_; + ParsedQuicVersionVector supported_versions_; const QuicStreamId kTestStreamId = 5u; }; @@ -168,7 +171,7 @@ TEST_F(QuicStreamTest, WriteAllData) { connection_->SetMaxPacketLength(length); EXPECT_CALL(*session_, WritevData(stream_, kTestStreamId, _, _, _)) - .WillOnce(Return(QuicConsumedData(kDataLen, true))); + .WillOnce(Invoke(&(MockQuicSession::ConsumeData))); stream_->WriteOrBufferData(kData1, false, nullptr); EXPECT_FALSE(HasWriteBlockedStreams()); } @@ -189,7 +192,9 @@ TEST_F(QuicStreamTest, BlockIfOnlySomeDataConsumed) { // Write some data and no fin. If we consume some but not all of the data, // we should be write blocked a not all the data was consumed. EXPECT_CALL(*session_, WritevData(stream_, kTestStreamId, _, _, _)) - .WillOnce(Return(QuicConsumedData(1, false))); + .WillOnce(InvokeWithoutArgs( + testing::CreateFunctor(&(MockQuicSession::ConsumeData), stream_, + stream_->id(), 1u, 0u, NO_FIN))); stream_->WriteOrBufferData(QuicStringPiece(kData1, 2), false, nullptr); ASSERT_EQ(1u, write_blocked_list_->NumBlockedStreams()); EXPECT_EQ(1u, stream_->BufferedDataBytes()); @@ -203,7 +208,9 @@ TEST_F(QuicStreamTest, BlockIfFinNotConsumedWithData) { // (This should never actually happen as the fin should be sent out with the // last data) EXPECT_CALL(*session_, WritevData(stream_, kTestStreamId, _, _, _)) - .WillOnce(Return(QuicConsumedData(2, false))); + .WillOnce(InvokeWithoutArgs( + testing::CreateFunctor(&(MockQuicSession::ConsumeData), stream_, + stream_->id(), 2u, 0u, NO_FIN))); stream_->WriteOrBufferData(QuicStringPiece(kData1, 2), true, nullptr); ASSERT_EQ(1u, write_blocked_list_->NumBlockedStreams()); } @@ -243,7 +250,9 @@ TEST_F(QuicStreamTest, WriteOrBufferData) { connection_->SetMaxPacketLength(length); EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) - .WillOnce(Return(QuicConsumedData(kDataLen - 1, false))); + .WillOnce(InvokeWithoutArgs( + testing::CreateFunctor(&(MockQuicSession::ConsumeData), stream_, + stream_->id(), kDataLen - 1, 0u, NO_FIN))); stream_->WriteOrBufferData(kData1, false, nullptr); EXPECT_EQ(1u, stream_->BufferedDataBytes()); EXPECT_TRUE(HasWriteBlockedStreams()); @@ -254,15 +263,33 @@ TEST_F(QuicStreamTest, WriteOrBufferData) { // Make sure we get the tail of the first write followed by the bytes_consumed InSequence s; EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) - .WillOnce(Return(QuicConsumedData(kDataLen - 1, false))); + .WillOnce(InvokeWithoutArgs(testing::CreateFunctor( + &(MockQuicSession::ConsumeData), stream_, stream_->id(), kDataLen - 1, + kDataLen - 1, NO_FIN))); stream_->OnCanWrite(); // And finally the end of the bytes_consumed. EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) - .WillOnce(Return(QuicConsumedData(2, true))); + .WillOnce(InvokeWithoutArgs( + testing::CreateFunctor(&(MockQuicSession::ConsumeData), stream_, + stream_->id(), 2u, 2 * kDataLen - 2, FIN))); stream_->OnCanWrite(); } +TEST_F(QuicStreamTest, WriteOrBufferDataReachStreamLimit) { + SetQuicReloadableFlag(quic_stream_too_long, true); + Initialize(kShouldProcessData); + string data("aaaaa"); + QuicStreamPeer::SetStreamBytesWritten(kMaxStreamLength - data.length(), + stream_); + EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) + .WillOnce(Invoke(&(MockQuicSession::ConsumeData))); + stream_->WriteOrBufferData(data, false, nullptr); + EXPECT_CALL(*connection_, CloseConnection(QUIC_STREAM_LENGTH_OVERFLOW, _, _)); + EXPECT_DFATAL(stream_->WriteOrBufferData("a", false, nullptr), + "Write too many data via stream"); +} + TEST_F(QuicStreamTest, ConnectionCloseAfterStreamClose) { Initialize(kShouldProcessData); @@ -287,7 +314,9 @@ TEST_F(QuicStreamTest, RstAlwaysSentIfNoFinSent) { // Write some data, with no FIN. EXPECT_CALL(*session_, WritevData(stream_, kTestStreamId, _, _, _)) - .WillOnce(Return(QuicConsumedData(1, false))); + .WillOnce(InvokeWithoutArgs( + testing::CreateFunctor(&(MockQuicSession::ConsumeData), stream_, + stream_->id(), 1u, 0u, NO_FIN))); stream_->WriteOrBufferData(QuicStringPiece(kData1, 1), false, nullptr); EXPECT_FALSE(fin_sent()); EXPECT_FALSE(rst_sent()); @@ -310,7 +339,9 @@ TEST_F(QuicStreamTest, RstNotSentIfFinSent) { // Write some data, with FIN. EXPECT_CALL(*session_, WritevData(stream_, kTestStreamId, _, _, _)) - .WillOnce(Return(QuicConsumedData(1, true))); + .WillOnce(InvokeWithoutArgs( + testing::CreateFunctor(&(MockQuicSession::ConsumeData), stream_, + stream_->id(), 1u, 0u, FIN))); stream_->WriteOrBufferData(QuicStringPiece(kData1, 1), true, nullptr); EXPECT_TRUE(fin_sent()); EXPECT_FALSE(rst_sent()); @@ -505,6 +536,49 @@ TEST_F(QuicStreamTest, FinalByteOffsetFromZeroLengthStreamFrame) { QuicFlowControllerPeer::ReceiveWindowOffset(session_->flow_controller())); } +TEST_F(QuicStreamTest, OnStreamResetOffsetOverflow) { + SetQuicReloadableFlag(quic_stream_too_long, true); + Initialize(kShouldProcessData); + QuicRstStreamFrame rst_frame(kInvalidControlFrameId, stream_->id(), + QUIC_STREAM_CANCELLED, kMaxStreamLength + 1); + EXPECT_CALL(*connection_, CloseConnection(QUIC_STREAM_LENGTH_OVERFLOW, _, _)); + stream_->OnStreamReset(rst_frame); +} + +TEST_F(QuicStreamTest, OnStreamFrameUpperLimit) { + SetQuicReloadableFlag(quic_stream_too_long, true); + Initialize(kShouldProcessData); + + // Modify receive window offset and sequencer buffer total_bytes_read_ to + // avoid flow control violation. + QuicFlowControllerPeer::SetReceiveWindowOffset(stream_->flow_controller(), + kMaxStreamLength + 5u); + QuicFlowControllerPeer::SetReceiveWindowOffset(session_->flow_controller(), + kMaxStreamLength + 5u); + QuicStreamSequencerPeer::SetFrameBufferTotalBytesRead( + QuicStreamPeer::sequencer(stream_), kMaxStreamLength - 10u); + + EXPECT_CALL(*connection_, CloseConnection(QUIC_STREAM_LENGTH_OVERFLOW, _, _)) + .Times(0); + QuicStreamFrame stream_frame(stream_->id(), false, kMaxStreamLength - 1, + QuicStringPiece(".")); + stream_->OnStreamFrame(stream_frame); + QuicStreamFrame stream_frame2(stream_->id(), true, kMaxStreamLength, + QuicStringPiece("")); + stream_->OnStreamFrame(stream_frame2); +} + +TEST_F(QuicStreamTest, StreamTooLong) { + SetQuicReloadableFlag(quic_stream_too_long, true); + Initialize(kShouldProcessData); + EXPECT_CALL(*connection_, CloseConnection(QUIC_STREAM_LENGTH_OVERFLOW, _, _)) + .Times(1); + QuicStreamFrame stream_frame(stream_->id(), false, kMaxStreamLength, + QuicStringPiece(".")); + EXPECT_DFATAL(stream_->OnStreamFrame(stream_frame), + "Receive stream frame reaches max stream length"); +} + TEST_F(QuicStreamTest, SetDrainingIncomingOutgoing) { // Don't have incoming data consumed. Initialize(kShouldNotProcessData); @@ -522,7 +596,9 @@ TEST_F(QuicStreamTest, SetDrainingIncomingOutgoing) { // Outgoing data with FIN. EXPECT_CALL(*session_, WritevData(stream_, kTestStreamId, _, _, _)) - .WillOnce(Return(QuicConsumedData(2, true))); + .WillOnce(InvokeWithoutArgs( + testing::CreateFunctor(&(MockQuicSession::ConsumeData), stream_, + stream_->id(), 2u, 0u, FIN))); stream_->WriteOrBufferData(QuicStringPiece(kData1, 2), true, nullptr); EXPECT_TRUE(stream_->write_side_closed()); @@ -537,7 +613,9 @@ TEST_F(QuicStreamTest, SetDrainingOutgoingIncoming) { // Outgoing data with FIN. EXPECT_CALL(*session_, WritevData(stream_, kTestStreamId, _, _, _)) - .WillOnce(Return(QuicConsumedData(2, true))); + .WillOnce(InvokeWithoutArgs( + testing::CreateFunctor(&(MockQuicSession::ConsumeData), stream_, + stream_->id(), 2u, 0u, FIN))); stream_->WriteOrBufferData(QuicStringPiece(kData1, 2), true, nullptr); EXPECT_TRUE(stream_->write_side_closed()); @@ -564,7 +642,7 @@ TEST_F(QuicStreamTest, EarlyResponseFinHandling) { Initialize(kShouldProcessData); EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0); EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) - .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData)); + .WillRepeatedly(Invoke(MockQuicSession::ConsumeData)); // Receive data for the request. QuicStreamFrame frame1(stream_->id(), false, 0, QuicStringPiece("Start")); @@ -588,7 +666,7 @@ TEST_F(QuicStreamTest, StreamWaitsForAcks) { new StrictMock<MockAckListener>); stream_->set_ack_listener(mock_ack_listener); EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) - .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData)); + .WillRepeatedly(Invoke(MockQuicSession::ConsumeData)); // Stream is not waiting for acks initially. EXPECT_FALSE(stream_->IsWaitingForAcks()); EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size()); @@ -614,7 +692,7 @@ TEST_F(QuicStreamTest, StreamWaitsForAcks) { // kData2 is retransmitted. EXPECT_CALL(*mock_ack_listener, OnPacketRetransmitted(9)); - stream_->OnStreamFrameRetransmitted(9, 9); + stream_->OnStreamFrameRetransmitted(9, 9, false); // kData2 is acked. EXPECT_CALL(*mock_ack_listener, OnPacketAcked(9, _)); @@ -633,7 +711,7 @@ TEST_F(QuicStreamTest, StreamWaitsForAcks) { TEST_F(QuicStreamTest, StreamDataGetAckedOutOfOrder) { Initialize(kShouldProcessData); EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) - .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData)); + .WillRepeatedly(Invoke(MockQuicSession::ConsumeData)); // Send data. stream_->WriteOrBufferData(kData1, false, nullptr); stream_->WriteOrBufferData(kData1, false, nullptr); @@ -657,7 +735,7 @@ TEST_F(QuicStreamTest, StreamDataGetAckedOutOfOrder) { TEST_F(QuicStreamTest, CancelStream) { Initialize(kShouldProcessData); EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) - .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData)); + .WillRepeatedly(Invoke(MockQuicSession::ConsumeData)); EXPECT_FALSE(stream_->IsWaitingForAcks()); EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size()); @@ -672,12 +750,7 @@ TEST_F(QuicStreamTest, CancelStream) { EXPECT_CALL(*session_, SendRstStream(stream_->id(), QUIC_STREAM_CANCELLED, 9)); stream_->Reset(QUIC_STREAM_CANCELLED); - stream_->OnStreamFrameDiscarded(0, 9, false); - if (!FLAGS_quic_reloadable_flag_quic_remove_on_stream_frame_discarded) { - EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size()); - } else { - EXPECT_EQ(1u, QuicStreamPeer::SendBuffer(stream_).size()); - } + EXPECT_EQ(1u, QuicStreamPeer::SendBuffer(stream_).size()); // Stream stops waiting for acks as data is not going to be retransmitted. EXPECT_FALSE(stream_->IsWaitingForAcks()); } @@ -685,7 +758,7 @@ TEST_F(QuicStreamTest, CancelStream) { TEST_F(QuicStreamTest, RstFrameReceivedStreamNotFinishSending) { Initialize(kShouldProcessData); EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) - .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData)); + .WillRepeatedly(Invoke(MockQuicSession::ConsumeData)); EXPECT_FALSE(stream_->IsWaitingForAcks()); EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size()); @@ -699,12 +772,7 @@ TEST_F(QuicStreamTest, RstFrameReceivedStreamNotFinishSending) { EXPECT_CALL(*session_, SendRstStream(stream_->id(), QUIC_RST_ACKNOWLEDGEMENT, 9)); stream_->OnStreamReset(rst_frame); - stream_->OnStreamFrameDiscarded(0, 9, false); - if (!FLAGS_quic_reloadable_flag_quic_remove_on_stream_frame_discarded) { - EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size()); - } else { - EXPECT_EQ(1u, QuicStreamPeer::SendBuffer(stream_).size()); - } + EXPECT_EQ(1u, QuicStreamPeer::SendBuffer(stream_).size()); // Stream stops waiting for acks as it does not finish sending and rst is // sent. EXPECT_FALSE(stream_->IsWaitingForAcks()); @@ -713,7 +781,7 @@ TEST_F(QuicStreamTest, RstFrameReceivedStreamNotFinishSending) { TEST_F(QuicStreamTest, RstFrameReceivedStreamFinishSending) { Initialize(kShouldProcessData); EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) - .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData)); + .WillRepeatedly(Invoke(MockQuicSession::ConsumeData)); EXPECT_FALSE(stream_->IsWaitingForAcks()); EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size()); @@ -733,7 +801,7 @@ TEST_F(QuicStreamTest, RstFrameReceivedStreamFinishSending) { TEST_F(QuicStreamTest, ConnectionClosed) { Initialize(kShouldProcessData); EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) - .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData)); + .WillRepeatedly(Invoke(MockQuicSession::ConsumeData)); EXPECT_FALSE(stream_->IsWaitingForAcks()); EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size()); @@ -744,12 +812,7 @@ TEST_F(QuicStreamTest, ConnectionClosed) { SendRstStream(stream_->id(), QUIC_RST_ACKNOWLEDGEMENT, 9)); stream_->OnConnectionClosed(QUIC_INTERNAL_ERROR, ConnectionCloseSource::FROM_SELF); - stream_->OnStreamFrameDiscarded(0, 9, false); - if (!FLAGS_quic_reloadable_flag_quic_remove_on_stream_frame_discarded) { - EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size()); - } else { - EXPECT_EQ(1u, QuicStreamPeer::SendBuffer(stream_).size()); - } + EXPECT_EQ(1u, QuicStreamPeer::SendBuffer(stream_).size()); // Stream stops waiting for acks as connection is going to close. EXPECT_FALSE(stream_->IsWaitingForAcks()); } @@ -766,7 +829,9 @@ TEST_F(QuicStreamTest, WriteBufferedData) { // Testing WriteOrBufferData. EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) - .WillOnce(Return(QuicConsumedData(100, false))); + .WillOnce(InvokeWithoutArgs( + testing::CreateFunctor(&(MockQuicSession::ConsumeData), stream_, + stream_->id(), 100u, 0u, NO_FIN))); stream_->WriteOrBufferData(data, false, nullptr); stream_->WriteOrBufferData(data, false, nullptr); stream_->WriteOrBufferData(data, false, nullptr); @@ -774,7 +839,9 @@ TEST_F(QuicStreamTest, WriteBufferedData) { EXPECT_EQ(3 * data.length() - 100, stream_->BufferedDataBytes()); EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) - .WillOnce(Return(QuicConsumedData(100, false))); + .WillOnce(InvokeWithoutArgs( + testing::CreateFunctor(&(MockQuicSession::ConsumeData), stream_, + stream_->id(), 100, 100u, NO_FIN))); // Buffered data size > threshold, do not ask upper layer for more data. EXPECT_CALL(*stream_, OnCanWriteNewData()).Times(0); stream_->OnCanWrite(); @@ -782,11 +849,12 @@ TEST_F(QuicStreamTest, WriteBufferedData) { EXPECT_FALSE(stream_->CanWriteNewData()); // Send buffered data to make buffered data size < threshold. + size_t data_to_write = 3 * data.length() - 200 - + GetQuicFlag(FLAGS_quic_buffered_data_threshold) + 1; EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) - .WillOnce(Return(QuicConsumedData( - 3 * data.length() - 200 - - GetQuicFlag(FLAGS_quic_buffered_data_threshold) + 1, - false))); + .WillOnce(InvokeWithoutArgs( + testing::CreateFunctor(&(MockQuicSession::ConsumeData), stream_, + stream_->id(), data_to_write, 200u, NO_FIN))); // Buffered data size < threshold, ask upper layer for more data. EXPECT_CALL(*stream_, OnCanWriteNewData()).Times(1); stream_->OnCanWrite(); @@ -796,7 +864,7 @@ TEST_F(QuicStreamTest, WriteBufferedData) { // Flush all buffered data. EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) - .WillOnce(Invoke(MockQuicSession::ConsumeAllData)); + .WillOnce(Invoke(MockQuicSession::ConsumeData)); EXPECT_CALL(*stream_, OnCanWriteNewData()).Times(1); stream_->OnCanWrite(); EXPECT_EQ(0u, stream_->BufferedDataBytes()); @@ -822,9 +890,13 @@ TEST_F(QuicStreamTest, WriteBufferedData) { EXPECT_FALSE(consumed.fin_consumed); EXPECT_EQ(data.length(), stream_->BufferedDataBytes()); + data_to_write = + data.length() - GetQuicFlag(FLAGS_quic_buffered_data_threshold) + 1; EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) - .WillOnce(Return(QuicConsumedData( - data.length() - FLAGS_quic_buffered_data_threshold + 1, false))); + .WillOnce(InvokeWithoutArgs( + testing::CreateFunctor(&(MockQuicSession::ConsumeData), stream_, + stream_->id(), data_to_write, 0u, NO_FIN))); + EXPECT_CALL(*stream_, OnCanWriteNewData()).Times(1); stream_->OnCanWrite(); EXPECT_EQ(GetQuicFlag(FLAGS_quic_buffered_data_threshold) - 1, @@ -841,6 +913,23 @@ TEST_F(QuicStreamTest, WriteBufferedData) { EXPECT_FALSE(stream_->CanWriteNewData()); } +TEST_F(QuicStreamTest, WritevDataReachStreamLimit) { + SetQuicReloadableFlag(quic_stream_too_long, true); + Initialize(kShouldProcessData); + string data("aaaaa"); + QuicStreamPeer::SetStreamBytesWritten(kMaxStreamLength - data.length(), + stream_); + EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) + .WillOnce(Invoke(&(MockQuicSession::ConsumeData))); + struct iovec iov = {const_cast<char*>(data.data()), 5u}; + QuicConsumedData consumed = stream_->WritevData(&iov, 1u, false); + EXPECT_EQ(data.length(), consumed.bytes_consumed); + struct iovec iov2 = {const_cast<char*>(data.data()), 1u}; + EXPECT_CALL(*connection_, CloseConnection(QUIC_STREAM_LENGTH_OVERFLOW, _, _)); + EXPECT_DFATAL(stream_->WritevData(&iov2, 1u, false), + "Write too many data via stream"); +} + TEST_F(QuicStreamTest, WriteMemSlices) { // Set buffered data low water mark to be 100. SetQuicFlag(&FLAGS_quic_buffered_data_threshold, 100); @@ -853,20 +942,22 @@ TEST_F(QuicStreamTest, WriteMemSlices) { } char data[1024]; std::vector<std::pair<char*, int>> buffers; - buffers.push_back(std::make_pair(data, arraysize(data))); - buffers.push_back(std::make_pair(data, arraysize(data))); + buffers.push_back(std::make_pair(data, QUIC_ARRAYSIZE(data))); + buffers.push_back(std::make_pair(data, QUIC_ARRAYSIZE(data))); QuicTestMemSliceVector vector1(buffers); QuicTestMemSliceVector vector2(buffers); QuicMemSliceSpan span1 = vector1.span(); QuicMemSliceSpan span2 = vector2.span(); EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) - .WillOnce(Return(QuicConsumedData(100, false))); + .WillOnce(InvokeWithoutArgs( + testing::CreateFunctor(&(MockQuicSession::ConsumeData), stream_, + stream_->id(), 100u, 0u, NO_FIN))); // There is no buffered data before, all data should be consumed. QuicConsumedData consumed = stream_->WriteMemSlices(span1, false); EXPECT_EQ(2048u, consumed.bytes_consumed); EXPECT_FALSE(consumed.fin_consumed); - EXPECT_EQ(2 * arraysize(data) - 100, stream_->BufferedDataBytes()); + EXPECT_EQ(2 * QUIC_ARRAYSIZE(data) - 100, stream_->BufferedDataBytes()); EXPECT_FALSE(stream_->fin_buffered()); EXPECT_CALL(*session_, WritevData(_, _, _, _, _)).Times(0); @@ -874,14 +965,15 @@ TEST_F(QuicStreamTest, WriteMemSlices) { consumed = stream_->WriteMemSlices(span2, true); EXPECT_EQ(0u, consumed.bytes_consumed); EXPECT_FALSE(consumed.fin_consumed); - EXPECT_EQ(2 * arraysize(data) - 100, stream_->BufferedDataBytes()); + EXPECT_EQ(2 * QUIC_ARRAYSIZE(data) - 100, stream_->BufferedDataBytes()); EXPECT_FALSE(stream_->fin_buffered()); + size_t data_to_write = 2 * QUIC_ARRAYSIZE(data) - 100 - + GetQuicFlag(FLAGS_quic_buffered_data_threshold) + 1; EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) - .WillOnce(Return(QuicConsumedData( - 2 * arraysize(data) - 100 - - GetQuicFlag(FLAGS_quic_buffered_data_threshold) + 1, - false))); + .WillOnce(InvokeWithoutArgs( + testing::CreateFunctor(&(MockQuicSession::ConsumeData), stream_, + stream_->id(), data_to_write, 100u, NO_FIN))); EXPECT_CALL(*stream_, OnCanWriteNewData()).Times(1); stream_->OnCanWrite(); EXPECT_EQ(GetQuicFlag(FLAGS_quic_buffered_data_threshold) - 1, @@ -891,28 +983,57 @@ TEST_F(QuicStreamTest, WriteMemSlices) { consumed = stream_->WriteMemSlices(span2, true); EXPECT_EQ(2048u, consumed.bytes_consumed); EXPECT_TRUE(consumed.fin_consumed); - EXPECT_EQ( - 2 * arraysize(data) + GetQuicFlag(FLAGS_quic_buffered_data_threshold) - 1, - stream_->BufferedDataBytes()); + EXPECT_EQ(2 * QUIC_ARRAYSIZE(data) + + GetQuicFlag(FLAGS_quic_buffered_data_threshold) - 1, + stream_->BufferedDataBytes()); EXPECT_TRUE(stream_->fin_buffered()); // Flush all buffered data. EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) - .WillOnce(Invoke(MockQuicSession::ConsumeAllData)); + .WillOnce(Invoke(MockQuicSession::ConsumeData)); stream_->OnCanWrite(); EXPECT_CALL(*stream_, OnCanWriteNewData()).Times(0); EXPECT_FALSE(stream_->HasBufferedData()); EXPECT_TRUE(stream_->write_side_closed()); } +TEST_F(QuicStreamTest, WriteMemSlicesReachStreamLimit) { + SetQuicReloadableFlag(quic_stream_too_long, true); + Initialize(kShouldProcessData); + if (!session_->can_use_slices()) { + return; + } + QuicStreamPeer::SetStreamBytesWritten(kMaxStreamLength - 5u, stream_); + char data[5]; + std::vector<std::pair<char*, int>> buffers; + buffers.push_back(std::make_pair(data, QUIC_ARRAYSIZE(data))); + QuicTestMemSliceVector vector1(buffers); + QuicMemSliceSpan span1 = vector1.span(); + EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) + .WillOnce(InvokeWithoutArgs( + testing::CreateFunctor(&(MockQuicSession::ConsumeData), stream_, + stream_->id(), 5u, 0u, NO_FIN))); + // There is no buffered data before, all data should be consumed. + QuicConsumedData consumed = stream_->WriteMemSlices(span1, false); + EXPECT_EQ(5u, consumed.bytes_consumed); + + std::vector<std::pair<char*, int>> buffers2; + buffers2.push_back(std::make_pair(data, 1u)); + QuicTestMemSliceVector vector2(buffers); + QuicMemSliceSpan span2 = vector2.span(); + EXPECT_CALL(*connection_, CloseConnection(QUIC_STREAM_LENGTH_OVERFLOW, _, _)); + EXPECT_DFATAL(stream_->WriteMemSlices(span2, false), + "Write too many data via stream"); +} + TEST_F(QuicStreamTest, StreamDataGetAckedMultipleTimes) { - FLAGS_quic_reloadable_flag_quic_allow_multiple_acks_for_data2 = true; + SetQuicReloadableFlag(quic_allow_multiple_acks_for_data2, true); Initialize(kShouldProcessData); QuicReferenceCountedPointer<MockAckListener> mock_ack_listener( new StrictMock<MockAckListener>); stream_->set_ack_listener(mock_ack_listener); EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) - .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData)); + .WillRepeatedly(Invoke(MockQuicSession::ConsumeData)); // Send [0, 27) and fin. stream_->WriteOrBufferData(kData1, false, nullptr); stream_->WriteOrBufferData(kData1, false, nullptr); @@ -956,6 +1077,94 @@ TEST_F(QuicStreamTest, StreamDataGetAckedMultipleTimes) { EXPECT_FALSE(stream_->IsWaitingForAcks()); } +TEST_F(QuicStreamTest, OnStreamFrameLost) { + if (!FLAGS_quic_reloadable_flag_quic_allow_multiple_acks_for_data2) { + return; + } + Initialize(kShouldProcessData); + + // Send [0, 9). + EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) + .WillOnce(Invoke(MockQuicSession::ConsumeData)); + stream_->WriteOrBufferData(kData1, false, nullptr); + EXPECT_FALSE(stream_->HasBufferedData()); + + // Try to send [9, 27), but connection is blocked. + EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) + .WillOnce(Return(QuicConsumedData(0, false))); + stream_->WriteOrBufferData(kData2, false, nullptr); + stream_->WriteOrBufferData(kData2, false, nullptr); + EXPECT_TRUE(stream_->HasBufferedData()); + EXPECT_FALSE(stream_->HasPendingRetransmission()); + + // Lost [0, 9). When stream gets a chance to write, only lost data is + // transmitted. + stream_->OnStreamFrameLost(0, 9, false); + EXPECT_TRUE(stream_->HasPendingRetransmission()); + EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) + .WillOnce(Invoke(MockQuicSession::ConsumeData)); + stream_->OnCanWrite(); + EXPECT_FALSE(stream_->HasPendingRetransmission()); + EXPECT_TRUE(stream_->HasBufferedData()); + + // This OnCanWrite causes [9, 27) to be sent. + EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) + .WillOnce(Invoke(MockQuicSession::ConsumeData)); + stream_->OnCanWrite(); + EXPECT_FALSE(stream_->HasBufferedData()); + + // Send a fin only frame. + EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) + .WillOnce(Invoke(MockQuicSession::ConsumeData)); + stream_->WriteOrBufferData("", true, nullptr); + + // Lost [9, 27) and fin. + stream_->OnStreamFrameLost(9, 18, false); + stream_->OnStreamFrameLost(27, 0, true); + EXPECT_TRUE(stream_->HasPendingRetransmission()); + + // Ack [9, 18). + stream_->OnStreamFrameAcked(9, 9, false, QuicTime::Delta::Zero()); + EXPECT_TRUE(stream_->HasPendingRetransmission()); + // This OnCanWrite causes [18, 27) and fin to be retransmitted. Verify fin can + // be bundled with data. + EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) + .WillOnce(InvokeWithoutArgs( + testing::CreateFunctor(&(MockQuicSession::ConsumeData), stream_, + stream_->id(), 9, 18u, FIN))); + stream_->OnCanWrite(); + EXPECT_FALSE(stream_->HasPendingRetransmission()); + // Lost [9, 18) again, but it is not considered as lost because kData2 + // has been acked. + stream_->OnStreamFrameLost(9, 9, false); + EXPECT_FALSE(stream_->HasPendingRetransmission()); +} + +TEST_F(QuicStreamTest, CannotBundleLostFin) { + Initialize(kShouldProcessData); + + // Send [0, 18) and fin. + EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) + .WillRepeatedly(Invoke(MockQuicSession::ConsumeData)); + stream_->WriteOrBufferData(kData1, false, nullptr); + stream_->WriteOrBufferData(kData2, true, nullptr); + + // Lost [0, 9) and fin. + stream_->OnStreamFrameLost(0, 9, false); + stream_->OnStreamFrameLost(18, 0, true); + + // Retransmit lost data. Verify [0, 9) and fin are retransmitted in two + // frames. + InSequence s; + EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) + .WillOnce(InvokeWithoutArgs( + testing::CreateFunctor(&(MockQuicSession::ConsumeData), stream_, + stream_->id(), 9, 0u, NO_FIN))); + EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) + .WillOnce(Return(QuicConsumedData(0, true))); + stream_->OnCanWrite(); +} + } // namespace } // namespace test } // namespace net diff --git a/chromium/net/quic/core/quic_tag.cc b/chromium/net/quic/core/quic_tag.cc index 2d0f1ecc083..9a44300a8fd 100644 --- a/chromium/net/quic/core/quic_tag.cc +++ b/chromium/net/quic/core/quic_tag.cc @@ -6,6 +6,7 @@ #include "base/macros.h" #include "base/stl_util.h" +#include "net/quic/platform/api/quic_arraysize.h" #include "net/quic/platform/api/quic_text_utils.h" namespace net { @@ -36,9 +37,10 @@ std::string QuicTagToString(QuicTag tag) { bool ascii = true; const QuicTag orig_tag = tag; - for (size_t i = 0; i < arraysize(chars); i++) { + for (size_t i = 0; i < QUIC_ARRAYSIZE(chars); i++) { chars[i] = static_cast<char>(tag); - if ((chars[i] == 0 || chars[i] == '\xff') && i == arraysize(chars) - 1) { + if ((chars[i] == 0 || chars[i] == '\xff') && + i == QUIC_ARRAYSIZE(chars) - 1) { chars[i] = ' '; } if (!isprint(static_cast<unsigned char>(chars[i]))) { diff --git a/chromium/net/quic/core/quic_unacked_packet_map.cc b/chromium/net/quic/core/quic_unacked_packet_map.cc index 8ff3645f5a3..18be0ba3839 100644 --- a/chromium/net/quic/core/quic_unacked_packet_map.cc +++ b/chromium/net/quic/core/quic_unacked_packet_map.cc @@ -17,7 +17,7 @@ QuicUnackedPacketMap::QuicUnackedPacketMap() least_unacked_(1), bytes_in_flight_(0), pending_crypto_packet_count_(0), - stream_notifier_(nullptr) {} + session_notifier_(nullptr) {} QuicUnackedPacketMap::~QuicUnackedPacketMap() { for (QuicTransmissionInfo& transmission_info : unacked_packets_) { @@ -102,10 +102,10 @@ void QuicUnackedPacketMap::TransferRetransmissionInfo( QuicTransmissionInfo* transmission_info = &unacked_packets_.at(old_packet_number - least_unacked_); QuicFrames* frames = &transmission_info->retransmittable_frames; - if (stream_notifier_ != nullptr) { + if (session_notifier_ != nullptr) { for (const QuicFrame& frame : *frames) { if (frame.type == STREAM_FRAME) { - stream_notifier_->OnStreamFrameRetransmitted(*frame.stream_frame); + session_notifier_->OnStreamFrameRetransmitted(*frame.stream_frame); } } } @@ -237,15 +237,6 @@ void QuicUnackedPacketMap::CancelRetransmissionsForStream( if (frames->empty()) { continue; } - if (stream_notifier_ != nullptr) { - for (const QuicFrame& frame : *frames) { - if (frame.type != STREAM_FRAME || - frame.stream_frame->stream_id != stream_id) { - continue; - } - stream_notifier_->OnStreamFrameDiscarded(*frame.stream_frame); - } - } RemoveFramesForStream(frames, stream_id); if (frames->empty()) { RemoveRetransmittability(packet_number); @@ -332,22 +323,19 @@ QuicPacketNumber QuicUnackedPacketMap::GetLeastUnacked() const { return least_unacked_; } -void QuicUnackedPacketMap::SetStreamNotifier( - StreamNotifierInterface* stream_notifier) { - stream_notifier_ = stream_notifier; +void QuicUnackedPacketMap::SetSessionNotifier( + SessionNotifierInterface* session_notifier) { + session_notifier_ = session_notifier; } -void QuicUnackedPacketMap::NotifyStreamFramesAcked( - const QuicTransmissionInfo& info, - QuicTime::Delta ack_delay) { - if (stream_notifier_ == nullptr) { +void QuicUnackedPacketMap::NotifyFramesAcked(const QuicTransmissionInfo& info, + QuicTime::Delta ack_delay) { + if (session_notifier_ == nullptr) { return; } for (const QuicFrame& frame : info.retransmittable_frames) { - if (frame.type == STREAM_FRAME) { - stream_notifier_->OnStreamFrameAcked(*frame.stream_frame, ack_delay); - } + session_notifier_->OnFrameAcked(frame, ack_delay); } } diff --git a/chromium/net/quic/core/quic_unacked_packet_map.h b/chromium/net/quic/core/quic_unacked_packet_map.h index 43bc635f278..6e2eb8a8f1c 100644 --- a/chromium/net/quic/core/quic_unacked_packet_map.h +++ b/chromium/net/quic/core/quic_unacked_packet_map.h @@ -11,7 +11,7 @@ #include "base/macros.h" #include "net/quic/core/quic_packets.h" #include "net/quic/core/quic_transmission_info.h" -#include "net/quic/core/stream_notifier_interface.h" +#include "net/quic/core/session_notifier_interface.h" #include "net/quic/platform/api/quic_export.h" namespace net { @@ -42,9 +42,9 @@ class QUIC_EXPORT_PRIVATE QuicUnackedPacketMap { // Returns true if the packet |packet_number| is unacked. bool IsUnacked(QuicPacketNumber packet_number) const; - // Notifies stream_notifier that stream frames have been acked. - void NotifyStreamFramesAcked(const QuicTransmissionInfo& info, - QuicTime::Delta ack_delay); + // Notifies session_notifier that frames have been acked. + void NotifyFramesAcked(const QuicTransmissionInfo& info, + QuicTime::Delta ack_delay); // Marks |info| as no longer in flight. void RemoveFromInFlight(QuicTransmissionInfo* info); @@ -141,7 +141,7 @@ class QUIC_EXPORT_PRIVATE QuicUnackedPacketMap { // RTT measurement purposes. void RemoveObsoletePackets(); - void SetStreamNotifier(StreamNotifierInterface* stream_notifier); + void SetSessionNotifier(SessionNotifierInterface* session_notifier); private: // Called when a packet is retransmitted with a new packet number. @@ -191,9 +191,8 @@ class QUIC_EXPORT_PRIVATE QuicUnackedPacketMap { // Number of retransmittable crypto handshake packets. size_t pending_crypto_packet_count_; - // Receives notifications of stream frames being retransmitted or - // acknowledged. - StreamNotifierInterface* stream_notifier_; + // Receives notifications of frames being retransmitted or acknowledged. + SessionNotifierInterface* session_notifier_; DISALLOW_COPY_AND_ASSIGN(QuicUnackedPacketMap); }; diff --git a/chromium/net/quic/core/quic_unacked_packet_map_test.cc b/chromium/net/quic/core/quic_unacked_packet_map_test.cc index 69e3315cef7..cf81a97be94 100644 --- a/chromium/net/quic/core/quic_unacked_packet_map_test.cc +++ b/chromium/net/quic/core/quic_unacked_packet_map_test.cc @@ -4,6 +4,7 @@ #include "net/quic/core/quic_unacked_packet_map.h" +#include "net/quic/platform/api/quic_arraysize.h" #include "net/quic/platform/api/quic_test.h" #include "net/quic/test_tools/quic_test_utils.h" @@ -16,20 +17,12 @@ namespace { // Default packet length. const uint32_t kDefaultLength = 1000; -class MockStreamNotifier : public StreamNotifierInterface { - public: - MOCK_METHOD2(OnStreamFrameAcked, - void(const QuicStreamFrame&, QuicTime::Delta)); - MOCK_METHOD1(OnStreamFrameRetransmitted, void(const QuicStreamFrame&)); - MOCK_METHOD1(OnStreamFrameDiscarded, void(const QuicStreamFrame&)); -}; - class QuicUnackedPacketMapTest : public QuicTest { protected: QuicUnackedPacketMapTest() : unacked_packets_(), now_(QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(1000)) { - unacked_packets_.SetStreamNotifier(¬ifier_); + unacked_packets_.SetSessionNotifier(¬ifier_); } ~QuicUnackedPacketMapTest() override {} @@ -115,7 +108,7 @@ class QuicUnackedPacketMapTest : public QuicTest { } QuicUnackedPacketMap unacked_packets_; QuicTime now_; - MockStreamNotifier notifier_; + MockSessionNotifier notifier_; }; TEST_F(QuicUnackedPacketMapTest, RttOnly) { @@ -124,7 +117,7 @@ TEST_F(QuicUnackedPacketMapTest, RttOnly) { unacked_packets_.AddSentPacket(&packet, 0, NOT_RETRANSMISSION, now_, false); QuicPacketNumber unacked[] = {1}; - VerifyUnackedPackets(unacked, arraysize(unacked)); + VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); VerifyInFlightPackets(nullptr, 0); VerifyRetransmittablePackets(nullptr, 0); @@ -140,18 +133,18 @@ TEST_F(QuicUnackedPacketMapTest, RetransmittableInflightAndRtt) { unacked_packets_.AddSentPacket(&packet, 0, NOT_RETRANSMISSION, now_, true); QuicPacketNumber unacked[] = {1}; - VerifyUnackedPackets(unacked, arraysize(unacked)); - VerifyInFlightPackets(unacked, arraysize(unacked)); - VerifyRetransmittablePackets(unacked, arraysize(unacked)); + VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); + VerifyInFlightPackets(unacked, QUIC_ARRAYSIZE(unacked)); + VerifyRetransmittablePackets(unacked, QUIC_ARRAYSIZE(unacked)); unacked_packets_.RemoveRetransmittability(1); - VerifyUnackedPackets(unacked, arraysize(unacked)); - VerifyInFlightPackets(unacked, arraysize(unacked)); + VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); + VerifyInFlightPackets(unacked, QUIC_ARRAYSIZE(unacked)); VerifyRetransmittablePackets(nullptr, 0); unacked_packets_.IncreaseLargestObserved(1); - VerifyUnackedPackets(unacked, arraysize(unacked)); - VerifyInFlightPackets(unacked, arraysize(unacked)); + VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); + VerifyInFlightPackets(unacked, QUIC_ARRAYSIZE(unacked)); VerifyRetransmittablePackets(nullptr, 0); unacked_packets_.RemoveFromInFlight(1); @@ -166,15 +159,15 @@ TEST_F(QuicUnackedPacketMapTest, StopRetransmission) { unacked_packets_.AddSentPacket(&packet, 0, NOT_RETRANSMISSION, now_, true); QuicPacketNumber unacked[] = {1}; - VerifyUnackedPackets(unacked, arraysize(unacked)); - VerifyInFlightPackets(unacked, arraysize(unacked)); + VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); + VerifyInFlightPackets(unacked, QUIC_ARRAYSIZE(unacked)); QuicPacketNumber retransmittable[] = {1}; - VerifyRetransmittablePackets(retransmittable, arraysize(retransmittable)); + VerifyRetransmittablePackets(retransmittable, + QUIC_ARRAYSIZE(retransmittable)); - EXPECT_CALL(notifier_, OnStreamFrameDiscarded(_)).Times(1); unacked_packets_.CancelRetransmissionsForStream(stream_id); - VerifyUnackedPackets(unacked, arraysize(unacked)); - VerifyInFlightPackets(unacked, arraysize(unacked)); + VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); + VerifyInFlightPackets(unacked, QUIC_ARRAYSIZE(unacked)); VerifyRetransmittablePackets(nullptr, 0); } @@ -184,17 +177,18 @@ TEST_F(QuicUnackedPacketMapTest, StopRetransmissionOnOtherStream) { unacked_packets_.AddSentPacket(&packet, 0, NOT_RETRANSMISSION, now_, true); QuicPacketNumber unacked[] = {1}; - VerifyUnackedPackets(unacked, arraysize(unacked)); - VerifyInFlightPackets(unacked, arraysize(unacked)); + VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); + VerifyInFlightPackets(unacked, QUIC_ARRAYSIZE(unacked)); QuicPacketNumber retransmittable[] = {1}; - VerifyRetransmittablePackets(retransmittable, arraysize(retransmittable)); + VerifyRetransmittablePackets(retransmittable, + QUIC_ARRAYSIZE(retransmittable)); // Stop retransmissions on another stream and verify the packet is unchanged. - EXPECT_CALL(notifier_, OnStreamFrameDiscarded(_)).Times(0); unacked_packets_.CancelRetransmissionsForStream(stream_id + 2); - VerifyUnackedPackets(unacked, arraysize(unacked)); - VerifyInFlightPackets(unacked, arraysize(unacked)); - VerifyRetransmittablePackets(retransmittable, arraysize(retransmittable)); + VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); + VerifyInFlightPackets(unacked, QUIC_ARRAYSIZE(unacked)); + VerifyRetransmittablePackets(retransmittable, + QUIC_ARRAYSIZE(retransmittable)); } TEST_F(QuicUnackedPacketMapTest, StopRetransmissionAfterRetransmission) { @@ -205,15 +199,15 @@ TEST_F(QuicUnackedPacketMapTest, StopRetransmissionAfterRetransmission) { unacked_packets_.AddSentPacket(&packet2, 1, LOSS_RETRANSMISSION, now_, true); QuicPacketNumber unacked[] = {1, 2}; - VerifyUnackedPackets(unacked, arraysize(unacked)); - VerifyInFlightPackets(unacked, arraysize(unacked)); + VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); + VerifyInFlightPackets(unacked, QUIC_ARRAYSIZE(unacked)); QuicPacketNumber retransmittable[] = {2}; - VerifyRetransmittablePackets(retransmittable, arraysize(retransmittable)); + VerifyRetransmittablePackets(retransmittable, + QUIC_ARRAYSIZE(retransmittable)); - EXPECT_CALL(notifier_, OnStreamFrameDiscarded(_)).Times(1); unacked_packets_.CancelRetransmissionsForStream(stream_id); - VerifyUnackedPackets(unacked, arraysize(unacked)); - VerifyInFlightPackets(unacked, arraysize(unacked)); + VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); + VerifyInFlightPackets(unacked, QUIC_ARRAYSIZE(unacked)); VerifyRetransmittablePackets(nullptr, 0); } @@ -226,25 +220,26 @@ TEST_F(QuicUnackedPacketMapTest, RetransmittedPacket) { unacked_packets_.AddSentPacket(&packet2, 1, LOSS_RETRANSMISSION, now_, true); QuicPacketNumber unacked[] = {1, 2}; - VerifyUnackedPackets(unacked, arraysize(unacked)); - VerifyInFlightPackets(unacked, arraysize(unacked)); + VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); + VerifyInFlightPackets(unacked, QUIC_ARRAYSIZE(unacked)); QuicPacketNumber retransmittable[] = {2}; - VerifyRetransmittablePackets(retransmittable, arraysize(retransmittable)); + VerifyRetransmittablePackets(retransmittable, + QUIC_ARRAYSIZE(retransmittable)); unacked_packets_.RemoveRetransmittability(1); - VerifyUnackedPackets(unacked, arraysize(unacked)); - VerifyInFlightPackets(unacked, arraysize(unacked)); + VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); + VerifyInFlightPackets(unacked, QUIC_ARRAYSIZE(unacked)); VerifyRetransmittablePackets(nullptr, 0); unacked_packets_.IncreaseLargestObserved(2); - VerifyUnackedPackets(unacked, arraysize(unacked)); - VerifyInFlightPackets(unacked, arraysize(unacked)); + VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); + VerifyInFlightPackets(unacked, QUIC_ARRAYSIZE(unacked)); VerifyRetransmittablePackets(nullptr, 0); unacked_packets_.RemoveFromInFlight(2); QuicPacketNumber unacked2[] = {1}; - VerifyUnackedPackets(unacked2, arraysize(unacked2)); - VerifyInFlightPackets(unacked2, arraysize(unacked2)); + VerifyUnackedPackets(unacked2, QUIC_ARRAYSIZE(unacked2)); + VerifyInFlightPackets(unacked2, QUIC_ARRAYSIZE(unacked2)); VerifyRetransmittablePackets(nullptr, 0); unacked_packets_.RemoveFromInFlight(1); @@ -261,10 +256,11 @@ TEST_F(QuicUnackedPacketMapTest, RetransmitThreeTimes) { unacked_packets_.AddSentPacket(&packet2, 0, NOT_RETRANSMISSION, now_, true); QuicPacketNumber unacked[] = {1, 2}; - VerifyUnackedPackets(unacked, arraysize(unacked)); - VerifyInFlightPackets(unacked, arraysize(unacked)); + VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); + VerifyInFlightPackets(unacked, QUIC_ARRAYSIZE(unacked)); QuicPacketNumber retransmittable[] = {1, 2}; - VerifyRetransmittablePackets(retransmittable, arraysize(retransmittable)); + VerifyRetransmittablePackets(retransmittable, + QUIC_ARRAYSIZE(retransmittable)); // Early retransmit 1 as 3 and send new data as 4. unacked_packets_.IncreaseLargestObserved(2); @@ -277,11 +273,12 @@ TEST_F(QuicUnackedPacketMapTest, RetransmitThreeTimes) { unacked_packets_.AddSentPacket(&packet4, 0, NOT_RETRANSMISSION, now_, true); QuicPacketNumber unacked2[] = {1, 3, 4}; - VerifyUnackedPackets(unacked2, arraysize(unacked2)); + VerifyUnackedPackets(unacked2, QUIC_ARRAYSIZE(unacked2)); QuicPacketNumber pending2[] = {3, 4}; - VerifyInFlightPackets(pending2, arraysize(pending2)); + VerifyInFlightPackets(pending2, QUIC_ARRAYSIZE(pending2)); QuicPacketNumber retransmittable2[] = {3, 4}; - VerifyRetransmittablePackets(retransmittable2, arraysize(retransmittable2)); + VerifyRetransmittablePackets(retransmittable2, + QUIC_ARRAYSIZE(retransmittable2)); // Early retransmit 3 (formerly 1) as 5, and remove 1 from unacked. unacked_packets_.IncreaseLargestObserved(4); @@ -293,11 +290,12 @@ TEST_F(QuicUnackedPacketMapTest, RetransmitThreeTimes) { unacked_packets_.AddSentPacket(&packet6, 0, NOT_RETRANSMISSION, now_, true); QuicPacketNumber unacked3[] = {3, 5, 6}; - VerifyUnackedPackets(unacked3, arraysize(unacked3)); + VerifyUnackedPackets(unacked3, QUIC_ARRAYSIZE(unacked3)); QuicPacketNumber pending3[] = {3, 5, 6}; - VerifyInFlightPackets(pending3, arraysize(pending3)); + VerifyInFlightPackets(pending3, QUIC_ARRAYSIZE(pending3)); QuicPacketNumber retransmittable3[] = {5, 6}; - VerifyRetransmittablePackets(retransmittable3, arraysize(retransmittable3)); + VerifyRetransmittablePackets(retransmittable3, + QUIC_ARRAYSIZE(retransmittable3)); // Early retransmit 5 as 7 and ensure in flight packet 3 is not removed. unacked_packets_.IncreaseLargestObserved(6); @@ -307,17 +305,18 @@ TEST_F(QuicUnackedPacketMapTest, RetransmitThreeTimes) { unacked_packets_.AddSentPacket(&packet7, 5, LOSS_RETRANSMISSION, now_, true); QuicPacketNumber unacked4[] = {3, 5, 7}; - VerifyUnackedPackets(unacked4, arraysize(unacked4)); + VerifyUnackedPackets(unacked4, QUIC_ARRAYSIZE(unacked4)); QuicPacketNumber pending4[] = {3, 5, 7}; - VerifyInFlightPackets(pending4, arraysize(pending4)); + VerifyInFlightPackets(pending4, QUIC_ARRAYSIZE(pending4)); QuicPacketNumber retransmittable4[] = {7}; - VerifyRetransmittablePackets(retransmittable4, arraysize(retransmittable4)); + VerifyRetransmittablePackets(retransmittable4, + QUIC_ARRAYSIZE(retransmittable4)); // Remove the older two transmissions from in flight. unacked_packets_.RemoveFromInFlight(3); unacked_packets_.RemoveFromInFlight(5); QuicPacketNumber pending5[] = {7}; - VerifyInFlightPackets(pending5, arraysize(pending5)); + VerifyInFlightPackets(pending5, QUIC_ARRAYSIZE(pending5)); } TEST_F(QuicUnackedPacketMapTest, RetransmitFourTimes) { @@ -328,10 +327,11 @@ TEST_F(QuicUnackedPacketMapTest, RetransmitFourTimes) { unacked_packets_.AddSentPacket(&packet2, 0, NOT_RETRANSMISSION, now_, true); QuicPacketNumber unacked[] = {1, 2}; - VerifyUnackedPackets(unacked, arraysize(unacked)); - VerifyInFlightPackets(unacked, arraysize(unacked)); + VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); + VerifyInFlightPackets(unacked, QUIC_ARRAYSIZE(unacked)); QuicPacketNumber retransmittable[] = {1, 2}; - VerifyRetransmittablePackets(retransmittable, arraysize(retransmittable)); + VerifyRetransmittablePackets(retransmittable, + QUIC_ARRAYSIZE(retransmittable)); // Early retransmit 1 as 3. unacked_packets_.IncreaseLargestObserved(2); @@ -342,11 +342,12 @@ TEST_F(QuicUnackedPacketMapTest, RetransmitFourTimes) { unacked_packets_.AddSentPacket(&packet3, 1, LOSS_RETRANSMISSION, now_, true); QuicPacketNumber unacked2[] = {1, 3}; - VerifyUnackedPackets(unacked2, arraysize(unacked2)); + VerifyUnackedPackets(unacked2, QUIC_ARRAYSIZE(unacked2)); QuicPacketNumber pending2[] = {3}; - VerifyInFlightPackets(pending2, arraysize(pending2)); + VerifyInFlightPackets(pending2, QUIC_ARRAYSIZE(pending2)); QuicPacketNumber retransmittable2[] = {3}; - VerifyRetransmittablePackets(retransmittable2, arraysize(retransmittable2)); + VerifyRetransmittablePackets(retransmittable2, + QUIC_ARRAYSIZE(retransmittable2)); // TLP 3 (formerly 1) as 4, and don't remove 1 from unacked. SerializedPacket packet4(CreateNonRetransmittablePacket(4)); @@ -355,11 +356,12 @@ TEST_F(QuicUnackedPacketMapTest, RetransmitFourTimes) { unacked_packets_.AddSentPacket(&packet5, 0, NOT_RETRANSMISSION, now_, true); QuicPacketNumber unacked3[] = {1, 3, 4, 5}; - VerifyUnackedPackets(unacked3, arraysize(unacked3)); + VerifyUnackedPackets(unacked3, QUIC_ARRAYSIZE(unacked3)); QuicPacketNumber pending3[] = {3, 4, 5}; - VerifyInFlightPackets(pending3, arraysize(pending3)); + VerifyInFlightPackets(pending3, QUIC_ARRAYSIZE(pending3)); QuicPacketNumber retransmittable3[] = {4, 5}; - VerifyRetransmittablePackets(retransmittable3, arraysize(retransmittable3)); + VerifyRetransmittablePackets(retransmittable3, + QUIC_ARRAYSIZE(retransmittable3)); // Early retransmit 4 as 6 and ensure in flight packet 3 is removed. unacked_packets_.IncreaseLargestObserved(5); @@ -371,11 +373,12 @@ TEST_F(QuicUnackedPacketMapTest, RetransmitFourTimes) { unacked_packets_.AddSentPacket(&packet6, 4, LOSS_RETRANSMISSION, now_, true); QuicPacketNumber unacked4[] = {4, 6}; - VerifyUnackedPackets(unacked4, arraysize(unacked4)); + VerifyUnackedPackets(unacked4, QUIC_ARRAYSIZE(unacked4)); QuicPacketNumber pending4[] = {6}; - VerifyInFlightPackets(pending4, arraysize(pending4)); + VerifyInFlightPackets(pending4, QUIC_ARRAYSIZE(pending4)); QuicPacketNumber retransmittable4[] = {6}; - VerifyRetransmittablePackets(retransmittable4, arraysize(retransmittable4)); + VerifyRetransmittablePackets(retransmittable4, + QUIC_ARRAYSIZE(retransmittable4)); } TEST_F(QuicUnackedPacketMapTest, SendWithGap) { diff --git a/chromium/net/quic/core/quic_utils.cc b/chromium/net/quic/core/quic_utils.cc index cce8c16c57f..109f3760a71 100644 --- a/chromium/net/quic/core/quic_utils.cc +++ b/chromium/net/quic/core/quic_utils.cc @@ -6,13 +6,12 @@ #include <algorithm> #include <cstdint> -#include <vector> -#include "base/containers/adapters.h" -#include "base/logging.h" #include "net/quic/core/quic_constants.h" +#include "net/quic/platform/api/quic_aligned.h" #include "net/quic/platform/api/quic_bug_tracker.h" #include "net/quic/platform/api/quic_flags.h" +#include "net/quic/platform/api/quic_prefetch.h" using std::string; @@ -237,16 +236,12 @@ void QuicUtils::CopyToBuffer(const struct iovec* iov, // generally, the iov_offset is not 0, input iov consists of 2K buffers and // the output buffer is ~1.4K. if (copy_len == iov_available && iovnum + 1 < iov_count) { - // TODO(ckrasic) - this is unused without prefetch() - // char* next_base = static_cast<char*>(iov.iov[iovnum + 1].iov_base); - // char* next_base = static_cast<char*>(iov.iov[iovnum + 1].iov_base); + char* next_base = static_cast<char*>(iov[iovnum + 1].iov_base); // Prefetch 2 cachelines worth of data to get the prefetcher started; leave // it to the hardware prefetcher after that. - // TODO(ckrasic) - investigate what to do about prefetch directives. - // ::base::PrefetchT0(next_base); + QuicPrefetchT0(next_base); if (iov[iovnum + 1].iov_len >= 64) { - // TODO(ckrasic) - investigate what to do about prefetch directives. - // ::base::PrefetchT0(next_base + ABSL_CACHELINE_SIZE); + QuicPrefetchT0(next_base + QUIC_CACHELINE_SIZE); } } diff --git a/chromium/net/quic/core/quic_version_manager.cc b/chromium/net/quic/core/quic_version_manager.cc index 610189fdee1..489b7beacfd 100644 --- a/chromium/net/quic/core/quic_version_manager.cc +++ b/chromium/net/quic/core/quic_version_manager.cc @@ -10,42 +10,42 @@ namespace net { QuicVersionManager::QuicVersionManager( - QuicTransportVersionVector supported_versions) + ParsedQuicVersionVector supported_versions) : enable_version_43_(GetQuicFlag(FLAGS_quic_enable_version_43)), enable_version_42_(GetQuicFlag(FLAGS_quic_enable_version_42)), - enable_version_41_(FLAGS_quic_reloadable_flag_quic_enable_version_41), - enable_version_39_(FLAGS_quic_reloadable_flag_quic_enable_version_39), - enable_version_38_(FLAGS_quic_reloadable_flag_quic_enable_version_38), - allowed_supported_versions_(supported_versions), - filtered_supported_versions_( - FilterSupportedTransportVersions(supported_versions)) {} + allowed_supported_versions_(std::move(supported_versions)) { + RefilterSupportedVersions(); +} QuicVersionManager::~QuicVersionManager() {} const QuicTransportVersionVector& QuicVersionManager::GetSupportedTransportVersions() { - MaybeRefilterSupportedTransportVersions(); + MaybeRefilterSupportedVersions(); + return filtered_transport_versions_; +} + +const ParsedQuicVersionVector& QuicVersionManager::GetSupportedVersions() { + MaybeRefilterSupportedVersions(); return filtered_supported_versions_; } -void QuicVersionManager::MaybeRefilterSupportedTransportVersions() { +void QuicVersionManager::MaybeRefilterSupportedVersions() { if (enable_version_43_ != GetQuicFlag(FLAGS_quic_enable_version_43) || - enable_version_42_ != GetQuicFlag(FLAGS_quic_enable_version_42) || - enable_version_41_ != FLAGS_quic_reloadable_flag_quic_enable_version_41 || - enable_version_39_ != FLAGS_quic_reloadable_flag_quic_enable_version_39 || - enable_version_38_ != FLAGS_quic_reloadable_flag_quic_enable_version_38) { + enable_version_42_ != GetQuicFlag(FLAGS_quic_enable_version_42)) { enable_version_43_ = GetQuicFlag(FLAGS_quic_enable_version_43); enable_version_42_ = GetQuicFlag(FLAGS_quic_enable_version_42); - enable_version_41_ = FLAGS_quic_reloadable_flag_quic_enable_version_41; - enable_version_39_ = FLAGS_quic_reloadable_flag_quic_enable_version_39; - enable_version_38_ = FLAGS_quic_reloadable_flag_quic_enable_version_38; - RefilterSupportedTransportVersions(); + RefilterSupportedVersions(); } } -void QuicVersionManager::RefilterSupportedTransportVersions() { +void QuicVersionManager::RefilterSupportedVersions() { filtered_supported_versions_ = - FilterSupportedTransportVersions(allowed_supported_versions_); + FilterSupportedVersions(allowed_supported_versions_); + filtered_transport_versions_.clear(); + for (ParsedQuicVersion version : filtered_supported_versions_) { + filtered_transport_versions_.push_back(version.transport_version); + } } } // namespace net diff --git a/chromium/net/quic/core/quic_version_manager.h b/chromium/net/quic/core/quic_version_manager.h index 732180223c4..0982873d447 100644 --- a/chromium/net/quic/core/quic_version_manager.h +++ b/chromium/net/quic/core/quic_version_manager.h @@ -13,21 +13,25 @@ namespace net { // Used to generate filtered supported versions based on flags. class QUIC_EXPORT_PRIVATE QuicVersionManager { public: - explicit QuicVersionManager(QuicTransportVersionVector supported_versions); + explicit QuicVersionManager(ParsedQuicVersionVector supported_versions); virtual ~QuicVersionManager(); // Returns currently supported QUIC versions. + // TODO(nharper): Remove this method once it is unused. const QuicTransportVersionVector& GetSupportedTransportVersions(); + // Returns currently supported QUIC versions. + const ParsedQuicVersionVector& GetSupportedVersions(); + protected: // Maybe refilter filtered_supported_versions_ based on flags. - void MaybeRefilterSupportedTransportVersions(); + void MaybeRefilterSupportedVersions(); // Refilters filtered_supported_versions_. - virtual void RefilterSupportedTransportVersions(); + virtual void RefilterSupportedVersions(); const QuicTransportVersionVector& filtered_supported_versions() const { - return filtered_supported_versions_; + return filtered_transport_versions_; } private: @@ -35,17 +39,15 @@ class QUIC_EXPORT_PRIVATE QuicVersionManager { bool enable_version_43_; // FLAGS_quic_enable_version_42 bool enable_version_42_; - // FLAGS_quic_reloadable_flag_quic_enable_version_41 - bool enable_version_41_; - // FLAGS_quic_reloadable_flag_quic_enable_version_39 - bool enable_version_39_; - // FLAGS_quic_reloadable_flag_quic_enable_version_38 - bool enable_version_38_; // The list of versions that may be supported. - QuicTransportVersionVector allowed_supported_versions_; + ParsedQuicVersionVector allowed_supported_versions_; // This vector contains QUIC versions which are currently supported based on // flags. - QuicTransportVersionVector filtered_supported_versions_; + ParsedQuicVersionVector filtered_supported_versions_; + // This vector contains the transport versions from + // |filtered_supported_versions_|. No guarantees are made that the same + // transport version isn't repeated. + QuicTransportVersionVector filtered_transport_versions_; }; } // namespace net diff --git a/chromium/net/quic/core/quic_version_manager_test.cc b/chromium/net/quic/core/quic_version_manager_test.cc index 94deeee6509..ab8c101b0e2 100644 --- a/chromium/net/quic/core/quic_version_manager_test.cc +++ b/chromium/net/quic/core/quic_version_manager_test.cc @@ -18,37 +18,10 @@ class QuicVersionManagerTest : public QuicTest {}; TEST_F(QuicVersionManagerTest, QuicVersionManager) { SetQuicFlag(&FLAGS_quic_enable_version_43, false); SetQuicFlag(&FLAGS_quic_enable_version_42, false); - FLAGS_quic_reloadable_flag_quic_enable_version_41 = false; - FLAGS_quic_reloadable_flag_quic_enable_version_39 = false; - FLAGS_quic_reloadable_flag_quic_enable_version_38 = false; - QuicVersionManager manager(AllSupportedTransportVersions()); - EXPECT_EQ(FilterSupportedTransportVersions(AllSupportedTransportVersions()), - manager.GetSupportedTransportVersions()); - - EXPECT_EQ(FilterSupportedTransportVersions(AllSupportedTransportVersions()), - manager.GetSupportedTransportVersions()); - ASSERT_EQ(2u, manager.GetSupportedTransportVersions().size()); - EXPECT_EQ(QUIC_VERSION_37, manager.GetSupportedTransportVersions()[0]); - EXPECT_EQ(QUIC_VERSION_35, manager.GetSupportedTransportVersions()[1]); + QuicVersionManager manager(AllSupportedVersions()); - FLAGS_quic_reloadable_flag_quic_enable_version_38 = true; EXPECT_EQ(FilterSupportedTransportVersions(AllSupportedTransportVersions()), manager.GetSupportedTransportVersions()); - ASSERT_EQ(3u, manager.GetSupportedTransportVersions().size()); - EXPECT_EQ(QUIC_VERSION_38, manager.GetSupportedTransportVersions()[0]); - EXPECT_EQ(QUIC_VERSION_37, manager.GetSupportedTransportVersions()[1]); - EXPECT_EQ(QUIC_VERSION_35, manager.GetSupportedTransportVersions()[2]); - - FLAGS_quic_reloadable_flag_quic_enable_version_39 = true; - EXPECT_EQ(FilterSupportedTransportVersions(AllSupportedTransportVersions()), - manager.GetSupportedTransportVersions()); - ASSERT_EQ(4u, manager.GetSupportedTransportVersions().size()); - EXPECT_EQ(QUIC_VERSION_39, manager.GetSupportedTransportVersions()[0]); - EXPECT_EQ(QUIC_VERSION_38, manager.GetSupportedTransportVersions()[1]); - EXPECT_EQ(QUIC_VERSION_37, manager.GetSupportedTransportVersions()[2]); - EXPECT_EQ(QUIC_VERSION_35, manager.GetSupportedTransportVersions()[3]); - - FLAGS_quic_reloadable_flag_quic_enable_version_41 = true; ASSERT_EQ(5u, manager.GetSupportedTransportVersions().size()); EXPECT_EQ(QUIC_VERSION_41, manager.GetSupportedTransportVersions()[0]); EXPECT_EQ(QUIC_VERSION_39, manager.GetSupportedTransportVersions()[1]); diff --git a/chromium/net/quic/core/quic_versions.cc b/chromium/net/quic/core/quic_versions.cc index af86dc4d6fd..d9fec40a738 100644 --- a/chromium/net/quic/core/quic_versions.cc +++ b/chromium/net/quic/core/quic_versions.cc @@ -21,16 +21,16 @@ namespace { // Constructs a version label from the 4 bytes such that the on-the-wire // order will be: d, c, b, a. QuicVersionLabel MakeVersionLabel(char a, char b, char c, char d) { - if (!FLAGS_quic_reloadable_flag_quic_use_net_byte_order_version_label) { - return MakeQuicTag(a, b, c, d); - } - QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_use_net_byte_order_version_label, - 1, 10); return MakeQuicTag(d, c, b, a); } } // namespace +std::ostream& operator<<(std::ostream& os, const ParsedQuicVersion& version) { + os << ParsedQuicVersionToString(version); + return os; +} + QuicVersionLabel CreateQuicVersionLabel(ParsedQuicVersion parsed_version) { char proto = 0; switch (parsed_version.handshake_protocol) { @@ -93,49 +93,62 @@ ParsedQuicVersion ParseQuicVersionLabel(QuicVersionLabel version_label) { QuicTransportVersionVector AllSupportedTransportVersions() { QuicTransportVersionVector supported_versions; - for (size_t i = 0; i < arraysize(kSupportedTransportVersions); ++i) { - supported_versions.push_back(kSupportedTransportVersions[i]); + for (QuicTransportVersion version : kSupportedTransportVersions) { + supported_versions.push_back(version); + } + return supported_versions; +} + +ParsedQuicVersionVector AllSupportedVersions() { + ParsedQuicVersionVector supported_versions; + for (HandshakeProtocol protocol : kSupportedHandshakeProtocols) { + if (protocol == PROTOCOL_TLS1_3 && !FLAGS_quic_supports_tls_handshake) { + continue; + } + for (QuicTransportVersion version : kSupportedTransportVersions) { + supported_versions.push_back(ParsedQuicVersion(protocol, version)); + } } return supported_versions; } +// TODO(nharper): Remove this function when it is no longer in use. QuicTransportVersionVector CurrentSupportedTransportVersions() { return FilterSupportedTransportVersions(AllSupportedTransportVersions()); } +ParsedQuicVersionVector CurrentSupportedVersions() { + return FilterSupportedVersions(AllSupportedVersions()); +} + +// TODO(nharper): Remove this function when it is no longer in use. QuicTransportVersionVector FilterSupportedTransportVersions( QuicTransportVersionVector versions) { - QuicTransportVersionVector filtered_versions(versions.size()); - filtered_versions.clear(); // Guaranteed by spec not to change capacity. + ParsedQuicVersionVector parsed_versions; for (QuicTransportVersion version : versions) { - if (version == QUIC_VERSION_43) { + parsed_versions.push_back(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version)); + } + ParsedQuicVersionVector filtered_parsed_versions = + FilterSupportedVersions(parsed_versions); + QuicTransportVersionVector filtered_versions; + for (ParsedQuicVersion version : filtered_parsed_versions) { + filtered_versions.push_back(version.transport_version); + } + return filtered_versions; +} + +ParsedQuicVersionVector FilterSupportedVersions( + ParsedQuicVersionVector versions) { + ParsedQuicVersionVector filtered_versions; + filtered_versions.reserve(versions.size()); + for (ParsedQuicVersion version : versions) { + if (version.transport_version == QUIC_VERSION_43) { if (GetQuicFlag(FLAGS_quic_enable_version_43) && - GetQuicFlag(FLAGS_quic_enable_version_42) && - FLAGS_quic_reloadable_flag_quic_enable_version_41 && - FLAGS_quic_reloadable_flag_quic_enable_version_39 && - FLAGS_quic_reloadable_flag_quic_enable_version_38) { - filtered_versions.push_back(version); - } - } else if (version == QUIC_VERSION_42) { - if (GetQuicFlag(FLAGS_quic_enable_version_42) && - FLAGS_quic_reloadable_flag_quic_enable_version_41 && - FLAGS_quic_reloadable_flag_quic_enable_version_39 && - FLAGS_quic_reloadable_flag_quic_enable_version_38) { - filtered_versions.push_back(version); - } - } else if (version == QUIC_VERSION_41) { - if (FLAGS_quic_reloadable_flag_quic_enable_version_41 && - FLAGS_quic_reloadable_flag_quic_enable_version_39 && - FLAGS_quic_reloadable_flag_quic_enable_version_38) { + GetQuicFlag(FLAGS_quic_enable_version_42)) { filtered_versions.push_back(version); } - } else if (version == QUIC_VERSION_39) { - if (FLAGS_quic_reloadable_flag_quic_enable_version_39 && - FLAGS_quic_reloadable_flag_quic_enable_version_38) { - filtered_versions.push_back(version); - } - } else if (version == QUIC_VERSION_38) { - if (FLAGS_quic_reloadable_flag_quic_enable_version_38) { + } else if (version.transport_version == QUIC_VERSION_42) { + if (GetQuicFlag(FLAGS_quic_enable_version_42)) { filtered_versions.push_back(version); } } else { @@ -158,6 +171,30 @@ QuicTransportVersionVector VersionOfIndex( return version; } +ParsedQuicVersionVector ParsedVersionOfIndex( + const ParsedQuicVersionVector& versions, + int index) { + ParsedQuicVersionVector version; + int version_count = versions.size(); + if (index >= 0 && index < version_count) { + version.push_back(versions[index]); + } else { + version.push_back( + ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED)); + } + return version; +} + +QuicTransportVersionVector ParsedVersionsToTransportVersions( + const ParsedQuicVersionVector& versions) { + QuicTransportVersionVector transport_versions; + transport_versions.resize(versions.size()); + for (size_t i = 0; i < versions.size(); ++i) { + transport_versions[i] = versions[i].transport_version; + } + return transport_versions; +} + QuicVersionLabel QuicVersionToQuicVersionLabel( QuicTransportVersion transport_version) { return CreateQuicVersionLabel( @@ -165,11 +202,6 @@ QuicVersionLabel QuicVersionToQuicVersionLabel( } string QuicVersionLabelToString(QuicVersionLabel version_label) { - if (!FLAGS_quic_reloadable_flag_quic_use_net_byte_order_version_label) { - return QuicTagToString(version_label); - } - QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_use_net_byte_order_version_label, - 2, 10); return QuicTagToString(QuicEndian::HostToNet32(version_label)); } @@ -201,6 +233,10 @@ string QuicVersionToString(QuicTransportVersion transport_version) { } } +string ParsedQuicVersionToString(ParsedQuicVersion version) { + return QuicVersionLabelToString(CreateQuicVersionLabel(version)); +} + string QuicTransportVersionVectorToString( const QuicTransportVersionVector& versions) { string result = ""; @@ -213,4 +249,16 @@ string QuicTransportVersionVectorToString( return result; } +string ParsedQuicVersionVectorToString( + const ParsedQuicVersionVector& versions) { + string result = ""; + for (size_t i = 0; i < versions.size(); ++i) { + if (i != 0) { + result.append(","); + } + result.append(ParsedQuicVersionToString(versions[i])); + } + return result; +} + } // namespace net diff --git a/chromium/net/quic/core/quic_versions.h b/chromium/net/quic/core/quic_versions.h index 33c2824b6fa..b99596ff688 100644 --- a/chromium/net/quic/core/quic_versions.h +++ b/chromium/net/quic/core/quic_versions.h @@ -59,12 +59,34 @@ struct ParsedQuicVersion { : handshake_protocol(handshake_protocol), transport_version(transport_version) {} + ParsedQuicVersion(const ParsedQuicVersion& other) + : handshake_protocol(other.handshake_protocol), + transport_version(other.transport_version) {} + + ParsedQuicVersion& operator=(const ParsedQuicVersion& other) { + if (this != &other) { + handshake_protocol = other.handshake_protocol; + transport_version = other.transport_version; + } + return *this; + } + bool operator==(const ParsedQuicVersion& other) const { return handshake_protocol == other.handshake_protocol && transport_version == other.transport_version; } + + bool operator!=(const ParsedQuicVersion& other) const { + return handshake_protocol != other.handshake_protocol || + transport_version != other.transport_version; + } }; +QUIC_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os, + const ParsedQuicVersion& version); + +using ParsedQuicVersionVector = std::vector<ParsedQuicVersion>; + // Representation of the on-the-wire QUIC version number. Will be written/read // to the wire in network-byte-order. using QuicVersionLabel = uint32_t; @@ -81,26 +103,57 @@ static const QuicTransportVersion kSupportedTransportVersions[] = { QUIC_VERSION_43, QUIC_VERSION_42, QUIC_VERSION_41, QUIC_VERSION_39, QUIC_VERSION_38, QUIC_VERSION_37, QUIC_VERSION_35}; +// This vector contains all crypto handshake protocols that are supported. +static const HandshakeProtocol kSupportedHandshakeProtocols[] = { + PROTOCOL_QUIC_CRYPTO, PROTOCOL_TLS1_3}; + typedef std::vector<QuicTransportVersion> QuicTransportVersionVector; // Returns a vector of QUIC versions in kSupportedTransportVersions. QUIC_EXPORT_PRIVATE QuicTransportVersionVector AllSupportedTransportVersions(); +// Returns a vector of QUIC versions that is the cartesian product of +// kSupportedTransportVersions and kSupportedHandshakeProtocols. +QUIC_EXPORT_PRIVATE ParsedQuicVersionVector AllSupportedVersions(); + // Returns a vector of QUIC versions from kSupportedTransportVersions which // exclude any versions which are disabled by flags. QUIC_EXPORT_PRIVATE QuicTransportVersionVector CurrentSupportedTransportVersions(); +// Returns a vector of QUIC versions that is the cartesian product of +// kSupportedTransportVersions and kSupportedHandshakeProtocols, with any +// versions disabled by flags excluded. +QUIC_EXPORT_PRIVATE ParsedQuicVersionVector CurrentSupportedVersions(); + // Returns a vector of QUIC versions from |versions| which exclude any versions // which are disabled by flags. QUIC_EXPORT_PRIVATE QuicTransportVersionVector FilterSupportedTransportVersions(QuicTransportVersionVector versions); +// Returns a vector of QUIC versions from |versions| which exclude any versions +// which are disabled by flags. +QUIC_EXPORT_PRIVATE ParsedQuicVersionVector +FilterSupportedVersions(ParsedQuicVersionVector versions); + // Returns QUIC version of |index| in result of |versions|. Returns // QUIC_VERSION_UNSUPPORTED if |index| is out of bounds. QUIC_EXPORT_PRIVATE QuicTransportVersionVector VersionOfIndex(const QuicTransportVersionVector& versions, int index); +// Returns QUIC version of |index| in result of |versions|. Returns +// ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED) if |index| +// is out of bounds. +QUIC_EXPORT_PRIVATE ParsedQuicVersionVector +ParsedVersionOfIndex(const ParsedQuicVersionVector& versions, int index); + +// Returns a vector of QuicTransportVersions corresponding to just the transport +// versions in |versions|. If the input vector contains multiple parsed versions +// with different handshake protocols (but the same transport version), that +// transport version will appear in the resulting vector multiple times. +QUIC_EXPORT_PRIVATE QuicTransportVersionVector +ParsedVersionsToTransportVersions(const ParsedQuicVersionVector& versions); + // QuicVersionLabel is written to and read from the wire, but we prefer to use // the more readable ParsedQuicVersion at other levels. // Helper function which translates from a QuicVersionLabel to a @@ -138,11 +191,21 @@ QuicVersionLabelToHandshakeProtocol(QuicVersionLabel version_label); QUIC_EXPORT_PRIVATE std::string QuicVersionToString( QuicTransportVersion transport_version); +// Helper function which translates from a ParsedQuicVersion to a std::string. +// Returns std::strings corresponding to the on-the-wire tag. +QUIC_EXPORT_PRIVATE std::string ParsedQuicVersionToString( + ParsedQuicVersion version); + // Returns comma separated list of string representations of QuicVersion enum // values in the supplied |versions| vector. QUIC_EXPORT_PRIVATE std::string QuicTransportVersionVectorToString( const QuicTransportVersionVector& versions); +// Returns comma separated list of std::string representations of +// ParsedQuicVersion values in the supplied |versions| vector. +QUIC_EXPORT_PRIVATE std::string ParsedQuicVersionVectorToString( + const ParsedQuicVersionVector& versions); + } // namespace net #endif // NET_QUIC_CORE_QUIC_VERSIONS_H_ diff --git a/chromium/net/quic/core/quic_versions_test.cc b/chromium/net/quic/core/quic_versions_test.cc index 60fe66e1fd1..1a4a553a53e 100644 --- a/chromium/net/quic/core/quic_versions_test.cc +++ b/chromium/net/quic/core/quic_versions_test.cc @@ -4,6 +4,7 @@ #include "net/quic/core/quic_versions.h" +#include "net/quic/platform/api/quic_arraysize.h" #include "net/quic/platform/api/quic_flags.h" #include "net/quic/platform/api/quic_test.h" #include "net/quic/test_tools/quic_test_utils.h" @@ -15,9 +16,6 @@ namespace { class QuicVersionsTest : public QuicTest { protected: QuicVersionLabel MakeVersionLabel(char a, char b, char c, char d) { - if (!FLAGS_quic_reloadable_flag_quic_use_net_byte_order_version_label) { - return MakeQuicTag(a, b, c, d); - } return MakeQuicTag(d, c, b, a); } }; @@ -36,20 +34,15 @@ TEST_F(QuicVersionsTest, QuicVersionToQuicVersionLabel) { #endif // Explicitly test a specific version. - if (!FLAGS_quic_reloadable_flag_quic_use_net_byte_order_version_label) { - EXPECT_EQ(MakeQuicTag('Q', '0', '3', '5'), - QuicVersionToQuicVersionLabel(QUIC_VERSION_35)); - } else { EXPECT_EQ(MakeQuicTag('5', '3', '0', 'Q'), QuicVersionToQuicVersionLabel(QUIC_VERSION_35)); - } // Loop over all supported versions and make sure that we never hit the // default case (i.e. all supported versions should be successfully converted // to valid QuicVersionLabels). - for (size_t i = 0; i < arraysize(kSupportedTransportVersions); ++i) { - QuicTransportVersion version = kSupportedTransportVersions[i]; - EXPECT_LT(0u, QuicVersionToQuicVersionLabel(version)); + for (size_t i = 0; i < QUIC_ARRAYSIZE(kSupportedTransportVersions); ++i) { + QuicTransportVersion version = kSupportedTransportVersions[i]; + EXPECT_LT(0u, QuicVersionToQuicVersionLabel(version)); } } @@ -83,15 +76,10 @@ TEST_F(QuicVersionsTest, QuicVersionLabelToQuicTransportVersion) { #endif // Explicitly test specific versions. - if (!FLAGS_quic_reloadable_flag_quic_use_net_byte_order_version_label) { - EXPECT_EQ(QUIC_VERSION_35, - QuicVersionLabelToQuicVersion(MakeQuicTag('Q', '0', '3', '5'))); - } else { - EXPECT_EQ(QUIC_VERSION_35, - QuicVersionLabelToQuicVersion(MakeQuicTag('5', '3', '0', 'Q'))); - } + EXPECT_EQ(QUIC_VERSION_35, + QuicVersionLabelToQuicVersion(MakeQuicTag('5', '3', '0', 'Q'))); - for (size_t i = 0; i < arraysize(kSupportedTransportVersions); ++i) { + for (size_t i = 0; i < QUIC_ARRAYSIZE(kSupportedTransportVersions); ++i) { QuicTransportVersion version = kSupportedTransportVersions[i]; // Get the label from the version (we can loop over QuicVersions easily). @@ -111,15 +99,9 @@ TEST_F(QuicVersionsTest, QuicVersionLabelToQuicVersionUnsupported) { #if 0 ScopedMockLog log(kDoNotCaptureLogsYet); #ifndef NDEBUG - if (!FLAGS_quic_reloadable_flag_quic_use_net_byte_order_version_label) { - EXPECT_CALL(log, Log(base_logging::INFO, _, - "Unsupported QuicVersionLabel version: FAKE")) - .Times(1); - } else { - EXPECT_CALL(log, Log(base_logging::INFO, _, - "Unsupported QuicVersionLabel version: EKAF")) - .Times(1); - } + EXPECT_CALL(log, Log(base_logging::INFO, _, + "Unsupported QuicVersionLabel version: EKAF")) + .Times(1); #endif log.StartCapturingLogs(); #endif @@ -136,7 +118,7 @@ TEST_F(QuicVersionsTest, QuicVersionLabelToHandshakeProtocol) { log.StartCapturingLogs(); #endif - for (size_t i = 0; i < arraysize(kSupportedTransportVersions); ++i) { + for (size_t i = 0; i < QUIC_ARRAYSIZE(kSupportedTransportVersions); ++i) { QuicVersionLabel version_label = QuicVersionToQuicVersionLabel(kSupportedTransportVersions[i]); EXPECT_EQ(PROTOCOL_QUIC_CRYPTO, @@ -145,12 +127,7 @@ TEST_F(QuicVersionsTest, QuicVersionLabelToHandshakeProtocol) { // Test a TLS version: FLAGS_quic_supports_tls_handshake = true; - QuicTag tls_tag; - if (!FLAGS_quic_reloadable_flag_quic_use_net_byte_order_version_label) { - tls_tag = MakeQuicTag('T', '0', '4', '1'); - } else { - tls_tag = MakeQuicTag('1', '4', '0', 'T'); - } + QuicTag tls_tag = MakeQuicTag('1', '4', '0', 'T'); EXPECT_EQ(PROTOCOL_TLS1_3, QuicVersionLabelToHandshakeProtocol(tls_tag)); FLAGS_quic_supports_tls_handshake = false; @@ -285,7 +262,7 @@ TEST_F(QuicVersionsTest, QuicVersionToString) { QuicTransportVersion single_version[] = {QUIC_VERSION_35}; QuicTransportVersionVector versions_vector; - for (size_t i = 0; i < arraysize(single_version); ++i) { + for (size_t i = 0; i < QUIC_ARRAYSIZE(single_version); ++i) { versions_vector.push_back(single_version[i]); } EXPECT_EQ("QUIC_VERSION_35", @@ -294,57 +271,57 @@ TEST_F(QuicVersionsTest, QuicVersionToString) { QuicTransportVersion multiple_versions[] = {QUIC_VERSION_UNSUPPORTED, QUIC_VERSION_35}; versions_vector.clear(); - for (size_t i = 0; i < arraysize(multiple_versions); ++i) { + for (size_t i = 0; i < QUIC_ARRAYSIZE(multiple_versions); ++i) { versions_vector.push_back(multiple_versions[i]); } EXPECT_EQ("QUIC_VERSION_UNSUPPORTED,QUIC_VERSION_35", QuicTransportVersionVectorToString(versions_vector)); // Make sure that all supported versions are present in QuicVersionToString. - for (size_t i = 0; i < arraysize(kSupportedTransportVersions); ++i) { + for (size_t i = 0; i < QUIC_ARRAYSIZE(kSupportedTransportVersions); ++i) { QuicTransportVersion version = kSupportedTransportVersions[i]; EXPECT_NE("QUIC_VERSION_UNSUPPORTED", QuicVersionToString(version)); } } -TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo38) { - QuicTransportVersionVector all_versions = {QUIC_VERSION_35, QUIC_VERSION_37, - QUIC_VERSION_38, QUIC_VERSION_39}; +TEST_F(QuicVersionsTest, ParsedQuicVersionToString) { + ParsedQuicVersion unsupported(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED); + ParsedQuicVersion version35(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_35); + EXPECT_EQ("Q035", ParsedQuicVersionToString(version35)); + EXPECT_EQ("0", ParsedQuicVersionToString(unsupported)); - FLAGS_quic_reloadable_flag_quic_enable_version_38 = false; + ParsedQuicVersionVector versions_vector = {version35}; + EXPECT_EQ("Q035", ParsedQuicVersionVectorToString(versions_vector)); - QuicTransportVersionVector filtered_versions = - FilterSupportedTransportVersions(all_versions); - ASSERT_EQ(2u, filtered_versions.size()); - EXPECT_EQ(QUIC_VERSION_35, filtered_versions[0]); - EXPECT_EQ(QUIC_VERSION_37, filtered_versions[1]); -} + versions_vector = {unsupported, version35}; + EXPECT_EQ("0,Q035", ParsedQuicVersionVectorToString(versions_vector)); -TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo39) { - QuicTransportVersionVector all_versions = {QUIC_VERSION_35, QUIC_VERSION_37, - QUIC_VERSION_38, QUIC_VERSION_39}; - - FLAGS_quic_reloadable_flag_quic_enable_version_38 = true; - FLAGS_quic_reloadable_flag_quic_enable_version_39 = false; - - QuicTransportVersionVector filtered_versions = - FilterSupportedTransportVersions(all_versions); - ASSERT_EQ(3u, filtered_versions.size()); - EXPECT_EQ(QUIC_VERSION_35, filtered_versions[0]); - EXPECT_EQ(QUIC_VERSION_37, filtered_versions[1]); - EXPECT_EQ(QUIC_VERSION_38, filtered_versions[2]); + // Make sure that all supported versions are present in + // ParsedQuicVersionToString. + FLAGS_quic_supports_tls_handshake = true; + for (QuicTransportVersion transport_version : kSupportedTransportVersions) { + for (HandshakeProtocol protocol : kSupportedHandshakeProtocols) { + EXPECT_NE("0", ParsedQuicVersionToString( + ParsedQuicVersion(protocol, transport_version))); + } + } } TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsAllVersions) { QuicTransportVersionVector all_versions = {QUIC_VERSION_35, QUIC_VERSION_37, QUIC_VERSION_38, QUIC_VERSION_39}; - - FLAGS_quic_reloadable_flag_quic_enable_version_38 = true; - FLAGS_quic_reloadable_flag_quic_enable_version_39 = true; + ParsedQuicVersionVector parsed_versions; + for (QuicTransportVersion version : all_versions) { + parsed_versions.push_back(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version)); + } QuicTransportVersionVector filtered_versions = FilterSupportedTransportVersions(all_versions); ASSERT_EQ(all_versions, filtered_versions); + + ParsedQuicVersionVector filtered_parsed_versions = + FilterSupportedVersions(parsed_versions); + ASSERT_EQ(parsed_versions, filtered_parsed_versions); } TEST_F(QuicVersionsTest, LookUpVersionByIndex) { @@ -359,11 +336,36 @@ TEST_F(QuicVersionsTest, LookUpVersionByIndex) { } } } + +TEST_F(QuicVersionsTest, LookUpParsedVersionByIndex) { + ParsedQuicVersionVector all_versions = AllSupportedVersions(); + int version_count = all_versions.size(); + for (int i = -5; i <= version_count + 1; ++i) { + if (i >= 0 && i < version_count) { + EXPECT_EQ(all_versions[i], ParsedVersionOfIndex(all_versions, i)[0]); + } else { + EXPECT_EQ( + ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED), + ParsedVersionOfIndex(all_versions, i)[0]); + } + } +} + +TEST_F(QuicVersionsTest, ParsedVersionsToTransportVersions) { + ParsedQuicVersionVector all_versions = AllSupportedVersions(); + QuicTransportVersionVector transport_versions = + ParsedVersionsToTransportVersions(all_versions); + ASSERT_EQ(all_versions.size(), transport_versions.size()); + for (size_t i = 0; i < all_versions.size(); ++i) { + EXPECT_EQ(transport_versions[i], all_versions[i].transport_version); + } +} + // This test may appear to be so simplistic as to be unnecessary, // 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, CheckVersionNumbersForTypos) { - static_assert(arraysize(net::kSupportedTransportVersions) == 7u, + static_assert(QUIC_ARRAYSIZE(net::kSupportedTransportVersions) == 7u, "Supported versions out of sync"); EXPECT_EQ(QUIC_VERSION_35, 35); EXPECT_EQ(QUIC_VERSION_37, 37); diff --git a/chromium/net/quic/core/session_notifier_interface.h b/chromium/net/quic/core/session_notifier_interface.h new file mode 100644 index 00000000000..9a1e4e37d3f --- /dev/null +++ b/chromium/net/quic/core/session_notifier_interface.h @@ -0,0 +1,32 @@ +// 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 NET_QUIC_CORE_SESSION_NOTIFIER_INTERFACE_H_ +#define NET_QUIC_CORE_SESSION_NOTIFIER_INTERFACE_H_ + +#include "net/quic/core/frames/quic_frame.h" +#include "net/quic/core/quic_time.h" + +namespace net { + +// Pure virtual class to be notified when a packet containing a frame is acked +// or lost. +class QUIC_EXPORT_PRIVATE SessionNotifierInterface { + public: + virtual ~SessionNotifierInterface() {} + + // Called when |frame| is acked. + virtual void OnFrameAcked(const QuicFrame& frame, + QuicTime::Delta ack_delay_time) = 0; + + // Called when |frame| is retransmitted. + virtual void OnStreamFrameRetransmitted(const QuicStreamFrame& frame) = 0; + + // Called when |frame| is considered as lost. + virtual void OnFrameLost(const QuicFrame& frame) = 0; +}; + +} // namespace net + +#endif // NET_QUIC_CORE_SESSION_NOTIFIER_INTERFACE_H_ diff --git a/chromium/net/quic/core/stream_notifier_interface.h b/chromium/net/quic/core/stream_notifier_interface.h deleted file mode 100644 index 1237e5c52f1..00000000000 --- a/chromium/net/quic/core/stream_notifier_interface.h +++ /dev/null @@ -1,33 +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 NET_QUIC_CORE_STREAM_NOTIFIER_INTERFACE_H_ -#define NET_QUIC_CORE_STREAM_NOTIFIER_INTERFACE_H_ - -#include "net/quic/core/frames/quic_stream_frame.h" -#include "net/quic/core/quic_time.h" - -namespace net { - -// Pure virtual class to be notified when a packet containing a stream frame is -// acked or lost. -class QUIC_EXPORT_PRIVATE StreamNotifierInterface { - public: - virtual ~StreamNotifierInterface() {} - - // Called when |frame| is acked. - virtual void OnStreamFrameAcked(const QuicStreamFrame& frame, - QuicTime::Delta ack_delay_time) = 0; - - // Called when |frame| is retransmitted. - virtual void OnStreamFrameRetransmitted(const QuicStreamFrame& frame) = 0; - - // Called when |frame| is discarded from unacked packet map because stream is - // reset. - virtual void OnStreamFrameDiscarded(const QuicStreamFrame& frame) = 0; -}; - -} // namespace net - -#endif // NET_QUIC_CORE_STREAM_NOTIFIER_INTERFACE_H_ diff --git a/chromium/net/quic/core/tls_client_handshaker.cc b/chromium/net/quic/core/tls_client_handshaker.cc index c540a25bc69..9f64a86d365 100644 --- a/chromium/net/quic/core/tls_client_handshaker.cc +++ b/chromium/net/quic/core/tls_client_handshaker.cc @@ -46,7 +46,8 @@ TlsClientHandshaker::TlsClientHandshaker(QuicCryptoStream* stream, : TlsHandshaker(stream, session, ssl_ctx), server_id_(server_id), proof_verifier_(proof_verifier), - verify_context_(verify_context) {} + verify_context_(verify_context), + crypto_negotiated_params_(new QuicCryptoNegotiatedParameters) {} TlsClientHandshaker::~TlsClientHandshaker() { if (proof_verify_callback_) { @@ -54,6 +55,11 @@ TlsClientHandshaker::~TlsClientHandshaker() { } } +// static +bssl::UniquePtr<SSL_CTX> TlsClientHandshaker::CreateSslCtx() { + return TlsHandshaker::CreateSslCtx(); +} + bool TlsClientHandshaker::CryptoConnect() { state_ = STATE_HANDSHAKE_RUNNING; // Configure certificate verification. @@ -169,25 +175,41 @@ void TlsClientHandshaker::FinishHandshake() { QUIC_LOG(INFO) << "Client: handshake finished"; state_ = STATE_HANDSHAKE_COMPLETE; std::vector<uint8_t> client_secret, server_secret; - if (!DeriveSecrets(ssl(), &client_secret, &server_secret)) { + if (!DeriveSecrets(&client_secret, &server_secret)) { CloseConnection(); return; } - // TODO(nharper): Use |client_secret| and |server_secret| to set the - // appropriate crypters on the connection, and set |encryption_established_| - // to true. Whenever encryption keys are set, call - // session()->connection()->NeuterUnencryptedPackets(). + QUIC_LOG(INFO) << "Client: setting crypters"; + QuicEncrypter* initial_encrypter = CreateEncrypter(client_secret); + session()->connection()->SetEncrypter(ENCRYPTION_INITIAL, initial_encrypter); + QuicEncrypter* encrypter = CreateEncrypter(client_secret); + session()->connection()->SetEncrypter(ENCRYPTION_FORWARD_SECURE, encrypter); + + QuicDecrypter* initial_decrypter = CreateDecrypter(server_secret); + session()->connection()->SetDecrypter(ENCRYPTION_INITIAL, initial_decrypter); + QuicDecrypter* decrypter = CreateDecrypter(server_secret); + session()->connection()->SetAlternativeDecrypter(ENCRYPTION_FORWARD_SECURE, + decrypter, true); + + session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); + + session()->NeuterUnencryptedData(); + encryption_established_ = true; handshake_confirmed_ = true; } // static +TlsClientHandshaker* TlsClientHandshaker::HandshakerFromSsl(SSL* ssl) { + return static_cast<TlsClientHandshaker*>( + TlsHandshaker::HandshakerFromSsl(ssl)); +} + +// static enum ssl_verify_result_t TlsClientHandshaker::VerifyCallback( SSL* ssl, uint8_t* out_alert) { - return static_cast<TlsClientHandshaker*>( - TlsHandshaker::HandshakerFromSsl(ssl)) - ->VerifyCert(out_alert); + return HandshakerFromSsl(ssl)->VerifyCert(out_alert); } enum ssl_verify_result_t TlsClientHandshaker::VerifyCert(uint8_t* out_alert) { diff --git a/chromium/net/quic/core/tls_client_handshaker.h b/chromium/net/quic/core/tls_client_handshaker.h index 85c362f40d3..39234dd57b2 100644 --- a/chromium/net/quic/core/tls_client_handshaker.h +++ b/chromium/net/quic/core/tls_client_handshaker.h @@ -31,6 +31,10 @@ class QUIC_EXPORT_PRIVATE TlsClientHandshaker ~TlsClientHandshaker() override; + // Creates and configures an SSL_CTX to be used with a TlsClientHandshaker. + // The caller is responsible for ownership of the newly created struct. + static bssl::UniquePtr<SSL_CTX> CreateSslCtx(); + // From QuicCryptoClientStream::HandshakerDelegate bool CryptoConnect() override; int num_sent_client_hellos() const override; @@ -85,6 +89,11 @@ class QUIC_EXPORT_PRIVATE TlsClientHandshaker // Static method to supply to SSL_set_custom_verify. static enum ssl_verify_result_t VerifyCallback(SSL* ssl, uint8_t* out_alert); + // Takes an SSL* |ssl| and returns a pointer to the TlsClientHandshaker that + // it belongs to. This is a specialization of + // TlsHandshaker::HandshakerFromSsl. + static TlsClientHandshaker* HandshakerFromSsl(SSL* ssl); + QuicServerId server_id_; // Objects used for verifying the server's certificate chain. diff --git a/chromium/net/quic/core/tls_handshaker.cc b/chromium/net/quic/core/tls_handshaker.cc index 72380b8ff69..ba15d0cdff5 100644 --- a/chromium/net/quic/core/tls_handshaker.cc +++ b/chromium/net/quic/core/tls_handshaker.cc @@ -6,7 +6,9 @@ #include "base/memory/singleton.h" #include "net/quic/core/quic_crypto_stream.h" -#include "third_party/boringssl/src/include/openssl/ssl.h" +#include "net/quic/core/tls_client_handshaker.h" +#include "net/quic/core/tls_server_handshaker.h" +#include "net/quic/platform/api/quic_arraysize.h" namespace net { @@ -17,29 +19,6 @@ const char kServerLabel[] = "EXPORTER-QUIC server 1-RTT Secret"; } // namespace -// static -bool TlsHandshaker::DeriveSecrets(SSL* ssl, - std::vector<uint8_t>* client_secret_out, - std::vector<uint8_t>* server_secret_out) { - const SSL_CIPHER* cipher = SSL_get_current_cipher(ssl); - if (cipher == nullptr) { - return false; - } - const EVP_MD* prf = EVP_get_digestbynid(SSL_CIPHER_get_prf_nid(cipher)); - if (prf == nullptr) { - return false; - } - size_t hash_len = EVP_MD_size(prf); - client_secret_out->resize(hash_len); - server_secret_out->resize(hash_len); - return SSL_export_keying_material(ssl, client_secret_out->data(), hash_len, - kClientLabel, arraysize(kClientLabel), - nullptr, 0, 0) && - SSL_export_keying_material(ssl, server_secret_out->data(), hash_len, - kServerLabel, arraysize(kServerLabel), - nullptr, 0, 0); -} - namespace { class SslIndexSingleton { @@ -72,6 +51,66 @@ TlsHandshaker* TlsHandshaker::HandshakerFromSsl(const SSL* ssl) { ssl, SslIndexSingleton::GetInstance()->HandshakerIndex())); } +const EVP_MD* TlsHandshaker::Prf() { + return EVP_get_digestbynid( + SSL_CIPHER_get_prf_nid(SSL_get_current_cipher(ssl()))); +} + +bool TlsHandshaker::DeriveSecrets(std::vector<uint8_t>* client_secret_out, + std::vector<uint8_t>* server_secret_out) { + size_t hash_len = EVP_MD_size(Prf()); + client_secret_out->resize(hash_len); + server_secret_out->resize(hash_len); + return (SSL_export_keying_material( + ssl(), client_secret_out->data(), hash_len, kClientLabel, + QUIC_ARRAYSIZE(kClientLabel) - 1, nullptr, 0, 0) == 1) && + (SSL_export_keying_material( + ssl(), server_secret_out->data(), hash_len, kServerLabel, + QUIC_ARRAYSIZE(kServerLabel) - 1, nullptr, 0, 0) == 1); +} + +namespace { + +template <class QuicCrypter> +void SetKeyAndIV(const EVP_MD* prf, + const std::vector<uint8_t>& pp_secret, + QuicCrypter* crypter) { + std::vector<uint8_t> key = CryptoUtils::HkdfExpandLabel( + prf, pp_secret, "key", crypter->GetKeySize()); + std::vector<uint8_t> iv = + CryptoUtils::HkdfExpandLabel(prf, pp_secret, "iv", crypter->GetIVSize()); + crypter->SetKey( + QuicStringPiece(reinterpret_cast<char*>(key.data()), key.size())); + crypter->SetIV( + QuicStringPiece(reinterpret_cast<char*>(iv.data()), iv.size())); +} + +} // namespace + +QuicEncrypter* TlsHandshaker::CreateEncrypter( + const std::vector<uint8_t>& pp_secret) { + QuicEncrypter* encrypter = QuicEncrypter::CreateFromCipherSuite( + SSL_CIPHER_get_id(SSL_get_current_cipher(ssl()))); + SetKeyAndIV(Prf(), pp_secret, encrypter); + return encrypter; +} + +QuicDecrypter* TlsHandshaker::CreateDecrypter( + const std::vector<uint8_t>& pp_secret) { + QuicDecrypter* decrypter = QuicDecrypter::CreateFromCipherSuite( + SSL_CIPHER_get_id(SSL_get_current_cipher(ssl()))); + SetKeyAndIV(Prf(), pp_secret, decrypter); + return decrypter; +} + +// static +bssl::UniquePtr<SSL_CTX> TlsHandshaker::CreateSslCtx() { + bssl::UniquePtr<SSL_CTX> ssl_ctx(SSL_CTX_new(TLS_with_buffers_method())); + SSL_CTX_set_min_proto_version(ssl_ctx.get(), TLS1_3_VERSION); + SSL_CTX_set_max_proto_version(ssl_ctx.get(), TLS1_3_VERSION); + return ssl_ctx; +} + TlsHandshaker::TlsHandshaker(QuicCryptoStream* stream, QuicSession* session, SSL_CTX* ssl_ctx) diff --git a/chromium/net/quic/core/tls_handshaker.h b/chromium/net/quic/core/tls_handshaker.h index bdef510788d..c542be36aff 100644 --- a/chromium/net/quic/core/tls_handshaker.h +++ b/chromium/net/quic/core/tls_handshaker.h @@ -6,6 +6,8 @@ #define NET_QUIC_CORE_TLS_HANDSHAKER_H_ #include "net/quic/core/crypto/crypto_handshake.h" +#include "net/quic/core/crypto/quic_decrypter.h" +#include "net/quic/core/crypto/quic_encrypter.h" #include "net/quic/core/crypto/quic_tls_adapter.h" #include "net/quic/platform/api/quic_export.h" #include "third_party/boringssl/src/include/openssl/base.h" @@ -29,14 +31,6 @@ class QUIC_EXPORT_PRIVATE TlsHandshaker : public QuicTlsAdapter::Visitor { ~TlsHandshaker() override; - // Computes the 1-RTT secrets client_pp_secret_0 and server_pp_secret_0 from - // which the packet protection keys are derived, as defined in - // draft-ietf-quic-tls section 5.2.2. Returns true on success and false if - // |ssl| is not in a state to export secrets. - static bool DeriveSecrets(SSL* ssl, - std::vector<uint8_t>* client_secret_out, - std::vector<uint8_t>* server_secret_out); - // From QuicTlsAdapter::Visitor void OnDataAvailableForBIO() override; void OnDataReceivedFromBIO(const QuicStringPiece& data) override; @@ -51,12 +45,29 @@ class QUIC_EXPORT_PRIVATE TlsHandshaker : public QuicTlsAdapter::Visitor { protected: virtual void AdvanceHandshake() = 0; + // Creates an SSL_CTX and configures it with the options that are appropriate + // for both client and server. The caller is responsible for ownership of the + // newly created struct. + static bssl::UniquePtr<SSL_CTX> CreateSslCtx(); + // From a given SSL* |ssl|, returns a pointer to the TlsHandshaker that it // belongs to. This is a helper method for implementing callbacks set on an // SSL, as it allows the callback function to find the TlsHandshaker instance // and call an instance method. static TlsHandshaker* HandshakerFromSsl(const SSL* ssl); + // Returns the PRF used by the cipher suite negotiated in the TLS handshake. + const EVP_MD* Prf(); + + // Computes the 1-RTT secrets client_pp_secret_0 and server_pp_secret_0 from + // which the packet protection keys are derived, as defined in + // draft-ietf-quic-tls section 5.2.2. + bool DeriveSecrets(std::vector<uint8_t>* client_secret_out, + std::vector<uint8_t>* server_secret_out); + + QuicEncrypter* CreateEncrypter(const std::vector<uint8_t>& pp_secret); + QuicDecrypter* CreateDecrypter(const std::vector<uint8_t>& pp_secret); + SSL* ssl() { return ssl_.get(); } QuicCryptoStream* stream() { return stream_; } QuicSession* session() { return session_; } diff --git a/chromium/net/quic/core/tls_handshaker_test.cc b/chromium/net/quic/core/tls_handshaker_test.cc index d0f90b164d9..08919bd504d 100644 --- a/chromium/net/quic/core/tls_handshaker_test.cc +++ b/chromium/net/quic/core/tls_handshaker_test.cc @@ -4,6 +4,7 @@ #include "net/quic/core/tls_client_handshaker.h" #include "net/quic/core/tls_server_handshaker.h" +#include "net/quic/platform/api/quic_arraysize.h" #include "net/quic/platform/api/quic_test.h" #include "net/quic/test_tools/crypto_test_utils.h" #include "net/quic/test_tools/fake_proof_source.h" @@ -178,17 +179,14 @@ class TestQuicCryptoClientStream : public TestQuicCryptoStream { explicit TestQuicCryptoClientStream(QuicSession* session) : TestQuicCryptoStream(session), proof_verifier_(new FakeProofVerifier), - ssl_ctx_(SSL_CTX_new(TLS_with_buffers_method())), + ssl_ctx_(TlsClientHandshaker::CreateSslCtx()), handshaker_(new TlsClientHandshaker( this, session, QuicServerId("test.example.com", 443), proof_verifier_.get(), ssl_ctx_.get(), - crypto_test_utils::ProofVerifyContextForTesting())) { - SSL_CTX_set_min_proto_version(ssl_ctx_.get(), TLS1_3_VERSION); - SSL_CTX_set_max_proto_version(ssl_ctx_.get(), TLS1_3_VERSION); - } + crypto_test_utils::ProofVerifyContextForTesting())) {} ~TestQuicCryptoClientStream() override = default; @@ -212,16 +210,11 @@ class TestQuicCryptoServerStream : public TestQuicCryptoStream { FakeProofSource* proof_source) : TestQuicCryptoStream(session), proof_source_(proof_source), - ssl_ctx_(SSL_CTX_new(TLS_with_buffers_method())), + ssl_ctx_(TlsServerHandshaker::CreateSslCtx()), handshaker_(new TlsServerHandshaker(this, session, ssl_ctx_.get(), - proof_source_)) { - SSL_CTX_set_min_proto_version(ssl_ctx_.get(), TLS1_3_VERSION); - SSL_CTX_set_max_proto_version(ssl_ctx_.get(), TLS1_3_VERSION); - SSL_CTX_set_tlsext_servername_callback( - ssl_ctx_.get(), TlsServerHandshaker::SelectCertificateCallback); - } + proof_source_)) {} ~TestQuicCryptoServerStream() override = default; @@ -286,10 +279,10 @@ TEST_F(TlsHandshakerTest, CryptoHandshake) { client_stream_.CryptoConnect(); MoveStreamFrames(&client_stream_, server_stream_.get()); - // TODO(nharper): Once encryption keys are set, check that - // encryption_established() is true on the streams. EXPECT_TRUE(client_stream_.handshake_confirmed()); + EXPECT_TRUE(client_stream_.encryption_established()); EXPECT_TRUE(server_stream_->handshake_confirmed()); + EXPECT_TRUE(server_stream_->encryption_established()); } TEST_F(TlsHandshakerTest, HandshakeWithAsyncProofSource) { @@ -309,10 +302,10 @@ TEST_F(TlsHandshakerTest, HandshakeWithAsyncProofSource) { MoveStreamFrames(&client_stream_, server_stream_.get()); - // TODO(nharper): Once encryption keys are set, check that - // encryption_established() is true on the streams. EXPECT_TRUE(client_stream_.handshake_confirmed()); + EXPECT_TRUE(client_stream_.encryption_established()); EXPECT_TRUE(server_stream_->handshake_confirmed()); + EXPECT_TRUE(server_stream_->encryption_established()); } TEST_F(TlsHandshakerTest, CancelPendingProofSource) { @@ -350,10 +343,10 @@ TEST_F(TlsHandshakerTest, HandshakeWithAsyncProofVerifier) { MoveStreamFrames(&client_stream_, server_stream_.get()); - // TODO(nharper): Once encryption keys are set, check that - // encryption_established() is true on the streams. EXPECT_TRUE(client_stream_.handshake_confirmed()); + EXPECT_TRUE(client_stream_.encryption_established()); EXPECT_TRUE(server_stream_->handshake_confirmed()); + EXPECT_TRUE(server_stream_->encryption_established()); } TEST_F(TlsHandshakerTest, ClientConnectionClosedOnTlsAlert) { @@ -373,7 +366,7 @@ TEST_F(TlsHandshakerTest, ClientConnectionClosedOnTlsAlert) { }; QuicStreamFrame alert(kCryptoStreamId, false, client_stream_.stream_bytes_read(), - QuicStringPiece(alert_msg, arraysize(alert_msg))); + QuicStringPiece(alert_msg, QUIC_ARRAYSIZE(alert_msg))); client_stream_.OnStreamFrame(alert); EXPECT_FALSE(client_stream_.handshake_confirmed()); @@ -394,7 +387,7 @@ TEST_F(TlsHandshakerTest, ServerConnectionClosedOnTlsAlert) { }; QuicStreamFrame alert(kCryptoStreamId, false, server_stream_->stream_bytes_read(), - QuicStringPiece(alert_msg, arraysize(alert_msg))); + QuicStringPiece(alert_msg, QUIC_ARRAYSIZE(alert_msg))); server_stream_->OnStreamFrame(alert); EXPECT_FALSE(server_stream_->handshake_confirmed()); diff --git a/chromium/net/quic/core/tls_server_handshaker.cc b/chromium/net/quic/core/tls_server_handshaker.cc index 0e7c491a9d0..31734e0e852 100644 --- a/chromium/net/quic/core/tls_server_handshaker.cc +++ b/chromium/net/quic/core/tls_server_handshaker.cc @@ -45,11 +45,21 @@ const SSL_PRIVATE_KEY_METHOD TlsServerHandshaker::kPrivateKeyMethod{ &TlsServerHandshaker::PrivateKeyComplete, }; +// static +bssl::UniquePtr<SSL_CTX> TlsServerHandshaker::CreateSslCtx() { + bssl::UniquePtr<SSL_CTX> ssl_ctx = TlsHandshaker::CreateSslCtx(); + SSL_CTX_set_tlsext_servername_callback( + ssl_ctx.get(), TlsServerHandshaker::SelectCertificateCallback); + return ssl_ctx; +} + TlsServerHandshaker::TlsServerHandshaker(QuicCryptoStream* stream, QuicSession* session, SSL_CTX* ssl_ctx, ProofSource* proof_source) - : TlsHandshaker(stream, session, ssl_ctx), proof_source_(proof_source) { + : TlsHandshaker(stream, session, ssl_ctx), + proof_source_(proof_source), + crypto_negotiated_params_(new QuicCryptoNegotiatedParameters) { // Set callback to provide SNI. // SSL_CTX_set_tlsext_servername_callback(ssl_ctx, SelectCertificateCallback); @@ -171,6 +181,7 @@ void TlsServerHandshaker::AdvanceHandshake() { if (should_close) { QUIC_LOG(WARNING) << "SSL_do_handshake failed; SSL_get_error returns " << ssl_error << ", state_ = " << state_; + ERR_print_errors_fp(stderr); CloseConnection(); } } @@ -188,14 +199,27 @@ void TlsServerHandshaker::FinishHandshake() { QUIC_LOG(INFO) << "Server: handshake finished"; state_ = STATE_HANDSHAKE_COMPLETE; std::vector<uint8_t> client_secret, server_secret; - if (!DeriveSecrets(ssl(), &client_secret, &server_secret)) { + if (!DeriveSecrets(&client_secret, &server_secret)) { CloseConnection(); return; } - // TODO(nharper): Use |client_secret| and |server_secret| to set the - // appropriate crypters on the connection, and set |encryption_established_| - // to true. Also call session()->connection()->NeuterUnencryptedPackets(). + QUIC_LOG(INFO) << "Server: setting crypters"; + QuicEncrypter* initial_encrypter = CreateEncrypter(server_secret); + session()->connection()->SetEncrypter(ENCRYPTION_INITIAL, initial_encrypter); + QuicEncrypter* encrypter = CreateEncrypter(server_secret); + session()->connection()->SetEncrypter(ENCRYPTION_FORWARD_SECURE, encrypter); + + QuicDecrypter* initial_decrypter = CreateDecrypter(client_secret); + session()->connection()->SetDecrypter(ENCRYPTION_INITIAL, initial_decrypter); + QuicDecrypter* decrypter = CreateDecrypter(client_secret); + session()->connection()->SetAlternativeDecrypter(ENCRYPTION_FORWARD_SECURE, + decrypter, true); + + session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); + + session()->NeuterUnencryptedData(); + encryption_established_ = true; handshake_confirmed_ = true; } diff --git a/chromium/net/quic/core/tls_server_handshaker.h b/chromium/net/quic/core/tls_server_handshaker.h index f07dcf47e83..382d7bb1ec2 100644 --- a/chromium/net/quic/core/tls_server_handshaker.h +++ b/chromium/net/quic/core/tls_server_handshaker.h @@ -6,6 +6,7 @@ #define NET_QUIC_CORE_TLS_SERVER_HANDSHAKER_H_ #include "net/quic/core/crypto/quic_tls_adapter.h" +#include "net/quic/core/proto/cached_network_parameters.pb.h" #include "net/quic/core/quic_crypto_server_stream.h" #include "net/quic/core/quic_crypto_stream.h" #include "net/quic/core/tls_handshaker.h" @@ -28,6 +29,10 @@ class QUIC_EXPORT_PRIVATE TlsServerHandshaker ~TlsServerHandshaker() override; + // Creates and configures an SSL_CTX to be used with a TlsServerHandshaker. + // The caller is responsible for ownership of the newly created struct. + static bssl::UniquePtr<SSL_CTX> CreateSslCtx(); + // From QuicCryptoServerStream::HandshakerDelegate void CancelOutstandingCallbacks() override; bool GetBase64SHA256ClientChannelID(std::string* output) const override; diff --git a/chromium/net/quic/http/decoder/quic_http_frame_decoder_adapter.cc b/chromium/net/quic/http/decoder/quic_http_frame_decoder_adapter.cc index 4dae7e3f2c5..aea455138ab 100644 --- a/chromium/net/quic/http/decoder/quic_http_frame_decoder_adapter.cc +++ b/chromium/net/quic/http/decoder/quic_http_frame_decoder_adapter.cc @@ -130,7 +130,11 @@ const char* QuicHttpDecoderAdapter::StateToString(int state) { return "UNKNOWN_STATE"; } -QuicHttpDecoderAdapter::QuicHttpDecoderAdapter() { +QuicHttpDecoderAdapter::QuicHttpDecoderAdapter() + : QuicHttpDecoderAdapter(false) {} + +QuicHttpDecoderAdapter::QuicHttpDecoderAdapter(bool h2_on_stream_pad_length) + : h2_on_stream_pad_length_(h2_on_stream_pad_length) { DVLOG(1) << "QuicHttpDecoderAdapter ctor"; ResetInternal(); } @@ -401,10 +405,13 @@ void QuicHttpDecoderAdapter::OnContinuationEnd() { void QuicHttpDecoderAdapter::OnPadLength(size_t trailing_length) { DVLOG(1) << "OnPadLength: " << trailing_length; opt_pad_length_ = trailing_length; + DCHECK_LT(trailing_length, 256u); if (frame_header_.type == QuicHttpFrameType::DATA) { - visitor()->OnStreamPadding(stream_id(), 1); - } else if (frame_header_.type == QuicHttpFrameType::HEADERS) { - CHECK_LT(trailing_length, 256u); + if (h2_on_stream_pad_length_) { + visitor()->OnStreamPadLength(stream_id(), trailing_length); + } else { + visitor()->OnStreamPadding(stream_id(), 1); + } } } diff --git a/chromium/net/quic/http/decoder/quic_http_frame_decoder_adapter.h b/chromium/net/quic/http/decoder/quic_http_frame_decoder_adapter.h index aa96f34a634..42a05166b57 100644 --- a/chromium/net/quic/http/decoder/quic_http_frame_decoder_adapter.h +++ b/chromium/net/quic/http/decoder/quic_http_frame_decoder_adapter.h @@ -54,6 +54,7 @@ class SPDY_EXPORT_PRIVATE QuicHttpDecoderAdapter static const char* StateToString(int state); QuicHttpDecoderAdapter(); + explicit QuicHttpDecoderAdapter(bool h2_on_stream_pad_length); ~QuicHttpDecoderAdapter() override; // Set callbacks to be called from the framer. A visitor must be set, or @@ -290,6 +291,9 @@ class SPDY_EXPORT_PRIVATE QuicHttpDecoderAdapter bool handling_extension_payload_ = false; bool process_single_input_frame_ = false; + + // Flag value latched at construction. + const bool h2_on_stream_pad_length_ : 1; }; } // namespace net diff --git a/chromium/net/quic/platform/api/quic_aligned.h b/chromium/net/quic/platform/api/quic_aligned.h index 7e5d9357a67..202c2197fd6 100644 --- a/chromium/net/quic/platform/api/quic_aligned.h +++ b/chromium/net/quic/platform/api/quic_aligned.h @@ -10,5 +10,6 @@ #define QUIC_ALIGN_OF QUIC_ALIGN_OF_IMPL #define QUIC_ALIGNED(X) QUIC_ALIGNED_IMPL(X) #define QUIC_CACHELINE_ALIGNED QUIC_CACHELINE_ALIGNED_IMPL +#define QUIC_CACHELINE_SIZE QUIC_CACHELINE_SIZE_IMPL #endif // NET_QUIC_PLATFORM_API_QUIC_ALIGNED_H_ diff --git a/chromium/net/quic/platform/api/quic_arraysize.h b/chromium/net/quic/platform/api/quic_arraysize.h new file mode 100644 index 00000000000..effd46fc180 --- /dev/null +++ b/chromium/net/quic/platform/api/quic_arraysize.h @@ -0,0 +1,12 @@ +// Copyright 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 NET_QUIC_PLATFORM_API_QUIC_ARRAYSIZE_H_ +#define NET_QUIC_PLATFORM_API_QUIC_ARRAYSIZE_H_ + +#include "net/quic/platform/impl/quic_arraysize_impl.h" + +#define QUIC_ARRAYSIZE(array) QUIC_ARRAYSIZE_IMPL(array) + +#endif // NET_QUIC_PLATFORM_API_QUIC_ARRAYSIZE_H_ diff --git a/chromium/net/quic/platform/api/quic_bug_tracker.h b/chromium/net/quic/platform/api/quic_bug_tracker.h index 1db197003c3..202d0e955d8 100644 --- a/chromium/net/quic/platform/api/quic_bug_tracker.h +++ b/chromium/net/quic/platform/api/quic_bug_tracker.h @@ -8,5 +8,7 @@ #define QUIC_BUG QUIC_BUG_IMPL #define QUIC_BUG_IF QUIC_BUG_IF_IMPL +#define QUIC_PEER_BUG QUIC_PEER_BUG_IMPL +#define QUIC_PEER_BUG_IF QUIC_PEER_BUG_IF_IMPL #endif // NET_QUIC_PLATFORM_API_QUIC_BUG_TRACKER_H_
\ No newline at end of file diff --git a/chromium/net/quic/platform/api/quic_flags.h b/chromium/net/quic/platform/api/quic_flags.h index 1739e37c275..a832ab78797 100644 --- a/chromium/net/quic/platform/api/quic_flags.h +++ b/chromium/net/quic/platform/api/quic_flags.h @@ -7,6 +7,11 @@ #include "net/quic/platform/impl/quic_flags_impl.h" +#define GetQuicReloadableFlag(flag) GetQuicReloadableFlagImpl(flag) +#define SetQuicReloadableFlag(flag, value) \ + SetQuicReloadableFlagImpl(flag, value) +#define GetQuicRestartFlag(flag) GetQuicRestartFlagImpl(flag) +#define SetQuicRestartFlag(flag, value) SetQuicRestartFlagImpl(flag, value) #define GetQuicFlag(flag) GetQuicFlagImpl(flag) #define SetQuicFlag(flag, value) SetQuicFlagImpl(flag, value) diff --git a/chromium/net/quic/platform/api/quic_hostname_utils.cc b/chromium/net/quic/platform/api/quic_hostname_utils.cc index 2f5e65dd96c..c7bbf27d1da 100644 --- a/chromium/net/quic/platform/api/quic_hostname_utils.cc +++ b/chromium/net/quic/platform/api/quic_hostname_utils.cc @@ -18,10 +18,4 @@ char* QuicHostnameUtils::NormalizeHostname(char* hostname) { return QuicHostnameUtilsImpl::NormalizeHostname(hostname); } -// static -void QuicHostnameUtils::StringToQuicServerId(const string& str, - QuicServerId* out) { - QuicHostnameUtilsImpl::StringToQuicServerId(str, out); -} - } // namespace net diff --git a/chromium/net/quic/platform/api/quic_hostname_utils.h b/chromium/net/quic/platform/api/quic_hostname_utils.h index 9c46d68356c..382d93a2540 100644 --- a/chromium/net/quic/platform/api/quic_hostname_utils.h +++ b/chromium/net/quic/platform/api/quic_hostname_utils.h @@ -12,8 +12,6 @@ namespace net { -class QuicServerId; - class QUIC_EXPORT_PRIVATE QuicHostnameUtils { public: // Returns true if the sni is valid, false otherwise. @@ -26,10 +24,6 @@ class QUIC_EXPORT_PRIVATE QuicHostnameUtils { // WARNING: mutates |hostname| in place and returns |hostname|. static char* NormalizeHostname(char* hostname); - // Creates a QuicServerId from a string formatted in same manner as - // QuicServerId::ToString(). - static void StringToQuicServerId(const std::string& str, QuicServerId* out); - private: DISALLOW_COPY_AND_ASSIGN(QuicHostnameUtils); }; diff --git a/chromium/net/quic/platform/api/quic_hostname_utils_test.cc b/chromium/net/quic/platform/api/quic_hostname_utils_test.cc index 65bbcb17491..9412d5b93e5 100644 --- a/chromium/net/quic/platform/api/quic_hostname_utils_test.cc +++ b/chromium/net/quic/platform/api/quic_hostname_utils_test.cc @@ -4,6 +4,7 @@ #include "net/quic/platform/api/quic_hostname_utils.h" +#include "net/quic/platform/api/quic_arraysize.h" #include "net/quic/platform/api/quic_test.h" using std::string; @@ -53,7 +54,7 @@ TEST_F(QuicHostnameUtilsTest, NormalizeHostname) { }, }; - for (size_t i = 0; i < arraysize(tests); ++i) { + for (size_t i = 0; i < QUIC_ARRAYSIZE(tests); ++i) { char buf[256]; snprintf(buf, sizeof(buf), "%s", tests[i].input); EXPECT_EQ(string(tests[i].expected), diff --git a/chromium/net/quic/platform/api/quic_mem_slice_span_test.cc b/chromium/net/quic/platform/api/quic_mem_slice_span_test.cc index 0ad1d299abc..6e37f08409e 100644 --- a/chromium/net/quic/platform/api/quic_mem_slice_span_test.cc +++ b/chromium/net/quic/platform/api/quic_mem_slice_span_test.cc @@ -29,8 +29,7 @@ class QuicMemSliceSpanImplTest : public QuicTest { TEST_F(QuicMemSliceSpanImplTest, SaveDataInSendBuffer) { SimpleBufferAllocator allocator; QuicStreamSendBuffer send_buffer( - &allocator, - FLAGS_quic_reloadable_flag_quic_allow_multiple_acks_for_data2); + &allocator, GetQuicReloadableFlag(quic_allow_multiple_acks_for_data2)); QuicTestMemSliceVector vector(buffers_); EXPECT_EQ(10 * 1024u, vector.span().SaveMemSlicesInSendBuffer(&send_buffer)); @@ -40,8 +39,7 @@ TEST_F(QuicMemSliceSpanImplTest, SaveDataInSendBuffer) { TEST_F(QuicMemSliceSpanImplTest, SaveEmptyMemSliceInSendBuffer) { SimpleBufferAllocator allocator; QuicStreamSendBuffer send_buffer( - &allocator, - FLAGS_quic_reloadable_flag_quic_allow_multiple_acks_for_data2); + &allocator, GetQuicReloadableFlag(quic_allow_multiple_acks_for_data2)); buffers_.push_back(std::make_pair(nullptr, 0)); QuicTestMemSliceVector vector(buffers_); EXPECT_EQ(10 * 1024u, vector.span().SaveMemSlicesInSendBuffer(&send_buffer)); diff --git a/chromium/net/quic/platform/api/quic_prefetch.h b/chromium/net/quic/platform/api/quic_prefetch.h new file mode 100644 index 00000000000..edc73a63d4c --- /dev/null +++ b/chromium/net/quic/platform/api/quic_prefetch.h @@ -0,0 +1,39 @@ +// Copyright 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 NET_QUIC_PLATFORM_API_QUIC_PREFETCH_H_ +#define NET_QUIC_PLATFORM_API_QUIC_PREFETCH_H_ + +#include "net/quic/platform/impl/quic_prefetch_impl.h" + +namespace net { + +// Move data into the cache before it is read, or "prefetch" it. +// +// The value of `addr` is the address of the memory to prefetch. If +// the target and compiler support it, data prefetch instructions are +// generated. If the prefetch is done some time before the memory is +// read, it may be in the cache by the time the read occurs. +// +// The function names specify the temporal locality heuristic applied, +// using the names of Intel prefetch instructions: +// +// T0 - high degree of temporal locality; data should be left in as +// many levels of the cache possible +// T1 - moderate degree of temporal locality +// T2 - low degree of temporal locality +// Nta - no temporal locality, data need not be left in the cache +// after the read +// +// Incorrect or gratuitous use of these functions can degrade +// performance, so use them only when representative benchmarks show +// an improvement. + +inline void QuicPrefetchT0(const void* addr) { + return QuicPrefetchT0Impl(addr); +} + +} // namespace net + +#endif // NET_QUIC_PLATFORM_API_QUIC_PREFETCH_H_ diff --git a/chromium/net/quic/platform/api/quic_reference_counted.h b/chromium/net/quic/platform/api/quic_reference_counted.h index 296fe483e1a..16e7936ac1f 100644 --- a/chromium/net/quic/platform/api/quic_reference_counted.h +++ b/chromium/net/quic/platform/api/quic_reference_counted.h @@ -114,8 +114,8 @@ class QuicReferenceCountedPointer { explicit operator bool() const { return static_cast<bool>(impl_); } // Assignment operator on raw pointer. Drops a reference to current pointee, - // if any and replaces it with |p|. This garantee the reference count of *p is - // 1. This should only be used when a new object is created, calling this + // if any, and replaces it with |p|. This guarantees the reference count of *p + // is 1. This should only be used when a new object is created, calling this // on a already existent object is undefined behavior. QuicReferenceCountedPointer<T>& operator=(T* p) { impl_ = p; diff --git a/chromium/net/quic/platform/impl/quic_aligned_impl.h b/chromium/net/quic/platform/impl/quic_aligned_impl.h index 3ca83db3c9b..f38835e4b35 100644 --- a/chromium/net/quic/platform/impl/quic_aligned_impl.h +++ b/chromium/net/quic/platform/impl/quic_aligned_impl.h @@ -17,6 +17,7 @@ // TODO(rtenneti): Change the default 64 alignas value (used the default // value from ABSL_CACHELINE_SIZE). -#define QUIC_CACHELINE_ALIGNED_IMPL ALIGNAS(64) +#define QUIC_CACHELINE_SIZE_IMPL (64) +#define QUIC_CACHELINE_ALIGNED_IMPL ALIGNAS(QUIC_CACHELINE_SIZE) #endif // NET_QUIC_PLATFORM_IMPL_QUIC_ALIGNED_IMPL_H_ diff --git a/chromium/net/quic/platform/impl/quic_arraysize_impl.h b/chromium/net/quic/platform/impl/quic_arraysize_impl.h new file mode 100644 index 00000000000..0dd9cb3de3c --- /dev/null +++ b/chromium/net/quic/platform/impl/quic_arraysize_impl.h @@ -0,0 +1,10 @@ +// Copyright 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 NET_QUIC_PLATFORM_IMPL_QUIC_ARRAYSIZE_IMPL_H_ +#define NET_QUIC_PLATFORM_IMPL_QUIC_ARRAYSIZE_IMPL_H_ + +#define QUIC_ARRAYSIZE_IMPL(array) arraysize(array) + +#endif // NET_QUIC_PLATFORM_IMPL_QUIC_ARRAYSIZE_IMPL_H_ diff --git a/chromium/net/quic/platform/impl/quic_bug_tracker_impl.h b/chromium/net/quic/platform/impl/quic_bug_tracker_impl.h index a0b0efd1acf..d0afd5e4722 100644 --- a/chromium/net/quic/platform/impl/quic_bug_tracker_impl.h +++ b/chromium/net/quic/platform/impl/quic_bug_tracker_impl.h @@ -8,5 +8,7 @@ #define QUIC_BUG_IMPL QUIC_LOG(DFATAL) #define QUIC_BUG_IF_IMPL(condition) QUIC_LOG_IF(DFATAL, condition) +#define QUIC_PEER_BUG_IMPL QUIC_LOG(DFATAL) +#define QUIC_PEER_BUG_IF_IMPL(condition) QUIC_LOG_IF(DFATAL, condition) #endif // NET_QUIC_PLATFORM_IMPL_QUIC_BUG_TRACKER_IMPL_H_ diff --git a/chromium/net/quic/platform/impl/quic_flags_impl.h b/chromium/net/quic/platform/impl/quic_flags_impl.h index 22885431b25..666cea57419 100644 --- a/chromium/net/quic/platform/impl/quic_flags_impl.h +++ b/chromium/net/quic/platform/impl/quic_flags_impl.h @@ -61,5 +61,18 @@ inline void SetQuicFlagImpl(std::string* f, const std::string& v) { *f = v; } +// ------------------------------------------------------------------------ +// // QUIC feature flags implementation. +// // ------------------------------------------------------------------------ +#define RELOADABLE_FLAG(flag) FLAGS_quic_reloadable_flag_##flag +#define RESTART_FLAG(flag) FLAGS_quic_restart_flag_##flag + +#define GetQuicReloadableFlagImpl(flag) GetQuicFlag(RELOADABLE_FLAG(flag)) +#define SetQuicReloadableFlagImpl(flag, value) \ + SetQuicFlag(&RELOADABLE_FLAG(flag), value) +#define GetQuicRestartFlagImpl(flag) GetQuicFlag(RESTART_FLAG(flag)) +#define SetQuicRestartFlagImpl(flag, value) \ + SetQuicFlag(&RESTART_FLAG(flag), value) + } // namespace net #endif // NET_QUIC_PLATFORM_IMPL_QUIC_FLAGS_IMPL_H_ diff --git a/chromium/net/quic/platform/impl/quic_hostname_utils_impl.cc b/chromium/net/quic/platform/impl/quic_hostname_utils_impl.cc index 040a724ce4f..750b3d4674a 100644 --- a/chromium/net/quic/platform/impl/quic_hostname_utils_impl.cc +++ b/chromium/net/quic/platform/impl/quic_hostname_utils_impl.cc @@ -48,17 +48,4 @@ char* QuicHostnameUtilsImpl::NormalizeHostname(char* hostname) { return hostname; } -// static -void QuicHostnameUtilsImpl::StringToQuicServerId(const string& str, - QuicServerId* out) { - GURL url(str); - if (!url.is_valid()) { - *out = QuicServerId(); - return; - } - *out = QuicServerId(HostPortPair::FromURL(url), url.path_piece() == "/private" - ? PRIVACY_MODE_ENABLED - : PRIVACY_MODE_DISABLED); -} - } // namespace net diff --git a/chromium/net/quic/platform/impl/quic_hostname_utils_impl.h b/chromium/net/quic/platform/impl/quic_hostname_utils_impl.h index 57c67473e00..3883a638d2c 100644 --- a/chromium/net/quic/platform/impl/quic_hostname_utils_impl.h +++ b/chromium/net/quic/platform/impl/quic_hostname_utils_impl.h @@ -6,7 +6,6 @@ #define NET_QUIC_PLATFORM_IMPL_QUIC_HOSTNAME_UTILS_IMPL_H_ #include "base/macros.h" -#include "net/quic/core/quic_server_id.h" #include "net/quic/platform/api/quic_export.h" #include "net/quic/platform/api/quic_string_piece.h" @@ -24,10 +23,6 @@ class QUIC_EXPORT_PRIVATE QuicHostnameUtilsImpl { // WARNING: mutates |hostname| in place and returns |hostname|. static char* NormalizeHostname(char* hostname); - // Creates a QuicServerId from a string formatted in same manner as - // QuicServerId::ToString(). - static void StringToQuicServerId(const std::string& str, QuicServerId* out); - private: DISALLOW_COPY_AND_ASSIGN(QuicHostnameUtilsImpl); }; diff --git a/chromium/net/quic/platform/impl/quic_prefetch_impl.h b/chromium/net/quic/platform/impl/quic_prefetch_impl.h new file mode 100644 index 00000000000..2f5d1eb943b --- /dev/null +++ b/chromium/net/quic/platform/impl/quic_prefetch_impl.h @@ -0,0 +1,24 @@ +// Copyright 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 NET_QUIC_PLATFORM_IMPL_QUIC_PREFETCH_IMPL_H_ +#define NET_QUIC_PLATFORM_IMPL_QUIC_PREFETCH_IMPL_H_ + +#if defined(_MSC_VER) +#include <intrin.h> +#endif + +namespace net { + +inline void QuicPrefetchT0Impl(const void* addr) { +#if defined(__GNUC__) + __builtin_prefetch(addr, 0, 3); +#elif defined(_MSC_VER) + _mm_prefetch(reinterpret_cast<const char*>(addr), _MM_HINT_T0); +#endif +} + +} // namespace net + +#endif // NET_QUIC_PLATFORM_IMPL_QUIC_PREFETCH_IMPL_H_ diff --git a/chromium/net/quic/platform/impl/quic_text_utils_impl.h b/chromium/net/quic/platform/impl/quic_text_utils_impl.h index 40871774d28..05fa6122474 100644 --- a/chromium/net/quic/platform/impl/quic_text_utils_impl.h +++ b/chromium/net/quic/platform/impl/quic_text_utils_impl.h @@ -70,7 +70,7 @@ class QuicTextUtilsImpl { // Returns a new std::string representing |in|. static std::string Uint64ToString(uint64_t in) { - return base::Uint64ToString(in); + return base::NumberToString(in); } // This converts |length| bytes of binary to a 2*|length|-character diff --git a/chromium/net/quic/quartc/quartc_factory.cc b/chromium/net/quic/quartc/quartc_factory.cc index b45011d6d9e..3e182fa99e1 100644 --- a/chromium/net/quic/quartc/quartc_factory.cc +++ b/chromium/net/quic/quartc/quartc_factory.cc @@ -113,13 +113,14 @@ std::unique_ptr<QuartcSessionInterface> QuartcFactory::CreateQuartcSession( std::unique_ptr<QuicConnection> quic_connection = CreateQuicConnection(quartc_session_config, perspective); QuicTagVector copt; + copt.push_back(kNSTP); if (quartc_session_config.congestion_control == QuartcCongestionControl::kBBR) { copt.push_back(kTBBR); - FLAGS_quic_reloadable_flag_quic_bbr_slower_startup = true; - FLAGS_quic_reloadable_flag_quic_bbr_fully_drain_queue = true; - FLAGS_quic_reloadable_flag_quic_bbr_less_probe_rtt = true; + // Note: These settings have no effect for Exoblaze builds since + // SetQuicReloadableFlag() gets stubbed out. + SetQuicReloadableFlag(quic_bbr_less_probe_rtt, true); for (const auto option : quartc_session_config.bbr_options) { switch (option) { case (QuartcBbrOptions::kSlowerStartup): @@ -176,7 +177,7 @@ std::unique_ptr<QuicConnection> QuartcFactory::CreateQuicConnection( return std::unique_ptr<QuicConnection>(new QuicConnection( dummy_id, dummy_address, this, /*QuicConnectionHelperInterface*/ this /*QuicAlarmFactory*/, writer.release(), true /*own the writer*/, - perspective, AllSupportedTransportVersions())); + perspective, AllSupportedVersions())); } QuicAlarm* QuartcFactory::CreateAlarm(QuicAlarm::Delegate* delegate) { diff --git a/chromium/net/quic/quartc/quartc_packet_writer.cc b/chromium/net/quic/quartc/quartc_packet_writer.cc index 73ddbe8439f..70ff00a48c5 100644 --- a/chromium/net/quic/quartc/quartc_packet_writer.cc +++ b/chromium/net/quic/quartc/quartc_packet_writer.cc @@ -20,6 +20,7 @@ WriteResult QuartcPacketWriter::WritePacket( DCHECK(packet_transport_); int bytes_written = packet_transport_->Write(buffer, buf_len); if (bytes_written <= 0) { + writable_ = false; return WriteResult(WRITE_STATUS_BLOCKED, EWOULDBLOCK); } return WriteResult(WRITE_STATUS_OK, bytes_written); @@ -30,8 +31,7 @@ bool QuartcPacketWriter::IsWriteBlockedDataBuffered() const { } bool QuartcPacketWriter::IsWriteBlocked() const { - DCHECK(packet_transport_); - return !packet_transport_->CanWrite(); + return !writable_; } QuicByteCount QuartcPacketWriter::GetMaxPacketSize( @@ -39,6 +39,8 @@ QuicByteCount QuartcPacketWriter::GetMaxPacketSize( return max_packet_size_; } -void QuartcPacketWriter::SetWritable() {} +void QuartcPacketWriter::SetWritable() { + writable_ = true; +} } // namespace net diff --git a/chromium/net/quic/quartc/quartc_packet_writer.h b/chromium/net/quic/quartc/quartc_packet_writer.h index ab855eb13cf..d50626c6868 100644 --- a/chromium/net/quic/quartc/quartc_packet_writer.h +++ b/chromium/net/quic/quartc/quartc_packet_writer.h @@ -32,8 +32,8 @@ class QUIC_EXPORT_PRIVATE QuartcPacketWriter : public QuicPacketWriter { bool IsWriteBlockedDataBuffered() const override; // Whether the underneath |transport_| is blocked. If this returns true, - // outgoing QUIC packets are queued by QuicConnection until - // Transport::Observer::OnCanWrite() is called. + // 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 @@ -42,8 +42,7 @@ class QUIC_EXPORT_PRIVATE QuartcPacketWriter : public QuicPacketWriter { QuicByteCount GetMaxPacketSize( const QuicSocketAddress& peer_address) const override; - // This method is not used because the network layer in WebRTC will determine - // the writing states. + // Sets the packet writer to a writable (non-blocked) state. void SetWritable() override; private: @@ -51,6 +50,9 @@ class QUIC_EXPORT_PRIVATE QuartcPacketWriter : public QuicPacketWriter { QuartcSessionInterface::PacketTransport* 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 net diff --git a/chromium/net/quic/quartc/quartc_session.cc b/chromium/net/quic/quartc/quartc_session.cc index a4c74d20ff0..68b0e0a301b 100644 --- a/chromium/net/quic/quartc/quartc_session.cc +++ b/chromium/net/quic/quartc/quartc_session.cc @@ -4,6 +4,8 @@ #include "net/quic/quartc/quartc_session.h" +#include "net/quic/core/tls_client_handshaker.h" +#include "net/quic/core/tls_server_handshaker.h" #include "net/quic/platform/api/quic_ptr_util.h" using std::string; @@ -128,8 +130,8 @@ QuartcSession::QuartcSession(std::unique_ptr<QuicConnection> connection, // Initialization with default crypto configuration. if (perspective_ == Perspective::IS_CLIENT) { std::unique_ptr<ProofVerifier> proof_verifier(new InsecureProofVerifier); - quic_crypto_client_config_.reset( - new QuicCryptoClientConfig(std::move(proof_verifier))); + quic_crypto_client_config_.reset(new QuicCryptoClientConfig( + std::move(proof_verifier), TlsClientHandshaker::CreateSslCtx())); } else { std::unique_ptr<ProofSource> proof_source(new DummyProofSource); // Generate a random source address token secret. For long-running servers @@ -140,7 +142,8 @@ QuartcSession::QuartcSession(std::unique_ptr<QuicConnection> connection, kInputKeyingMaterialLength); quic_crypto_server_config_.reset(new QuicCryptoServerConfig( string(source_address_token_secret, kInputKeyingMaterialLength), - helper_->GetRandomGenerator(), std::move(proof_source))); + helper_->GetRandomGenerator(), std::move(proof_source), + TlsServerHandshaker::CreateSslCtx())); // Provide server with serialized config string to prove ownership. QuicCryptoServerConfig::ConfigOptions options; // The |message| is used to handle the return value of AddDefaultConfig @@ -282,6 +285,7 @@ void QuartcSession::SetDelegate( } void QuartcSession::OnTransportCanWrite() { + connection()->writer()->SetWritable(); if (HasDataToWrite()) { connection()->OnCanWrite(); } diff --git a/chromium/net/quic/quartc/quartc_session_interface.h b/chromium/net/quic/quartc/quartc_session_interface.h index 536079a88c1..59233839d52 100644 --- a/chromium/net/quic/quartc/quartc_session_interface.h +++ b/chromium/net/quic/quartc/quartc_session_interface.h @@ -95,11 +95,6 @@ class QUIC_EXPORT_PRIVATE QuartcSessionInterface { public: virtual ~PacketTransport() {} - // Called by the QuartcPacketWriter to check if the underneath transport is - // writable. True if packets written are expected to be sent. False if - // packets will be dropped. - virtual bool CanWrite() = 0; - // 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) = 0; diff --git a/chromium/net/quic/quartc/quartc_session_test.cc b/chromium/net/quic/quartc/quartc_session_test.cc index 9e82001309c..549c8ec110b 100644 --- a/chromium/net/quic/quartc/quartc_session_test.cc +++ b/chromium/net/quic/quartc/quartc_session_test.cc @@ -7,6 +7,8 @@ #include "net/quic/core/crypto/crypto_server_config_protobuf.h" #include "net/quic/core/quic_simple_buffer_allocator.h" #include "net/quic/core/quic_types.h" +#include "net/quic/core/tls_client_handshaker.h" +#include "net/quic/core/tls_server_handshaker.h" #include "net/quic/quartc/quartc_factory.h" #include "net/quic/quartc/quartc_factory_interface.h" #include "net/quic/quartc/quartc_packet_writer.h" @@ -300,8 +302,6 @@ class FakeTransport : public QuartcSessionInterface::PacketTransport { public: explicit FakeTransport(FakeTransportChannel* channel) : channel_(channel) {} - bool CanWrite() override { return true; } - int Write(const char* buffer, size_t buf_len) override { DCHECK(channel_); return channel_->SendPacket(buffer, buf_len); @@ -422,6 +422,9 @@ class QuartcSessionTest : public ::testing::Test, new QuartcPacketWriter(client_transport_.get(), kDefaultMaxPacketSize)); server_writer_.reset( new QuartcPacketWriter(server_transport_.get(), kDefaultMaxPacketSize)); + + client_writer_->SetWritable(); + server_writer_->SetWritable(); } // The parameters are used to control whether the handshake will success or @@ -435,14 +438,16 @@ class QuartcSessionTest : public ::testing::Test, client_channel_->SetObserver(client_peer_.get()); server_channel_->SetObserver(server_peer_.get()); - client_peer_->SetClientCryptoConfig( - new QuicCryptoClientConfig(std::unique_ptr<ProofVerifier>( - new FakeProofVerifier(client_handshake_success)))); + client_peer_->SetClientCryptoConfig(new QuicCryptoClientConfig( + std::unique_ptr<ProofVerifier>( + new FakeProofVerifier(client_handshake_success)), + TlsClientHandshaker::CreateSslCtx())); QuicCryptoServerConfig* server_config = new QuicCryptoServerConfig( "TESTING", QuicRandom::GetInstance(), std::unique_ptr<FakeProofSource>( - new FakeProofSource(server_handshake_success))); + new FakeProofSource(server_handshake_success)), + TlsServerHandshaker::CreateSslCtx()); // Provide server with serialized config string to prove ownership. QuicCryptoServerConfig::ConfigOptions options; std::unique_ptr<QuicServerConfigProtobuf> primary_config( @@ -481,7 +486,7 @@ class QuartcSessionTest : public ::testing::Test, return std::unique_ptr<QuicConnection>(new QuicConnection( 0, QuicSocketAddress(ip, 0), this /*QuicConnectionHelperInterface*/, alarm_factory_.get(), writer, owns_writer, perspective, - AllSupportedTransportVersions())); + AllSupportedVersions())); } // Runs all tasks scheduled in the next 200 ms. diff --git a/chromium/net/quic/quartc/quartc_stream_test.cc b/chromium/net/quic/quartc/quartc_stream_test.cc index b065f9a1cc7..408f18d6eb6 100644 --- a/chromium/net/quic/quartc/quartc_stream_test.cc +++ b/chromium/net/quic/quartc/quartc_stream_test.cc @@ -168,7 +168,7 @@ class QuartcStreamTest : public ::testing::Test, connection_.reset(new QuicConnection( 0, QuicSocketAddress(ip, 0), this /*QuicConnectionHelperInterface*/, alarm_factory_.get(), new DummyPacketWriter(), owns_writer, perspective, - AllSupportedTransportVersions())); + AllSupportedVersions())); session_.reset( new MockQuicSession(connection_.get(), QuicConfig(), &write_buffer_)); diff --git a/chromium/net/quic/test_tools/crypto_test_utils.cc b/chromium/net/quic/test_tools/crypto_test_utils.cc index 2115559a7bd..7f43881ccee 100644 --- a/chromium/net/quic/test_tools/crypto_test_utils.cc +++ b/chromium/net/quic/test_tools/crypto_test_utils.cc @@ -20,6 +20,8 @@ #include "net/quic/core/quic_crypto_stream.h" #include "net/quic/core/quic_server_id.h" #include "net/quic/core/quic_utils.h" +#include "net/quic/core/tls_client_handshaker.h" +#include "net/quic/core/tls_server_handshaker.h" #include "net/quic/platform/api/quic_bug_tracker.h" #include "net/quic/platform/api/quic_clock.h" #include "net/quic/platform/api/quic_logging.h" @@ -390,9 +392,9 @@ int HandshakeWithFakeServer(QuicConfig* server_quic_config, new PacketSavingConnection(helper, alarm_factory, Perspective::IS_SERVER, client_conn->supported_versions()); - QuicCryptoServerConfig crypto_config(QuicCryptoServerConfig::TESTING, - QuicRandom::GetInstance(), - ProofSourceForTesting()); + QuicCryptoServerConfig crypto_config( + QuicCryptoServerConfig::TESTING, QuicRandom::GetInstance(), + ProofSourceForTesting(), TlsServerHandshaker::CreateSslCtx()); QuicCompressedCertsCache compressed_certs_cache( QuicCompressedCertsCache::kQuicCompressedCertsCacheSize); SetupCryptoServerConfigForTest(server_conn->clock(), @@ -427,12 +429,22 @@ int HandshakeWithFakeClient(MockQuicConnectionHelper* helper, QuicCryptoServerStream* server, const QuicServerId& server_id, const FakeClientOptions& options) { - PacketSavingConnection* client_conn = - new PacketSavingConnection(helper, alarm_factory, Perspective::IS_CLIENT); + ParsedQuicVersionVector supported_versions = AllSupportedVersions(); + if (options.only_tls_versions) { + supported_versions.clear(); + for (QuicTransportVersion transport_version : + AllSupportedTransportVersions()) { + supported_versions.push_back( + ParsedQuicVersion(PROTOCOL_TLS1_3, transport_version)); + } + } + PacketSavingConnection* client_conn = new PacketSavingConnection( + helper, alarm_factory, Perspective::IS_CLIENT, supported_versions); // Advance the time, because timers do not like uninitialized times. client_conn->AdvanceTime(QuicTime::Delta::FromSeconds(1)); - QuicCryptoClientConfig crypto_config(ProofVerifierForTesting()); + QuicCryptoClientConfig crypto_config(ProofVerifierForTesting(), + TlsClientHandshaker::CreateSslCtx()); AsyncTestChannelIDSource* async_channel_id_source = nullptr; if (options.channel_id_enabled) { ChannelIDSource* source = ChannelIDSourceForTesting(); @@ -515,7 +527,7 @@ void CommunicateHandshakeMessagesAndRunCallbacks( QuicCryptoStream* server, CallbackSource* callback_source) { size_t client_i = 0, server_i = 0; - while (!client->handshake_confirmed()) { + while (!client->handshake_confirmed() || !server->handshake_confirmed()) { ASSERT_GT(client_conn->encrypted_packets_.size(), client_i); QUIC_LOG(INFO) << "Processing " << client_conn->encrypted_packets_.size() - client_i @@ -897,11 +909,37 @@ ChannelIDSource* ChannelIDSourceForTesting() { return new TestChannelIDSource(); } +void MovePacketsForTlsHandshake(PacketSavingConnection* source_conn, + size_t* inout_packet_index, + QuicCryptoStream* dest_stream, + PacketSavingConnection* dest_conn, + Perspective dest_perspective) { + SimpleQuicFramer framer(source_conn->supported_versions(), dest_perspective); + size_t index = *inout_packet_index; + for (; index < source_conn->encrypted_packets_.size(); index++) { + 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. + break; + } + + for (const auto& stream_frame : framer.stream_frames()) { + dest_conn->OnStreamFrame(*stream_frame); + } + } + *inout_packet_index = index; +} + void MovePackets(PacketSavingConnection* source_conn, size_t* inout_packet_index, QuicCryptoStream* dest_stream, PacketSavingConnection* dest_conn, Perspective dest_perspective) { + if (dest_stream->handshake_protocol() == PROTOCOL_TLS1_3) { + MovePacketsForTlsHandshake(source_conn, inout_packet_index, dest_stream, + dest_conn, dest_perspective); + return; + } SimpleQuicFramer framer(source_conn->supported_versions(), dest_perspective); CryptoFramer crypto_framer; CryptoFramerVisitor crypto_visitor; diff --git a/chromium/net/quic/test_tools/crypto_test_utils.h b/chromium/net/quic/test_tools/crypto_test_utils.h index 38dc33e7a58..b3baa5c5659 100644 --- a/chromium/net/quic/test_tools/crypto_test_utils.h +++ b/chromium/net/quic/test_tools/crypto_test_utils.h @@ -112,6 +112,10 @@ struct FakeClientOptions { // The Token Binding params that the client supports and will negotiate. QuicTagVector token_binding_params; + + // If only_tls_versions is set, then the client will only use TLS for the + // crypto handshake. + bool only_tls_versions = false; }; // returns: the number of client hellos that the client sent. diff --git a/chromium/net/quic/test_tools/crypto_test_utils_test.cc b/chromium/net/quic/test_tools/crypto_test_utils_test.cc index b3fcf55ab2c..053c468200e 100644 --- a/chromium/net/quic/test_tools/crypto_test_utils_test.cc +++ b/chromium/net/quic/test_tools/crypto_test_utils_test.cc @@ -6,6 +6,7 @@ #include "net/quic/core/crypto/crypto_server_config_protobuf.h" #include "net/quic/core/quic_utils.h" +#include "net/quic/core/tls_server_handshaker.h" #include "net/quic/platform/api/quic_test.h" #include "net/quic/platform/api/quic_text_utils.h" #include "net/quic/test_tools/mock_clock.h" @@ -115,7 +116,8 @@ TEST(CryptoTestUtilsTest, TestGenerateFullCHLO) { MockClock clock; QuicCryptoServerConfig crypto_config( QuicCryptoServerConfig::TESTING, QuicRandom::GetInstance(), - crypto_test_utils::ProofSourceForTesting()); + crypto_test_utils::ProofSourceForTesting(), + TlsServerHandshaker::CreateSslCtx()); QuicSocketAddress server_addr; QuicSocketAddress client_addr(QuicIpAddress::Loopback4(), 1); QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config( diff --git a/chromium/net/quic/test_tools/mock_decrypter.cc b/chromium/net/quic/test_tools/mock_decrypter.cc index f33eec96d2d..f48ff7b1f68 100644 --- a/chromium/net/quic/test_tools/mock_decrypter.cc +++ b/chromium/net/quic/test_tools/mock_decrypter.cc @@ -49,6 +49,14 @@ bool MockDecrypter::DecryptPacket(QuicTransportVersion version, return true; } +size_t MockDecrypter::GetKeySize() const { + return 0; +} + +size_t MockDecrypter::GetIVSize() const { + return 0; +} + QuicStringPiece MockDecrypter::GetKey() const { return QuicStringPiece(); } diff --git a/chromium/net/quic/test_tools/mock_decrypter.h b/chromium/net/quic/test_tools/mock_decrypter.h index 67449a4b472..6f4a43c79f7 100644 --- a/chromium/net/quic/test_tools/mock_decrypter.h +++ b/chromium/net/quic/test_tools/mock_decrypter.h @@ -39,6 +39,8 @@ class MockDecrypter : public QuicDecrypter { char* output, size_t* output_length, size_t max_output_length) override; + size_t GetKeySize() const override; + size_t GetIVSize() const override; QuicStringPiece GetKey() const override; QuicStringPiece GetNoncePrefix() const override; diff --git a/chromium/net/quic/test_tools/mock_encrypter.cc b/chromium/net/quic/test_tools/mock_encrypter.cc index 7ebcea38d1d..1d2fe633548 100644 --- a/chromium/net/quic/test_tools/mock_encrypter.cc +++ b/chromium/net/quic/test_tools/mock_encrypter.cc @@ -46,6 +46,10 @@ size_t MockEncrypter::GetNoncePrefixSize() const { return 0; } +size_t MockEncrypter::GetIVSize() const { + return 0; +} + size_t MockEncrypter::GetMaxPlaintextSize(size_t ciphertext_size) const { return ciphertext_size; } diff --git a/chromium/net/quic/test_tools/mock_encrypter.h b/chromium/net/quic/test_tools/mock_encrypter.h index 59b8097e1ce..0432ea9a2ee 100644 --- a/chromium/net/quic/test_tools/mock_encrypter.h +++ b/chromium/net/quic/test_tools/mock_encrypter.h @@ -37,6 +37,7 @@ class MockEncrypter : public QuicEncrypter { size_t max_output_length) override; size_t GetKeySize() const override; size_t GetNoncePrefixSize() const override; + size_t GetIVSize() const override; size_t GetMaxPlaintextSize(size_t ciphertext_size) const override; size_t GetCiphertextSize(size_t plaintext_size) const override; QuicStringPiece GetKey() const override; diff --git a/chromium/net/quic/test_tools/quic_spdy_session_peer.cc b/chromium/net/quic/test_tools/quic_spdy_session_peer.cc index 06350f8c3ff..acd51f2b72e 100644 --- a/chromium/net/quic/test_tools/quic_spdy_session_peer.cc +++ b/chromium/net/quic/test_tools/quic_spdy_session_peer.cc @@ -55,8 +55,11 @@ size_t QuicSpdySessionPeer::WriteHeadersImpl( SpdyHeaderBlock headers, bool fin, SpdyPriority priority, + QuicStreamId parent_stream_id, + bool exclusive, QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) { return session->WriteHeadersImpl(id, std::move(headers), fin, priority, + parent_stream_id, exclusive, std::move(ack_listener)); } diff --git a/chromium/net/quic/test_tools/quic_spdy_session_peer.h b/chromium/net/quic/test_tools/quic_spdy_session_peer.h index ea844e6e30d..fa1faffea8a 100644 --- a/chromium/net/quic/test_tools/quic_spdy_session_peer.h +++ b/chromium/net/quic/test_tools/quic_spdy_session_peer.h @@ -39,6 +39,8 @@ class QuicSpdySessionPeer { SpdyHeaderBlock headers, bool fin, SpdyPriority priority, + QuicStreamId parent_stream_id, + bool exclusive, QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener); // Helper functions for stream ids, to allow test logic to abstract // over the HTTP stream numbering scheme (i.e. whether one or diff --git a/chromium/net/quic/test_tools/quic_stream_send_buffer_peer.cc b/chromium/net/quic/test_tools/quic_stream_send_buffer_peer.cc index 7e6dbc43aa5..5ca41adbfd2 100644 --- a/chromium/net/quic/test_tools/quic_stream_send_buffer_peer.cc +++ b/chromium/net/quic/test_tools/quic_stream_send_buffer_peer.cc @@ -15,6 +15,14 @@ void QuicStreamSendBufferPeer::SetStreamOffset( send_buffer->stream_offset_ = stream_offset; } +// static +const BufferedSlice* QuicStreamSendBufferPeer::CurrentWriteSlice( + QuicStreamSendBuffer* send_buffer) { + if (send_buffer->write_index_ == -1) { + return nullptr; + } + return &send_buffer->buffered_slices_[send_buffer->write_index_]; +} } // namespace test } // namespace net diff --git a/chromium/net/quic/test_tools/quic_stream_send_buffer_peer.h b/chromium/net/quic/test_tools/quic_stream_send_buffer_peer.h index 2b1ec7720b9..6b8b115e718 100644 --- a/chromium/net/quic/test_tools/quic_stream_send_buffer_peer.h +++ b/chromium/net/quic/test_tools/quic_stream_send_buffer_peer.h @@ -15,6 +15,9 @@ class QuicStreamSendBufferPeer { public: static void SetStreamOffset(QuicStreamSendBuffer* send_buffer, QuicStreamOffset stream_offset); + + static const BufferedSlice* CurrentWriteSlice( + QuicStreamSendBuffer* send_buffer); }; } // namespace test diff --git a/chromium/net/quic/test_tools/quic_stream_sequencer_buffer_peer.cc b/chromium/net/quic/test_tools/quic_stream_sequencer_buffer_peer.cc index da5754a68f2..c7aa8e969f4 100644 --- a/chromium/net/quic/test_tools/quic_stream_sequencer_buffer_peer.cc +++ b/chromium/net/quic/test_tools/quic_stream_sequencer_buffer_peer.cc @@ -64,16 +64,16 @@ bool QuicStreamSequencerBufferPeer::CheckInitialState() { bool QuicStreamSequencerBufferPeer::CheckBufferInvariants() { QuicStreamOffset data_span = - buffer_->gaps_.back().begin_offset - buffer_->total_bytes_read_; + buffer_->NextExpectedByte() - buffer_->total_bytes_read_; bool capacity_sane = data_span <= buffer_->max_buffer_capacity_bytes_ && data_span >= buffer_->num_bytes_buffered_; if (!capacity_sane) { QUIC_LOG(ERROR) << "data span is larger than capacity."; QUIC_LOG(ERROR) << "total read: " << buffer_->total_bytes_read_ - << " last byte: " << buffer_->gaps_.back().begin_offset; + << " last byte: " << buffer_->NextExpectedByte(); } bool total_read_sane = - buffer_->gaps_.front().begin_offset >= buffer_->total_bytes_read_; + buffer_->FirstMissingByte() >= buffer_->total_bytes_read_; if (!total_read_sane) { QUIC_LOG(ERROR) << "read across 1st gap."; } @@ -106,7 +106,24 @@ BufferBlock* QuicStreamSequencerBufferPeer::GetBlock(size_t index) { } int QuicStreamSequencerBufferPeer::GapSize() { - return buffer_->gaps_.size(); + if (!buffer_->allow_overlapping_data_) { + return buffer_->gaps_.size(); + } + if (buffer_->bytes_received_.Empty()) { + return 1; + } + int gap_size = buffer_->bytes_received_.Size() + 1; + if (buffer_->bytes_received_.Empty()) { + return gap_size; + } + if (buffer_->bytes_received_.begin()->min() == 0) { + --gap_size; + } + if (buffer_->bytes_received_.rbegin()->max() == + std::numeric_limits<uint64_t>::max()) { + --gap_size; + } + return gap_size; } std::list<Gap> QuicStreamSequencerBufferPeer::GetGaps() { @@ -135,6 +152,11 @@ void QuicStreamSequencerBufferPeer::set_gaps(const std::list<Gap>& gaps) { buffer_->gaps_ = gaps; } +void QuicStreamSequencerBufferPeer::AddBytesReceived(QuicStreamOffset offset, + QuicByteCount length) { + buffer_->bytes_received_.Add(offset, offset + length); +} + bool QuicStreamSequencerBufferPeer::IsBufferAllocated() { return buffer_->blocks_ != nullptr; } @@ -142,5 +164,15 @@ bool QuicStreamSequencerBufferPeer::IsBufferAllocated() { size_t QuicStreamSequencerBufferPeer::block_count() { return buffer_->blocks_count_; } + +const QuicIntervalSet<QuicStreamOffset>& +QuicStreamSequencerBufferPeer::bytes_received() { + return buffer_->bytes_received_; +} + +bool QuicStreamSequencerBufferPeer::allow_overlapping_data() { + return buffer_->allow_overlapping_data_; +} + } // namespace test } // namespace net diff --git a/chromium/net/quic/test_tools/quic_stream_sequencer_buffer_peer.h b/chromium/net/quic/test_tools/quic_stream_sequencer_buffer_peer.h index 1255d3a723b..655e78b8cda 100644 --- a/chromium/net/quic/test_tools/quic_stream_sequencer_buffer_peer.h +++ b/chromium/net/quic/test_tools/quic_stream_sequencer_buffer_peer.h @@ -34,6 +34,8 @@ class QuicStreamSequencerBufferPeer { QuicStreamSequencerBuffer::BufferBlock* GetBlock(size_t index); + // TODO(fayang): Rename this to IntervalSize when deprecating + // quic_reloadable_flag_quic_allow_receiving_overlapping_data. int GapSize(); std::list<QuicStreamSequencerBuffer::Gap> GetGaps(); @@ -49,10 +51,16 @@ class QuicStreamSequencerBufferPeer { void set_gaps(const std::list<QuicStreamSequencerBuffer::Gap>& gaps); + void AddBytesReceived(QuicStreamOffset offset, QuicByteCount length); + bool IsBufferAllocated(); size_t block_count(); + const QuicIntervalSet<QuicStreamOffset>& bytes_received(); + + bool allow_overlapping_data(); + private: QuicStreamSequencerBuffer* buffer_; DISALLOW_COPY_AND_ASSIGN(QuicStreamSequencerBufferPeer); diff --git a/chromium/net/quic/test_tools/quic_stream_sequencer_peer.cc b/chromium/net/quic/test_tools/quic_stream_sequencer_peer.cc index 29c8741afa3..beb24e84da8 100644 --- a/chromium/net/quic/test_tools/quic_stream_sequencer_peer.cc +++ b/chromium/net/quic/test_tools/quic_stream_sequencer_peer.cc @@ -31,5 +31,12 @@ bool QuicStreamSequencerPeer::IsUnderlyingBufferAllocated( return buffer_peer.IsBufferAllocated(); } +// static +void QuicStreamSequencerPeer::SetFrameBufferTotalBytesRead( + QuicStreamSequencer* sequencer, + QuicStreamOffset total_bytes_read) { + QuicStreamSequencerBufferPeer buffer_peer(&(sequencer->buffered_frames_)); + buffer_peer.set_total_bytes_read(total_bytes_read); +} } // namespace test } // namespace net diff --git a/chromium/net/quic/test_tools/quic_stream_sequencer_peer.h b/chromium/net/quic/test_tools/quic_stream_sequencer_peer.h index 9982e738977..538e903aa96 100644 --- a/chromium/net/quic/test_tools/quic_stream_sequencer_peer.h +++ b/chromium/net/quic/test_tools/quic_stream_sequencer_peer.h @@ -22,6 +22,9 @@ class QuicStreamSequencerPeer { static bool IsUnderlyingBufferAllocated(QuicStreamSequencer* sequencer); + static void SetFrameBufferTotalBytesRead(QuicStreamSequencer* sequencer, + QuicStreamOffset total_bytes_read); + private: DISALLOW_COPY_AND_ASSIGN(QuicStreamSequencerPeer); }; diff --git a/chromium/net/quic/test_tools/quic_test_utils.cc b/chromium/net/quic/test_tools/quic_test_utils.cc index 5d1b1dc029d..3725ca92234 100644 --- a/chromium/net/quic/test_tools/quic_test_utils.cc +++ b/chromium/net/quic/test_tools/quic_test_utils.cc @@ -17,6 +17,7 @@ #include "net/quic/core/quic_framer.h" #include "net/quic/core/quic_packet_creator.h" #include "net/quic/core/quic_utils.h" +#include "net/quic/platform/api/quic_arraysize.h" #include "net/quic/platform/api/quic_endian.h" #include "net/quic/platform/api/quic_flags.h" #include "net/quic/platform/api/quic_logging.h" @@ -45,7 +46,7 @@ QuicAckFrame InitAckFrame(const std::vector<QuicAckBlock>& ack_blocks) { end_of_previous_block = block.limit; } - ack.deprecated_largest_observed = ack.packets.Max(); + ack.largest_acked = ack.packets.Max(); return ack; } @@ -57,7 +58,7 @@ QuicAckFrame InitAckFrame(QuicPacketNumber largest_acked) { QuicAckFrame MakeAckFrameWithAckBlocks(size_t num_ack_blocks, QuicPacketNumber least_unacked) { QuicAckFrame ack; - ack.deprecated_largest_observed = 2 * num_ack_blocks + least_unacked; + ack.largest_acked = 2 * num_ack_blocks + least_unacked; // Add enough received packets to get num_ack_blocks ack blocks. for (QuicPacketNumber i = 2; i < 2 * num_ack_blocks + 1; i += 2) { ack.packets.Add(least_unacked + i); @@ -100,7 +101,7 @@ string Sha1Hash(QuicStringPiece data) { char buffer[SHA_DIGEST_LENGTH]; SHA1(reinterpret_cast<const uint8_t*>(data.data()), data.size(), reinterpret_cast<uint8_t*>(buffer)); - return string(buffer, arraysize(buffer)); + return string(buffer, QUIC_ARRAYSIZE(buffer)); } uint64_t SimpleRandom::RandUint64() { @@ -161,8 +162,7 @@ MockFramerVisitor::MockFramerVisitor() { MockFramerVisitor::~MockFramerVisitor() {} -bool NoOpFramerVisitor::OnProtocolVersionMismatch( - QuicTransportVersion version) { +bool NoOpFramerVisitor::OnProtocolVersionMismatch(ParsedQuicVersion version) { return false; } @@ -269,7 +269,7 @@ MockQuicConnection::MockQuicConnection(MockQuicConnectionHelper* helper, helper, alarm_factory, perspective, - AllSupportedTransportVersions()) {} + AllSupportedVersions()) {} MockQuicConnection::MockQuicConnection(QuicSocketAddress address, MockQuicConnectionHelper* helper, @@ -280,7 +280,7 @@ MockQuicConnection::MockQuicConnection(QuicSocketAddress address, helper, alarm_factory, perspective, - AllSupportedTransportVersions()) {} + AllSupportedVersions()) {} MockQuicConnection::MockQuicConnection(QuicConnectionId connection_id, MockQuicConnectionHelper* helper, @@ -291,13 +291,13 @@ MockQuicConnection::MockQuicConnection(QuicConnectionId connection_id, helper, alarm_factory, perspective, - CurrentSupportedTransportVersions()) {} + CurrentSupportedVersions()) {} MockQuicConnection::MockQuicConnection( MockQuicConnectionHelper* helper, MockAlarmFactory* alarm_factory, Perspective perspective, - const QuicTransportVersionVector& supported_versions) + const ParsedQuicVersionVector& supported_versions) : MockQuicConnection(QuicEndian::NetToHost64(kTestConnectionId), QuicSocketAddress(TestPeerIPAddress(), kTestPort), helper, @@ -311,7 +311,7 @@ MockQuicConnection::MockQuicConnection( MockQuicConnectionHelper* helper, MockAlarmFactory* alarm_factory, Perspective perspective, - const QuicTransportVersionVector& supported_versions) + const ParsedQuicVersionVector& supported_versions) : QuicConnection(connection_id, address, helper, @@ -331,8 +331,7 @@ void MockQuicConnection::AdvanceTime(QuicTime::Delta delta) { static_cast<MockQuicConnectionHelper*>(helper())->AdvanceTime(delta); } -bool MockQuicConnection::OnProtocolVersionMismatch( - QuicTransportVersion version) { +bool MockQuicConnection::OnProtocolVersionMismatch(ParsedQuicVersion version) { return false; } @@ -345,7 +344,7 @@ PacketSavingConnection::PacketSavingConnection( MockQuicConnectionHelper* helper, MockAlarmFactory* alarm_factory, Perspective perspective, - const QuicTransportVersionVector& supported_versions) + const ParsedQuicVersionVector& supported_versions) : MockQuicConnection(helper, alarm_factory, perspective, @@ -358,9 +357,9 @@ void PacketSavingConnection::SendOrQueuePacket(SerializedPacket* packet) { CopyBuffer(*packet), packet->encrypted_length, true)); // Transfer ownership of the packet to the SentPacketManager and the // ack notifier to the AckNotifierManager. - sent_packet_manager_.OnPacketSent(packet, 0, QuicTime::Zero(), - NOT_RETRANSMISSION, - HAS_RETRANSMITTABLE_DATA); + QuicConnectionPeer::GetSentPacketManager(this)->OnPacketSent( + packet, 0, QuicTime::Zero(), NOT_RETRANSMISSION, + HAS_RETRANSMITTABLE_DATA); } MockQuicSession::MockQuicSession(QuicConnection* connection) @@ -384,11 +383,18 @@ const QuicCryptoStream* MockQuicSession::GetCryptoStream() const { } // static -QuicConsumedData MockQuicSession::ConsumeAllData(QuicStream* /*stream*/, - QuicStreamId /*id*/, - size_t write_length, - QuicStreamOffset /*offset*/, - StreamSendingState state) { +QuicConsumedData MockQuicSession::ConsumeData(QuicStream* stream, + QuicStreamId /*id*/, + size_t write_length, + QuicStreamOffset offset, + StreamSendingState state) { + if (write_length > 0) { + auto buf = QuicMakeUnique<char[]>(write_length); + QuicDataWriter writer(write_length, buf.get(), HOST_BYTE_ORDER); + stream->WriteStreamData(offset, write_length, &writer); + } else { + DCHECK(state != NO_FIN); + } return QuicConsumedData(write_length, state != NO_FIN); } @@ -473,7 +479,7 @@ TestQuicSpdyServerSession::CreateQuicCryptoServerStream( QuicCompressedCertsCache* compressed_certs_cache) { return new QuicCryptoServerStream( crypto_config, compressed_certs_cache, - FLAGS_quic_reloadable_flag_enable_quic_stateless_reject_support, this, + GetQuicReloadableFlag(enable_quic_stateless_reject_support), this, &helper_); } @@ -602,11 +608,19 @@ QuicIpAddress TestPeerIPAddress() { return QuicIpAddress::Loopback4(); } -QuicTransportVersion QuicVersionMax() { +ParsedQuicVersion QuicVersionMax() { + return AllSupportedVersions().front(); +} + +ParsedQuicVersion QuicVersionMin() { + return AllSupportedVersions().back(); +} + +QuicTransportVersion QuicTransportVersionMax() { return AllSupportedTransportVersions().front(); } -QuicTransportVersion QuicVersionMin() { +QuicTransportVersion QuicTransportVersionMin() { return AllSupportedTransportVersions().back(); } @@ -641,7 +655,7 @@ QuicEncryptedPacket* ConstructEncryptedPacket( const string& data, QuicConnectionIdLength connection_id_length, QuicPacketNumberLength packet_number_length, - QuicTransportVersionVector* versions) { + ParsedQuicVersionVector* versions) { return ConstructEncryptedPacket(connection_id, version_flag, reset_flag, packet_number, data, connection_id_length, packet_number_length, versions, @@ -655,7 +669,7 @@ QuicEncryptedPacket* ConstructEncryptedPacket( const string& data, QuicConnectionIdLength connection_id_length, QuicPacketNumberLength packet_number_length, - QuicTransportVersionVector* versions, + ParsedQuicVersionVector* versions, Perspective perspective) { QuicPacketHeader header; header.connection_id = connection_id; @@ -669,7 +683,7 @@ QuicEncryptedPacket* ConstructEncryptedPacket( QuicFrames frames; frames.push_back(frame); QuicFramer framer( - versions != nullptr ? *versions : CurrentSupportedTransportVersions(), + versions != nullptr ? *versions : CurrentSupportedVersions(), QuicTime::Zero(), perspective); std::unique_ptr<QuicPacket> packet( @@ -699,7 +713,7 @@ QuicEncryptedPacket* ConstructMisFramedEncryptedPacket( const string& data, QuicConnectionIdLength connection_id_length, QuicPacketNumberLength packet_number_length, - QuicTransportVersionVector* versions, + ParsedQuicVersionVector* versions, Perspective perspective) { QuicPacketHeader header; header.connection_id = connection_id; @@ -712,9 +726,8 @@ QuicEncryptedPacket* ConstructMisFramedEncryptedPacket( QuicFrame frame(&stream_frame); QuicFrames frames; frames.push_back(frame); - QuicFramer framer( - versions != nullptr ? *versions : AllSupportedTransportVersions(), - QuicTime::Zero(), perspective); + QuicFramer framer(versions != nullptr ? *versions : AllSupportedVersions(), + QuicTime::Zero(), perspective); std::unique_ptr<QuicPacket> packet( BuildUnsizedDataPacket(&framer, header, frames)); @@ -817,6 +830,12 @@ QuicTransportVersionVector SupportedTransportVersions( return versions; } +ParsedQuicVersionVector SupportedVersions(ParsedQuicVersion version) { + ParsedQuicVersionVector versions; + versions.push_back(version); + return versions; +} + MockQuicConnectionDebugVisitor::MockQuicConnectionDebugVisitor() {} MockQuicConnectionDebugVisitor::~MockQuicConnectionDebugVisitor() {} @@ -833,15 +852,19 @@ MockConnectionCloseDelegate::~MockConnectionCloseDelegate() {} MockPacketCreatorDelegate::MockPacketCreatorDelegate() {} MockPacketCreatorDelegate::~MockPacketCreatorDelegate() {} -void CreateClientSessionForTest(QuicServerId server_id, - bool supports_stateless_rejects, - QuicTime::Delta connection_start_time, - QuicTransportVersionVector supported_versions, - MockQuicConnectionHelper* helper, - MockAlarmFactory* alarm_factory, - QuicCryptoClientConfig* crypto_client_config, - PacketSavingConnection** client_connection, - TestQuicSpdyClientSession** client_session) { +MockSessionNotifier::MockSessionNotifier() {} +MockSessionNotifier::~MockSessionNotifier() {} + +void CreateClientSessionForTest( + QuicServerId server_id, + bool supports_stateless_rejects, + QuicTime::Delta connection_start_time, + const ParsedQuicVersionVector& supported_versions, + MockQuicConnectionHelper* helper, + MockAlarmFactory* alarm_factory, + QuicCryptoClientConfig* crypto_client_config, + PacketSavingConnection** client_connection, + TestQuicSpdyClientSession** client_session) { CHECK(crypto_client_config); CHECK(client_connection); CHECK(client_session); @@ -862,7 +885,7 @@ void CreateClientSessionForTest(QuicServerId server_id, void CreateServerSessionForTest( QuicServerId server_id, QuicTime::Delta connection_start_time, - QuicTransportVersionVector supported_versions, + ParsedQuicVersionVector supported_versions, MockQuicConnectionHelper* helper, MockAlarmFactory* alarm_factory, QuicCryptoServerConfig* server_crypto_config, diff --git a/chromium/net/quic/test_tools/quic_test_utils.h b/chromium/net/quic/test_tools/quic_test_utils.h index c94a32bdd7f..375ad0e10f6 100644 --- a/chromium/net/quic/test_tools/quic_test_utils.h +++ b/chromium/net/quic/test_tools/quic_test_utils.h @@ -54,13 +54,21 @@ static const uint32_t kInitialSessionFlowControlWindowForTest = QuicIpAddress TestPeerIPAddress(); // Upper limit on versions we support. -QuicTransportVersion QuicVersionMax(); +ParsedQuicVersion QuicVersionMax(); // Lower limit on versions we support. -QuicTransportVersion QuicVersionMin(); +ParsedQuicVersion QuicVersionMin(); + +// Upper limit on versions we support. +// TODO(nharper): Remove this function when it is no longer used. +QuicTransportVersion QuicTransportVersionMax(); + +// Lower limit on versions we support. +// TODO(nharper): Remove this function when it is no longer used. +QuicTransportVersion QuicTransportVersionMin(); // Create an encrypted packet for testing. -// If versions == nullptr, uses &AllSupportedTransportVersions(). +// If versions == nullptr, uses &AllSupportedVersions(). // Note that the packet is encrypted with NullEncrypter, so to decrypt the // constructed packet, the framer must be set to use NullDecrypter. QuicEncryptedPacket* ConstructEncryptedPacket( @@ -71,11 +79,11 @@ QuicEncryptedPacket* ConstructEncryptedPacket( const std::string& data, QuicConnectionIdLength connection_id_length, QuicPacketNumberLength packet_number_length, - QuicTransportVersionVector* versions, + ParsedQuicVersionVector* versions, Perspective perspective); // Create an encrypted packet for testing. -// If versions == nullptr, uses &AllSupportedTransportVersions(). +// If versions == nullptr, uses &AllSupportedVersions(). // Note that the packet is encrypted with NullEncrypter, so to decrypt the // constructed packet, the framer must be set to use NullDecrypter. QuicEncryptedPacket* ConstructEncryptedPacket( @@ -86,7 +94,7 @@ QuicEncryptedPacket* ConstructEncryptedPacket( const std::string& data, QuicConnectionIdLength connection_id_length, QuicPacketNumberLength packet_number_length, - QuicTransportVersionVector* versions); + ParsedQuicVersionVector* versions); // This form assumes |versions| == nullptr. QuicEncryptedPacket* ConstructEncryptedPacket( @@ -126,7 +134,7 @@ QuicEncryptedPacket* ConstructMisFramedEncryptedPacket( const std::string& data, QuicConnectionIdLength connection_id_length, QuicPacketNumberLength packet_number_length, - QuicTransportVersionVector* versions, + ParsedQuicVersionVector* versions, Perspective perspective); void CompareCharArraysWithHexError(const std::string& description, @@ -155,6 +163,8 @@ QuicConfig DefaultQuicConfigStatelessRejects(); QuicTransportVersionVector SupportedTransportVersions( QuicTransportVersion version); +ParsedQuicVersionVector SupportedVersions(ParsedQuicVersion version); + struct QuicAckBlock { QuicPacketNumber start; // Included QuicPacketNumber limit; // Excluded @@ -224,7 +234,7 @@ class MockFramerVisitor : public QuicFramerVisitorInterface { MOCK_METHOD1(OnError, void(QuicFramer* framer)); // The constructor sets this up to return false by default. - MOCK_METHOD1(OnProtocolVersionMismatch, bool(QuicTransportVersion version)); + MOCK_METHOD1(OnProtocolVersionMismatch, bool(ParsedQuicVersion version)); MOCK_METHOD0(OnPacket, void()); MOCK_METHOD1(OnPublicResetPacket, void(const QuicPublicResetPacket& header)); MOCK_METHOD1(OnVersionNegotiationPacket, @@ -262,7 +272,7 @@ class NoOpFramerVisitor : public QuicFramerVisitorInterface { void OnPublicResetPacket(const QuicPublicResetPacket& packet) override {} void OnVersionNegotiationPacket( const QuicVersionNegotiationPacket& packet) override {} - bool OnProtocolVersionMismatch(QuicTransportVersion version) override; + bool OnProtocolVersionMismatch(ParsedQuicVersion version) override; bool OnUnauthenticatedHeader(const QuicPacketHeader& header) override; bool OnUnauthenticatedPublicHeader(const QuicPacketHeader& header) override; void OnDecryptedPacket(EncryptionLevel level) override {} @@ -383,14 +393,14 @@ class MockQuicConnection : public QuicConnection { MockQuicConnection(MockQuicConnectionHelper* helper, MockAlarmFactory* alarm_factory, Perspective perspective, - const QuicTransportVersionVector& supported_versions); + const ParsedQuicVersionVector& supported_versions); MockQuicConnection(QuicConnectionId connection_id, QuicSocketAddress address, MockQuicConnectionHelper* helper, MockAlarmFactory* alarm_factory, Perspective perspective, - const QuicTransportVersionVector& supported_versions); + const ParsedQuicVersionVector& supported_versions); ~MockQuicConnection() override; @@ -444,7 +454,7 @@ class MockQuicConnection : public QuicConnection { QuicConnection::ProcessUdpPacket(self_address, peer_address, packet); } - bool OnProtocolVersionMismatch(QuicTransportVersion version) override; + bool OnProtocolVersionMismatch(ParsedQuicVersion version) override; void ReallySendGoAway(QuicErrorCode error, QuicStreamId last_good_stream_id, @@ -472,7 +482,7 @@ class PacketSavingConnection : public MockQuicConnection { PacketSavingConnection(MockQuicConnectionHelper* helper, MockAlarmFactory* alarm_factory, Perspective perspective, - const QuicTransportVersionVector& supported_versions); + const ParsedQuicVersionVector& supported_versions); ~PacketSavingConnection() override; @@ -525,11 +535,11 @@ class MockQuicSession : public QuicSession { // Returns a QuicConsumedData that indicates all of |write_length| (and |fin| // if set) has been consumed. - static QuicConsumedData ConsumeAllData(QuicStream* stream, - QuicStreamId id, - size_t write_length, - QuicStreamOffset offset, - StreamSendingState state); + static QuicConsumedData ConsumeData(QuicStream* stream, + QuicStreamId id, + size_t write_length, + QuicStreamOffset offset, + StreamSendingState state); private: std::unique_ptr<QuicCryptoStream> crypto_stream_; @@ -861,7 +871,7 @@ class MockQuicConnectionDebugVisitor : public QuicConnectionDebugVisitor { MOCK_METHOD1(OnIncorrectConnectionId, void(QuicConnectionId)); - MOCK_METHOD1(OnProtocolVersionMismatch, void(QuicTransportVersion)); + MOCK_METHOD1(OnProtocolVersionMismatch, void(ParsedQuicVersion)); MOCK_METHOD1(OnPacketHeader, void(const QuicPacketHeader& header)); @@ -926,6 +936,16 @@ class MockPacketCreatorDelegate : public QuicPacketCreator::DelegateInterface { DISALLOW_COPY_AND_ASSIGN(MockPacketCreatorDelegate); }; +class MockSessionNotifier : public SessionNotifierInterface { + public: + MockSessionNotifier(); + ~MockSessionNotifier() override; + + MOCK_METHOD2(OnFrameAcked, void(const QuicFrame&, QuicTime::Delta)); + MOCK_METHOD1(OnStreamFrameRetransmitted, void(const QuicStreamFrame&)); + MOCK_METHOD1(OnFrameLost, void(const QuicFrame&)); +}; + // Creates a client session for testing. // // server_id: The server id associated with this stream. @@ -942,15 +962,16 @@ class MockPacketCreatorDelegate : public QuicPacketCreator::DelegateInterface { // client_session. // client_session: Pointer reference for the newly created client // session. The new object will be owned by the caller. -void CreateClientSessionForTest(QuicServerId server_id, - bool supports_stateless_rejects, - QuicTime::Delta connection_start_time, - QuicTransportVersionVector supported_versions, - MockQuicConnectionHelper* helper, - MockAlarmFactory* alarm_factory, - QuicCryptoClientConfig* crypto_client_config, - PacketSavingConnection** client_connection, - TestQuicSpdyClientSession** client_session); +void CreateClientSessionForTest( + QuicServerId server_id, + bool supports_stateless_rejects, + QuicTime::Delta connection_start_time, + const ParsedQuicVersionVector& supported_versions, + MockQuicConnectionHelper* helper, + MockAlarmFactory* alarm_factory, + QuicCryptoClientConfig* crypto_client_config, + PacketSavingConnection** client_connection, + TestQuicSpdyClientSession** client_session); // Creates a server session for testing. // @@ -970,7 +991,7 @@ void CreateClientSessionForTest(QuicServerId server_id, void CreateServerSessionForTest( QuicServerId server_id, QuicTime::Delta connection_start_time, - QuicTransportVersionVector supported_versions, + ParsedQuicVersionVector supported_versions, MockQuicConnectionHelper* helper, MockAlarmFactory* alarm_factory, QuicCryptoServerConfig* crypto_server_config, diff --git a/chromium/net/quic/test_tools/quic_time_wait_list_manager_peer.cc b/chromium/net/quic/test_tools/quic_time_wait_list_manager_peer.cc index ba47d8b9e36..c2d4c79c901 100644 --- a/chromium/net/quic/test_tools/quic_time_wait_list_manager_peer.cc +++ b/chromium/net/quic/test_tools/quic_time_wait_list_manager_peer.cc @@ -22,7 +22,8 @@ QuicTransportVersion QuicTimeWaitListManagerPeer::GetQuicVersionFromConnectionId( QuicTimeWaitListManager* manager, QuicConnectionId connection_id) { - return manager->GetQuicVersionFromConnectionId(connection_id); + return manager->GetQuicVersionFromConnectionId(connection_id) + .transport_version; } QuicAlarm* QuicTimeWaitListManagerPeer::expiration_alarm( diff --git a/chromium/net/quic/test_tools/simple_data_producer.cc b/chromium/net/quic/test_tools/simple_data_producer.cc index 14f2f6c8910..e581357fbab 100644 --- a/chromium/net/quic/test_tools/simple_data_producer.cc +++ b/chromium/net/quic/test_tools/simple_data_producer.cc @@ -26,8 +26,7 @@ void SimpleDataProducer::SaveStreamData(QuicStreamId id, } if (!QuicContainsKey(send_buffer_map_, id)) { send_buffer_map_[id] = QuicMakeUnique<QuicStreamSendBuffer>( - &allocator_, - FLAGS_quic_reloadable_flag_quic_allow_multiple_acks_for_data2); + &allocator_, GetQuicReloadableFlag(quic_allow_multiple_acks_for_data2)); } send_buffer_map_[id]->SaveStreamData(iov, iov_count, iov_offset, data_length); } @@ -39,21 +38,6 @@ bool SimpleDataProducer::WriteStreamData(QuicStreamId id, return send_buffer_map_[id]->WriteStreamData(offset, data_length, writer); } -void SimpleDataProducer::OnStreamFrameAcked( - const QuicStreamFrame& frame, - QuicTime::Delta /*ack_delay_time*/) { - OnStreamFrameDiscarded(frame); -} - -void SimpleDataProducer::OnStreamFrameDiscarded(const QuicStreamFrame& frame) { - if (!QuicContainsKey(send_buffer_map_, frame.stream_id)) { - return; - } - QuicByteCount newly_acked_length = 0; - send_buffer_map_[frame.stream_id]->OnStreamDataAcked( - frame.offset, frame.data_length, &newly_acked_length); -} - } // namespace test } // namespace net diff --git a/chromium/net/quic/test_tools/simple_data_producer.h b/chromium/net/quic/test_tools/simple_data_producer.h index 22b6d0b5337..4cb678f7b43 100644 --- a/chromium/net/quic/test_tools/simple_data_producer.h +++ b/chromium/net/quic/test_tools/simple_data_producer.h @@ -8,7 +8,6 @@ #include "net/quic/core/quic_simple_buffer_allocator.h" #include "net/quic/core/quic_stream_frame_data_producer.h" #include "net/quic/core/quic_stream_send_buffer.h" -#include "net/quic/core/stream_notifier_interface.h" #include "net/quic/platform/api/quic_containers.h" namespace net { @@ -17,8 +16,7 @@ namespace test { // A simple data producer which copies stream data into a map from stream // id to send buffer. -class SimpleDataProducer : public QuicStreamFrameDataProducer, - public StreamNotifierInterface { +class SimpleDataProducer : public QuicStreamFrameDataProducer { public: SimpleDataProducer(); ~SimpleDataProducer() override; @@ -36,12 +34,6 @@ class SimpleDataProducer : public QuicStreamFrameDataProducer, QuicByteCount data_length, QuicDataWriter* writer) override; - // StreamNotifierInterface methods: - void OnStreamFrameAcked(const QuicStreamFrame& frame, - QuicTime::Delta ack_delay_time) override; - void OnStreamFrameRetransmitted(const QuicStreamFrame& frame) override {} - void OnStreamFrameDiscarded(const QuicStreamFrame& frame) override; - private: using SendBufferMap = QuicUnorderedMap<QuicStreamId, std::unique_ptr<QuicStreamSendBuffer>>; diff --git a/chromium/net/quic/test_tools/simple_quic_framer.cc b/chromium/net/quic/test_tools/simple_quic_framer.cc index 87775550ecd..2cab678f1e4 100644 --- a/chromium/net/quic/test_tools/simple_quic_framer.cc +++ b/chromium/net/quic/test_tools/simple_quic_framer.cc @@ -25,7 +25,7 @@ class SimpleFramerVisitor : public QuicFramerVisitorInterface { void OnError(QuicFramer* framer) override { error_ = framer->error(); } - bool OnProtocolVersionMismatch(QuicTransportVersion version) override { + bool OnProtocolVersionMismatch(ParsedQuicVersion version) override { return false; } @@ -159,16 +159,16 @@ class SimpleFramerVisitor : public QuicFramerVisitorInterface { }; SimpleQuicFramer::SimpleQuicFramer() - : framer_(AllSupportedTransportVersions(), + : framer_(AllSupportedVersions(), QuicTime::Zero(), Perspective::IS_SERVER) {} SimpleQuicFramer::SimpleQuicFramer( - const QuicTransportVersionVector& supported_versions) + const ParsedQuicVersionVector& supported_versions) : framer_(supported_versions, QuicTime::Zero(), Perspective::IS_SERVER) {} SimpleQuicFramer::SimpleQuicFramer( - const QuicTransportVersionVector& supported_versions, + const ParsedQuicVersionVector& supported_versions, Perspective perspective) : framer_(supported_versions, QuicTime::Zero(), perspective) {} diff --git a/chromium/net/quic/test_tools/simple_quic_framer.h b/chromium/net/quic/test_tools/simple_quic_framer.h index 5e0ebb0fd48..c9030df799c 100644 --- a/chromium/net/quic/test_tools/simple_quic_framer.h +++ b/chromium/net/quic/test_tools/simple_quic_framer.h @@ -24,9 +24,8 @@ class SimpleFramerVisitor; class SimpleQuicFramer { public: SimpleQuicFramer(); - explicit SimpleQuicFramer( - const QuicTransportVersionVector& supported_versions); - SimpleQuicFramer(const QuicTransportVersionVector& supported_versions, + explicit SimpleQuicFramer(const ParsedQuicVersionVector& supported_versions); + SimpleQuicFramer(const ParsedQuicVersionVector& supported_versions, Perspective perspective); ~SimpleQuicFramer(); @@ -48,9 +47,8 @@ class SimpleQuicFramer { QuicFramer* framer(); - void SetSupportedTransportVersions( - const QuicTransportVersionVector& versions) { - framer_.SetSupportedTransportVersions(versions); + void SetSupportedVersions(const ParsedQuicVersionVector& versions) { + framer_.SetSupportedVersions(versions); } private: diff --git a/chromium/net/quic/test_tools/simulator/quic_endpoint.cc b/chromium/net/quic/test_tools/simulator/quic_endpoint.cc index 032a8f18ae6..79650e0aad9 100644 --- a/chromium/net/quic/test_tools/simulator/quic_endpoint.cc +++ b/chromium/net/quic/test_tools/simulator/quic_endpoint.cc @@ -73,7 +73,7 @@ QuicEndpoint::QuicEndpoint(Simulator* simulator, &writer_, false, perspective, - CurrentSupportedTransportVersions()), + CurrentSupportedVersions()), bytes_to_transfer_(0), bytes_transferred_(0), write_blocked_count_(0), diff --git a/chromium/net/reporting/reporting_browsing_data_remover.cc b/chromium/net/reporting/reporting_browsing_data_remover.cc index 9b391d49371..8f42253c9a8 100644 --- a/chromium/net/reporting/reporting_browsing_data_remover.cc +++ b/chromium/net/reporting/reporting_browsing_data_remover.cc @@ -17,7 +17,7 @@ namespace net { void ReportingBrowsingDataRemover::RemoveBrowsingData( ReportingCache* cache, int data_type_mask, - base::Callback<bool(const GURL&)> origin_filter) { + const base::RepeatingCallback<bool(const GURL&)>& origin_filter) { bool remove_reports = (data_type_mask & DATA_TYPE_REPORTS) != 0; bool remove_clients = (data_type_mask & DATA_TYPE_CLIENTS) != 0; diff --git a/chromium/net/reporting/reporting_browsing_data_remover.h b/chromium/net/reporting/reporting_browsing_data_remover.h index f93d6348a27..abb34bc9d25 100644 --- a/chromium/net/reporting/reporting_browsing_data_remover.h +++ b/chromium/net/reporting/reporting_browsing_data_remover.h @@ -33,7 +33,7 @@ class NET_EXPORT ReportingBrowsingDataRemover { static void RemoveBrowsingData( ReportingCache* cache, int data_type_mask, - base::Callback<bool(const GURL&)> origin_filter); + const base::RepeatingCallback<bool(const GURL&)>& origin_filter); 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 ceaf9d59d8a..3d8d10d8122 100644 --- a/chromium/net/reporting/reporting_browsing_data_remover_unittest.cc +++ b/chromium/net/reporting/reporting_browsing_data_remover_unittest.cc @@ -29,16 +29,29 @@ class ReportingBrowsingDataRemoverTest : public ReportingTestBase { if (remove_clients) data_type_mask |= ReportingBrowsingDataRemover::DATA_TYPE_CLIENTS; - base::Callback<bool(const GURL&)> origin_filter; + base::RepeatingCallback<bool(const GURL&)> origin_filter; if (!host.empty()) { origin_filter = - base::Bind(&ReportingBrowsingDataRemoverTest::HostIs, host); + base::BindRepeating(&ReportingBrowsingDataRemoverTest::HostIs, host); } ReportingBrowsingDataRemover::RemoveBrowsingData(cache(), data_type_mask, origin_filter); } + void AddReport(const GURL& url) { + cache()->AddReport(url, kGroup_, kType_, + std::make_unique<base::DictionaryValue>(), + tick_clock()->NowTicks(), 0); + } + + void SetClient(const url::Origin& origin, const GURL& endpoint) { + cache()->SetClient( + origin, endpoint, ReportingClient::Subdomains::EXCLUDE, kGroup_, + tick_clock()->NowTicks() + base::TimeDelta::FromDays(7), + ReportingClient::kDefaultPriority, ReportingClient::kDefaultWeight); + } + static bool HostIs(std::string host, const GURL& url) { return url.host() == host; } @@ -65,18 +78,11 @@ class ReportingBrowsingDataRemoverTest : public ReportingTestBase { }; TEST_F(ReportingBrowsingDataRemoverTest, RemoveNothing) { - cache()->AddReport(kUrl1_, kGroup_, kType_, - std::make_unique<base::DictionaryValue>(), - tick_clock()->NowTicks(), 0); - cache()->AddReport(kUrl2_, kGroup_, kType_, - std::make_unique<base::DictionaryValue>(), - tick_clock()->NowTicks(), 0); - cache()->SetClient(kOrigin1_, kEndpoint_, - ReportingClient::Subdomains::EXCLUDE, kGroup_, - tick_clock()->NowTicks() + base::TimeDelta::FromDays(7)); - cache()->SetClient(kOrigin2_, kEndpoint_, - ReportingClient::Subdomains::EXCLUDE, kGroup_, - tick_clock()->NowTicks() + base::TimeDelta::FromDays(7)); + AddReport(kUrl1_); + AddReport(kUrl2_); + + SetClient(kOrigin1_, kEndpoint_); + SetClient(kOrigin2_, kEndpoint_); RemoveBrowsingData(/* remove_reports= */ false, /* remove_clients= */ false, /* host= */ ""); @@ -85,18 +91,11 @@ TEST_F(ReportingBrowsingDataRemoverTest, RemoveNothing) { } TEST_F(ReportingBrowsingDataRemoverTest, RemoveAllReports) { - cache()->AddReport(kUrl1_, kGroup_, kType_, - std::make_unique<base::DictionaryValue>(), - tick_clock()->NowTicks(), 0); - cache()->AddReport(kUrl2_, kGroup_, kType_, - std::make_unique<base::DictionaryValue>(), - tick_clock()->NowTicks(), 0); - cache()->SetClient(kOrigin1_, kEndpoint_, - ReportingClient::Subdomains::EXCLUDE, kGroup_, - tick_clock()->NowTicks() + base::TimeDelta::FromDays(7)); - cache()->SetClient(kOrigin2_, kEndpoint_, - ReportingClient::Subdomains::EXCLUDE, kGroup_, - tick_clock()->NowTicks() + base::TimeDelta::FromDays(7)); + AddReport(kUrl1_); + AddReport(kUrl2_); + + SetClient(kOrigin1_, kEndpoint_); + SetClient(kOrigin2_, kEndpoint_); RemoveBrowsingData(/* remove_reports= */ true, /* remove_clients= */ false, /* host= */ ""); @@ -105,18 +104,11 @@ TEST_F(ReportingBrowsingDataRemoverTest, RemoveAllReports) { } TEST_F(ReportingBrowsingDataRemoverTest, RemoveAllClients) { - cache()->AddReport(kUrl1_, kGroup_, kType_, - std::make_unique<base::DictionaryValue>(), - tick_clock()->NowTicks(), 0); - cache()->AddReport(kUrl2_, kGroup_, kType_, - std::make_unique<base::DictionaryValue>(), - tick_clock()->NowTicks(), 0); - cache()->SetClient(kOrigin1_, kEndpoint_, - ReportingClient::Subdomains::EXCLUDE, kGroup_, - tick_clock()->NowTicks() + base::TimeDelta::FromDays(7)); - cache()->SetClient(kOrigin2_, kEndpoint_, - ReportingClient::Subdomains::EXCLUDE, kGroup_, - tick_clock()->NowTicks() + base::TimeDelta::FromDays(7)); + AddReport(kUrl1_); + AddReport(kUrl2_); + + SetClient(kOrigin1_, kEndpoint_); + SetClient(kOrigin2_, kEndpoint_); RemoveBrowsingData(/* remove_reports= */ false, /* remove_clients= */ true, /* host= */ ""); @@ -125,18 +117,11 @@ TEST_F(ReportingBrowsingDataRemoverTest, RemoveAllClients) { } TEST_F(ReportingBrowsingDataRemoverTest, RemoveAllReportsAndClients) { - cache()->AddReport(kUrl1_, kGroup_, kType_, - std::make_unique<base::DictionaryValue>(), - tick_clock()->NowTicks(), 0); - cache()->AddReport(kUrl2_, kGroup_, kType_, - std::make_unique<base::DictionaryValue>(), - tick_clock()->NowTicks(), 0); - cache()->SetClient(kOrigin1_, kEndpoint_, - ReportingClient::Subdomains::EXCLUDE, kGroup_, - tick_clock()->NowTicks() + base::TimeDelta::FromDays(7)); - cache()->SetClient(kOrigin2_, kEndpoint_, - ReportingClient::Subdomains::EXCLUDE, kGroup_, - tick_clock()->NowTicks() + base::TimeDelta::FromDays(7)); + AddReport(kUrl1_); + AddReport(kUrl2_); + + SetClient(kOrigin1_, kEndpoint_); + SetClient(kOrigin2_, kEndpoint_); RemoveBrowsingData(/* remove_reports= */ true, /* remove_clients= */ true, /* host= */ ""); @@ -145,18 +130,11 @@ TEST_F(ReportingBrowsingDataRemoverTest, RemoveAllReportsAndClients) { } TEST_F(ReportingBrowsingDataRemoverTest, RemoveSomeReports) { - cache()->AddReport(kUrl1_, kGroup_, kType_, - std::make_unique<base::DictionaryValue>(), - tick_clock()->NowTicks(), 0); - cache()->AddReport(kUrl2_, kGroup_, kType_, - std::make_unique<base::DictionaryValue>(), - tick_clock()->NowTicks(), 0); - cache()->SetClient(kOrigin1_, kEndpoint_, - ReportingClient::Subdomains::EXCLUDE, kGroup_, - tick_clock()->NowTicks() + base::TimeDelta::FromDays(7)); - cache()->SetClient(kOrigin2_, kEndpoint_, - ReportingClient::Subdomains::EXCLUDE, kGroup_, - tick_clock()->NowTicks() + base::TimeDelta::FromDays(7)); + AddReport(kUrl1_); + AddReport(kUrl2_); + + SetClient(kOrigin1_, kEndpoint_); + SetClient(kOrigin2_, kEndpoint_); RemoveBrowsingData(/* remove_reports= */ true, /* remove_clients= */ false, /* host= */ kUrl1_.host()); @@ -169,18 +147,11 @@ TEST_F(ReportingBrowsingDataRemoverTest, RemoveSomeReports) { } TEST_F(ReportingBrowsingDataRemoverTest, RemoveSomeClients) { - cache()->AddReport(kUrl1_, kGroup_, kType_, - std::make_unique<base::DictionaryValue>(), - tick_clock()->NowTicks(), 0); - cache()->AddReport(kUrl2_, kGroup_, kType_, - std::make_unique<base::DictionaryValue>(), - tick_clock()->NowTicks(), 0); - cache()->SetClient(kOrigin1_, kEndpoint_, - ReportingClient::Subdomains::EXCLUDE, kGroup_, - tick_clock()->NowTicks() + base::TimeDelta::FromDays(7)); - cache()->SetClient(kOrigin2_, kEndpoint_, - ReportingClient::Subdomains::EXCLUDE, kGroup_, - tick_clock()->NowTicks() + base::TimeDelta::FromDays(7)); + AddReport(kUrl1_); + AddReport(kUrl2_); + + SetClient(kOrigin1_, kEndpoint_); + SetClient(kOrigin2_, kEndpoint_); RemoveBrowsingData(/* remove_reports= */ false, /* remove_clients= */ true, /* host= */ kUrl1_.host()); diff --git a/chromium/net/reporting/reporting_cache.cc b/chromium/net/reporting/reporting_cache.cc index dde13eda388..0ed130bc52e 100644 --- a/chromium/net/reporting/reporting_cache.cc +++ b/chromium/net/reporting/reporting_cache.cc @@ -167,43 +167,13 @@ class ReportingCacheImpl : public ReportingCache { context_->NotifyCacheUpdated(); } - void GetClients( - std::vector<const ReportingClient*>* clients_out) const override { - clients_out->clear(); - for (const auto& it : clients_) - for (const auto& endpoint_and_client : it.second) - clients_out->push_back(endpoint_and_client.second.get()); - } - - void GetClientsForOriginAndGroup( - const url::Origin& origin, - const std::string& group, - std::vector<const ReportingClient*>* clients_out) const override { - clients_out->clear(); - - const auto it = clients_.find(origin); - if (it != clients_.end()) { - for (const auto& endpoint_and_client : it->second) { - if (endpoint_and_client.second->group == group) - clients_out->push_back(endpoint_and_client.second.get()); - } - } - - // If no clients were found, try successive superdomain suffixes until a - // client with includeSubdomains is found or there are no more domain - // components left. - std::string domain = origin.host(); - while (clients_out->empty() && !domain.empty()) { - GetWildcardClientsForDomainAndGroup(domain, group, clients_out); - domain = GetSuperdomain(domain); - } - } - void SetClient(const url::Origin& origin, const GURL& endpoint, ReportingClient::Subdomains subdomains, const std::string& group, - base::TimeTicks expires) override { + base::TimeTicks expires, + int priority, + int weight) override { DCHECK(endpoint.SchemeIsCryptographic()); base::TimeTicks last_used = tick_clock()->NowTicks(); @@ -215,9 +185,10 @@ class ReportingCacheImpl : public ReportingCache { RemoveClient(old_client); } - AddClient(std::make_unique<ReportingClient>(origin, endpoint, subdomains, - group, expires), - last_used); + AddClient( + std::make_unique<ReportingClient>(origin, endpoint, subdomains, group, + expires, priority, weight), + last_used); if (client_last_used_.size() > context_->policy().max_client_count) { // There should only ever be one extra client, added above. @@ -242,6 +213,51 @@ class ReportingCacheImpl : public ReportingCache { client_last_used_[client] = tick_clock()->NowTicks(); } + void GetClients( + std::vector<const ReportingClient*>* clients_out) const override { + clients_out->clear(); + for (const auto& it : clients_) + for (const auto& endpoint_and_client : it.second) + clients_out->push_back(endpoint_and_client.second.get()); + } + + void GetClientsForOriginAndGroup( + const url::Origin& origin, + const std::string& group, + std::vector<const ReportingClient*>* clients_out) const override { + clients_out->clear(); + + const auto it = clients_.find(origin); + if (it != clients_.end()) { + for (const auto& endpoint_and_client : it->second) { + if (endpoint_and_client.second->group == group) + clients_out->push_back(endpoint_and_client.second.get()); + } + } + + // If no clients were found, try successive superdomain suffixes until a + // client with includeSubdomains is found or there are no more domain + // components left. + std::string domain = origin.host(); + while (clients_out->empty() && !domain.empty()) { + GetWildcardClientsForDomainAndGroup(domain, group, clients_out); + domain = GetSuperdomain(domain); + } + } + + // TODO(juliatuttle): Unittests. + void GetEndpointsForOrigin(const url::Origin& origin, + std::vector<GURL>* endpoints_out) const override { + endpoints_out->clear(); + + const auto it = clients_.find(origin); + if (it == clients_.end()) + return; + + for (const auto& endpoint_and_client : it->second) + endpoints_out->push_back(endpoint_and_client.first); + } + void RemoveClients( const std::vector<const ReportingClient*>& clients_to_remove) override { for (const ReportingClient* client : clients_to_remove) @@ -295,36 +311,6 @@ class ReportingCacheImpl : public ReportingCache { } private: - ReportingContext* context_; - - // Owns all reports, keyed by const raw pointer for easier lookup. - std::unordered_map<const ReportingReport*, std::unique_ptr<ReportingReport>> - reports_; - - // Reports that have been marked pending (in use elsewhere and should not be - // deleted until no longer pending). - std::unordered_set<const ReportingReport*> pending_reports_; - - // Reports that have been marked doomed (would have been deleted, but were - // pending when the deletion was requested). - std::unordered_set<const ReportingReport*> doomed_reports_; - - // Owns all clients, keyed by origin, then endpoint URL. - // (These would be unordered_map, but neither url::Origin nor GURL has a hash - // function implemented.) - std::map<url::Origin, std::map<GURL, std::unique_ptr<ReportingClient>>> - clients_; - - // References but does not own all clients with includeSubdomains set, keyed - // by domain name. - std::unordered_map<std::string, std::unordered_set<const ReportingClient*>> - wildcard_clients_; - - // The time that each client has last been used. - std::unordered_map<const ReportingClient*, base::TimeTicks> client_last_used_; - - base::TickClock* tick_clock() { return context_->tick_clock(); } - void RemoveReportInternal(const ReportingReport* report) { reports_[report]->RecordOutcome(tick_clock()->NowTicks()); size_t erased = reports_.erase(report); @@ -454,6 +440,36 @@ class ReportingCacheImpl : public ReportingCache { else return earliest_used; } + + base::TickClock* tick_clock() { return context_->tick_clock(); } + + ReportingContext* context_; + + // Owns all reports, keyed by const raw pointer for easier lookup. + std::unordered_map<const ReportingReport*, std::unique_ptr<ReportingReport>> + reports_; + + // Reports that have been marked pending (in use elsewhere and should not be + // deleted until no longer pending). + std::unordered_set<const ReportingReport*> pending_reports_; + + // Reports that have been marked doomed (would have been deleted, but were + // pending when the deletion was requested). + std::unordered_set<const ReportingReport*> doomed_reports_; + + // Owns all clients, keyed by origin, then endpoint URL. + // (These would be unordered_map, but neither url::Origin nor GURL has a hash + // function implemented.) + std::map<url::Origin, std::map<GURL, std::unique_ptr<ReportingClient>>> + clients_; + + // References but does not own all clients with includeSubdomains set, keyed + // by domain name. + std::unordered_map<std::string, std::unordered_set<const ReportingClient*>> + wildcard_clients_; + + // The time that each client has last been used. + std::unordered_map<const ReportingClient*, base::TimeTicks> client_last_used_; }; } // namespace @@ -464,6 +480,6 @@ std::unique_ptr<ReportingCache> ReportingCache::Create( return std::make_unique<ReportingCacheImpl>(context); } -ReportingCache::~ReportingCache() {} +ReportingCache::~ReportingCache() = default; } // namespace net diff --git a/chromium/net/reporting/reporting_cache.h b/chromium/net/reporting/reporting_cache.h index 2cd4bb7172c..eca3c5cd0ec 100644 --- a/chromium/net/reporting/reporting_cache.h +++ b/chromium/net/reporting/reporting_cache.h @@ -87,14 +87,16 @@ class NET_EXPORT ReportingCache { // endpoint. // // All parameters correspond to the desired values for the fields in - // |Client|. + // ReportingClient. // // |endpoint| must use a cryptographic scheme. virtual void SetClient(const url::Origin& origin, const GURL& endpoint, ReportingClient::Subdomains subdomains, const std::string& group, - base::TimeTicks expires) = 0; + base::TimeTicks expires, + int priority, + int client) = 0; virtual void MarkClientUsed(const url::Origin& origin, const GURL& endpoint) = 0; @@ -126,6 +128,13 @@ class NET_EXPORT ReportingCache { const std::string& group, std::vector<const ReportingClient*>* clients_out) const = 0; + // Gets all of the endpoints in the cache configured for a particular origin. + // Does not pay attention to wildcard hosts; only returns endpoints configured + // by |origin| itself. + virtual void GetEndpointsForOrigin( + const url::Origin& origin, + std::vector<GURL>* endpoints_out) const = 0; + // Removes a set of clients. // // May invalidate ReportingClient pointers returned by |GetClients| or diff --git a/chromium/net/reporting/reporting_cache_unittest.cc b/chromium/net/reporting/reporting_cache_unittest.cc index 9c77e71b4b0..6e447fcf01f 100644 --- a/chromium/net/reporting/reporting_cache_unittest.cc +++ b/chromium/net/reporting/reporting_cache_unittest.cc @@ -60,6 +60,18 @@ class ReportingCacheTest : public ReportingTestBase { return clients.size(); } + void SetClient(const url::Origin& origin, + const GURL& endpoint, + bool subdomains, + const std::string& group, + base::TimeTicks expires) { + cache()->SetClient(origin, endpoint, + subdomains ? ReportingClient::Subdomains::INCLUDE + : ReportingClient::Subdomains::EXCLUDE, + group, expires, ReportingClient::kDefaultPriority, + ReportingClient::kDefaultWeight); + } + const GURL kUrl1_ = GURL("https://origin1/path"); const url::Origin kOrigin1_ = url::Origin::Create(GURL("https://origin1/")); const url::Origin kOrigin2_ = url::Origin::Create(GURL("https://origin2/")); @@ -195,9 +207,7 @@ TEST_F(ReportingCacheTest, RemoveAllPendingReports) { } TEST_F(ReportingCacheTest, Endpoints) { - cache()->SetClient(kOrigin1_, kEndpoint1_, - ReportingClient::Subdomains::EXCLUDE, kGroup1_, - kExpires1_); + SetClient(kOrigin1_, kEndpoint1_, false, kGroup1_, kExpires1_); EXPECT_EQ(1, observer()->cache_update_count()); const ReportingClient* client = @@ -209,8 +219,7 @@ TEST_F(ReportingCacheTest, Endpoints) { EXPECT_EQ(kGroup1_, client->group); EXPECT_EQ(kExpires1_, client->expires); - cache()->SetClient(kOrigin1_, kEndpoint1_, - ReportingClient::Subdomains::INCLUDE, kGroup2, kExpires2_); + SetClient(kOrigin1_, kEndpoint1_, true, kGroup2, kExpires2_); EXPECT_EQ(2, observer()->cache_update_count()); client = FindClientInCache(cache(), kOrigin1_, kEndpoint1_); @@ -229,14 +238,9 @@ TEST_F(ReportingCacheTest, Endpoints) { } TEST_F(ReportingCacheTest, GetClientsForOriginAndGroup) { - cache()->SetClient(kOrigin1_, kEndpoint1_, - ReportingClient::Subdomains::EXCLUDE, kGroup1_, - kExpires1_); - cache()->SetClient(kOrigin1_, kEndpoint2_, - ReportingClient::Subdomains::EXCLUDE, kGroup2, kExpires1_); - cache()->SetClient(kOrigin2_, kEndpoint1_, - ReportingClient::Subdomains::EXCLUDE, kGroup1_, - kExpires1_); + SetClient(kOrigin1_, kEndpoint1_, false, kGroup1_, kExpires1_); + SetClient(kOrigin1_, kEndpoint2_, false, kGroup2, kExpires1_); + SetClient(kOrigin2_, kEndpoint1_, false, kGroup1_, kExpires1_); std::vector<const ReportingClient*> clients; cache()->GetClientsForOriginAndGroup(kOrigin1_, kGroup1_, &clients); @@ -248,14 +252,9 @@ TEST_F(ReportingCacheTest, GetClientsForOriginAndGroup) { } TEST_F(ReportingCacheTest, RemoveClientForOriginAndEndpoint) { - cache()->SetClient(kOrigin1_, kEndpoint1_, - ReportingClient::Subdomains::EXCLUDE, kGroup1_, - kExpires1_); - cache()->SetClient(kOrigin1_, kEndpoint2_, - ReportingClient::Subdomains::EXCLUDE, kGroup2, kExpires1_); - cache()->SetClient(kOrigin2_, kEndpoint1_, - ReportingClient::Subdomains::EXCLUDE, kGroup1_, - kExpires1_); + SetClient(kOrigin1_, kEndpoint1_, false, kGroup1_, kExpires1_); + SetClient(kOrigin1_, kEndpoint2_, false, kGroup2, kExpires1_); + SetClient(kOrigin2_, kEndpoint1_, false, kGroup1_, kExpires1_); EXPECT_EQ(3, observer()->cache_update_count()); cache()->RemoveClientForOriginAndEndpoint(kOrigin1_, kEndpoint1_); @@ -273,14 +272,9 @@ TEST_F(ReportingCacheTest, RemoveClientForOriginAndEndpoint) { } TEST_F(ReportingCacheTest, RemoveClientsForEndpoint) { - cache()->SetClient(kOrigin1_, kEndpoint1_, - ReportingClient::Subdomains::EXCLUDE, kGroup1_, - kExpires1_); - cache()->SetClient(kOrigin1_, kEndpoint2_, - ReportingClient::Subdomains::EXCLUDE, kGroup2, kExpires1_); - cache()->SetClient(kOrigin2_, kEndpoint1_, - ReportingClient::Subdomains::EXCLUDE, kGroup1_, - kExpires1_); + SetClient(kOrigin1_, kEndpoint1_, false, kGroup1_, kExpires1_); + SetClient(kOrigin1_, kEndpoint2_, false, kGroup2, kExpires1_); + SetClient(kOrigin2_, kEndpoint1_, false, kGroup1_, kExpires1_); EXPECT_EQ(3, observer()->cache_update_count()); cache()->RemoveClientsForEndpoint(kEndpoint1_); @@ -298,12 +292,8 @@ TEST_F(ReportingCacheTest, RemoveClientsForEndpoint) { } TEST_F(ReportingCacheTest, RemoveAllClients) { - cache()->SetClient(kOrigin1_, kEndpoint1_, - ReportingClient::Subdomains::EXCLUDE, kGroup1_, - kExpires1_); - cache()->SetClient(kOrigin2_, kEndpoint2_, - ReportingClient::Subdomains::EXCLUDE, kGroup1_, - kExpires1_); + SetClient(kOrigin1_, kEndpoint1_, false, kGroup1_, kExpires1_); + SetClient(kOrigin2_, kEndpoint2_, false, kGroup1_, kExpires1_); EXPECT_EQ(2, observer()->cache_update_count()); cache()->RemoveAllClients(); @@ -319,9 +309,7 @@ TEST_F(ReportingCacheTest, ExcludeSubdomainsDifferentPort) { const url::Origin kDifferentPortOrigin = url::Origin::Create(GURL("https://example:444/")); - cache()->SetClient(kDifferentPortOrigin, kEndpoint1_, - ReportingClient::Subdomains::EXCLUDE, kGroup1_, - kExpires1_); + SetClient(kDifferentPortOrigin, kEndpoint1_, false, kGroup1_, kExpires1_); std::vector<const ReportingClient*> clients; cache()->GetClientsForOriginAndGroup(kOrigin, kGroup1_, &clients); @@ -333,9 +321,7 @@ TEST_F(ReportingCacheTest, ExcludeSubdomainsSuperdomain) { const url::Origin kSuperOrigin = url::Origin::Create(GURL("https://example/")); - cache()->SetClient(kSuperOrigin, kEndpoint1_, - ReportingClient::Subdomains::EXCLUDE, kGroup1_, - kExpires1_); + SetClient(kSuperOrigin, kEndpoint1_, false, kGroup1_, kExpires1_); std::vector<const ReportingClient*> clients; cache()->GetClientsForOriginAndGroup(kOrigin, kGroup1_, &clients); @@ -347,9 +333,7 @@ TEST_F(ReportingCacheTest, IncludeSubdomainsDifferentPort) { const url::Origin kDifferentPortOrigin = url::Origin::Create(GURL("https://example:444/")); - cache()->SetClient(kDifferentPortOrigin, kEndpoint1_, - ReportingClient::Subdomains::INCLUDE, kGroup1_, - kExpires1_); + SetClient(kDifferentPortOrigin, kEndpoint1_, true, kGroup1_, kExpires1_); std::vector<const ReportingClient*> clients; cache()->GetClientsForOriginAndGroup(kOrigin, kGroup1_, &clients); @@ -362,9 +346,7 @@ TEST_F(ReportingCacheTest, IncludeSubdomainsSuperdomain) { const url::Origin kSuperOrigin = url::Origin::Create(GURL("https://example/")); - cache()->SetClient(kSuperOrigin, kEndpoint1_, - ReportingClient::Subdomains::INCLUDE, kGroup1_, - kExpires1_); + SetClient(kSuperOrigin, kEndpoint1_, true, kGroup1_, kExpires1_); std::vector<const ReportingClient*> clients; cache()->GetClientsForOriginAndGroup(kOrigin, kGroup1_, &clients); @@ -377,11 +359,8 @@ TEST_F(ReportingCacheTest, IncludeSubdomainsPreferOriginToDifferentPort) { const url::Origin kDifferentPortOrigin = url::Origin::Create(GURL("https://example:444/")); - cache()->SetClient(kOrigin, kEndpoint1_, ReportingClient::Subdomains::INCLUDE, - kGroup1_, kExpires1_); - cache()->SetClient(kDifferentPortOrigin, kEndpoint1_, - ReportingClient::Subdomains::INCLUDE, kGroup1_, - kExpires1_); + SetClient(kOrigin, kEndpoint1_, true, kGroup1_, kExpires1_); + SetClient(kDifferentPortOrigin, kEndpoint1_, true, kGroup1_, kExpires1_); std::vector<const ReportingClient*> clients; cache()->GetClientsForOriginAndGroup(kOrigin, kGroup1_, &clients); @@ -394,11 +373,8 @@ TEST_F(ReportingCacheTest, IncludeSubdomainsPreferOriginToSuperdomain) { const url::Origin kSuperOrigin = url::Origin::Create(GURL("https://example/")); - cache()->SetClient(kOrigin, kEndpoint1_, ReportingClient::Subdomains::INCLUDE, - kGroup1_, kExpires1_); - cache()->SetClient(kSuperOrigin, kEndpoint1_, - ReportingClient::Subdomains::INCLUDE, kGroup1_, - kExpires1_); + SetClient(kOrigin, kEndpoint1_, true, kGroup1_, kExpires1_); + SetClient(kSuperOrigin, kEndpoint1_, true, kGroup1_, kExpires1_); std::vector<const ReportingClient*> clients; cache()->GetClientsForOriginAndGroup(kOrigin, kGroup1_, &clients); @@ -414,12 +390,8 @@ TEST_F(ReportingCacheTest, IncludeSubdomainsPreferMoreSpecificSuperdomain) { const url::Origin kSuperSuperOrigin = url::Origin::Create(GURL("https://example/")); - cache()->SetClient(kSuperOrigin, kEndpoint1_, - ReportingClient::Subdomains::INCLUDE, kGroup1_, - kExpires1_); - cache()->SetClient(kSuperSuperOrigin, kEndpoint1_, - ReportingClient::Subdomains::INCLUDE, kGroup1_, - kExpires1_); + SetClient(kSuperOrigin, kEndpoint1_, true, kGroup1_, kExpires1_); + SetClient(kSuperSuperOrigin, kEndpoint1_, true, kGroup1_, kExpires1_); std::vector<const ReportingClient*> clients; cache()->GetClientsForOriginAndGroup(kOrigin, kGroup1_, &clients); @@ -502,9 +474,7 @@ TEST_F(ReportingCacheTest, EvictLRUClient) { ASSERT_GT(std::numeric_limits<size_t>::max(), max_client_count); for (size_t i = 0; i < max_client_count; ++i) { - cache()->SetClient(kOrigin1_, MakeEndpoint(i), - ReportingClient::Subdomains::EXCLUDE, kGroup1_, - tomorrow()); + SetClient(kOrigin1_, MakeEndpoint(i), false, kGroup1_, tomorrow()); } EXPECT_EQ(max_client_count, client_count()); @@ -515,9 +485,8 @@ TEST_F(ReportingCacheTest, EvictLRUClient) { } // Add one more client, forcing the cache to evict the LRU. - cache()->SetClient(kOrigin1_, MakeEndpoint(max_client_count), - ReportingClient::Subdomains::EXCLUDE, kGroup1_, - tomorrow()); + SetClient(kOrigin1_, MakeEndpoint(max_client_count), false, kGroup1_, + tomorrow()); EXPECT_EQ(max_client_count, client_count()); EXPECT_FALSE(FindClientInCache(cache(), kOrigin1_, MakeEndpoint(max_client_count - 1))); @@ -532,15 +501,13 @@ TEST_F(ReportingCacheTest, EvictExpiredClient) { for (size_t i = 0; i < max_client_count; ++i) { base::TimeTicks expires = (i == max_client_count - 1) ? yesterday() : tomorrow(); - cache()->SetClient(kOrigin1_, MakeEndpoint(i), - ReportingClient::Subdomains::EXCLUDE, kGroup1_, expires); + SetClient(kOrigin1_, MakeEndpoint(i), false, kGroup1_, expires); } EXPECT_EQ(max_client_count, client_count()); // Add one more client, forcing the cache to evict the expired one. - cache()->SetClient(kOrigin1_, MakeEndpoint(max_client_count), - ReportingClient::Subdomains::EXCLUDE, kGroup1_, - tomorrow()); + SetClient(kOrigin1_, MakeEndpoint(max_client_count), false, kGroup1_, + tomorrow()); EXPECT_EQ(max_client_count, client_count()); EXPECT_FALSE(FindClientInCache(cache(), kOrigin1_, MakeEndpoint(max_client_count - 1))); diff --git a/chromium/net/reporting/reporting_client.cc b/chromium/net/reporting/reporting_client.cc index d8c8a0f35b7..5f01048ceda 100644 --- a/chromium/net/reporting/reporting_client.cc +++ b/chromium/net/reporting/reporting_client.cc @@ -12,17 +12,27 @@ namespace net { +const char ReportingClient::kDefaultGroup[] = "default"; +const int ReportingClient::kDefaultPriority = 0; +const int ReportingClient::kDefaultWeight = 1; + ReportingClient::ReportingClient(const url::Origin& origin, const GURL& endpoint, Subdomains subdomains, const std::string& group, - base::TimeTicks expires) + base::TimeTicks expires, + int priority, + int weight) : origin(origin), endpoint(endpoint), subdomains(subdomains), group(group), - expires(expires) {} + expires(expires), + priority(priority), + weight(weight) { + DCHECK_LT(0, weight); +} -ReportingClient::~ReportingClient() {} +ReportingClient::~ReportingClient() = default; } // namespace net diff --git a/chromium/net/reporting/reporting_client.h b/chromium/net/reporting/reporting_client.h index 0aa11bea57d..c2b87f4fd11 100644 --- a/chromium/net/reporting/reporting_client.h +++ b/chromium/net/reporting/reporting_client.h @@ -18,13 +18,19 @@ namespace net { // The configuration by an origin to use an endpoint for report delivery. struct NET_EXPORT ReportingClient { public: + static const char kDefaultGroup[]; + static const int kDefaultPriority; + static const int kDefaultWeight; + enum class Subdomains { EXCLUDE = 0, INCLUDE = 1 }; ReportingClient(const url::Origin& origin, const GURL& endpoint, Subdomains subdomains, const std::string& group, - base::TimeTicks expires); + base::TimeTicks expires, + int priority, + int weight); ~ReportingClient(); // The origin from which reports will be delivered. @@ -39,11 +45,20 @@ struct NET_EXPORT ReportingClient { Subdomains subdomains = Subdomains::EXCLUDE; // The endpoint group to which this client belongs. - std::string group = "default"; + std::string group = kDefaultGroup; // When this client's max-age has expired. base::TimeTicks expires; + // Priority when multiple endpoints are configured for an origin; endpoints + // with numerically lower priorities are used first. + int priority = kDefaultPriority; + + // Weight when multiple endpoints are configured for an origin with the same + // priority; among those with the same priority, each endpoint has a chance of + // being chosen that is proportional to its weight. + int weight = kDefaultWeight; + private: DISALLOW_COPY_AND_ASSIGN(ReportingClient); }; diff --git a/chromium/net/reporting/reporting_context.cc b/chromium/net/reporting/reporting_context.cc index b46bc865a5d..8f2a280e5b2 100644 --- a/chromium/net/reporting/reporting_context.cc +++ b/chromium/net/reporting/reporting_context.cc @@ -6,13 +6,16 @@ #include <utility> +#include "base/bind.h" #include "base/observer_list.h" +#include "base/rand_util.h" #include "base/time/clock.h" #include "base/time/default_clock.h" #include "base/time/default_tick_clock.h" #include "base/time/tick_clock.h" #include "base/time/time.h" #include "net/base/backoff_entry.h" +#include "net/base/rand_callback.h" #include "net/reporting/reporting_cache.h" #include "net/reporting/reporting_delegate.h" #include "net/reporting/reporting_delivery_agent.h" @@ -20,7 +23,6 @@ #include "net/reporting/reporting_garbage_collector.h" #include "net/reporting/reporting_network_change_observer.h" #include "net/reporting/reporting_observer.h" -#include "net/reporting/reporting_persister.h" #include "net/reporting/reporting_policy.h" #include "net/reporting/reporting_uploader.h" @@ -35,8 +37,9 @@ class ReportingContextImpl : public ReportingContext { ReportingContextImpl(const ReportingPolicy& policy, URLRequestContext* request_context) : ReportingContext(policy, - std::make_unique<base::DefaultClock>(), - std::make_unique<base::DefaultTickClock>(), + base::DefaultClock::GetInstance(), + base::DefaultTickClock::GetInstance(), + base::BindRepeating(&base::RandInt), ReportingUploader::Create(request_context), ReportingDelegate::Create(request_context)) {} }; @@ -50,7 +53,7 @@ std::unique_ptr<ReportingContext> ReportingContext::Create( return std::make_unique<ReportingContextImpl>(policy, request_context); } -ReportingContext::~ReportingContext() {} +ReportingContext::~ReportingContext() = default; void ReportingContext::AddObserver(ReportingObserver* observer) { DCHECK(!observers_.HasObserver(observer)); @@ -68,19 +71,19 @@ void ReportingContext::NotifyCacheUpdated() { } ReportingContext::ReportingContext(const ReportingPolicy& policy, - std::unique_ptr<base::Clock> clock, - std::unique_ptr<base::TickClock> tick_clock, + base::Clock* clock, + base::TickClock* tick_clock, + const RandIntCallback& rand_callback, std::unique_ptr<ReportingUploader> uploader, std::unique_ptr<ReportingDelegate> delegate) : policy_(policy), - clock_(std::move(clock)), - tick_clock_(std::move(tick_clock)), + clock_(clock), + tick_clock_(tick_clock), uploader_(std::move(uploader)), delegate_(std::move(delegate)), cache_(ReportingCache::Create(this)), - endpoint_manager_(ReportingEndpointManager::Create(this)), + endpoint_manager_(ReportingEndpointManager::Create(this, rand_callback)), delivery_agent_(ReportingDeliveryAgent::Create(this)), - persister_(ReportingPersister::Create(this)), garbage_collector_(ReportingGarbageCollector::Create(this)), network_change_observer_(ReportingNetworkChangeObserver::Create(this)) {} diff --git a/chromium/net/reporting/reporting_context.h b/chromium/net/reporting/reporting_context.h index 139ca02dbc5..9b4a6021279 100644 --- a/chromium/net/reporting/reporting_context.h +++ b/chromium/net/reporting/reporting_context.h @@ -11,6 +11,7 @@ #include "base/time/time.h" #include "net/base/backoff_entry.h" #include "net/base/net_export.h" +#include "net/base/rand_callback.h" #include "net/reporting/reporting_policy.h" namespace base { @@ -27,7 +28,6 @@ class ReportingEndpointManager; class ReportingGarbageCollector; class ReportingNetworkChangeObserver; class ReportingObserver; -class ReportingPersister; class ReportingUploader; class URLRequestContext; @@ -43,8 +43,8 @@ class NET_EXPORT ReportingContext { const ReportingPolicy& policy() { return policy_; } - base::Clock* clock() { return clock_.get(); } - base::TickClock* tick_clock() { return tick_clock_.get(); } + base::Clock* clock() { return clock_; } + base::TickClock* tick_clock() { return tick_clock_; } ReportingUploader* uploader() { return uploader_.get(); } ReportingDelegate* delegate() { return delegate_.get(); } @@ -57,8 +57,6 @@ class NET_EXPORT ReportingContext { return garbage_collector_.get(); } - ReportingPersister* persister() { return persister_.get(); } - void AddObserver(ReportingObserver* observer); void RemoveObserver(ReportingObserver* observer); @@ -66,16 +64,17 @@ class NET_EXPORT ReportingContext { protected: ReportingContext(const ReportingPolicy& policy, - std::unique_ptr<base::Clock> clock, - std::unique_ptr<base::TickClock> tick_clock, + base::Clock* clock, + base::TickClock* tick_clock, + const RandIntCallback& rand_callback, std::unique_ptr<ReportingUploader> uploader, std::unique_ptr<ReportingDelegate> delegate); private: ReportingPolicy policy_; - std::unique_ptr<base::Clock> clock_; - std::unique_ptr<base::TickClock> tick_clock_; + base::Clock* clock_; + base::TickClock* tick_clock_; std::unique_ptr<ReportingUploader> uploader_; base::ObserverList<ReportingObserver, /* check_empty= */ true> observers_; @@ -91,9 +90,6 @@ class NET_EXPORT ReportingContext { // |cache_|, and |endpoint_manager_|. std::unique_ptr<ReportingDeliveryAgent> delivery_agent_; - // |persister_| must come after |clock_|, |tick_clock_|, and |cache_|. - std::unique_ptr<ReportingPersister> persister_; - // |garbage_collector_| must come after |tick_clock_| and |cache_|. std::unique_ptr<ReportingGarbageCollector> garbage_collector_; diff --git a/chromium/net/reporting/reporting_delegate.cc b/chromium/net/reporting/reporting_delegate.cc index 4e4e3d12375..42006db4b49 100644 --- a/chromium/net/reporting/reporting_delegate.cc +++ b/chromium/net/reporting/reporting_delegate.cc @@ -18,7 +18,7 @@ class ReportingDelegateImpl : public ReportingDelegate { DCHECK(request_context); } - ~ReportingDelegateImpl() override {} + ~ReportingDelegateImpl() override = default; bool CanQueueReport(const url::Origin& origin) const override { return network_delegate() && @@ -58,6 +58,6 @@ std::unique_ptr<ReportingDelegate> ReportingDelegate::Create( return std::make_unique<ReportingDelegateImpl>(request_context); } -ReportingDelegate::~ReportingDelegate() {} +ReportingDelegate::~ReportingDelegate() = default; } // namespace net diff --git a/chromium/net/reporting/reporting_delivery_agent.cc b/chromium/net/reporting/reporting_delivery_agent.cc index ad439cb2617..8786e3068c2 100644 --- a/chromium/net/reporting/reporting_delivery_agent.cc +++ b/chromium/net/reporting/reporting_delivery_agent.cc @@ -81,7 +81,7 @@ class ReportingDeliveryAgentImpl : public ReportingDeliveryAgent, const std::vector<const ReportingReport*>& reports) : endpoint(endpoint), reports(reports) {} - ~Delivery() {} + ~Delivery() = default; const GURL endpoint; const std::vector<const ReportingReport*> reports; @@ -97,8 +97,8 @@ class ReportingDeliveryAgentImpl : public ReportingDeliveryAgent, void StartTimer() { timer_->Start(FROM_HERE, policy().delivery_interval, - base::Bind(&ReportingDeliveryAgentImpl::OnTimerFired, - base::Unretained(this))); + base::BindRepeating(&ReportingDeliveryAgentImpl::OnTimerFired, + base::Unretained(this))); } void OnTimerFired() { @@ -160,9 +160,9 @@ class ReportingDeliveryAgentImpl : public ReportingDeliveryAgent, uploader()->StartUpload( endpoint, json, - base::Bind(&ReportingDeliveryAgentImpl::OnUploadComplete, - weak_factory_.GetWeakPtr(), - std::make_unique<Delivery>(endpoint, reports))); + base::BindOnce(&ReportingDeliveryAgentImpl::OnUploadComplete, + weak_factory_.GetWeakPtr(), + std::make_unique<Delivery>(endpoint, reports))); } } @@ -219,6 +219,6 @@ std::unique_ptr<ReportingDeliveryAgent> ReportingDeliveryAgent::Create( return std::make_unique<ReportingDeliveryAgentImpl>(context); } -ReportingDeliveryAgent::~ReportingDeliveryAgent() {} +ReportingDeliveryAgent::~ReportingDeliveryAgent() = default; } // namespace net diff --git a/chromium/net/reporting/reporting_delivery_agent_unittest.cc b/chromium/net/reporting/reporting_delivery_agent_unittest.cc index 4bc74893bfb..c4e233a9ad2 100644 --- a/chromium/net/reporting/reporting_delivery_agent_unittest.cc +++ b/chromium/net/reporting/reporting_delivery_agent_unittest.cc @@ -42,6 +42,14 @@ class ReportingDeliveryAgentTest : public ReportingTestBase { return tick_clock()->NowTicks() + base::TimeDelta::FromDays(1); } + void SetClient(const url::Origin& origin, + const GURL& endpoint, + const std::string& group) { + cache()->SetClient(origin, endpoint, ReportingClient::Subdomains::EXCLUDE, + group, tomorrow(), ReportingClient::kDefaultPriority, + ReportingClient::kDefaultWeight); + } + const GURL kUrl_ = GURL("https://origin/path"); const url::Origin kOrigin_ = url::Origin::Create(GURL("https://origin/")); const GURL kEndpoint_ = GURL("https://endpoint/"); @@ -55,8 +63,7 @@ TEST_F(ReportingDeliveryAgentTest, SuccessfulUpload) { base::DictionaryValue body; body.SetString("key", "value"); - cache()->SetClient(kOrigin_, kEndpoint_, ReportingClient::Subdomains::EXCLUDE, - kGroup_, tomorrow()); + SetClient(kOrigin_, kEndpoint_, kGroup_); cache()->AddReport(kUrl_, kGroup_, kType_, body.CreateDeepCopy(), tick_clock()->NowTicks(), 0); @@ -94,8 +101,7 @@ TEST_F(ReportingDeliveryAgentTest, SuccessfulUpload) { } TEST_F(ReportingDeliveryAgentTest, FailedUpload) { - cache()->SetClient(kOrigin_, kEndpoint_, ReportingClient::Subdomains::EXCLUDE, - kGroup_, tomorrow()); + SetClient(kOrigin_, kEndpoint_, kGroup_); cache()->AddReport(kUrl_, kGroup_, kType_, std::make_unique<base::DictionaryValue>(), tick_clock()->NowTicks(), 0); @@ -124,10 +130,8 @@ TEST_F(ReportingDeliveryAgentTest, RemoveEndpointUpload) { static const url::Origin kDifferentOrigin = url::Origin::Create(GURL("https://origin2/")); - cache()->SetClient(kOrigin_, kEndpoint_, ReportingClient::Subdomains::EXCLUDE, - kGroup_, tomorrow()); - cache()->SetClient(kDifferentOrigin, kEndpoint_, - ReportingClient::Subdomains::EXCLUDE, kGroup_, tomorrow()); + SetClient(kOrigin_, kEndpoint_, kGroup_); + SetClient(kDifferentOrigin, kEndpoint_, kGroup_); ASSERT_TRUE(FindClientInCache(cache(), kOrigin_, kEndpoint_)); ASSERT_TRUE(FindClientInCache(cache(), kDifferentOrigin, kEndpoint_)); @@ -159,8 +163,7 @@ TEST_F(ReportingDeliveryAgentTest, RemoveEndpointUpload) { } TEST_F(ReportingDeliveryAgentTest, ConcurrentRemove) { - cache()->SetClient(kOrigin_, kEndpoint_, ReportingClient::Subdomains::EXCLUDE, - kGroup_, tomorrow()); + SetClient(kOrigin_, kEndpoint_, kGroup_); cache()->AddReport(kUrl_, kGroup_, kType_, std::make_unique<base::DictionaryValue>(), tick_clock()->NowTicks(), 0); @@ -200,10 +203,8 @@ TEST_F(ReportingDeliveryAgentTest, static const url::Origin kDifferentOrigin = url::Origin::Create(kDifferentUrl); - cache()->SetClient(kOrigin_, kEndpoint_, ReportingClient::Subdomains::EXCLUDE, - kGroup_, tomorrow()); - cache()->SetClient(kDifferentOrigin, kEndpoint_, - ReportingClient::Subdomains::EXCLUDE, kGroup_, tomorrow()); + SetClient(kOrigin_, kEndpoint_, kGroup_); + SetClient(kDifferentOrigin, kEndpoint_, kGroup_); cache()->AddReport(kUrl_, kGroup_, kType_, std::make_unique<base::DictionaryValue>(), @@ -228,10 +229,8 @@ TEST_F(ReportingDeliveryAgentTest, SerializeUploadsToEndpoint) { static const url::Origin kDifferentOrigin = url::Origin::Create(kDifferentUrl); - cache()->SetClient(kOrigin_, kEndpoint_, ReportingClient::Subdomains::EXCLUDE, - kGroup_, tomorrow()); - cache()->SetClient(kDifferentOrigin, kEndpoint_, - ReportingClient::Subdomains::EXCLUDE, kGroup_, tomorrow()); + SetClient(kOrigin_, kEndpoint_, kGroup_); + SetClient(kDifferentOrigin, kEndpoint_, kGroup_); cache()->AddReport(kUrl_, kGroup_, kType_, std::make_unique<base::DictionaryValue>(), @@ -266,10 +265,8 @@ TEST_F(ReportingDeliveryAgentTest, SerializeUploadsToEndpoint) { TEST_F(ReportingDeliveryAgentTest, SerializeUploadsToGroup) { static const GURL kDifferentEndpoint("https://endpoint2/"); - cache()->SetClient(kOrigin_, kEndpoint_, ReportingClient::Subdomains::EXCLUDE, - kGroup_, tomorrow()); - cache()->SetClient(kOrigin_, kDifferentEndpoint, - ReportingClient::Subdomains::EXCLUDE, kGroup_, tomorrow()); + SetClient(kOrigin_, kEndpoint_, kGroup_); + SetClient(kOrigin_, kDifferentEndpoint, kGroup_); cache()->AddReport(kUrl_, kGroup_, kType_, std::make_unique<base::DictionaryValue>(), @@ -304,11 +301,8 @@ TEST_F(ReportingDeliveryAgentTest, ParallelizeUploadsAcrossGroups) { static const GURL kDifferentEndpoint("https://endpoint2/"); static const std::string kDifferentGroup("group2"); - cache()->SetClient(kOrigin_, kEndpoint_, ReportingClient::Subdomains::EXCLUDE, - kGroup_, tomorrow()); - cache()->SetClient(kOrigin_, kDifferentEndpoint, - ReportingClient::Subdomains::EXCLUDE, kDifferentGroup, - tomorrow()); + SetClient(kOrigin_, kEndpoint_, kGroup_); + SetClient(kOrigin_, kDifferentEndpoint, kDifferentGroup); cache()->AddReport(kUrl_, kGroup_, kType_, std::make_unique<base::DictionaryValue>(), diff --git a/chromium/net/reporting/reporting_endpoint_manager.cc b/chromium/net/reporting/reporting_endpoint_manager.cc index f216a86da2f..6a4c6c126a5 100644 --- a/chromium/net/reporting/reporting_endpoint_manager.cc +++ b/chromium/net/reporting/reporting_endpoint_manager.cc @@ -15,6 +15,7 @@ #include "base/stl_util.h" #include "base/time/tick_clock.h" #include "net/base/backoff_entry.h" +#include "net/base/rand_callback.h" #include "net/reporting/reporting_cache.h" #include "net/reporting/reporting_client.h" #include "net/reporting/reporting_delegate.h" @@ -28,9 +29,11 @@ namespace { class ReportingEndpointManagerImpl : public ReportingEndpointManager { public: - ReportingEndpointManagerImpl(ReportingContext* context) : context_(context) {} + ReportingEndpointManagerImpl(ReportingContext* context, + const RandIntCallback& rand_callback) + : context_(context), rand_callback_(rand_callback) {} - ~ReportingEndpointManagerImpl() override {} + ~ReportingEndpointManagerImpl() override = default; bool FindEndpointForOriginAndGroup(const url::Origin& origin, const std::string& group, @@ -38,8 +41,12 @@ class ReportingEndpointManagerImpl : public ReportingEndpointManager { std::vector<const ReportingClient*> clients; cache()->GetClientsForOriginAndGroup(origin, group, &clients); - // Filter out expired, pending, and backed-off endpoints. + // Highest-priority client(s) that are not expired, pending, failing, or + // forbidden for use by the ReportingDelegate. std::vector<const ReportingClient*> available_clients; + // Total weight of clients in available_clients. + int total_weight = 0; + base::TimeTicks now = tick_clock()->NowTicks(); for (const ReportingClient* client : clients) { if (client->expires < now) @@ -52,7 +59,23 @@ class ReportingEndpointManagerImpl : public ReportingEndpointManager { } if (!delegate()->CanUseClient(client->origin, client->endpoint)) continue; + + // If this client is lower priority than the ones we've found, skip it. + if (!available_clients.empty() && + client->priority > available_clients[0]->priority) { + continue; + } + + // If this client is higher priority than the ones we've found (or we + // haven't found any), forget about those ones and remember this one. + if (available_clients.empty() || + client->priority < available_clients[0]->priority) { + available_clients.clear(); + total_weight = 0; + } + available_clients.push_back(client); + total_weight += client->weight; } if (available_clients.empty()) { @@ -60,9 +83,20 @@ class ReportingEndpointManagerImpl : public ReportingEndpointManager { return false; } - int random_index = base::RandInt(0, available_clients.size() - 1); - *endpoint_url_out = available_clients[random_index]->endpoint; - return true; + int random_index = rand_callback_.Run(0, total_weight - 1); + int weight_so_far = 0; + for (size_t i = 0; i < available_clients.size(); ++i) { + const ReportingClient* client = available_clients[i]; + weight_so_far += client->weight; + if (random_index < weight_so_far) { + *endpoint_url_out = client->endpoint; + return true; + } + } + + // TODO(juliatuttle): Can we reach this in some weird overflow case? + NOTREACHED(); + return false; } void SetEndpointPending(const GURL& endpoint) override { @@ -91,6 +125,8 @@ class ReportingEndpointManagerImpl : public ReportingEndpointManager { ReportingContext* context_; + RandIntCallback rand_callback_; + std::set<GURL> pending_endpoints_; // Note: Currently the ReportingBrowsingDataRemover does not clear this data @@ -105,10 +141,11 @@ class ReportingEndpointManagerImpl : public ReportingEndpointManager { // static std::unique_ptr<ReportingEndpointManager> ReportingEndpointManager::Create( - ReportingContext* context) { - return std::make_unique<ReportingEndpointManagerImpl>(context); + ReportingContext* context, + const RandIntCallback& rand_callback) { + return std::make_unique<ReportingEndpointManagerImpl>(context, rand_callback); } -ReportingEndpointManager::~ReportingEndpointManager() {} +ReportingEndpointManager::~ReportingEndpointManager() = default; } // namespace net diff --git a/chromium/net/reporting/reporting_endpoint_manager.h b/chromium/net/reporting/reporting_endpoint_manager.h index 1f35198479a..6df5f38b2c5 100644 --- a/chromium/net/reporting/reporting_endpoint_manager.h +++ b/chromium/net/reporting/reporting_endpoint_manager.h @@ -10,6 +10,7 @@ #include "base/macros.h" #include "net/base/net_export.h" +#include "net/base/rand_callback.h" #include "net/reporting/reporting_context.h" class GURL; @@ -27,7 +28,8 @@ class NET_EXPORT ReportingEndpointManager { public: // |context| must outlive the ReportingEndpointManager. static std::unique_ptr<ReportingEndpointManager> Create( - ReportingContext* context); + ReportingContext* context, + const RandIntCallback& rand_callback); virtual ~ReportingEndpointManager(); diff --git a/chromium/net/reporting/reporting_endpoint_manager_unittest.cc b/chromium/net/reporting/reporting_endpoint_manager_unittest.cc index 28915e07f66..de26c007f2a 100644 --- a/chromium/net/reporting/reporting_endpoint_manager_unittest.cc +++ b/chromium/net/reporting/reporting_endpoint_manager_unittest.cc @@ -22,6 +22,11 @@ namespace { class ReportingEndpointManagerTest : public ReportingTestBase { protected: + void SetClient(const GURL& endpoint, int priority, int weight) { + cache()->SetClient(kOrigin_, endpoint, ReportingClient::Subdomains::EXCLUDE, + kGroup_, tomorrow(), priority, weight); + } + const url::Origin kOrigin_ = url::Origin::Create(GURL("https://origin/")); const GURL kEndpoint_ = GURL("https://endpoint/"); const std::string kGroup_ = "group"; @@ -35,8 +40,8 @@ TEST_F(ReportingEndpointManagerTest, NoEndpoint) { } TEST_F(ReportingEndpointManagerTest, Endpoint) { - cache()->SetClient(kOrigin_, kEndpoint_, ReportingClient::Subdomains::EXCLUDE, - kGroup_, tomorrow()); + SetClient(kEndpoint_, ReportingClient::kDefaultPriority, + ReportingClient::kDefaultWeight); GURL endpoint_url; bool found_endpoint = endpoint_manager()->FindEndpointForOriginAndGroup( @@ -46,8 +51,11 @@ TEST_F(ReportingEndpointManagerTest, Endpoint) { } TEST_F(ReportingEndpointManagerTest, ExpiredEndpoint) { - cache()->SetClient(kOrigin_, kEndpoint_, ReportingClient::Subdomains::EXCLUDE, - kGroup_, yesterday()); + SetClient(kEndpoint_, ReportingClient::kDefaultPriority, + ReportingClient::kDefaultWeight); + + // Default expiration is "tomorrow", so make sure we're past that. + tick_clock()->Advance(base::TimeDelta::FromDays(2)); GURL endpoint_url; bool found_endpoint = endpoint_manager()->FindEndpointForOriginAndGroup( @@ -56,8 +64,8 @@ TEST_F(ReportingEndpointManagerTest, ExpiredEndpoint) { } TEST_F(ReportingEndpointManagerTest, PendingEndpoint) { - cache()->SetClient(kOrigin_, kEndpoint_, ReportingClient::Subdomains::EXCLUDE, - kGroup_, tomorrow()); + SetClient(kEndpoint_, ReportingClient::kDefaultPriority, + ReportingClient::kDefaultWeight); endpoint_manager()->SetEndpointPending(kEndpoint_); @@ -80,8 +88,8 @@ TEST_F(ReportingEndpointManagerTest, BackedOffEndpoint) { base::TimeDelta initial_delay = base::TimeDelta::FromMilliseconds( policy().endpoint_backoff_policy.initial_delay_ms); - cache()->SetClient(kOrigin_, kEndpoint_, ReportingClient::Subdomains::EXCLUDE, - kGroup_, tomorrow()); + SetClient(kEndpoint_, ReportingClient::kDefaultPriority, + ReportingClient::kDefaultWeight); endpoint_manager()->InformOfEndpointRequest(kEndpoint_, false); @@ -142,28 +150,28 @@ TEST_F(ReportingEndpointManagerTest, BackedOffEndpoint) { // Make sure that multiple endpoints will all be returned at some point, to // avoid accidentally or intentionally implementing any priority ordering. TEST_F(ReportingEndpointManagerTest, RandomEndpoint) { - static const GURL kEndpoint_1("https://endpoint1/"); - static const GURL kEndpoint_2("https://endpoint2/"); + static const GURL kEndpoint1("https://endpoint1/"); + static const GURL kEndpoint2("https://endpoint2/"); static const int kMaxAttempts = 20; - cache()->SetClient(kOrigin_, kEndpoint_1, - ReportingClient::Subdomains::EXCLUDE, kGroup_, tomorrow()); - cache()->SetClient(kOrigin_, kEndpoint_2, - ReportingClient::Subdomains::EXCLUDE, kGroup_, tomorrow()); + SetClient(kEndpoint1, ReportingClient::kDefaultPriority, + ReportingClient::kDefaultWeight); + SetClient(kEndpoint2, ReportingClient::kDefaultPriority, + ReportingClient::kDefaultWeight); bool endpoint1_seen = false; bool endpoint2_seen = false; - for (int i = 0; i < kMaxAttempts; i++) { + for (int i = 0; i < kMaxAttempts; ++i) { GURL endpoint_url; bool found_endpoint = endpoint_manager()->FindEndpointForOriginAndGroup( kOrigin_, kGroup_, &endpoint_url); ASSERT_TRUE(found_endpoint); - ASSERT_TRUE(endpoint_url == kEndpoint_1 || endpoint_url == kEndpoint_2); + ASSERT_TRUE(endpoint_url == kEndpoint1 || endpoint_url == kEndpoint2); - if (endpoint_url == kEndpoint_1) + if (endpoint_url == kEndpoint1) endpoint1_seen = true; - else if (endpoint_url == kEndpoint_2) + else if (endpoint_url == kEndpoint2) endpoint2_seen = true; if (endpoint1_seen && endpoint2_seen) @@ -174,5 +182,68 @@ TEST_F(ReportingEndpointManagerTest, RandomEndpoint) { EXPECT_TRUE(endpoint2_seen); } +TEST_F(ReportingEndpointManagerTest, Priority) { + static const GURL kPrimaryEndpoint("https://endpoint1/"); + static const GURL kBackupEndpoint("https://endpoint2/"); + + SetClient(kPrimaryEndpoint, 10, ReportingClient::kDefaultWeight); + SetClient(kBackupEndpoint, 20, ReportingClient::kDefaultWeight); + + GURL endpoint_url; + + bool found_endpoint = endpoint_manager()->FindEndpointForOriginAndGroup( + kOrigin_, kGroup_, &endpoint_url); + ASSERT_TRUE(found_endpoint); + EXPECT_EQ(kPrimaryEndpoint, endpoint_url); + + endpoint_manager()->SetEndpointPending(kPrimaryEndpoint); + + found_endpoint = endpoint_manager()->FindEndpointForOriginAndGroup( + kOrigin_, kGroup_, &endpoint_url); + ASSERT_TRUE(found_endpoint); + EXPECT_EQ(kBackupEndpoint, endpoint_url); + + endpoint_manager()->ClearEndpointPending(kPrimaryEndpoint); + + found_endpoint = endpoint_manager()->FindEndpointForOriginAndGroup( + kOrigin_, kGroup_, &endpoint_url); + ASSERT_TRUE(found_endpoint); + EXPECT_EQ(kPrimaryEndpoint, endpoint_url); +} + +// Note: This test depends on the deterministic mock RandIntCallback set up in +// TestReportingContext, which returns consecutive integers starting at 0 +// (modulo the requested range, plus the requested minimum). +TEST_F(ReportingEndpointManagerTest, Weight) { + static const GURL kEndpoint1("https://endpoint1/"); + static const GURL kEndpoint2("https://endpoint2/"); + + static const int kEndpoint1Weight = 5; + static const int kEndpoint2Weight = 2; + static const int kTotalEndpointWeight = kEndpoint1Weight + kEndpoint2Weight; + + SetClient(kEndpoint1, ReportingClient::kDefaultPriority, kEndpoint1Weight); + SetClient(kEndpoint2, ReportingClient::kDefaultPriority, kEndpoint2Weight); + + int endpoint1_count = 0; + int endpoint2_count = 0; + + for (int i = 0; i < kTotalEndpointWeight; ++i) { + GURL endpoint_url; + bool found_endpoint = endpoint_manager()->FindEndpointForOriginAndGroup( + kOrigin_, kGroup_, &endpoint_url); + ASSERT_TRUE(found_endpoint); + ASSERT_TRUE(endpoint_url == kEndpoint1 || endpoint_url == kEndpoint2); + + if (endpoint_url == kEndpoint1) + ++endpoint1_count; + else if (endpoint_url == kEndpoint2) + ++endpoint2_count; + } + + EXPECT_EQ(kEndpoint1Weight, endpoint1_count); + EXPECT_EQ(kEndpoint2Weight, endpoint2_count); +} + } // namespace } // namespace net diff --git a/chromium/net/reporting/reporting_garbage_collector.cc b/chromium/net/reporting/reporting_garbage_collector.cc index 3cefeaa2524..bb66cb0349d 100644 --- a/chromium/net/reporting/reporting_garbage_collector.cc +++ b/chromium/net/reporting/reporting_garbage_collector.cc @@ -43,9 +43,10 @@ class ReportingGarbageCollectorImpl : public ReportingGarbageCollector, if (timer_->IsRunning()) return; - timer_->Start(FROM_HERE, context_->policy().garbage_collection_interval, - base::Bind(&ReportingGarbageCollectorImpl::CollectGarbage, - base::Unretained(this))); + timer_->Start( + FROM_HERE, context_->policy().garbage_collection_interval, + base::BindRepeating(&ReportingGarbageCollectorImpl::CollectGarbage, + base::Unretained(this))); } private: @@ -86,6 +87,6 @@ std::unique_ptr<ReportingGarbageCollector> ReportingGarbageCollector::Create( return std::make_unique<ReportingGarbageCollectorImpl>(context); } -ReportingGarbageCollector::~ReportingGarbageCollector() {} +ReportingGarbageCollector::~ReportingGarbageCollector() = default; } // namespace net diff --git a/chromium/net/reporting/reporting_header_parser.cc b/chromium/net/reporting/reporting_header_parser.cc index e5db601c748..5512a5b7fe5 100644 --- a/chromium/net/reporting/reporting_header_parser.cc +++ b/chromium/net/reporting/reporting_header_parser.cc @@ -13,6 +13,7 @@ #include "base/time/time.h" #include "base/values.h" #include "net/reporting/reporting_cache.h" +#include "net/reporting/reporting_client.h" #include "net/reporting/reporting_context.h" #include "net/reporting/reporting_delegate.h" @@ -49,9 +50,19 @@ enum class HeaderEndpointOutcome { SET_REJECTED_BY_DELEGATE = 10, SET = 11, + DISCARDED_PRIORITY_NOT_INTEGER = 12, + DISCARDED_WEIGHT_NOT_INTEGER = 13, + DISCARDED_WEIGHT_NOT_POSITIVE = 14, + MAX }; +bool EndpointParsedSuccessfully(HeaderEndpointOutcome outcome) { + return outcome == HeaderEndpointOutcome::REMOVED || + outcome == HeaderEndpointOutcome::SET_REJECTED_BY_DELEGATE || + outcome == HeaderEndpointOutcome::SET; +} + void RecordHeaderEndpointOutcome(HeaderEndpointOutcome outcome) { UMA_HISTOGRAM_ENUMERATION("Reporting.HeaderEndpointOutcome", outcome, HeaderEndpointOutcome::MAX); @@ -62,12 +73,24 @@ const char kIncludeSubdomainsKey[] = "includeSubdomains"; const char kGroupKey[] = "group"; const char kGroupDefaultValue[] = "default"; const char kMaxAgeKey[] = "max-age"; - +const char kPriorityKey[] = "priority"; +const char kWeightKey[] = "weight"; + +// Processes a single endpoint tuple received in a Report-To header. +// +// |origin| is the origin that sent the Report-To header. +// +// |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, ReportingCache* cache, base::TimeTicks now, - const GURL& url, - const base::Value& value) { + const url::Origin& origin, + const base::Value& value, + GURL* endpoint_url_out) { + *endpoint_url_out = GURL(); + const base::DictionaryValue* dict = nullptr; if (!value.GetAsDictionary(&dict)) return HeaderEndpointOutcome::DISCARDED_NOT_DICTIONARY; @@ -105,18 +128,29 @@ HeaderEndpointOutcome ProcessEndpoint(ReportingDelegate* delegate, subdomains = ReportingClient::Subdomains::INCLUDE; } + int priority = ReportingClient::kDefaultPriority; + if (dict->HasKey(kPriorityKey) && !dict->GetInteger(kPriorityKey, &priority)) + return HeaderEndpointOutcome::DISCARDED_PRIORITY_NOT_INTEGER; + + int weight = ReportingClient::kDefaultWeight; + if (dict->HasKey(kWeightKey) && !dict->GetInteger(kWeightKey, &weight)) + return HeaderEndpointOutcome::DISCARDED_WEIGHT_NOT_INTEGER; + if (weight <= 0) + return HeaderEndpointOutcome::DISCARDED_WEIGHT_NOT_POSITIVE; + + *endpoint_url_out = endpoint_url; + if (ttl_sec == 0) { - cache->RemoveClientForOriginAndEndpoint(url::Origin::Create(url), - endpoint_url); + cache->RemoveClientForOriginAndEndpoint(origin, endpoint_url); return HeaderEndpointOutcome::REMOVED; } - url::Origin origin = url::Origin::Create(url); if (!delegate->CanSetClient(origin, endpoint_url)) return HeaderEndpointOutcome::SET_REJECTED_BY_DELEGATE; cache->SetClient(origin, endpoint_url, subdomains, group, - now + base::TimeDelta::FromSeconds(ttl_sec)); + now + base::TimeDelta::FromSeconds(ttl_sec), priority, + weight); return HeaderEndpointOutcome::SET; } @@ -150,19 +184,37 @@ void ReportingHeaderParser::ParseHeader(ReportingContext* context, return; } - const base::ListValue* list = nullptr; - bool is_list = value->GetAsList(&list); + const base::ListValue* endpoint_list = nullptr; + bool is_list = value->GetAsList(&endpoint_list); DCHECK(is_list); ReportingDelegate* delegate = context->delegate(); ReportingCache* cache = context->cache(); + + url::Origin origin = url::Origin::Create(url); + + std::vector<GURL> old_endpoints; + cache->GetEndpointsForOrigin(origin, &old_endpoints); + + std::set<GURL> new_endpoints; + base::TimeTicks now = context->tick_clock()->NowTicks(); - for (size_t i = 0; i < list->GetSize(); i++) { + for (size_t i = 0; i < endpoint_list->GetSize(); i++) { const base::Value* endpoint = nullptr; - bool got_endpoint = list->Get(i, &endpoint); + bool got_endpoint = endpoint_list->Get(i, &endpoint); DCHECK(got_endpoint); - RecordHeaderEndpointOutcome( - ProcessEndpoint(delegate, cache, now, url, *endpoint)); + GURL endpoint_url; + HeaderEndpointOutcome outcome = + ProcessEndpoint(delegate, cache, now, origin, *endpoint, &endpoint_url); + if (EndpointParsedSuccessfully(outcome)) + new_endpoints.insert(endpoint_url); + RecordHeaderEndpointOutcome(outcome); + } + + // Remove any endpoints that weren't specified in the current header(s). + for (const GURL& old_endpoint : old_endpoints) { + if (new_endpoints.count(old_endpoint) == 0u) + cache->RemoveClientForOriginAndEndpoint(origin, old_endpoint); } } diff --git a/chromium/net/reporting/reporting_header_parser_fuzzer.cc b/chromium/net/reporting/reporting_header_parser_fuzzer.cc index 1c31b9ec17b..470d496a633 100644 --- a/chromium/net/reporting/reporting_header_parser_fuzzer.cc +++ b/chromium/net/reporting/reporting_header_parser_fuzzer.cc @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/time/default_clock.h" +#include "base/time/default_tick_clock.h" #include "base/time/time.h" #include "net/reporting/reporting_cache.h" #include "net/reporting/reporting_client.h" @@ -24,7 +26,9 @@ namespace net_reporting_header_parser_fuzzer { void FuzzReportingHeaderParser(const std::string& data, const net::ReportingPolicy& policy) { - net::TestReportingContext context(policy); + net::TestReportingContext context(base::DefaultClock::GetInstance(), + base::DefaultTickClock::GetInstance(), + policy); net::ReportingHeaderParser::ParseHeader(&context, kUrl_, data.c_str()); std::vector<const net::ReportingClient*> clients; context.cache()->GetClients(&clients); diff --git a/chromium/net/reporting/reporting_header_parser_unittest.cc b/chromium/net/reporting/reporting_header_parser_unittest.cc index 7d8710ad936..151675e6d12 100644 --- a/chromium/net/reporting/reporting_header_parser_unittest.cc +++ b/chromium/net/reporting/reporting_header_parser_unittest.cc @@ -49,6 +49,16 @@ TEST_F(ReportingHeaderParserTest, Invalid) { // Note that a non-boolean includeSubdomains field is *not* invalid, per // the spec. + {"{\"url\":\"https://endpoint/\",\"max-age\":1,\"priority\":\"\"}", + "non-integer priority"}, + + {"{\"url\":\"https://endpoint/\",\"max-age\":1,\"weight\":\"\"}", + "non-integer weight"}, + {"{\"url\":\"https://endpoint/\",\"max-age\":1,\"weight\":-1}", + "negative weight"}, + {"{\"url\":\"https://endpoint/\",\"max-age\":1,\"weight\":0}", + "zero weight"}, + {"[{\"url\":\"https://a/\",\"max-age\":1}," "{\"url\":\"https://b/\",\"max-age\":1}]", "wrapped in list"}}; @@ -78,6 +88,21 @@ TEST_F(ReportingHeaderParserTest, Valid) { EXPECT_EQ(kEndpoint_, client->endpoint); EXPECT_EQ(ReportingClient::Subdomains::EXCLUDE, client->subdomains); EXPECT_EQ(86400, (client->expires - tick_clock()->NowTicks()).InSeconds()); + EXPECT_EQ(ReportingClient::kDefaultPriority, client->priority); + EXPECT_EQ(ReportingClient::kDefaultWeight, client->weight); +} + +TEST_F(ReportingHeaderParserTest, ZeroMaxAge) { + cache()->SetClient( + kOrigin_, kEndpoint_, ReportingClient::Subdomains::EXCLUDE, kGroup_, + tick_clock()->NowTicks() + base::TimeDelta::FromDays(1), + ReportingClient::kDefaultPriority, ReportingClient::kDefaultWeight); + + ReportingHeaderParser::ParseHeader( + context(), kUrl_, + "{\"url\":\"" + kEndpoint_.spec() + "\",\"max-age\":0}"); + + EXPECT_EQ(nullptr, FindClientInCache(cache(), kOrigin_, kEndpoint_)); } TEST_F(ReportingHeaderParserTest, Subdomains) { @@ -92,16 +117,57 @@ TEST_F(ReportingHeaderParserTest, Subdomains) { EXPECT_EQ(ReportingClient::Subdomains::INCLUDE, client->subdomains); } -TEST_F(ReportingHeaderParserTest, ZeroMaxAge) { - cache()->SetClient(kOrigin_, kEndpoint_, ReportingClient::Subdomains::EXCLUDE, - kGroup_, - tick_clock()->NowTicks() + base::TimeDelta::FromDays(1)); +TEST_F(ReportingHeaderParserTest, PriorityPositive) { + ReportingHeaderParser::ParseHeader(context(), kUrl_, + "{\"url\":\"" + kEndpoint_.spec() + + "\",\"max-age\":86400," + "\"priority\":2}"); + + const ReportingClient* client = + FindClientInCache(cache(), kOrigin_, kEndpoint_); + ASSERT_TRUE(client); + EXPECT_EQ(2, client->priority); +} + +TEST_F(ReportingHeaderParserTest, PriorityNegative) { + ReportingHeaderParser::ParseHeader(context(), kUrl_, + "{\"url\":\"" + kEndpoint_.spec() + + "\",\"max-age\":86400," + "\"priority\":-2}"); + + const ReportingClient* client = + FindClientInCache(cache(), kOrigin_, kEndpoint_); + ASSERT_TRUE(client); + EXPECT_EQ(-2, client->priority); +} + +TEST_F(ReportingHeaderParserTest, Weight) { + ReportingHeaderParser::ParseHeader(context(), kUrl_, + "{\"url\":\"" + kEndpoint_.spec() + + "\",\"max-age\":86400," + "\"weight\":3}"); + + const ReportingClient* client = + FindClientInCache(cache(), kOrigin_, kEndpoint_); + ASSERT_TRUE(client); + EXPECT_EQ(3, client->weight); +} + +TEST_F(ReportingHeaderParserTest, RemoveOld) { + static const GURL kDifferentEndpoint_ = GURL("https://endpoint2/"); ReportingHeaderParser::ParseHeader( context(), kUrl_, - "{\"url\":\"" + kEndpoint_.spec() + "\",\"max-age\":0}"); + "{\"url\":\"" + kEndpoint_.spec() + "\",\"max-age\":86400}"); - EXPECT_EQ(nullptr, FindClientInCache(cache(), kOrigin_, kEndpoint_)); + EXPECT_TRUE(FindClientInCache(cache(), kOrigin_, kEndpoint_)); + + ReportingHeaderParser::ParseHeader( + context(), kUrl_, + "{\"url\":\"" + kDifferentEndpoint_.spec() + "\",\"max-age\":86400}"); + + EXPECT_FALSE(FindClientInCache(cache(), kOrigin_, kEndpoint_)); + EXPECT_TRUE(FindClientInCache(cache(), kOrigin_, kDifferentEndpoint_)); } } // namespace diff --git a/chromium/net/reporting/reporting_network_change_observer.cc b/chromium/net/reporting/reporting_network_change_observer.cc index 2141efaafb1..20e33a303eb 100644 --- a/chromium/net/reporting/reporting_network_change_observer.cc +++ b/chromium/net/reporting/reporting_network_change_observer.cc @@ -60,6 +60,6 @@ ReportingNetworkChangeObserver::Create(ReportingContext* context) { return std::make_unique<ReportingNetworkChangeObserverImpl>(context); } -ReportingNetworkChangeObserver::~ReportingNetworkChangeObserver() {} +ReportingNetworkChangeObserver::~ReportingNetworkChangeObserver() = default; } // namespace net diff --git a/chromium/net/reporting/reporting_network_change_observer_unittest.cc b/chromium/net/reporting/reporting_network_change_observer_unittest.cc index 8350e8dd34d..ce114d1ab3b 100644 --- a/chromium/net/reporting/reporting_network_change_observer_unittest.cc +++ b/chromium/net/reporting/reporting_network_change_observer_unittest.cc @@ -32,6 +32,13 @@ class ReportingNetworkChangeObserverTest : public ReportingTestBase { base::RunLoop().RunUntilIdle(); } + void SetClient() { + cache()->SetClient( + kOrigin_, kEndpoint_, ReportingClient::Subdomains::EXCLUDE, kGroup_, + tick_clock()->NowTicks() + base::TimeDelta::FromDays(7), + ReportingClient::kDefaultPriority, ReportingClient::kDefaultWeight); + } + size_t report_count() { std::vector<const ReportingReport*> reports; cache()->GetReports(&reports); @@ -60,9 +67,7 @@ TEST_F(ReportingNetworkChangeObserverTest, ClearNothing) { cache()->AddReport(kUrl_, kGroup_, kType_, std::make_unique<base::DictionaryValue>(), tick_clock()->NowTicks(), 0); - cache()->SetClient(kOrigin_, kEndpoint_, ReportingClient::Subdomains::EXCLUDE, - kGroup_, - tick_clock()->NowTicks() + base::TimeDelta::FromDays(7)); + SetClient(); ASSERT_EQ(1u, report_count()); ASSERT_EQ(1u, client_count()); @@ -81,9 +86,7 @@ TEST_F(ReportingNetworkChangeObserverTest, ClearReports) { cache()->AddReport(kUrl_, kGroup_, kType_, std::make_unique<base::DictionaryValue>(), tick_clock()->NowTicks(), 0); - cache()->SetClient(kOrigin_, kEndpoint_, ReportingClient::Subdomains::EXCLUDE, - kGroup_, - tick_clock()->NowTicks() + base::TimeDelta::FromDays(7)); + SetClient(); ASSERT_EQ(1u, report_count()); ASSERT_EQ(1u, client_count()); @@ -102,9 +105,7 @@ TEST_F(ReportingNetworkChangeObserverTest, ClearClients) { cache()->AddReport(kUrl_, kGroup_, kType_, std::make_unique<base::DictionaryValue>(), tick_clock()->NowTicks(), 0); - cache()->SetClient(kOrigin_, kEndpoint_, ReportingClient::Subdomains::EXCLUDE, - kGroup_, - tick_clock()->NowTicks() + base::TimeDelta::FromDays(7)); + SetClient(); ASSERT_EQ(1u, report_count()); ASSERT_EQ(1u, client_count()); @@ -123,9 +124,7 @@ TEST_F(ReportingNetworkChangeObserverTest, ClearReportsAndClients) { cache()->AddReport(kUrl_, kGroup_, kType_, std::make_unique<base::DictionaryValue>(), tick_clock()->NowTicks(), 0); - cache()->SetClient(kOrigin_, kEndpoint_, ReportingClient::Subdomains::EXCLUDE, - kGroup_, - tick_clock()->NowTicks() + base::TimeDelta::FromDays(7)); + SetClient(); ASSERT_EQ(1u, report_count()); ASSERT_EQ(1u, client_count()); diff --git a/chromium/net/reporting/reporting_observer.cc b/chromium/net/reporting/reporting_observer.cc index 5e8d778a61b..a37548c73c8 100644 --- a/chromium/net/reporting/reporting_observer.cc +++ b/chromium/net/reporting/reporting_observer.cc @@ -8,8 +8,8 @@ namespace net { void ReportingObserver::OnCacheUpdated() {} -ReportingObserver::ReportingObserver() {} +ReportingObserver::ReportingObserver() = default; -ReportingObserver::~ReportingObserver() {} +ReportingObserver::~ReportingObserver() = default; } // namespace net diff --git a/chromium/net/reporting/reporting_persister.cc b/chromium/net/reporting/reporting_persister.cc deleted file mode 100644 index 198ee76b98b..00000000000 --- a/chromium/net/reporting/reporting_persister.cc +++ /dev/null @@ -1,321 +0,0 @@ -// Copyright 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/reporting/reporting_persister.h" - -#include <utility> -#include <vector> - -#include "base/strings/string_number_conversions.h" -#include "base/time/clock.h" -#include "base/time/tick_clock.h" -#include "base/time/time.h" -#include "base/timer/timer.h" -#include "base/values.h" -#include "net/reporting/reporting_cache.h" -#include "net/reporting/reporting_client.h" -#include "net/reporting/reporting_context.h" -#include "net/reporting/reporting_observer.h" -#include "net/reporting/reporting_policy.h" -#include "net/reporting/reporting_report.h" - -namespace net { -namespace { - -std::unique_ptr<base::Value> SerializeOrigin(const url::Origin& origin) { - auto serialized = std::make_unique<base::DictionaryValue>(); - - serialized->SetString("scheme", origin.scheme()); - serialized->SetString("host", origin.host()); - serialized->SetInteger("port", origin.port()); - serialized->SetString("suborigin", origin.suborigin()); - - return std::move(serialized); -} - -bool DeserializeOrigin(const base::DictionaryValue& serialized, - url::Origin* origin_out) { - std::string scheme; - if (!serialized.GetString("scheme", &scheme)) - return false; - - std::string host; - if (!serialized.GetString("host", &host)) - return false; - - int port_int; - if (!serialized.GetInteger("port", &port_int)) - return false; - uint16_t port = static_cast<uint16_t>(port_int); - if (port_int != port) - return false; - - std::string suborigin; - if (!serialized.GetString("suborigin", &suborigin)) - return false; - - *origin_out = url::Origin::CreateFromNormalizedTupleWithSuborigin( - scheme, host, port, suborigin); - return true; -} - -class ReportingPersisterImpl : public ReportingPersister { - public: - ReportingPersisterImpl(ReportingContext* context) : context_(context) {} - - // ReportingPersister implementation: - - ~ReportingPersisterImpl() override {} - - private: - std::string SerializeTicks(base::TimeTicks time_ticks) { - base::Time time = time_ticks - tick_clock()->NowTicks() + clock()->Now(); - return base::Int64ToString(time.ToInternalValue()); - } - - bool DeserializeTicks(const std::string& serialized, - base::TimeTicks* time_ticks_out) { - int64_t internal; - if (!base::StringToInt64(serialized, &internal)) - return false; - - base::Time time = base::Time::FromInternalValue(internal); - *time_ticks_out = time - clock()->Now() + tick_clock()->NowTicks(); - return true; - } - - std::unique_ptr<base::Value> SerializeReport(const ReportingReport& report) { - auto serialized = std::make_unique<base::DictionaryValue>(); - - serialized->SetString("url", report.url.spec()); - serialized->SetString("group", report.group); - serialized->SetString("type", report.type); - serialized->Set("body", report.body->CreateDeepCopy()); - serialized->SetString("queued", SerializeTicks(report.queued)); - serialized->SetInteger("attempts", report.attempts); - - return std::move(serialized); - } - - bool DeserializeReport(const base::DictionaryValue& report) { - std::string url_string; - if (!report.GetString("url", &url_string)) - return false; - GURL url(url_string); - if (!url.is_valid()) - return false; - - std::string group; - if (!report.GetString("group", &group)) - return false; - - std::string type; - if (!report.GetString("type", &type)) - return false; - - const base::Value* body_original; - if (!report.Get("body", &body_original)) - return false; - std::unique_ptr<base::Value> body = body_original->CreateDeepCopy(); - - std::string queued_string; - if (!report.GetString("queued", &queued_string)) - return false; - base::TimeTicks queued; - if (!DeserializeTicks(queued_string, &queued)) - return false; - - int attempts; - if (!report.GetInteger("attempts", &attempts)) - return false; - if (attempts < 0) - return false; - - cache()->AddReport(url, group, type, std::move(body), queued, attempts); - return true; - } - - std::unique_ptr<base::Value> SerializeReports() { - std::vector<const ReportingReport*> reports; - cache()->GetReports(&reports); - - auto serialized = std::make_unique<base::ListValue>(); - for (const ReportingReport* report : reports) - serialized->Append(SerializeReport(*report)); - - return std::move(serialized); - } - - bool DeserializeReports(const base::ListValue& reports) { - for (size_t i = 0; i < reports.GetSize(); ++i) { - const base::DictionaryValue* report; - if (!reports.GetDictionary(i, &report)) - return false; - if (!DeserializeReport(*report)) - return false; - } - - return true; - } - - std::unique_ptr<base::Value> SerializeClient(const ReportingClient& client) { - auto serialized = std::make_unique<base::DictionaryValue>(); - - serialized->Set("origin", SerializeOrigin(client.origin)); - serialized->SetString("endpoint", client.endpoint.spec()); - serialized->SetBoolean( - "subdomains", - client.subdomains == ReportingClient::Subdomains::INCLUDE); - serialized->SetString("group", client.group); - serialized->SetString("expires", SerializeTicks(client.expires)); - - return std::move(serialized); - } - - bool DeserializeClient(const base::DictionaryValue& client) { - const base::DictionaryValue* origin_value; - if (!client.GetDictionary("origin", &origin_value)) - return false; - url::Origin origin; - if (!DeserializeOrigin(*origin_value, &origin)) - return false; - - std::string endpoint_string; - if (!client.GetString("endpoint", &endpoint_string)) - return false; - GURL endpoint(endpoint_string); - if (!endpoint.is_valid()) - return false; - - bool subdomains_bool; - if (!client.GetBoolean("subdomains", &subdomains_bool)) - return false; - ReportingClient::Subdomains subdomains = - subdomains_bool ? ReportingClient::Subdomains::INCLUDE - : ReportingClient::Subdomains::EXCLUDE; - - std::string group; - if (!client.GetString("group", &group)) - return false; - - std::string expires_string; - if (!client.GetString("expires", &expires_string)) - return false; - base::TimeTicks expires; - if (!DeserializeTicks(expires_string, &expires)) - return false; - - cache()->SetClient(origin, endpoint, subdomains, group, expires); - return true; - } - - std::unique_ptr<base::Value> SerializeClients() { - std::vector<const ReportingClient*> clients; - cache()->GetClients(&clients); - - auto serialized = std::make_unique<base::ListValue>(); - for (const ReportingClient* client : clients) - serialized->Append(SerializeClient(*client)); - - return std::move(serialized); - } - - bool DeserializeClients(const base::ListValue& clients) { - for (size_t i = 0; i < clients.GetSize(); ++i) { - const base::DictionaryValue* client; - if (!clients.GetDictionary(i, &client)) - return false; - if (!DeserializeClient(*client)) - return false; - } - - return true; - } - - static const int kSupportedVersion = 1; - - std::unique_ptr<base::Value> Serialize() { - auto serialized = std::make_unique<base::DictionaryValue>(); - - serialized->SetInteger("reporting_serialized_cache_version", - kSupportedVersion); - - bool persist_reports = policy().persist_reports_across_restarts; - serialized->SetBoolean("includes_reports", persist_reports); - if (persist_reports) - serialized->Set("reports", SerializeReports()); - - bool persist_clients = policy().persist_clients_across_restarts; - serialized->SetBoolean("includes_clients", persist_clients); - if (persist_clients) - serialized->Set("clients", SerializeClients()); - - return std::move(serialized); - } - - bool Deserialize(const base::Value& serialized_value) { - std::vector<const ReportingReport*> reports; - cache()->GetReports(&reports); - DCHECK(reports.empty()); - - std::vector<const ReportingClient*> clients; - cache()->GetClients(&clients); - DCHECK(clients.empty()); - - int version; - - const base::DictionaryValue* serialized; - if (!serialized_value.GetAsDictionary(&serialized)) - return false; - - if (!serialized->GetInteger("reporting_serialized_cache_version", &version)) - return false; - if (version != kSupportedVersion) - return false; - - bool includes_reports; - bool includes_clients; - if (!serialized->GetBoolean("includes_reports", &includes_reports) || - !serialized->GetBoolean("includes_clients", &includes_clients)) { - return false; - } - - if (includes_reports) { - const base::ListValue* reports; - if (!serialized->GetList("reports", &reports)) - return false; - if (!DeserializeReports(*reports)) - return false; - } - - if (includes_clients) { - const base::ListValue* clients; - if (!serialized->GetList("clients", &clients)) - return false; - if (!DeserializeClients(*clients)) - return false; - } - - return true; - } - - const ReportingPolicy& policy() { return context_->policy(); } - base::Clock* clock() { return context_->clock(); } - base::TickClock* tick_clock() { return context_->tick_clock(); } - ReportingCache* cache() { return context_->cache(); } - - ReportingContext* context_; -}; - -} // namespace - -// static -std::unique_ptr<ReportingPersister> ReportingPersister::Create( - ReportingContext* context) { - return std::make_unique<ReportingPersisterImpl>(context); -} - -ReportingPersister::~ReportingPersister() {} - -} // namespace net diff --git a/chromium/net/reporting/reporting_persister.h b/chromium/net/reporting/reporting_persister.h deleted file mode 100644 index 40414f0c9e1..00000000000 --- a/chromium/net/reporting/reporting_persister.h +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 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 NET_REPORTING_REPORTING_PERSISTER_H_ -#define NET_REPORTING_REPORTING_PERSISTER_H_ - -#include <memory> - -#include "base/callback.h" -#include "net/base/net_export.h" - -namespace net { - -class ReportingContext; - -// Will persist the state of the Reporting system to (reasonably) stable -// storage using an as-yet-unwritten persistence mechanism within //net. -class NET_EXPORT ReportingPersister { - public: - // Creates a ReportingPersister. |context| must outlive the persister. - static std::unique_ptr<ReportingPersister> Create(ReportingContext* context); - - virtual ~ReportingPersister(); -}; - -} // namespace net - -#endif // NET_REPORTING_REPORTING_PERSISTER_H_ diff --git a/chromium/net/reporting/reporting_persister_unittest.cc b/chromium/net/reporting/reporting_persister_unittest.cc deleted file mode 100644 index 547c7208382..00000000000 --- a/chromium/net/reporting/reporting_persister_unittest.cc +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 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/reporting/reporting_persister.h" - -#include "base/json/json_writer.h" -#include "base/test/simple_test_clock.h" -#include "base/test/simple_test_tick_clock.h" -#include "base/time/time.h" -#include "base/timer/mock_timer.h" -#include "base/values.h" -#include "net/base/test_completion_callback.h" -#include "net/reporting/reporting_cache.h" -#include "net/reporting/reporting_client.h" -#include "net/reporting/reporting_policy.h" -#include "net/reporting/reporting_report.h" -#include "net/reporting/reporting_test_util.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace net { -namespace { - -class ReportingPersisterTest : public ReportingTestBase { - protected: - const GURL kUrl_ = GURL("https://origin/path"); - const url::Origin kOrigin_ = url::Origin::Create(kUrl_); - const GURL kEndpoint_ = GURL("https://endpoint/"); - const std::string kGroup_ = "group"; - const std::string kType_ = "default"; -}; - -// Disabled because the Persister has no persistence layer to use yet. -TEST_F(ReportingPersisterTest, DISABLED_Test) { - ReportingPolicy policy; - policy.persist_reports_across_restarts = true; - policy.persist_clients_across_restarts = true; - // Make sure reports don't expire on our simulated restart. - policy.max_report_age = base::TimeDelta::FromDays(30); - UsePolicy(policy); - - static const int kAttempts = 3; - - base::DictionaryValue body; - body.SetString("key", "value"); - - cache()->AddReport(kUrl_, kGroup_, kType_, body.CreateDeepCopy(), - tick_clock()->NowTicks(), kAttempts); - cache()->SetClient(kOrigin_, kEndpoint_, ReportingClient::Subdomains::EXCLUDE, - kGroup_, - tick_clock()->NowTicks() + base::TimeDelta::FromDays(1)); - - // TODO: Actually save data, once it's possible. - - SimulateRestart(/* delta= */ base::TimeDelta::FromHours(1), - /* delta_ticks= */ base::TimeDelta::FromHours(-3)); - - // TODO: Actually load data, once it's possible. - - std::vector<const ReportingReport*> reports; - cache()->GetReports(&reports); - ASSERT_EQ(1u, reports.size()); - EXPECT_EQ(kUrl_, reports[0]->url); - EXPECT_EQ(kGroup_, reports[0]->group); - EXPECT_EQ(kType_, reports[0]->type); - EXPECT_EQ(body, *reports[0]->body); - EXPECT_EQ(tick_clock()->NowTicks() - base::TimeDelta::FromHours(1), - reports[0]->queued); - EXPECT_EQ(kAttempts, reports[0]->attempts); - - const ReportingClient* client = - FindClientInCache(cache(), kOrigin_, kEndpoint_); - ASSERT_TRUE(client); - EXPECT_EQ(ReportingClient::Subdomains::EXCLUDE, client->subdomains); - EXPECT_EQ(kGroup_, client->group); - EXPECT_EQ(tick_clock()->NowTicks() + base::TimeDelta::FromDays(1) - - base::TimeDelta::FromHours(1), - client->expires); -} - -// TODO(juliatuttle): Test asynchronous behavior. - -} // namespace -} // namespace net diff --git a/chromium/net/reporting/reporting_policy.cc b/chromium/net/reporting/reporting_policy.cc index 62b7f68ce56..007eb89bd9a 100644 --- a/chromium/net/reporting/reporting_policy.cc +++ b/chromium/net/reporting/reporting_policy.cc @@ -29,21 +29,8 @@ ReportingPolicy::ReportingPolicy() endpoint_backoff_policy.always_use_initial_delay = false; } -ReportingPolicy::ReportingPolicy(const ReportingPolicy& other) - : max_report_count(other.max_report_count), - max_client_count(other.max_client_count), - delivery_interval(other.delivery_interval), - endpoint_backoff_policy(other.endpoint_backoff_policy), - persistence_interval(other.persistence_interval), - persist_reports_across_restarts(other.persist_reports_across_restarts), - persist_clients_across_restarts(other.persist_clients_across_restarts), - garbage_collection_interval(other.garbage_collection_interval), - max_report_age(other.max_report_age), - max_report_attempts(other.max_report_attempts), - clear_reports_on_network_changes(other.clear_reports_on_network_changes), - clear_clients_on_network_changes(other.clear_clients_on_network_changes) { -} +ReportingPolicy::ReportingPolicy(const ReportingPolicy& other) = default; -ReportingPolicy::~ReportingPolicy() {} +ReportingPolicy::~ReportingPolicy() = default; } // namespace net diff --git a/chromium/net/reporting/reporting_service.cc b/chromium/net/reporting/reporting_service.cc index e72eb7520cd..59976e23224 100644 --- a/chromium/net/reporting/reporting_service.cc +++ b/chromium/net/reporting/reporting_service.cc @@ -16,7 +16,7 @@ #include "net/reporting/reporting_context.h" #include "net/reporting/reporting_delegate.h" #include "net/reporting/reporting_header_parser.h" -#include "net/reporting/reporting_persister.h" +#include "net/reporting/reporting_uploader.h" #include "url/gurl.h" namespace net { @@ -28,12 +28,17 @@ class ReportingServiceImpl : public ReportingService { ReportingServiceImpl(std::unique_ptr<ReportingContext> context) : context_(std::move(context)) {} - ~ReportingServiceImpl() override {} + // ReportingService implementation: + + ~ReportingServiceImpl() override = default; void QueueReport(const GURL& url, const std::string& group, const std::string& type, std::unique_ptr<const base::Value> body) override { + DCHECK(context_); + DCHECK(context_->delegate()); + if (!context_->delegate()->CanQueueReport(url::Origin::Create(url))) return; @@ -46,13 +51,17 @@ class ReportingServiceImpl : public ReportingService { ReportingHeaderParser::ParseHeader(context_.get(), url, header_value); } - void RemoveBrowsingData( - int data_type_mask, - base::Callback<bool(const GURL&)> origin_filter) override { + void RemoveBrowsingData(int data_type_mask, + const base::RepeatingCallback<bool(const GURL&)>& + origin_filter) override { ReportingBrowsingDataRemover::RemoveBrowsingData( context_->cache(), data_type_mask, origin_filter); } + bool RequestIsUpload(const URLRequest& request) override { + return context_->uploader()->RequestIsUpload(request); + } + private: std::unique_ptr<ReportingContext> context_; @@ -61,7 +70,7 @@ class ReportingServiceImpl : public ReportingService { } // namespace -ReportingService::~ReportingService() {} +ReportingService::~ReportingService() = default; // static std::unique_ptr<ReportingService> ReportingService::Create( diff --git a/chromium/net/reporting/reporting_service.h b/chromium/net/reporting/reporting_service.h index 45f9ac7830f..aa7dc40e369 100644 --- a/chromium/net/reporting/reporting_service.h +++ b/chromium/net/reporting/reporting_service.h @@ -22,6 +22,7 @@ namespace net { class ReportingContext; struct ReportingPolicy; +class URLRequest; class URLRequestContext; // The external interface to the Reporting system, used by the embedder of //net @@ -63,7 +64,11 @@ class NET_EXPORT ReportingService { // ReportingBrowsingDataRemover for more details. virtual void RemoveBrowsingData( int data_type_mask, - base::Callback<bool(const GURL&)> origin_filter) = 0; + const base::RepeatingCallback<bool(const GURL&)>& origin_filter) = 0; + + // Checks whether |request| is a Reporting upload, to avoid loops of reporting + // about report uploads. + virtual bool RequestIsUpload(const URLRequest& request) = 0; protected: ReportingService() {} diff --git a/chromium/net/reporting/reporting_service_unittest.cc b/chromium/net/reporting/reporting_service_unittest.cc index d8978c81f27..24ebceda354 100644 --- a/chromium/net/reporting/reporting_service_unittest.cc +++ b/chromium/net/reporting/reporting_service_unittest.cc @@ -30,7 +30,8 @@ class ReportingServiceTest : public ::testing::Test { const std::string kType_ = "type"; ReportingServiceTest() - : context_(new TestReportingContext(ReportingPolicy())), + : context_( + new TestReportingContext(&clock_, &tick_clock_, ReportingPolicy())), service_( ReportingService::CreateForTesting(base::WrapUnique(context_))) {} @@ -38,6 +39,9 @@ class ReportingServiceTest : public ::testing::Test { ReportingService* service() { return service_.get(); } private: + base::SimpleTestClock clock_; + base::SimpleTestTickClock tick_clock_; + TestReportingContext* context_; std::unique_ptr<ReportingService> service_; }; diff --git a/chromium/net/reporting/reporting_test_util.cc b/chromium/net/reporting/reporting_test_util.cc index d5f0a8ce755..17671b21a80 100644 --- a/chromium/net/reporting/reporting_test_util.cc +++ b/chromium/net/reporting/reporting_test_util.cc @@ -10,17 +10,18 @@ #include "base/bind.h" #include "base/json/json_reader.h" +#include "base/logging.h" #include "base/memory/ptr_util.h" #include "base/test/simple_test_clock.h" #include "base/test/simple_test_tick_clock.h" #include "base/timer/mock_timer.h" +#include "net/base/rand_callback.h" #include "net/reporting/reporting_cache.h" #include "net/reporting/reporting_client.h" #include "net/reporting/reporting_context.h" #include "net/reporting/reporting_delegate.h" #include "net/reporting/reporting_delivery_agent.h" #include "net/reporting/reporting_garbage_collector.h" -#include "net/reporting/reporting_persister.h" #include "net/reporting/reporting_policy.h" #include "net/reporting/reporting_uploader.h" #include "testing/gtest/include/gtest/gtest.h" @@ -33,17 +34,16 @@ namespace { class PendingUploadImpl : public TestReportingUploader::PendingUpload { public: - PendingUploadImpl( - const GURL& url, - const std::string& json, - const ReportingUploader::Callback& callback, - const base::Callback<void(PendingUpload*)>& complete_callback) + PendingUploadImpl(const GURL& url, + const std::string& json, + ReportingUploader::UploadCallback callback, + base::OnceCallback<void(PendingUpload*)> complete_callback) : url_(url), json_(json), - callback_(callback), - complete_callback_(complete_callback) {} + callback_(std::move(callback)), + complete_callback_(std::move(complete_callback)) {} - ~PendingUploadImpl() override {} + ~PendingUploadImpl() override = default; // PendingUpload implementationP: const GURL& url() const override { return url_; } @@ -53,16 +53,16 @@ class PendingUploadImpl : public TestReportingUploader::PendingUpload { } void Complete(ReportingUploader::Outcome outcome) override { - callback_.Run(outcome); + std::move(callback_).Run(outcome); // Deletes |this|. - complete_callback_.Run(this); + std::move(complete_callback_).Run(this); } private: GURL url_; std::string json_; - ReportingUploader::Callback callback_; - base::Callback<void(PendingUpload*)> complete_callback_; + ReportingUploader::UploadCallback callback_; + base::OnceCallback<void(PendingUpload*)> complete_callback_; }; void ErasePendingUpload( @@ -91,22 +91,28 @@ const ReportingClient* FindClientInCache(const ReportingCache* cache, return nullptr; } -TestReportingUploader::PendingUpload::~PendingUpload() {} -TestReportingUploader::PendingUpload::PendingUpload() {} +TestReportingUploader::PendingUpload::~PendingUpload() = default; +TestReportingUploader::PendingUpload::PendingUpload() = default; -TestReportingUploader::TestReportingUploader() {} -TestReportingUploader::~TestReportingUploader() {} +TestReportingUploader::TestReportingUploader() = default; +TestReportingUploader::~TestReportingUploader() = default; void TestReportingUploader::StartUpload(const GURL& url, const std::string& json, - const Callback& callback) { + UploadCallback callback) { pending_uploads_.push_back(std::make_unique<PendingUploadImpl>( - url, json, callback, base::Bind(&ErasePendingUpload, &pending_uploads_))); + url, json, std::move(callback), + base::BindOnce(&ErasePendingUpload, &pending_uploads_))); } -TestReportingDelegate::TestReportingDelegate() {} +bool TestReportingUploader::RequestIsUpload(const URLRequest& request) { + NOTIMPLEMENTED(); + return true; +} + +TestReportingDelegate::TestReportingDelegate() = default; -TestReportingDelegate::~TestReportingDelegate() {} +TestReportingDelegate::~TestReportingDelegate() = default; bool TestReportingDelegate::CanQueueReport(const url::Origin& origin) const { return true; @@ -126,12 +132,18 @@ bool TestReportingDelegate::CanUseClient(const url::Origin& origin, return true; } -TestReportingContext::TestReportingContext(const ReportingPolicy& policy) - : ReportingContext(policy, - std::make_unique<base::SimpleTestClock>(), - std::make_unique<base::SimpleTestTickClock>(), - std::make_unique<TestReportingUploader>(), - std::make_unique<TestReportingDelegate>()), +TestReportingContext::TestReportingContext(base::Clock* clock, + base::TickClock* tick_clock, + const ReportingPolicy& policy) + : ReportingContext( + policy, + clock, + tick_clock, + base::BindRepeating(&TestReportingContext::RandIntCallback, + base::Unretained(this)), + std::make_unique<TestReportingUploader>(), + std::make_unique<TestReportingDelegate>()), + rand_counter_(0), delivery_timer_(new base::MockTimer(/* retain_user_task= */ false, /* is_repeating= */ false)), garbage_collection_timer_( @@ -147,6 +159,11 @@ TestReportingContext::~TestReportingContext() { garbage_collection_timer_ = nullptr; } +int TestReportingContext::RandIntCallback(int min, int max) { + DCHECK_LE(min, max); + return min + (rand_counter_++ % (max - min + 1)); +} + ReportingTestBase::ReportingTestBase() { // For tests, disable jitter. ReportingPolicy policy; @@ -155,7 +172,7 @@ ReportingTestBase::ReportingTestBase() { CreateContext(policy, base::Time::Now(), base::TimeTicks::Now()); } -ReportingTestBase::~ReportingTestBase() {} +ReportingTestBase::~ReportingTestBase() = default; void ReportingTestBase::UsePolicy(const ReportingPolicy& new_policy) { CreateContext(new_policy, clock()->Now(), tick_clock()->NowTicks()); @@ -170,7 +187,8 @@ void ReportingTestBase::SimulateRestart(base::TimeDelta delta, void ReportingTestBase::CreateContext(const ReportingPolicy& policy, base::Time now, base::TimeTicks now_ticks) { - context_ = std::make_unique<TestReportingContext>(policy); + context_ = + std::make_unique<TestReportingContext>(&clock_, &tick_clock_, policy); clock()->SetNow(now); tick_clock()->SetNowTicks(now_ticks); } diff --git a/chromium/net/reporting/reporting_test_util.h b/chromium/net/reporting/reporting_test_util.h index 488284ee7e5..f2dff8fb6a1 100644 --- a/chromium/net/reporting/reporting_test_util.h +++ b/chromium/net/reporting/reporting_test_util.h @@ -10,6 +10,8 @@ #include <vector> #include "base/macros.h" +#include "base/test/simple_test_clock.h" +#include "base/test/simple_test_tick_clock.h" #include "net/reporting/reporting_context.h" #include "net/reporting/reporting_delegate.h" #include "net/reporting/reporting_uploader.h" @@ -66,9 +68,12 @@ class TestReportingUploader : public ReportingUploader { } // ReportingUploader implementation: + void StartUpload(const GURL& url, const std::string& json, - const Callback& callback) override; + UploadCallback callback) override; + + bool RequestIsUpload(const URLRequest& request) override; private: std::vector<std::unique_ptr<PendingUpload>> pending_uploads_; @@ -102,15 +107,11 @@ class TestReportingDelegate : public ReportingDelegate { // Clock, TickClock, Timer, and ReportingUploader. class TestReportingContext : public ReportingContext { public: - TestReportingContext(const ReportingPolicy& policy); + TestReportingContext(base::Clock* clock, + base::TickClock* tick_clock, + const ReportingPolicy& policy); ~TestReportingContext(); - base::SimpleTestClock* test_clock() { - return reinterpret_cast<base::SimpleTestClock*>(clock()); - } - base::SimpleTestTickClock* test_tick_clock() { - return reinterpret_cast<base::SimpleTestTickClock*>(tick_clock()); - } base::MockTimer* test_delivery_timer() { return delivery_timer_; } base::MockTimer* test_garbage_collection_timer() { return garbage_collection_timer_; @@ -123,8 +124,12 @@ class TestReportingContext : public ReportingContext { } private: - // Owned by the Persister and GarbageCollector, respectively, but referenced - // here to preserve type: + int RandIntCallback(int min, int max); + + int rand_counter_; + + // Owned by the DeliveryAgent and GarbageCollector, respectively, but + // referenced here to preserve type: base::MockTimer* delivery_timer_; base::MockTimer* garbage_collection_timer_; @@ -151,10 +156,8 @@ class ReportingTestBase : public ::testing::Test { const ReportingPolicy& policy() { return context_->policy(); } - base::SimpleTestClock* clock() { return context_->test_clock(); } - base::SimpleTestTickClock* tick_clock() { - return context_->test_tick_clock(); - } + base::SimpleTestClock* clock() { return &clock_; } + base::SimpleTestTickClock* tick_clock() { return &tick_clock_; } base::MockTimer* delivery_timer() { return context_->test_delivery_timer(); } base::MockTimer* garbage_collection_timer() { return context_->test_garbage_collection_timer(); @@ -172,8 +175,6 @@ class ReportingTestBase : public ::testing::Test { return context_->garbage_collector(); } - ReportingPersister* persister() { return context_->persister(); } - base::TimeTicks yesterday(); base::TimeTicks now(); base::TimeTicks tomorrow(); @@ -188,6 +189,8 @@ class ReportingTestBase : public ::testing::Test { base::Time now, base::TimeTicks now_ticks); + base::SimpleTestClock clock_; + base::SimpleTestTickClock tick_clock_; std::unique_ptr<TestReportingContext> context_; DISALLOW_COPY_AND_ASSIGN(ReportingTestBase); diff --git a/chromium/net/reporting/reporting_uploader.cc b/chromium/net/reporting/reporting_uploader.cc index 72352ba6072..2220858c3b0 100644 --- a/chromium/net/reporting/reporting_uploader.cc +++ b/chromium/net/reporting/reporting_uploader.cc @@ -23,6 +23,15 @@ namespace net { namespace { +class UploadUserData : public base::SupportsUserData::Data { + public: + static const void* const kUserDataKey; +}; + +// SetUserData needs a unique const void* to serve as the key, so create a const +// void* and use its own address as the unique pointer. +const void* const UploadUserData::kUserDataKey = &UploadUserData::kUserDataKey; + ReportingUploader::Outcome ResponseCodeToOutcome(int response_code) { if (response_code >= 200 && response_code <= 299) return ReportingUploader::Outcome::SUCCESS; @@ -47,7 +56,7 @@ class ReportingUploaderImpl : public ReportingUploader, URLRequest::Delegate { void StartUpload(const GURL& url, const std::string& json, - const Callback& callback) override { + UploadCallback callback) override { net::NetworkTrafficAnnotationTag traffic_annotation = net::DefineNetworkTrafficAnnotation("reporting", R"( semantics { @@ -85,6 +94,9 @@ class ReportingUploaderImpl : public ReportingUploader, URLRequest::Delegate { request->set_upload( ElementsUploadDataStream::CreateWithReader(std::move(reader), 0)); + request->SetUserData(UploadUserData::kUserDataKey, + std::make_unique<UploadUserData>()); + // This inherently sets mode = "no-cors", but that doesn't matter, because // the origins that are included in the upload don't actually get to see // the response. @@ -95,7 +107,12 @@ class ReportingUploaderImpl : public ReportingUploader, URLRequest::Delegate { // Have to grab the unique_ptr* first to ensure request.get() happens // before std::move(request). std::unique_ptr<Upload>* upload = &uploads_[request.get()]; - *upload = std::make_unique<Upload>(std::move(request), callback); + *upload = std::make_unique<Upload>(std::move(request), std::move(callback)); + } + + // static + bool RequestIsUpload(const net::URLRequest& request) override { + return request.GetUserData(UploadUserData::kUserDataKey); } // URLRequest::Delegate implementation: @@ -140,7 +157,7 @@ class ReportingUploaderImpl : public ReportingUploader, URLRequest::Delegate { int response_code = headers ? headers->response_code() : 0; Outcome outcome = ResponseCodeToOutcome(response_code); - upload->second.Run(outcome); + std::move(upload->second).Run(outcome); request->Cancel(); } @@ -152,7 +169,7 @@ class ReportingUploaderImpl : public ReportingUploader, URLRequest::Delegate { } private: - using Upload = std::pair<std::unique_ptr<URLRequest>, Callback>; + using Upload = std::pair<std::unique_ptr<URLRequest>, UploadCallback>; const URLRequestContext* context_; std::map<const URLRequest*, std::unique_ptr<Upload>> uploads_; @@ -163,7 +180,7 @@ class ReportingUploaderImpl : public ReportingUploader, URLRequest::Delegate { // static const char ReportingUploader::kUploadContentType[] = "application/report"; -ReportingUploader::~ReportingUploader() {} +ReportingUploader::~ReportingUploader() = default; // static std::unique_ptr<ReportingUploader> ReportingUploader::Create( diff --git a/chromium/net/reporting/reporting_uploader.h b/chromium/net/reporting/reporting_uploader.h index dfe50e73624..f6c65c701b5 100644 --- a/chromium/net/reporting/reporting_uploader.h +++ b/chromium/net/reporting/reporting_uploader.h @@ -15,6 +15,7 @@ class GURL; namespace net { +class URLRequest; class URLRequestContext; // Uploads already-serialized reports and converts responses to one of the @@ -23,7 +24,7 @@ class NET_EXPORT ReportingUploader { public: enum class Outcome { SUCCESS, REMOVE_ENDPOINT, FAILURE }; - using Callback = base::Callback<void(Outcome outcome)>; + using UploadCallback = base::OnceCallback<void(Outcome outcome)>; static const char kUploadContentType[]; @@ -33,7 +34,10 @@ class NET_EXPORT ReportingUploader { // |url|, and calls |callback| when complete (whether successful or not). virtual void StartUpload(const GURL& url, const std::string& json, - const Callback& callback) = 0; + UploadCallback callback) = 0; + + // Returns whether |request| is an upload request sent by this uploader. + virtual bool RequestIsUpload(const URLRequest& request) = 0; // Creates a real implementation of |ReportingUploader| that uploads reports // using |context|. diff --git a/chromium/net/reporting/reporting_uploader_unittest.cc b/chromium/net/reporting/reporting_uploader_unittest.cc index a3a1526ed4a..9fcda4d0915 100644 --- a/chromium/net/reporting/reporting_uploader_unittest.cc +++ b/chromium/net/reporting/reporting_uploader_unittest.cc @@ -65,9 +65,9 @@ class TestUploadCallback { public: TestUploadCallback() : called_(false), waiting_(false) {} - ReportingUploader::Callback callback() { - return base::Bind(&TestUploadCallback::OnUploadComplete, - base::Unretained(this)); + ReportingUploader::UploadCallback callback() { + return base::BindOnce(&TestUploadCallback::OnUploadComplete, + base::Unretained(this)); } void WaitForCall() { @@ -104,8 +104,8 @@ class TestUploadCallback { }; TEST_F(ReportingUploaderTest, Upload) { - server_.RegisterRequestMonitor(base::Bind(&CheckUpload)); - server_.RegisterRequestHandler(base::Bind(&ReturnResponse, HTTP_OK)); + server_.RegisterRequestMonitor(base::BindRepeating(&CheckUpload)); + server_.RegisterRequestHandler(base::BindRepeating(&ReturnResponse, HTTP_OK)); ASSERT_TRUE(server_.Start()); TestUploadCallback callback; @@ -114,7 +114,7 @@ TEST_F(ReportingUploaderTest, Upload) { } TEST_F(ReportingUploaderTest, Success) { - server_.RegisterRequestHandler(base::Bind(&ReturnResponse, HTTP_OK)); + server_.RegisterRequestHandler(base::BindRepeating(&ReturnResponse, HTTP_OK)); ASSERT_TRUE(server_.Start()); TestUploadCallback callback; @@ -137,7 +137,7 @@ TEST_F(ReportingUploaderTest, NetworkError1) { } TEST_F(ReportingUploaderTest, NetworkError2) { - server_.RegisterRequestHandler(base::Bind(&ReturnInvalidResponse)); + server_.RegisterRequestHandler(base::BindRepeating(&ReturnInvalidResponse)); ASSERT_TRUE(server_.Start()); TestUploadCallback callback; @@ -149,7 +149,7 @@ TEST_F(ReportingUploaderTest, NetworkError2) { TEST_F(ReportingUploaderTest, ServerError) { server_.RegisterRequestHandler( - base::Bind(&ReturnResponse, HTTP_INTERNAL_SERVER_ERROR)); + base::BindRepeating(&ReturnResponse, HTTP_INTERNAL_SERVER_ERROR)); ASSERT_TRUE(server_.Start()); TestUploadCallback callback; @@ -160,7 +160,8 @@ TEST_F(ReportingUploaderTest, ServerError) { } TEST_F(ReportingUploaderTest, RemoveEndpoint) { - server_.RegisterRequestHandler(base::Bind(&ReturnResponse, HTTP_GONE)); + server_.RegisterRequestHandler( + base::BindRepeating(&ReturnResponse, HTTP_GONE)); ASSERT_TRUE(server_.Start()); TestUploadCallback callback; @@ -199,8 +200,10 @@ std::unique_ptr<test_server::HttpResponse> CheckRedirect( TEST_F(ReportingUploaderTest, FollowHttpsRedirect) { bool followed = false; - server_.RegisterRequestHandler(base::Bind(&ReturnRedirect, kRedirectPath)); - server_.RegisterRequestHandler(base::Bind(&CheckRedirect, &followed)); + server_.RegisterRequestHandler( + base::BindRepeating(&ReturnRedirect, kRedirectPath)); + server_.RegisterRequestHandler( + base::BindRepeating(&CheckRedirect, &followed)); ASSERT_TRUE(server_.Start()); TestUploadCallback callback; @@ -215,11 +218,13 @@ TEST_F(ReportingUploaderTest, DontFollowHttpRedirect) { bool followed = false; test_server::EmbeddedTestServer http_server_; - http_server_.RegisterRequestHandler(base::Bind(&CheckRedirect, &followed)); + http_server_.RegisterRequestHandler( + base::BindRepeating(&CheckRedirect, &followed)); ASSERT_TRUE(http_server_.Start()); const GURL target = http_server_.GetURL(kRedirectPath); - server_.RegisterRequestHandler(base::Bind(&ReturnRedirect, target.spec())); + server_.RegisterRequestHandler( + base::BindRepeating(&ReturnRedirect, target.spec())); ASSERT_TRUE(server_.Start()); TestUploadCallback callback; @@ -236,15 +241,15 @@ void CheckNoCookie(const test_server::HttpRequest& request) { } TEST_F(ReportingUploaderTest, DontSendCookies) { - server_.RegisterRequestMonitor(base::Bind(&CheckNoCookie)); - server_.RegisterRequestHandler(base::Bind(&ReturnResponse, HTTP_OK)); + server_.RegisterRequestMonitor(base::BindRepeating(&CheckNoCookie)); + server_.RegisterRequestHandler(base::BindRepeating(&ReturnResponse, HTTP_OK)); ASSERT_TRUE(server_.Start()); ResultSavingCookieCallback<bool> cookie_callback; context_.cookie_store()->SetCookieWithOptionsAsync( server_.GetURL("/"), "foo=bar", CookieOptions(), - base::Bind(&ResultSavingCookieCallback<bool>::Run, - base::Unretained(&cookie_callback))); + base::BindRepeating(&ResultSavingCookieCallback<bool>::Run, + base::Unretained(&cookie_callback))); cookie_callback.WaitUntilDone(); ASSERT_TRUE(cookie_callback.result()); @@ -265,7 +270,7 @@ std::unique_ptr<test_server::HttpResponse> SendCookie( } TEST_F(ReportingUploaderTest, DontSaveCookies) { - server_.RegisterRequestHandler(base::Bind(&SendCookie)); + server_.RegisterRequestHandler(base::BindRepeating(&SendCookie)); ASSERT_TRUE(server_.Start()); TestUploadCallback upload_callback; @@ -276,8 +281,8 @@ TEST_F(ReportingUploaderTest, DontSaveCookies) { GetCookieListCallback cookie_callback; context_.cookie_store()->GetCookieListWithOptionsAsync( server_.GetURL("/"), CookieOptions(), - base::Bind(&GetCookieListCallback::Run, - base::Unretained(&cookie_callback))); + base::BindRepeating(&GetCookieListCallback::Run, + base::Unretained(&cookie_callback))); cookie_callback.WaitUntilDone(); EXPECT_TRUE(cookie_callback.cookies().empty()); @@ -302,7 +307,7 @@ std::unique_ptr<test_server::HttpResponse> ReturnCacheableResponse( TEST_F(ReportingUploaderTest, DontCacheResponse) { int request_count = 0; server_.RegisterRequestHandler( - base::Bind(&ReturnCacheableResponse, &request_count)); + base::BindRepeating(&ReturnCacheableResponse, &request_count)); ASSERT_TRUE(server_.Start()); { diff --git a/chromium/net/server/http_server_unittest.cc b/chromium/net/server/http_server_unittest.cc index cd60a7fcdd6..aca53999a12 100644 --- a/chromium/net/server/http_server_unittest.cc +++ b/chromium/net/server/http_server_unittest.cc @@ -123,9 +123,9 @@ class TestHttpClient { private: void Write() { int result = socket_->Write( - write_buffer_.get(), - write_buffer_->BytesRemaining(), - base::Bind(&TestHttpClient::OnWrite, base::Unretained(this))); + write_buffer_.get(), write_buffer_->BytesRemaining(), + base::Bind(&TestHttpClient::OnWrite, base::Unretained(this)), + TRAFFIC_ANNOTATION_FOR_TESTS); if (result != ERR_IO_PENDING) OnWrite(result); } @@ -579,6 +579,7 @@ class MockStreamSocket : public StreamSocket { NOTIMPLEMENTED(); return 0; } + void ApplySocketTag(const SocketTag& tag) override {} // Socket int Read(IOBuffer* buf, @@ -600,9 +601,11 @@ class MockStreamSocket : public StreamSocket { pending_read_data_.erase(0, read_len); return read_len; } + int Write(IOBuffer* buf, int buf_len, - const CompletionCallback& callback) override { + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& traffic_annotation) override { return ERR_NOT_IMPLEMENTED; } int SetReceiveBufferSize(int32_t size) override { diff --git a/chromium/net/socket/client_socket_handle.h b/chromium/net/socket/client_socket_handle.h index 53e471972c4..1a0afb96e88 100644 --- a/chromium/net/socket/client_socket_handle.h +++ b/chromium/net/socket/client_socket_handle.h @@ -28,6 +28,8 @@ namespace net { +class SocketTag; + // A container for a StreamSocket. // // The handle's |group_name| uniquely identifies the origin and type of the @@ -80,6 +82,7 @@ class NET_EXPORT ClientSocketHandle { int Init(const std::string& group_name, const scoped_refptr<typename PoolType::SocketParams>& socket_params, RequestPriority priority, + const SocketTag& socket_tag, ClientSocketPool::RespectLimits respect_limits, const CompletionCallback& callback, PoolType* pool, @@ -240,6 +243,7 @@ int ClientSocketHandle::Init( const std::string& group_name, const scoped_refptr<typename PoolType::SocketParams>& socket_params, RequestPriority priority, + const SocketTag& socket_tag, ClientSocketPool::RespectLimits respect_limits, const CompletionCallback& callback, PoolType* pool, @@ -251,8 +255,9 @@ int ClientSocketHandle::Init( ResetErrorState(); pool_ = pool; group_name_ = group_name; - int rv = pool_->RequestSocket(group_name, &socket_params, priority, - respect_limits, this, callback_, net_log); + int rv = + pool_->RequestSocket(group_name, &socket_params, priority, socket_tag, + respect_limits, this, callback_, net_log); if (rv == ERR_IO_PENDING) { user_callback_ = callback; } else { diff --git a/chromium/net/socket/client_socket_pool.h b/chromium/net/socket/client_socket_pool.h index 8652bce23bb..c52188016d6 100644 --- a/chromium/net/socket/client_socket_pool.h +++ b/chromium/net/socket/client_socket_pool.h @@ -104,6 +104,7 @@ class NET_EXPORT ClientSocketPool : public LowerLayeredPool { virtual int RequestSocket(const std::string& group_name, const void* params, RequestPriority priority, + const SocketTag& socket_tag, RespectLimits respect_limits, ClientSocketHandle* handle, const CompletionCallback& callback, diff --git a/chromium/net/socket/client_socket_pool_base.cc b/chromium/net/socket/client_socket_pool_base.cc index d80dc8e30e5..1067aae8203 100644 --- a/chromium/net/socket/client_socket_pool_base.cc +++ b/chromium/net/socket/client_socket_pool_base.cc @@ -51,12 +51,14 @@ void SetSocketMotivation(StreamSocket* socket, ConnectJob::ConnectJob(const std::string& group_name, base::TimeDelta timeout_duration, RequestPriority priority, + const SocketTag& socket_tag, ClientSocketPool::RespectLimits respect_limits, Delegate* delegate, const NetLogWithSource& net_log) : group_name_(group_name), timeout_duration_(timeout_duration), priority_(priority), + socket_tag_(socket_tag), respect_limits_(respect_limits), delegate_(delegate), net_log_(net_log), @@ -146,6 +148,7 @@ ClientSocketPoolBaseHelper::Request::Request( ClientSocketHandle* handle, const CompletionCallback& callback, RequestPriority priority, + const SocketTag& socket_tag, ClientSocketPool::RespectLimits respect_limits, Flags flags, const NetLogWithSource& net_log) @@ -154,7 +157,8 @@ ClientSocketPoolBaseHelper::Request::Request( priority_(priority), respect_limits_(respect_limits), flags_(flags), - net_log_(net_log) { + net_log_(net_log), + socket_tag_(socket_tag) { if (respect_limits_ == ClientSocketPool::RespectLimits::DISABLED) DCHECK_EQ(priority_, MAXIMUM_PRIORITY); } @@ -292,6 +296,9 @@ int ClientSocketPoolBaseHelper::RequestSocket( int rv = RequestSocketInternal(group_name, *request, HttpRequestInfo::NORMAL_MOTIVATION); if (rv != ERR_IO_PENDING) { + if (rv == OK) { + request->handle()->socket()->ApplySocketTag(request->socket_tag()); + } request->net_log().EndEventWithNetErrorCode(NetLogEventType::SOCKET_POOL, rv); CHECK(!request->handle()->is_initialized()); @@ -965,7 +972,8 @@ void ClientSocketPoolBaseHelper::OnConnectJobComplete( connect_timing, request->handle(), base::TimeDelta(), group, request->net_log()); request->net_log().EndEvent(NetLogEventType::SOCKET_POOL); - InvokeUserCallbackLater(request->handle(), request->callback(), result); + InvokeUserCallbackLater(request->handle(), request->callback(), result, + request->socket_tag()); } else { AddIdleSocket(std::move(socket), group); OnAvailableSocketSlot(group_name, group); @@ -988,7 +996,8 @@ void ClientSocketPoolBaseHelper::OnConnectJobComplete( } request->net_log().EndEventWithNetErrorCode(NetLogEventType::SOCKET_POOL, result); - InvokeUserCallbackLater(request->handle(), request->callback(), result); + InvokeUserCallbackLater(request->handle(), request->callback(), result, + request->socket_tag()); } else { RemoveConnectJob(job, group); } @@ -1052,7 +1061,8 @@ void ClientSocketPoolBaseHelper::ProcessPendingRequest( request->net_log().EndEventWithNetErrorCode(NetLogEventType::SOCKET_POOL, rv); - InvokeUserCallbackLater(request->handle(), request->callback(), rv); + InvokeUserCallbackLater(request->handle(), request->callback(), rv, + request->socket_tag()); } } @@ -1130,7 +1140,8 @@ void ClientSocketPoolBaseHelper::CancelAllRequestsWithError(int error) { std::unique_ptr<Request> request = group->PopNextPendingRequest(); if (!request) break; - InvokeUserCallbackLater(request->handle(), request->callback(), error); + InvokeUserCallbackLater(request->handle(), request->callback(), error, + request->socket_tag()); } // Delete group if no longer needed. @@ -1197,9 +1208,15 @@ bool ClientSocketPoolBaseHelper::CloseOneIdleConnectionInHigherLayeredPool() { } void ClientSocketPoolBaseHelper::InvokeUserCallbackLater( - ClientSocketHandle* handle, const CompletionCallback& callback, int rv) { + ClientSocketHandle* handle, + const CompletionCallback& callback, + int rv, + const SocketTag& socket_tag) { CHECK(!base::ContainsKey(pending_callback_map_, handle)); pending_callback_map_[handle] = CallbackResultPair(callback, rv); + if (rv == OK) { + handle->socket()->ApplySocketTag(socket_tag); + } base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::Bind(&ClientSocketPoolBaseHelper::InvokeUserCallback, weak_factory_.GetWeakPtr(), handle)); diff --git a/chromium/net/socket/client_socket_pool_base.h b/chromium/net/socket/client_socket_pool_base.h index b363741fbbc..88ee1baf58b 100644 --- a/chromium/net/socket/client_socket_pool_base.h +++ b/chromium/net/socket/client_socket_pool_base.h @@ -89,6 +89,7 @@ class NET_EXPORT_PRIVATE ConnectJob { ConnectJob(const std::string& group_name, base::TimeDelta timeout_duration, RequestPriority priority, + const SocketTag& socket_tag, ClientSocketPool::RespectLimits respect_limits, Delegate* delegate, const NetLogWithSource& net_log); @@ -130,6 +131,7 @@ class NET_EXPORT_PRIVATE ConnectJob { protected: RequestPriority priority() const { return priority_; } + const SocketTag& socket_tag() const { return socket_tag_; } ClientSocketPool::RespectLimits respect_limits() const { return respect_limits_; } @@ -154,6 +156,7 @@ class NET_EXPORT_PRIVATE ConnectJob { const base::TimeDelta timeout_duration_; // TODO(akalin): Support reprioritization. const RequestPriority priority_; + const SocketTag socket_tag_; const ClientSocketPool::RespectLimits respect_limits_; // Timer to abort jobs that take too long. base::OneShotTimer timer_; @@ -191,6 +194,7 @@ class NET_EXPORT_PRIVATE ClientSocketPoolBaseHelper Request(ClientSocketHandle* handle, const CompletionCallback& callback, RequestPriority priority, + const SocketTag& socket_tag, ClientSocketPool::RespectLimits respect_limits, Flags flags, const NetLogWithSource& net_log); @@ -206,6 +210,7 @@ class NET_EXPORT_PRIVATE ClientSocketPoolBaseHelper } Flags flags() const { return flags_; } const NetLogWithSource& net_log() const { return net_log_; } + const SocketTag& socket_tag() const { return socket_tag_; } // TODO(eroman): Temporary until crbug.com/467797 is solved. void CrashIfInvalid() const; @@ -223,6 +228,7 @@ class NET_EXPORT_PRIVATE ClientSocketPoolBaseHelper const ClientSocketPool::RespectLimits respect_limits_; const Flags flags_; const NetLogWithSource net_log_; + const SocketTag socket_tag_; // TODO(eroman): Temporary until crbug.com/467797 is solved. Liveness liveness_ = ALIVE; @@ -624,9 +630,12 @@ class NET_EXPORT_PRIVATE ClientSocketPoolBaseHelper // Posts a task to call InvokeUserCallback() on the next iteration through the // current message loop. Inserts |callback| into |pending_callback_map_|, - // keyed by |handle|. - void InvokeUserCallbackLater( - ClientSocketHandle* handle, const CompletionCallback& callback, int rv); + // keyed by |handle|. Apply |socket_tag| to the socket if socket successfully + // created. + void InvokeUserCallbackLater(ClientSocketHandle* handle, + const CompletionCallback& callback, + int rv, + const SocketTag& socket_tag); // Invokes the user callback for |handle|. By the time this task has run, // it's possible that the request has been cancelled, so |handle| may not @@ -702,6 +711,7 @@ class ClientSocketPoolBase { Request(ClientSocketHandle* handle, const CompletionCallback& callback, RequestPriority priority, + const SocketTag& socket_tag, ClientSocketPool::RespectLimits respect_limits, internal::ClientSocketPoolBaseHelper::Flags flags, const scoped_refptr<SocketParams>& params, @@ -709,6 +719,7 @@ class ClientSocketPoolBase { : internal::ClientSocketPoolBaseHelper::Request(handle, callback, priority, + socket_tag, respect_limits, flags, net_log), @@ -775,12 +786,13 @@ class ClientSocketPoolBase { int RequestSocket(const std::string& group_name, const scoped_refptr<SocketParams>& params, RequestPriority priority, + const SocketTag& socket_tag, ClientSocketPool::RespectLimits respect_limits, ClientSocketHandle* handle, const CompletionCallback& callback, const NetLogWithSource& net_log) { std::unique_ptr<Request> request(new Request( - handle, callback, priority, respect_limits, + handle, callback, priority, socket_tag, respect_limits, internal::ClientSocketPoolBaseHelper::NORMAL, params, net_log)); return helper_.RequestSocket(group_name, std::move(request)); } @@ -794,7 +806,7 @@ class ClientSocketPoolBase { const NetLogWithSource& net_log, HttpRequestInfo::RequestMotivation motivation) { const Request request(nullptr /* no handle */, CompletionCallback(), IDLE, - ClientSocketPool::RespectLimits::ENABLED, + SocketTag(), ClientSocketPool::RespectLimits::ENABLED, internal::ClientSocketPoolBaseHelper::NO_IDLE_SOCKETS, params, net_log); helper_.RequestSockets(group_name, request, num_sockets, motivation); diff --git a/chromium/net/socket/client_socket_pool_base_unittest.cc b/chromium/net/socket/client_socket_pool_base_unittest.cc index 41dbccf7f83..7c9f22bbdcd 100644 --- a/chromium/net/socket/client_socket_pool_base_unittest.cc +++ b/chromium/net/socket/client_socket_pool_base_unittest.cc @@ -41,10 +41,12 @@ #include "net/socket/client_socket_handle.h" #include "net/socket/datagram_client_socket.h" #include "net/socket/socket_performance_watcher.h" +#include "net/socket/socket_tag.h" #include "net/socket/socket_test_util.h" #include "net/socket/ssl_client_socket.h" #include "net/socket/stream_socket.h" #include "net/test/gtest_util.h" +#include "net/traffic_annotation/network_traffic_annotation.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -151,9 +153,11 @@ class MockClientSocket : public StreamSocket { return ERR_UNEXPECTED; } - int Write(IOBuffer* /* buf */, - int len, - const CompletionCallback& /* callback */) override { + int Write( + IOBuffer* /* buf */, + int len, + const CompletionCallback& /* callback */, + const NetworkTrafficAnnotationTag& /*traffic_annotation*/) override { was_used_to_convey_data_ = true; return len; } @@ -201,6 +205,7 @@ class MockClientSocket : public StreamSocket { NOTIMPLEMENTED(); return 0; } + void ApplySocketTag(const SocketTag& tag) override {} private: bool connected_; @@ -293,6 +298,7 @@ class TestConnectJob : public ConnectJob { group_name, timeout_duration, request.priority(), + request.socket_tag(), request.respect_limits(), delegate, NetLogWithSource::Make(net_log, @@ -517,6 +523,7 @@ class TestClientSocketPool : public ClientSocketPool { int RequestSocket(const std::string& group_name, const void* params, RequestPriority priority, + const SocketTag& socket_tag, RespectLimits respect_limits, ClientSocketHandle* handle, const CompletionCallback& callback, @@ -524,7 +531,8 @@ class TestClientSocketPool : public ClientSocketPool { const scoped_refptr<TestSocketParams>* casted_socket_params = static_cast<const scoped_refptr<TestSocketParams>*>(params); return base_.RequestSocket(group_name, *casted_socket_params, priority, - respect_limits, handle, callback, net_log); + socket_tag, respect_limits, handle, callback, + net_log); } void RequestSockets(const std::string& group_name, @@ -770,7 +778,7 @@ TEST_F(ClientSocketPoolBaseTest, ConnectJob_NoTimeoutOnSynchronousCompletion) { TestConnectJobDelegate delegate; ClientSocketHandle ignored; TestClientSocketPoolBase::Request request( - &ignored, CompletionCallback(), DEFAULT_PRIORITY, + &ignored, CompletionCallback(), DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, internal::ClientSocketPoolBaseHelper::NORMAL, params_, NetLogWithSource()); @@ -787,7 +795,7 @@ TEST_F(ClientSocketPoolBaseTest, ConnectJob_TimedOut) { TestNetLog log; TestClientSocketPoolBase::Request request( - &ignored, CompletionCallback(), DEFAULT_PRIORITY, + &ignored, CompletionCallback(), DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, internal::ClientSocketPoolBaseHelper::NORMAL, params_, NetLogWithSource()); @@ -832,7 +840,7 @@ TEST_F(ClientSocketPoolBaseTest, BasicSynchronous) { BoundTestNetLog log; TestLoadTimingInfoNotConnected(handle); - EXPECT_EQ(OK, handle.Init("a", params_, DEFAULT_PRIORITY, + EXPECT_EQ(OK, handle.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), log.bound())); EXPECT_TRUE(handle.is_initialized()); @@ -870,7 +878,7 @@ TEST_F(ClientSocketPoolBaseTest, InitConnectionFailure) { info.headers = new HttpResponseHeaders(std::string()); handle.set_ssl_error_response_info(info); EXPECT_EQ(ERR_CONNECTION_FAILED, - handle.Init("a", params_, DEFAULT_PRIORITY, + handle.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), log.bound())); EXPECT_FALSE(handle.socket()); @@ -1206,7 +1214,7 @@ TEST_F(ClientSocketPoolBaseTest, StallAndThenCancelAndTriggerAvailableSocket) { ClientSocketHandle handle; TestCompletionCallback callback; EXPECT_EQ(ERR_IO_PENDING, - handle.Init("a", params_, DEFAULT_PRIORITY, + handle.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), NetLogWithSource())); @@ -1215,7 +1223,7 @@ TEST_F(ClientSocketPoolBaseTest, StallAndThenCancelAndTriggerAvailableSocket) { TestCompletionCallback callback; EXPECT_EQ( ERR_IO_PENDING, - handles[i].Init("b", params_, DEFAULT_PRIORITY, + handles[i].Init("b", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), NetLogWithSource())); } @@ -1235,18 +1243,18 @@ TEST_F(ClientSocketPoolBaseTest, CancelStalledSocketAtSocketLimit) { ClientSocketHandle handles[kDefaultMaxSockets]; TestCompletionCallback callbacks[kDefaultMaxSockets]; for (int i = 0; i < kDefaultMaxSockets; ++i) { - EXPECT_EQ(OK, - handles[i].Init(base::IntToString(i), params_, DEFAULT_PRIORITY, - ClientSocketPool::RespectLimits::ENABLED, - callbacks[i].callback(), pool_.get(), - NetLogWithSource())); + EXPECT_EQ(OK, handles[i].Init(base::IntToString(i), params_, + DEFAULT_PRIORITY, SocketTag(), + ClientSocketPool::RespectLimits::ENABLED, + callbacks[i].callback(), pool_.get(), + NetLogWithSource())); } // Force a stalled group. ClientSocketHandle stalled_handle; TestCompletionCallback callback; EXPECT_EQ(ERR_IO_PENDING, - stalled_handle.Init("foo", params_, DEFAULT_PRIORITY, + stalled_handle.Init("foo", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), NetLogWithSource())); @@ -1273,10 +1281,10 @@ TEST_F(ClientSocketPoolBaseTest, CancelPendingSocketAtSocketLimit) { for (int i = 0; i < kDefaultMaxSockets; ++i) { TestCompletionCallback callback; EXPECT_EQ(ERR_IO_PENDING, - handles[i].Init(base::IntToString(i), params_, DEFAULT_PRIORITY, - ClientSocketPool::RespectLimits::ENABLED, - callback.callback(), pool_.get(), - NetLogWithSource())); + handles[i].Init( + base::IntToString(i), params_, DEFAULT_PRIORITY, + SocketTag(), ClientSocketPool::RespectLimits::ENABLED, + callback.callback(), pool_.get(), NetLogWithSource())); } // Force a stalled group. @@ -1284,7 +1292,7 @@ TEST_F(ClientSocketPoolBaseTest, CancelPendingSocketAtSocketLimit) { ClientSocketHandle stalled_handle; TestCompletionCallback callback; EXPECT_EQ(ERR_IO_PENDING, - stalled_handle.Init("foo", params_, DEFAULT_PRIORITY, + stalled_handle.Init("foo", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), NetLogWithSource())); @@ -1327,7 +1335,7 @@ TEST_F(ClientSocketPoolBaseTest, WaitForStalledSocketAtSocketLimit) { for (int i = 0; i < kDefaultMaxSockets; ++i) { TestCompletionCallback callback; EXPECT_EQ(OK, handles[i].Init(base::StringPrintf("Take 2: %d", i), - params_, DEFAULT_PRIORITY, + params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), NetLogWithSource())); @@ -1339,7 +1347,7 @@ TEST_F(ClientSocketPoolBaseTest, WaitForStalledSocketAtSocketLimit) { // Now we will hit the socket limit. EXPECT_EQ(ERR_IO_PENDING, - stalled_handle.Init("foo", params_, DEFAULT_PRIORITY, + stalled_handle.Init("foo", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), NetLogWithSource())); @@ -1367,7 +1375,7 @@ TEST_F(ClientSocketPoolBaseTest, CloseIdleSocketAtSocketLimitDeleteGroup) { TestCompletionCallback callback; EXPECT_EQ( OK, handle.Init(base::IntToString(i), params_, DEFAULT_PRIORITY, - ClientSocketPool::RespectLimits::ENABLED, + SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), NetLogWithSource())); } @@ -1384,7 +1392,7 @@ TEST_F(ClientSocketPoolBaseTest, CloseIdleSocketAtSocketLimitDeleteGroup) { // which is the one which we would close an idle socket for. We shouldn't // close an idle socket though, since we should reuse the idle socket. EXPECT_EQ(OK, - handle.Init("0", params_, DEFAULT_PRIORITY, + handle.Init("0", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), NetLogWithSource())); @@ -1455,7 +1463,7 @@ TEST_F(ClientSocketPoolBaseTest, CancelRequestClearGroup) { ClientSocketHandle handle; TestCompletionCallback callback; EXPECT_EQ(ERR_IO_PENDING, - handle.Init("a", params_, DEFAULT_PRIORITY, + handle.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), NetLogWithSource())); handle.Reset(); @@ -1469,7 +1477,7 @@ TEST_F(ClientSocketPoolBaseTest, ConnectCancelConnect) { TestCompletionCallback callback; EXPECT_EQ(ERR_IO_PENDING, - handle.Init("a", params_, DEFAULT_PRIORITY, + handle.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), NetLogWithSource())); @@ -1477,7 +1485,7 @@ TEST_F(ClientSocketPoolBaseTest, ConnectCancelConnect) { TestCompletionCallback callback2; EXPECT_EQ(ERR_IO_PENDING, - handle.Init("a", params_, DEFAULT_PRIORITY, + handle.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback2.callback(), pool_.get(), NetLogWithSource())); @@ -1545,7 +1553,7 @@ void RequestSocketOnComplete(ClientSocketHandle* handle, scoped_refptr<TestSocketParams> params(new TestSocketParams()); TestCompletionCallback callback; - int rv = handle->Init("a", params, LOWEST, + int rv = handle->Init("a", params, LOWEST, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, nested_callback, pool, NetLogWithSource()); if (rv != ERR_IO_PENDING) { @@ -1566,7 +1574,8 @@ TEST_F(ClientSocketPoolBaseTest, RequestPendingJobTwice) { ClientSocketHandle handle; TestCompletionCallback second_result_callback; int rv = handle.Init( - "a", params_, DEFAULT_PRIORITY, ClientSocketPool::RespectLimits::ENABLED, + "a", params_, DEFAULT_PRIORITY, SocketTag(), + ClientSocketPool::RespectLimits::ENABLED, base::Bind(&RequestSocketOnComplete, &handle, pool_.get(), connect_job_factory_, TestConnectJob::kMockPendingJob, second_result_callback.callback()), @@ -1586,7 +1595,8 @@ TEST_F(ClientSocketPoolBaseTest, RequestPendingJobThenSynchronous) { ClientSocketHandle handle; TestCompletionCallback second_result_callback; int rv = handle.Init( - "a", params_, DEFAULT_PRIORITY, ClientSocketPool::RespectLimits::ENABLED, + "a", params_, DEFAULT_PRIORITY, SocketTag(), + ClientSocketPool::RespectLimits::ENABLED, base::Bind(&RequestSocketOnComplete, &handle, pool_.get(), connect_job_factory_, TestConnectJob::kMockPendingJob, second_result_callback.callback()), @@ -1675,7 +1685,7 @@ TEST_F(ClientSocketPoolBaseTest, CancelActiveRequestThenRequestSocket) { ClientSocketHandle handle; TestCompletionCallback callback; - int rv = handle.Init("a", params_, DEFAULT_PRIORITY, + int rv = handle.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); @@ -1683,7 +1693,7 @@ TEST_F(ClientSocketPoolBaseTest, CancelActiveRequestThenRequestSocket) { // Cancel the active request. handle.Reset(); - rv = handle.Init("a", params_, DEFAULT_PRIORITY, + rv = handle.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); @@ -1699,7 +1709,7 @@ TEST_F(ClientSocketPoolBaseTest, CloseIdleSocketsForced) { ClientSocketHandle handle; TestCompletionCallback callback; BoundTestNetLog log; - int rv = handle.Init("a", params_, LOWEST, + int rv = handle.Init("a", params_, LOWEST, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), log.bound()); EXPECT_THAT(rv, IsOk()); @@ -1713,16 +1723,16 @@ TEST_F(ClientSocketPoolBaseTest, CloseIdleSocketsInGroupForced) { TestCompletionCallback callback; BoundTestNetLog log; ClientSocketHandle handle1; - int rv = handle1.Init("a", params_, LOWEST, + int rv = handle1.Init("a", params_, LOWEST, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), log.bound()); EXPECT_THAT(rv, IsOk()); ClientSocketHandle handle2; - rv = handle2.Init("a", params_, LOWEST, + rv = handle2.Init("a", params_, LOWEST, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), log.bound()); ClientSocketHandle handle3; - rv = handle3.Init("b", params_, LOWEST, + rv = handle3.Init("b", params_, LOWEST, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), log.bound()); EXPECT_THAT(rv, IsOk()); @@ -1739,7 +1749,7 @@ TEST_F(ClientSocketPoolBaseTest, CleanUpUnusableIdleSockets) { ClientSocketHandle handle; TestCompletionCallback callback; BoundTestNetLog log; - int rv = handle.Init("a", params_, LOWEST, + int rv = handle.Init("a", params_, LOWEST, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), log.bound()); EXPECT_THAT(rv, IsOk()); @@ -1750,7 +1760,7 @@ TEST_F(ClientSocketPoolBaseTest, CleanUpUnusableIdleSockets) { // Disconnect socket now to make the socket unusable. socket->Disconnect(); ClientSocketHandle handle2; - rv = handle2.Init("a", params_, LOWEST, + rv = handle2.Init("a", params_, LOWEST, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), log.bound()); EXPECT_THAT(rv, IsOk()); @@ -1801,7 +1811,7 @@ TEST_F(ClientSocketPoolBaseTest, BasicAsynchronous) { ClientSocketHandle handle; TestCompletionCallback callback; BoundTestNetLog log; - int rv = handle.Init("a", params_, LOWEST, + int rv = handle.Init("a", params_, LOWEST, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), log.bound()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); @@ -1844,7 +1854,7 @@ TEST_F(ClientSocketPoolBaseTest, info.headers = new HttpResponseHeaders(std::string()); handle.set_ssl_error_response_info(info); EXPECT_EQ(ERR_IO_PENDING, - handle.Init("a", params_, DEFAULT_PRIORITY, + handle.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), log.bound())); EXPECT_EQ(LOAD_STATE_CONNECTING, pool_->GetLoadState("a", &handle)); @@ -1891,13 +1901,13 @@ TEST_F(ClientSocketPoolBaseTest, TwoRequestsCancelOne) { TestCompletionCallback callback2; EXPECT_EQ(ERR_IO_PENDING, - handle.Init("a", params_, DEFAULT_PRIORITY, + handle.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), NetLogWithSource())); BoundTestNetLog log2; EXPECT_EQ( ERR_IO_PENDING, - handle2.Init("a", params_, DEFAULT_PRIORITY, + handle2.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback2.callback(), pool_.get(), NetLogWithSource())); @@ -1946,9 +1956,10 @@ TEST_F(ClientSocketPoolBaseTest, ReleaseSockets) { std::vector<TestSocketRequest*> request_order; size_t completion_count; // unused TestSocketRequest req1(&request_order, &completion_count); - int rv = req1.handle()->Init( - "a", params_, DEFAULT_PRIORITY, ClientSocketPool::RespectLimits::ENABLED, - req1.callback(), pool_.get(), NetLogWithSource()); + int rv = + req1.handle()->Init("a", params_, DEFAULT_PRIORITY, SocketTag(), + ClientSocketPool::RespectLimits::ENABLED, + req1.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); EXPECT_THAT(req1.WaitForResult(), IsOk()); @@ -1957,12 +1968,12 @@ TEST_F(ClientSocketPoolBaseTest, ReleaseSockets) { connect_job_factory_->set_job_type(TestConnectJob::kMockWaitingJob); TestSocketRequest req2(&request_order, &completion_count); - rv = req2.handle()->Init("a", params_, DEFAULT_PRIORITY, + rv = req2.handle()->Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, req2.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); TestSocketRequest req3(&request_order, &completion_count); - rv = req3.handle()->Init("a", params_, DEFAULT_PRIORITY, + rv = req3.handle()->Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, req3.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); @@ -1998,13 +2009,14 @@ TEST_F(ClientSocketPoolBaseTest, PendingJobCompletionOrder) { std::vector<TestSocketRequest*> request_order; size_t completion_count; // unused TestSocketRequest req1(&request_order, &completion_count); - int rv = req1.handle()->Init( - "a", params_, DEFAULT_PRIORITY, ClientSocketPool::RespectLimits::ENABLED, - req1.callback(), pool_.get(), NetLogWithSource()); + int rv = + req1.handle()->Init("a", params_, DEFAULT_PRIORITY, SocketTag(), + ClientSocketPool::RespectLimits::ENABLED, + req1.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); TestSocketRequest req2(&request_order, &completion_count); - rv = req2.handle()->Init("a", params_, DEFAULT_PRIORITY, + rv = req2.handle()->Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, req2.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); @@ -2013,7 +2025,7 @@ TEST_F(ClientSocketPoolBaseTest, PendingJobCompletionOrder) { connect_job_factory_->set_job_type(TestConnectJob::kMockJob); TestSocketRequest req3(&request_order, &completion_count); - rv = req3.handle()->Init("a", params_, DEFAULT_PRIORITY, + rv = req3.handle()->Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, req3.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); @@ -2035,7 +2047,7 @@ TEST_F(ClientSocketPoolBaseTest, LoadStateOneRequest) { ClientSocketHandle handle; TestCompletionCallback callback; - int rv = handle.Init("a", params_, DEFAULT_PRIORITY, + int rv = handle.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); @@ -2056,7 +2068,7 @@ TEST_F(ClientSocketPoolBaseTest, LoadStateTwoRequests) { ClientSocketHandle handle; TestCompletionCallback callback; - int rv = handle.Init("a", params_, DEFAULT_PRIORITY, + int rv = handle.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); @@ -2064,7 +2076,7 @@ TEST_F(ClientSocketPoolBaseTest, LoadStateTwoRequests) { ClientSocketHandle handle2; TestCompletionCallback callback2; - rv = handle2.Init("a", params_, DEFAULT_PRIORITY, + rv = handle2.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback2.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); @@ -2089,14 +2101,14 @@ TEST_F(ClientSocketPoolBaseTest, LoadStateTwoRequestsChangeSecondRequestState) { ClientSocketHandle handle; TestCompletionCallback callback; - int rv = handle.Init("a", params_, DEFAULT_PRIORITY, + int rv = handle.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); ClientSocketHandle handle2; TestCompletionCallback callback2; - rv = handle2.Init("a", params_, DEFAULT_PRIORITY, + rv = handle2.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback2.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); @@ -2119,7 +2131,7 @@ TEST_F(ClientSocketPoolBaseTest, LoadStateGroupLimit) { ClientSocketHandle handle; TestCompletionCallback callback; - int rv = handle.Init("a", params_, MEDIUM, + int rv = handle.Init("a", params_, MEDIUM, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); @@ -2129,7 +2141,7 @@ TEST_F(ClientSocketPoolBaseTest, LoadStateGroupLimit) { // The first request should now be stalled at the socket group limit. ClientSocketHandle handle2; TestCompletionCallback callback2; - rv = handle2.Init("a", params_, HIGHEST, + rv = handle2.Init("a", params_, HIGHEST, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback2.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); @@ -2161,7 +2173,7 @@ TEST_F(ClientSocketPoolBaseTest, LoadStatePoolLimit) { ClientSocketHandle handle; TestCompletionCallback callback; - int rv = handle.Init("a", params_, DEFAULT_PRIORITY, + int rv = handle.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); @@ -2169,7 +2181,7 @@ TEST_F(ClientSocketPoolBaseTest, LoadStatePoolLimit) { // Request for socket from another pool. ClientSocketHandle handle2; TestCompletionCallback callback2; - rv = handle2.Init("b", params_, DEFAULT_PRIORITY, + rv = handle2.Init("b", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback2.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); @@ -2178,7 +2190,7 @@ TEST_F(ClientSocketPoolBaseTest, LoadStatePoolLimit) { // socket pool limit. ClientSocketHandle handle3; TestCompletionCallback callback3; - rv = handle3.Init("a", params_, DEFAULT_PRIORITY, + rv = handle3.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback2.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); @@ -2211,7 +2223,7 @@ TEST_F(ClientSocketPoolBaseTest, Recoverable) { ClientSocketHandle handle; TestCompletionCallback callback; EXPECT_EQ(ERR_PROXY_AUTH_REQUESTED, - handle.Init("a", params_, DEFAULT_PRIORITY, + handle.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), NetLogWithSource())); EXPECT_TRUE(handle.is_initialized()); @@ -2226,7 +2238,7 @@ TEST_F(ClientSocketPoolBaseTest, AsyncRecoverable) { ClientSocketHandle handle; TestCompletionCallback callback; EXPECT_EQ(ERR_IO_PENDING, - handle.Init("a", params_, DEFAULT_PRIORITY, + handle.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), NetLogWithSource())); EXPECT_EQ(LOAD_STATE_CONNECTING, pool_->GetLoadState("a", &handle)); @@ -2243,7 +2255,7 @@ TEST_F(ClientSocketPoolBaseTest, AdditionalErrorStateSynchronous) { ClientSocketHandle handle; TestCompletionCallback callback; EXPECT_EQ(ERR_CONNECTION_FAILED, - handle.Init("a", params_, DEFAULT_PRIORITY, + handle.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), NetLogWithSource())); EXPECT_FALSE(handle.is_initialized()); @@ -2260,7 +2272,7 @@ TEST_F(ClientSocketPoolBaseTest, AdditionalErrorStateAsynchronous) { ClientSocketHandle handle; TestCompletionCallback callback; EXPECT_EQ(ERR_IO_PENDING, - handle.Init("a", params_, DEFAULT_PRIORITY, + handle.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), NetLogWithSource())); EXPECT_EQ(LOAD_STATE_CONNECTING, pool_->GetLoadState("a", &handle)); @@ -2282,7 +2294,7 @@ TEST_F(ClientSocketPoolBaseTest, CleanupTimedOutIdleSocketsReuse) { ClientSocketHandle handle; TestCompletionCallback callback; - int rv = handle.Init("a", params_, LOWEST, + int rv = handle.Init("a", params_, LOWEST, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), NetLogWithSource()); ASSERT_THAT(rv, IsError(ERR_IO_PENDING)); @@ -2300,7 +2312,7 @@ TEST_F(ClientSocketPoolBaseTest, CleanupTimedOutIdleSocketsReuse) { // Request a new socket. This should reuse the old socket and complete // synchronously. BoundTestNetLog log; - rv = handle.Init("a", params_, LOWEST, + rv = handle.Init("a", params_, LOWEST, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, CompletionCallback(), pool_.get(), log.bound()); ASSERT_THAT(rv, IsOk()); @@ -2338,7 +2350,7 @@ TEST_F(ClientSocketPoolBaseTest, MAYBE_CleanupTimedOutIdleSocketsNoReuse) { ClientSocketHandle handle; TestCompletionCallback callback; - int rv = handle.Init("a", params_, LOWEST, + int rv = handle.Init("a", params_, LOWEST, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), NetLogWithSource()); ASSERT_THAT(rv, IsError(ERR_IO_PENDING)); @@ -2346,7 +2358,7 @@ TEST_F(ClientSocketPoolBaseTest, MAYBE_CleanupTimedOutIdleSocketsNoReuse) { ClientSocketHandle handle2; TestCompletionCallback callback2; - rv = handle2.Init("a", params_, LOWEST, + rv = handle2.Init("a", params_, LOWEST, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback2.callback(), pool_.get(), NetLogWithSource()); ASSERT_THAT(rv, IsError(ERR_IO_PENDING)); @@ -2377,7 +2389,7 @@ TEST_F(ClientSocketPoolBaseTest, MAYBE_CleanupTimedOutIdleSocketsNoReuse) { // A new socket will be created rather than reusing the idle one. BoundTestNetLog log; TestCompletionCallback callback3; - rv = handle.Init("a", params_, LOWEST, + rv = handle.Init("a", params_, LOWEST, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback3.callback(), pool_.get(), log.bound()); ASSERT_THAT(rv, IsError(ERR_IO_PENDING)); @@ -2409,28 +2421,28 @@ TEST_F(ClientSocketPoolBaseTest, MultipleReleasingDisconnectedSockets) { ClientSocketHandle handle; TestCompletionCallback callback; - int rv = handle.Init("a", params_, LOWEST, + int rv = handle.Init("a", params_, LOWEST, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsOk()); ClientSocketHandle handle2; TestCompletionCallback callback2; - rv = handle2.Init("a", params_, LOWEST, + rv = handle2.Init("a", params_, LOWEST, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback2.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsOk()); ClientSocketHandle handle3; TestCompletionCallback callback3; - rv = handle3.Init("a", params_, LOWEST, + rv = handle3.Init("a", params_, LOWEST, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback3.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); ClientSocketHandle handle4; TestCompletionCallback callback4; - rv = handle4.Init("a", params_, LOWEST, + rv = handle4.Init("a", params_, LOWEST, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback4.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); @@ -2467,11 +2479,11 @@ TEST_F(ClientSocketPoolBaseTest, SocketLimitReleasingSockets) { TestCompletionCallback callback_b[4]; for (int i = 0; i < 2; ++i) { - EXPECT_EQ(OK, handle_a[i].Init("a", params_, LOWEST, + EXPECT_EQ(OK, handle_a[i].Init("a", params_, LOWEST, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback_a[i].callback(), pool_.get(), NetLogWithSource())); - EXPECT_EQ(OK, handle_b[i].Init("b", params_, LOWEST, + EXPECT_EQ(OK, handle_b[i].Init("b", params_, LOWEST, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback_b[i].callback(), pool_.get(), NetLogWithSource())); @@ -2481,12 +2493,12 @@ TEST_F(ClientSocketPoolBaseTest, SocketLimitReleasingSockets) { for (int i = 2; i < 4; ++i) { EXPECT_EQ(ERR_IO_PENDING, - handle_a[i].Init("a", params_, LOWEST, + handle_a[i].Init("a", params_, LOWEST, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback_a[i].callback(), pool_.get(), NetLogWithSource())); EXPECT_EQ(ERR_IO_PENDING, - handle_b[i].Init("b", params_, LOWEST, + handle_b[i].Init("b", params_, LOWEST, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback_b[i].callback(), pool_.get(), NetLogWithSource())); @@ -2574,7 +2586,7 @@ class TestReleasingSocketRequest : public TestCompletionCallbackBase { scoped_refptr<TestSocketParams> con_params(new TestSocketParams()); EXPECT_EQ(expected_result_, - handle2_.Init("a", con_params, DEFAULT_PRIORITY, + handle2_.Init("a", con_params, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback2_.callback(), pool_, NetLogWithSource())); } @@ -2604,7 +2616,7 @@ TEST_F(ClientSocketPoolBaseTest, AdditionalErrorSocketsDontUseSlot) { TestReleasingSocketRequest req(pool_.get(), OK, false); EXPECT_EQ( ERR_IO_PENDING, - req.handle()->Init("a", params_, DEFAULT_PRIORITY, + req.handle()->Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, req.callback(), pool_.get(), NetLogWithSource())); // The next job should complete synchronously @@ -2632,7 +2644,7 @@ TEST_F(ClientSocketPoolBaseTest, CallbackThatReleasesPool) { ClientSocketHandle handle; TestCompletionCallback callback; EXPECT_EQ(ERR_IO_PENDING, - handle.Init("a", params_, DEFAULT_PRIORITY, + handle.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), NetLogWithSource())); @@ -2649,7 +2661,7 @@ TEST_F(ClientSocketPoolBaseTest, DoNotReuseSocketAfterFlush) { ClientSocketHandle handle; TestCompletionCallback callback; EXPECT_EQ(ERR_IO_PENDING, - handle.Init("a", params_, DEFAULT_PRIORITY, + handle.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), NetLogWithSource())); EXPECT_THAT(callback.WaitForResult(), IsOk()); @@ -2661,7 +2673,7 @@ TEST_F(ClientSocketPoolBaseTest, DoNotReuseSocketAfterFlush) { base::RunLoop().RunUntilIdle(); EXPECT_EQ(ERR_IO_PENDING, - handle.Init("a", params_, DEFAULT_PRIORITY, + handle.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), NetLogWithSource())); EXPECT_THAT(callback.WaitForResult(), IsOk()); @@ -2694,7 +2706,7 @@ class ConnectWithinCallback : public TestCompletionCallbackBase { SetResult(result); EXPECT_EQ( ERR_IO_PENDING, - handle_.Init(group_name_, params_, DEFAULT_PRIORITY, + handle_.Init(group_name_, params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, nested_callback_.callback(), pool_, NetLogWithSource())); } @@ -2718,7 +2730,7 @@ TEST_F(ClientSocketPoolBaseTest, AbortAllRequestsOnFlush) { ClientSocketHandle handle; ConnectWithinCallback callback("a", params_, pool_.get()); EXPECT_EQ(ERR_IO_PENDING, - handle.Init("a", params_, DEFAULT_PRIORITY, + handle.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), NetLogWithSource())); @@ -2743,7 +2755,7 @@ TEST_F(ClientSocketPoolBaseTest, BackupSocketCancelAtMaxSockets) { ClientSocketHandle handle; TestCompletionCallback callback; EXPECT_EQ(ERR_IO_PENDING, - handle.Init("bar", params_, DEFAULT_PRIORITY, + handle.Init("bar", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), NetLogWithSource())); @@ -2752,7 +2764,7 @@ TEST_F(ClientSocketPoolBaseTest, BackupSocketCancelAtMaxSockets) { ClientSocketHandle handles[kDefaultMaxSockets]; for (int i = 1; i < kDefaultMaxSockets; ++i) { TestCompletionCallback callback; - EXPECT_EQ(OK, handles[i].Init("bar", params_, DEFAULT_PRIORITY, + EXPECT_EQ(OK, handles[i].Init("bar", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), NetLogWithSource())); @@ -2781,7 +2793,7 @@ TEST_F(ClientSocketPoolBaseTest, CancelBackupSocketAfterCancelingAllRequests) { ClientSocketHandle handle; TestCompletionCallback callback; EXPECT_EQ(ERR_IO_PENDING, - handle.Init("bar", params_, DEFAULT_PRIORITY, + handle.Init("bar", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), NetLogWithSource())); ASSERT_TRUE(pool_->HasGroup("bar")); @@ -2809,7 +2821,7 @@ TEST_F(ClientSocketPoolBaseTest, CancelBackupSocketAfterFinishingAllRequests) { ClientSocketHandle handle; TestCompletionCallback callback; EXPECT_EQ(ERR_IO_PENDING, - handle.Init("bar", params_, DEFAULT_PRIORITY, + handle.Init("bar", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), NetLogWithSource())); connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob); @@ -2817,7 +2829,7 @@ TEST_F(ClientSocketPoolBaseTest, CancelBackupSocketAfterFinishingAllRequests) { TestCompletionCallback callback2; EXPECT_EQ( ERR_IO_PENDING, - handle2.Init("bar", params_, DEFAULT_PRIORITY, + handle2.Init("bar", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback2.callback(), pool_.get(), NetLogWithSource())); ASSERT_TRUE(pool_->HasGroup("bar")); @@ -2844,7 +2856,7 @@ TEST_F(ClientSocketPoolBaseTest, DelayedSocketBindingWaitingForConnect) { ClientSocketHandle handle1; TestCompletionCallback callback; EXPECT_EQ(ERR_IO_PENDING, - handle1.Init("a", params_, DEFAULT_PRIORITY, + handle1.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), NetLogWithSource())); EXPECT_THAT(callback.WaitForResult(), IsOk()); @@ -2857,7 +2869,7 @@ TEST_F(ClientSocketPoolBaseTest, DelayedSocketBindingWaitingForConnect) { connect_job_factory_->set_job_type(TestConnectJob::kMockWaitingJob); ClientSocketHandle handle2; EXPECT_EQ(ERR_IO_PENDING, - handle2.Init("a", params_, DEFAULT_PRIORITY, + handle2.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), NetLogWithSource())); // No idle sockets, and one connecting job. @@ -2896,7 +2908,7 @@ TEST_F(ClientSocketPoolBaseTest, DelayedSocketBindingAtGroupCapacity) { ClientSocketHandle handle1; TestCompletionCallback callback; EXPECT_EQ(ERR_IO_PENDING, - handle1.Init("a", params_, DEFAULT_PRIORITY, + handle1.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), NetLogWithSource())); EXPECT_THAT(callback.WaitForResult(), IsOk()); @@ -2909,7 +2921,7 @@ TEST_F(ClientSocketPoolBaseTest, DelayedSocketBindingAtGroupCapacity) { connect_job_factory_->set_job_type(TestConnectJob::kMockWaitingJob); ClientSocketHandle handle2; EXPECT_EQ(ERR_IO_PENDING, - handle2.Init("a", params_, DEFAULT_PRIORITY, + handle2.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), NetLogWithSource())); // No idle sockets, and one connecting job. @@ -2950,7 +2962,7 @@ TEST_F(ClientSocketPoolBaseTest, DelayedSocketBindingAtStall) { ClientSocketHandle handle1; TestCompletionCallback callback; EXPECT_EQ(ERR_IO_PENDING, - handle1.Init("a", params_, DEFAULT_PRIORITY, + handle1.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), NetLogWithSource())); EXPECT_THAT(callback.WaitForResult(), IsOk()); @@ -2963,7 +2975,7 @@ TEST_F(ClientSocketPoolBaseTest, DelayedSocketBindingAtStall) { connect_job_factory_->set_job_type(TestConnectJob::kMockWaitingJob); ClientSocketHandle handle2; EXPECT_EQ(ERR_IO_PENDING, - handle2.Init("a", params_, DEFAULT_PRIORITY, + handle2.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), NetLogWithSource())); // No idle sockets, and one connecting job. @@ -3008,7 +3020,7 @@ TEST_F(ClientSocketPoolBaseTest, SynchronouslyProcessOnePendingRequest) { TestCompletionCallback callback1; EXPECT_EQ( ERR_IO_PENDING, - handle1.Init("a", params_, DEFAULT_PRIORITY, + handle1.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback1.callback(), pool_.get(), NetLogWithSource())); EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a")); @@ -3022,7 +3034,7 @@ TEST_F(ClientSocketPoolBaseTest, SynchronouslyProcessOnePendingRequest) { // when created. EXPECT_EQ( ERR_IO_PENDING, - handle2.Init("a", params_, DEFAULT_PRIORITY, + handle2.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback2.callback(), pool_.get(), NetLogWithSource())); @@ -3042,7 +3054,7 @@ TEST_F(ClientSocketPoolBaseTest, PreferUsedSocketToUnusedSocket) { TestCompletionCallback callback1; EXPECT_EQ( ERR_IO_PENDING, - handle1.Init("a", params_, DEFAULT_PRIORITY, + handle1.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback1.callback(), pool_.get(), NetLogWithSource())); @@ -3050,14 +3062,14 @@ TEST_F(ClientSocketPoolBaseTest, PreferUsedSocketToUnusedSocket) { TestCompletionCallback callback2; EXPECT_EQ( ERR_IO_PENDING, - handle2.Init("a", params_, DEFAULT_PRIORITY, + handle2.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback2.callback(), pool_.get(), NetLogWithSource())); ClientSocketHandle handle3; TestCompletionCallback callback3; EXPECT_EQ( ERR_IO_PENDING, - handle3.Init("a", params_, DEFAULT_PRIORITY, + handle3.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback3.callback(), pool_.get(), NetLogWithSource())); @@ -3074,15 +3086,15 @@ TEST_F(ClientSocketPoolBaseTest, PreferUsedSocketToUnusedSocket) { handle3.Reset(); EXPECT_EQ( - OK, handle1.Init("a", params_, DEFAULT_PRIORITY, + OK, handle1.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback1.callback(), pool_.get(), NetLogWithSource())); EXPECT_EQ( - OK, handle2.Init("a", params_, DEFAULT_PRIORITY, + OK, handle2.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback2.callback(), pool_.get(), NetLogWithSource())); EXPECT_EQ( - OK, handle3.Init("a", params_, DEFAULT_PRIORITY, + OK, handle3.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback3.callback(), pool_.get(), NetLogWithSource())); @@ -3107,7 +3119,7 @@ TEST_F(ClientSocketPoolBaseTest, RequestSockets) { TestCompletionCallback callback1; EXPECT_EQ( ERR_IO_PENDING, - handle1.Init("a", params_, DEFAULT_PRIORITY, + handle1.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback1.callback(), pool_.get(), NetLogWithSource())); @@ -3115,7 +3127,7 @@ TEST_F(ClientSocketPoolBaseTest, RequestSockets) { TestCompletionCallback callback2; EXPECT_EQ( ERR_IO_PENDING, - handle2.Init("a", params_, DEFAULT_PRIORITY, + handle2.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback2.callback(), pool_.get(), NetLogWithSource())); @@ -3141,7 +3153,7 @@ TEST_F(ClientSocketPoolBaseTest, RequestSocketsWhenAlreadyHaveAConnectJob) { TestCompletionCallback callback1; EXPECT_EQ( ERR_IO_PENDING, - handle1.Init("a", params_, DEFAULT_PRIORITY, + handle1.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback1.callback(), pool_.get(), NetLogWithSource())); @@ -3161,7 +3173,7 @@ TEST_F(ClientSocketPoolBaseTest, RequestSocketsWhenAlreadyHaveAConnectJob) { TestCompletionCallback callback2; EXPECT_EQ( ERR_IO_PENDING, - handle2.Init("a", params_, DEFAULT_PRIORITY, + handle2.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback2.callback(), pool_.get(), NetLogWithSource())); @@ -3188,7 +3200,7 @@ TEST_F(ClientSocketPoolBaseTest, TestCompletionCallback callback1; EXPECT_EQ( ERR_IO_PENDING, - handle1.Init("a", params_, DEFAULT_PRIORITY, + handle1.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback1.callback(), pool_.get(), NetLogWithSource())); @@ -3196,7 +3208,7 @@ TEST_F(ClientSocketPoolBaseTest, TestCompletionCallback callback2; EXPECT_EQ( ERR_IO_PENDING, - handle2.Init("a", params_, DEFAULT_PRIORITY, + handle2.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback2.callback(), pool_.get(), NetLogWithSource())); @@ -3204,7 +3216,7 @@ TEST_F(ClientSocketPoolBaseTest, TestCompletionCallback callback3; EXPECT_EQ( ERR_IO_PENDING, - handle3.Init("a", params_, DEFAULT_PRIORITY, + handle3.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback3.callback(), pool_.get(), NetLogWithSource())); @@ -3286,7 +3298,7 @@ TEST_F(ClientSocketPoolBaseTest, RequestSocketsCountIdleSockets) { TestCompletionCallback callback1; EXPECT_EQ( ERR_IO_PENDING, - handle1.Init("a", params_, DEFAULT_PRIORITY, + handle1.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback1.callback(), pool_.get(), NetLogWithSource())); ASSERT_THAT(callback1.WaitForResult(), IsOk()); @@ -3313,7 +3325,7 @@ TEST_F(ClientSocketPoolBaseTest, RequestSocketsCountActiveSockets) { TestCompletionCallback callback1; EXPECT_EQ( ERR_IO_PENDING, - handle1.Init("a", params_, DEFAULT_PRIORITY, + handle1.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback1.callback(), pool_.get(), NetLogWithSource())); ASSERT_THAT(callback1.WaitForResult(), IsOk()); @@ -3392,14 +3404,14 @@ TEST_F(ClientSocketPoolBaseTest, RequestSocketsMultipleTimesDoesNothing) { TestCompletionCallback callback1; EXPECT_EQ( ERR_IO_PENDING, - handle1.Init("a", params_, DEFAULT_PRIORITY, + handle1.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback1.callback(), pool_.get(), NetLogWithSource())); ASSERT_THAT(callback1.WaitForResult(), IsOk()); ClientSocketHandle handle2; TestCompletionCallback callback2; - int rv = handle2.Init("a", params_, DEFAULT_PRIORITY, + int rv = handle2.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback2.callback(), pool_.get(), NetLogWithSource()); if (rv != OK) { @@ -3473,7 +3485,7 @@ TEST_F(ClientSocketPoolBaseTest, PreconnectJobsTakenByNormalRequests) { TestCompletionCallback callback1; EXPECT_EQ( ERR_IO_PENDING, - handle1.Init("a", params_, DEFAULT_PRIORITY, + handle1.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback1.callback(), pool_.get(), NetLogWithSource())); @@ -3507,7 +3519,7 @@ TEST_F(ClientSocketPoolBaseTest, ConnectedPreconnectJobsHaveNoConnectTimes) { ClientSocketHandle handle; TestCompletionCallback callback; EXPECT_EQ(OK, - handle.Init("a", params_, DEFAULT_PRIORITY, + handle.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), NetLogWithSource())); @@ -3534,7 +3546,7 @@ TEST_F(ClientSocketPoolBaseTest, PreconnectClosesIdleSocketRemovesGroup) { TestCompletionCallback callback1; EXPECT_EQ( ERR_IO_PENDING, - handle1.Init("a", params_, DEFAULT_PRIORITY, + handle1.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback1.callback(), pool_.get(), NetLogWithSource())); @@ -3547,12 +3559,12 @@ TEST_F(ClientSocketPoolBaseTest, PreconnectClosesIdleSocketRemovesGroup) { TestCompletionCallback callback2; EXPECT_EQ( ERR_IO_PENDING, - handle1.Init("b", params_, DEFAULT_PRIORITY, + handle1.Init("b", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback1.callback(), pool_.get(), NetLogWithSource())); EXPECT_EQ( ERR_IO_PENDING, - handle2.Init("b", params_, DEFAULT_PRIORITY, + handle2.Init("b", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback2.callback(), pool_.get(), NetLogWithSource())); @@ -3641,7 +3653,7 @@ TEST_F(ClientSocketPoolBaseTest, PreconnectWithBackupJob) { ClientSocketHandle handle; TestCompletionCallback callback; EXPECT_EQ(ERR_IO_PENDING, - handle.Init("a", params_, DEFAULT_PRIORITY, + handle.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), NetLogWithSource())); // Timer has started, but the backup connect job shouldn't be created yet. @@ -3679,7 +3691,7 @@ TEST_F(ClientSocketPoolBaseTest, PreconnectWithUnreadData) { ClientSocketHandle handle; TestCompletionCallback callback; EXPECT_EQ(OK, - handle.Init("a", params_, DEFAULT_PRIORITY, + handle.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), NetLogWithSource())); @@ -3714,7 +3726,7 @@ TEST_F(ClientSocketPoolBaseTest, PreconnectSetsMotivation) { TestCompletionCallback callback; EXPECT_EQ( ERR_IO_PENDING, - handle.Init("a", params_, DEFAULT_PRIORITY, + handle.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), NetLogWithSource())); @@ -3753,7 +3765,7 @@ TEST_F(ClientSocketPoolBaseTest, PreconnectPreservesExistingMotivation) { for (size_t i = 0; i < 3; ++i) { EXPECT_EQ(ERR_IO_PENDING, - handles[i].Init("a", params_, DEFAULT_PRIORITY, + handles[i].Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callbacks[i].callback(), pool_.get(), NetLogWithSource())); @@ -3794,14 +3806,14 @@ class MockLayeredPool : public HigherLayeredPool { int RequestSocket(TestClientSocketPool* pool) { scoped_refptr<TestSocketParams> params(new TestSocketParams()); - return handle_.Init(group_name_, params, DEFAULT_PRIORITY, + return handle_.Init(group_name_, params, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback_.callback(), pool, NetLogWithSource()); } int RequestSocketWithoutLimits(TestClientSocketPool* pool) { scoped_refptr<TestSocketParams> params(new TestSocketParams()); - return handle_.Init(group_name_, params, MAXIMUM_PRIORITY, + return handle_.Init(group_name_, params, MAXIMUM_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::DISABLED, callback_.callback(), pool, NetLogWithSource()); } @@ -3866,7 +3878,7 @@ TEST_F(ClientSocketPoolBaseTest, CloseIdleSocketsHeldByLayeredPoolWhenNeeded) { ClientSocketHandle handle; TestCompletionCallback callback; EXPECT_EQ(ERR_IO_PENDING, - handle.Init("a", params_, DEFAULT_PRIORITY, + handle.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), NetLogWithSource())); EXPECT_THAT(callback.WaitForResult(), IsOk()); @@ -3887,7 +3899,7 @@ TEST_F(ClientSocketPoolBaseTest, ClientSocketHandle handle1; TestCompletionCallback callback1; EXPECT_EQ( - OK, handle1.Init("group1", params_, DEFAULT_PRIORITY, + OK, handle1.Init("group1", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback1.callback(), pool_.get(), NetLogWithSource())); @@ -3899,7 +3911,7 @@ TEST_F(ClientSocketPoolBaseTest, ClientSocketHandle handle; TestCompletionCallback callback2; EXPECT_EQ(ERR_IO_PENDING, - handle.Init("group2", params_, DEFAULT_PRIORITY, + handle.Init("group2", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback2.callback(), pool_.get(), NetLogWithSource())); EXPECT_THAT(callback2.WaitForResult(), IsOk()); @@ -3920,7 +3932,7 @@ TEST_F(ClientSocketPoolBaseTest, ClientSocketHandle handle1; TestCompletionCallback callback1; EXPECT_EQ( - OK, handle1.Init("group1", params_, DEFAULT_PRIORITY, + OK, handle1.Init("group1", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback1.callback(), pool_.get(), NetLogWithSource())); @@ -3936,7 +3948,7 @@ TEST_F(ClientSocketPoolBaseTest, TestCompletionCallback callback3; EXPECT_EQ( ERR_IO_PENDING, - handle3.Init("group3", params_, DEFAULT_PRIORITY, + handle3.Init("group3", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback3.callback(), pool_.get(), NetLogWithSource())); @@ -3951,7 +3963,7 @@ TEST_F(ClientSocketPoolBaseTest, TestCompletionCallback callback4; EXPECT_EQ( ERR_IO_PENDING, - handle4.Init("group3", params_, DEFAULT_PRIORITY, + handle4.Init("group3", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback4.callback(), pool_.get(), NetLogWithSource())); EXPECT_THAT(callback3.WaitForResult(), IsOk()); @@ -3981,7 +3993,7 @@ TEST_F(ClientSocketPoolBaseTest, ClientSocketHandle handle1; TestCompletionCallback callback1; EXPECT_EQ( - OK, handle1.Init("group1", params_, DEFAULT_PRIORITY, + OK, handle1.Init("group1", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback1.callback(), pool_.get(), NetLogWithSource())); @@ -3997,7 +4009,7 @@ TEST_F(ClientSocketPoolBaseTest, TestCompletionCallback callback3; EXPECT_EQ( ERR_IO_PENDING, - handle3.Init("group3", params_, MEDIUM, + handle3.Init("group3", params_, MEDIUM, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback3.callback(), pool_.get(), NetLogWithSource())); @@ -4011,7 +4023,7 @@ TEST_F(ClientSocketPoolBaseTest, TestCompletionCallback callback4; EXPECT_EQ( ERR_IO_PENDING, - handle4.Init("group3", params_, HIGHEST, + handle4.Init("group3", params_, HIGHEST, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback4.callback(), pool_.get(), NetLogWithSource())); EXPECT_THAT(callback4.WaitForResult(), IsOk()); @@ -4041,7 +4053,7 @@ TEST_F(ClientSocketPoolBaseTest, ClientSocketHandle handle; TestCompletionCallback callback; EXPECT_EQ(ERR_IO_PENDING, - handle.Init("a", params_, DEFAULT_PRIORITY, + handle.Init("a", params_, DEFAULT_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), NetLogWithSource())); EXPECT_THAT(callback.WaitForResult(), IsOk()); diff --git a/chromium/net/socket/client_socket_pool_manager.cc b/chromium/net/socket/client_socket_pool_manager.cc index ffec16ff294..4bc94e61805 100644 --- a/chromium/net/socket/client_socket_pool_manager.cc +++ b/chromium/net/socket/client_socket_pool_manager.cc @@ -76,6 +76,7 @@ int InitSocketPoolHelper(ClientSocketPoolManager::SocketGroupType group_type, const SSLConfig& ssl_config_for_proxy, bool force_tunnel, PrivacyMode privacy_mode, + const SocketTag& socket_tag, const NetLogWithSource& net_log, int num_preconnect_streams, ClientSocketHandle* socket_handle, @@ -153,6 +154,14 @@ int InitSocketPoolHelper(ClientSocketPoolManager::SocketGroupType group_type, non_ssl_combine_connect_and_write_policy)); if (proxy_info.is_http() || proxy_info.is_https()) { + // TODO(mmenke): Would it be better to split these into two different + // socket pools? And maybe socks4/socks5 as well? + if (proxy_info.is_http()) { + connection_group = "http_proxy/" + connection_group; + } else { + connection_group = "https_proxy/" + connection_group; + } + std::string user_agent; request_extra_headers.GetHeader(HttpRequestHeaders::kUserAgent, &user_agent); @@ -177,8 +186,7 @@ int InitSocketPoolHelper(ClientSocketPoolManager::SocketGroupType group_type, proxy_tcp_params, ssl_params, QUIC_VERSION_UNSUPPORTED, user_agent, origin_host_port, session->http_auth_cache(), session->http_auth_handler_factory(), session->spdy_session_pool(), - session->quic_stream_factory(), force_tunnel || using_ssl, - session->context().proxy_delegate); + session->quic_stream_factory(), force_tunnel || using_ssl); } else { DCHECK(proxy_info.is_socks()); char socks_version; @@ -189,9 +197,9 @@ int InitSocketPoolHelper(ClientSocketPoolManager::SocketGroupType group_type, connection_group = base::StringPrintf( "socks%c/%s", socks_version, connection_group.c_str()); - socks_params = new SOCKSSocketParams(proxy_tcp_params, - socks_version == '5', - origin_host_port); + socks_params = new SOCKSSocketParams( + proxy_tcp_params, socks_version == '5', origin_host_port, + proxy_info.traffic_annotation()); } } @@ -225,7 +233,8 @@ int InitSocketPoolHelper(ClientSocketPoolManager::SocketGroupType group_type, } return socket_handle->Init(connection_group, ssl_params, request_priority, - respect_limits, callback, ssl_pool, net_log); + socket_tag, respect_limits, callback, ssl_pool, + net_log); } // Finally, get the connection started. @@ -240,8 +249,8 @@ int InitSocketPoolHelper(ClientSocketPoolManager::SocketGroupType group_type, } return socket_handle->Init(connection_group, http_proxy_params, - request_priority, respect_limits, callback, pool, - net_log); + request_priority, socket_tag, respect_limits, + callback, pool, net_log); } if (proxy_info.is_socks()) { @@ -254,7 +263,8 @@ int InitSocketPoolHelper(ClientSocketPoolManager::SocketGroupType group_type, } return socket_handle->Init(connection_group, socks_params, request_priority, - respect_limits, callback, pool, net_log); + socket_tag, respect_limits, callback, pool, + net_log); } DCHECK(proxy_info.is_direct()); @@ -270,7 +280,8 @@ int InitSocketPoolHelper(ClientSocketPoolManager::SocketGroupType group_type, } return socket_handle->Init(connection_group, tcp_params, request_priority, - respect_limits, callback, pool, net_log); + socket_tag, respect_limits, callback, pool, + net_log); } } // namespace @@ -353,6 +364,7 @@ int InitSocketHandleForHttpRequest( const SSLConfig& ssl_config_for_origin, const SSLConfig& ssl_config_for_proxy, PrivacyMode privacy_mode, + const SocketTag& socket_tag, const NetLogWithSource& net_log, ClientSocketHandle* socket_handle, const OnHostResolutionCallback& resolution_callback, @@ -362,7 +374,7 @@ int InitSocketHandleForHttpRequest( group_type, endpoint, request_extra_headers, request_load_flags, request_priority, session, proxy_info, expect_spdy, quic_version, ssl_config_for_origin, ssl_config_for_proxy, /*force_tunnel=*/false, - privacy_mode, net_log, 0, socket_handle, + privacy_mode, socket_tag, net_log, 0, socket_handle, HttpNetworkSession::NORMAL_SOCKET_POOL, resolution_callback, callback, HttpRequestInfo::NORMAL_MOTIVATION); } @@ -388,9 +400,9 @@ int InitSocketHandleForWebSocketRequest( group_type, endpoint, request_extra_headers, request_load_flags, request_priority, session, proxy_info, expect_spdy, QUIC_VERSION_UNSUPPORTED, ssl_config_for_origin, ssl_config_for_proxy, - /*force_tunnel=*/true, privacy_mode, net_log, 0, socket_handle, - HttpNetworkSession::WEBSOCKET_SOCKET_POOL, resolution_callback, callback, - HttpRequestInfo::NORMAL_MOTIVATION); + /*force_tunnel=*/true, privacy_mode, SocketTag(), net_log, 0, + socket_handle, HttpNetworkSession::WEBSOCKET_SOCKET_POOL, + resolution_callback, callback, HttpRequestInfo::NORMAL_MOTIVATION); } int InitSocketHandleForRawConnect(const HostPortPair& host_port_pair, @@ -411,7 +423,7 @@ int InitSocketHandleForRawConnect(const HostPortPair& host_port_pair, request_extra_headers, request_load_flags, request_priority, session, proxy_info, /*expect_spdy=*/false, QUIC_VERSION_UNSUPPORTED, ssl_config_for_origin, ssl_config_for_proxy, /*force_tunnel=*/true, - privacy_mode, net_log, 0, socket_handle, + privacy_mode, SocketTag(), net_log, 0, socket_handle, HttpNetworkSession::NORMAL_SOCKET_POOL, OnHostResolutionCallback(), callback, HttpRequestInfo::NORMAL_MOTIVATION); } @@ -433,8 +445,8 @@ int InitSocketHandleForTlsConnect(const HostPortPair& endpoint, ClientSocketPoolManager::SSL_GROUP, endpoint, request_extra_headers, request_load_flags, request_priority, session, proxy_info, /*expect_spdy=*/false, QUIC_VERSION_UNSUPPORTED, ssl_config_for_origin, - ssl_config_for_proxy, /*force_tunnel=*/true, privacy_mode, net_log, 0, - socket_handle, HttpNetworkSession::NORMAL_SOCKET_POOL, + ssl_config_for_proxy, /*force_tunnel=*/true, privacy_mode, SocketTag(), + net_log, 0, socket_handle, HttpNetworkSession::NORMAL_SOCKET_POOL, OnHostResolutionCallback(), callback, HttpRequestInfo::NORMAL_MOTIVATION); } @@ -457,9 +469,9 @@ int PreconnectSocketsForHttpRequest( group_type, endpoint, request_extra_headers, request_load_flags, request_priority, session, proxy_info, expect_spdy, QUIC_VERSION_UNSUPPORTED, ssl_config_for_origin, ssl_config_for_proxy, - /*force_tunnel=*/false, privacy_mode, net_log, num_preconnect_streams, - NULL, HttpNetworkSession::NORMAL_SOCKET_POOL, OnHostResolutionCallback(), - CompletionCallback(), motivation); + /*force_tunnel=*/false, privacy_mode, SocketTag(), net_log, + num_preconnect_streams, NULL, HttpNetworkSession::NORMAL_SOCKET_POOL, + OnHostResolutionCallback(), CompletionCallback(), motivation); } } // namespace net diff --git a/chromium/net/socket/client_socket_pool_manager.h b/chromium/net/socket/client_socket_pool_manager.h index e813854f14b..6412fe1bdb5 100644 --- a/chromium/net/socket/client_socket_pool_manager.h +++ b/chromium/net/socket/client_socket_pool_manager.h @@ -118,6 +118,7 @@ int InitSocketHandleForHttpRequest( const SSLConfig& ssl_config_for_origin, const SSLConfig& ssl_config_for_proxy, PrivacyMode privacy_mode, + const SocketTag& socket_tag, const NetLogWithSource& net_log, ClientSocketHandle* socket_handle, const OnHostResolutionCallback& resolution_callback, diff --git a/chromium/net/socket/datagram_client_socket.h b/chromium/net/socket/datagram_client_socket.h index dbec1c2b3b4..ca656b361df 100644 --- a/chromium/net/socket/datagram_client_socket.h +++ b/chromium/net/socket/datagram_client_socket.h @@ -13,6 +13,7 @@ namespace net { class IPEndPoint; +class SocketTag; class NET_EXPORT_PRIVATE DatagramClientSocket : public DatagramSocket, public Socket { @@ -41,6 +42,8 @@ class NET_EXPORT_PRIVATE DatagramClientSocket : public DatagramSocket, // ConnectUsingNetwork() or ConnectUsingDefaultNetwork(). virtual NetworkChangeNotifier::NetworkHandle GetBoundNetwork() const = 0; + // Apply |tag| to this socket. + virtual void ApplySocketTag(const SocketTag& tag) = 0; }; } // namespace net diff --git a/chromium/net/socket/fuzzed_datagram_client_socket.cc b/chromium/net/socket/fuzzed_datagram_client_socket.cc index 85db48582a6..65043f505e3 100644 --- a/chromium/net/socket/fuzzed_datagram_client_socket.cc +++ b/chromium/net/socket/fuzzed_datagram_client_socket.cc @@ -15,6 +15,7 @@ #include "net/base/io_buffer.h" #include "net/base/ip_address.h" #include "net/base/net_errors.h" +#include "net/traffic_annotation/network_traffic_annotation.h" namespace net { @@ -64,6 +65,8 @@ FuzzedDatagramClientSocket::GetBoundNetwork() const { return NetworkChangeNotifier::kInvalidNetworkHandle; } +void FuzzedDatagramClientSocket::ApplySocketTag(const SocketTag& tag) {} + void FuzzedDatagramClientSocket::Close() { connected_ = false; read_pending_ = false; @@ -130,9 +133,11 @@ int FuzzedDatagramClientSocket::Read(IOBuffer* buf, return ERR_IO_PENDING; } -int FuzzedDatagramClientSocket::Write(IOBuffer* buf, - int buf_len, - const CompletionCallback& callback) { +int FuzzedDatagramClientSocket::Write( + IOBuffer* buf, + int buf_len, + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& /* traffic_annotation */) { CHECK(!callback.is_null()); CHECK(!write_pending_); diff --git a/chromium/net/socket/fuzzed_datagram_client_socket.h b/chromium/net/socket/fuzzed_datagram_client_socket.h index a354e8ed790..6d195626ad9 100644 --- a/chromium/net/socket/fuzzed_datagram_client_socket.h +++ b/chromium/net/socket/fuzzed_datagram_client_socket.h @@ -14,6 +14,7 @@ #include "net/base/ip_endpoint.h" #include "net/base/network_change_notifier.h" #include "net/log/net_log_with_source.h" +#include "net/traffic_annotation/network_traffic_annotation.h" namespace base { class FuzzedDataProvider; @@ -38,6 +39,7 @@ class FuzzedDatagramClientSocket : public DatagramClientSocket { const IPEndPoint& address) override; int ConnectUsingDefaultNetwork(const IPEndPoint& address) override; NetworkChangeNotifier::NetworkHandle GetBoundNetwork() const override; + void ApplySocketTag(const SocketTag& tag) override; // DatagramSocket implementation: void Close() override; @@ -52,7 +54,8 @@ class FuzzedDatagramClientSocket : public DatagramClientSocket { const CompletionCallback& callback) override; int Write(IOBuffer* buf, int buf_len, - const CompletionCallback& callback) override; + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& traffic_annotation) override; int SetReceiveBufferSize(int32_t size) override; int SetSendBufferSize(int32_t size) override; int SetDoNotFragment() override; diff --git a/chromium/net/socket/fuzzed_socket.cc b/chromium/net/socket/fuzzed_socket.cc index 08be4bf2aa4..be62fff5a8b 100644 --- a/chromium/net/socket/fuzzed_socket.cc +++ b/chromium/net/socket/fuzzed_socket.cc @@ -13,6 +13,7 @@ #include "base/threading/thread_task_runner_handle.h" #include "net/base/io_buffer.h" #include "net/log/net_log_source_type.h" +#include "net/traffic_annotation/network_traffic_annotation.h" namespace net { @@ -89,9 +90,11 @@ int FuzzedSocket::Read(IOBuffer* buf, return ERR_IO_PENDING; } -int FuzzedSocket::Write(IOBuffer* buf, - int buf_len, - const CompletionCallback& callback) { +int FuzzedSocket::Write( + IOBuffer* buf, + int buf_len, + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& /* traffic_annotation */) { DCHECK(!connect_pending_); DCHECK(!write_pending_); @@ -240,6 +243,8 @@ int64_t FuzzedSocket::GetTotalReceivedBytes() const { return total_bytes_read_; } +void FuzzedSocket::ApplySocketTag(const net::SocketTag& tag) {} + Error FuzzedSocket::ConsumeReadWriteErrorFromData() { return data_provider_->PickValueInArray(kReadWriteErrors); } diff --git a/chromium/net/socket/fuzzed_socket.h b/chromium/net/socket/fuzzed_socket.h index 2da0b03cb5d..3340e4349d7 100644 --- a/chromium/net/socket/fuzzed_socket.h +++ b/chromium/net/socket/fuzzed_socket.h @@ -15,6 +15,7 @@ #include "net/base/net_errors.h" #include "net/log/net_log_with_source.h" #include "net/socket/stream_socket.h" +#include "net/traffic_annotation/network_traffic_annotation.h" namespace base { class FuzzedDataProvider; @@ -63,7 +64,8 @@ class FuzzedSocket : public StreamSocket { const CompletionCallback& callback) override; int Write(IOBuffer* buf, int buf_len, - const CompletionCallback& callback) override; + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& traffic_annotation) override; int SetReceiveBufferSize(int32_t size) override; int SetSendBufferSize(int32_t size) override; @@ -86,6 +88,7 @@ class FuzzedSocket : public StreamSocket { void ClearConnectionAttempts() override; void AddConnectionAttempts(const ConnectionAttempts& attempts) override; int64_t GetTotalReceivedBytes() const override; + void ApplySocketTag(const net::SocketTag& tag) override; private: // Returns a net::Error that can be returned by a read or a write. Reads and diff --git a/chromium/net/socket/fuzzed_socket_factory.cc b/chromium/net/socket/fuzzed_socket_factory.cc index 55ffd99125c..ca158aea386 100644 --- a/chromium/net/socket/fuzzed_socket_factory.cc +++ b/chromium/net/socket/fuzzed_socket_factory.cc @@ -16,6 +16,7 @@ #include "net/socket/fuzzed_datagram_client_socket.h" #include "net/socket/fuzzed_socket.h" #include "net/socket/ssl_client_socket.h" +#include "net/traffic_annotation/network_traffic_annotation.h" namespace net { @@ -39,7 +40,8 @@ class FailingSSLClientSocket : public SSLClientSocket { int Write(IOBuffer* buf, int buf_len, - const CompletionCallback& callback) override { + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& traffic_annotation) override { NOTREACHED(); return ERR_UNEXPECTED; } @@ -88,6 +90,8 @@ class FailingSSLClientSocket : public SSLClientSocket { int64_t GetTotalReceivedBytes() const override { return 0; } + void ApplySocketTag(const net::SocketTag& tag) override {} + // SSLSocket implementation: int ExportKeyingMaterial(const base::StringPiece& label, bool has_context, diff --git a/chromium/net/socket/sequenced_socket_data_unittest.cc b/chromium/net/socket/sequenced_socket_data_unittest.cc index 4d54f23322f..e2bae3a93e1 100644 --- a/chromium/net/socket/sequenced_socket_data_unittest.cc +++ b/chromium/net/socket/sequenced_socket_data_unittest.cc @@ -12,6 +12,7 @@ #include "net/base/test_completion_callback.h" #include "net/log/net_log_with_source.h" #include "net/socket/client_socket_handle.h" +#include "net/socket/socket_tag.h" #include "net/socket/socket_test_util.h" #include "net/socket/transport_client_socket_pool.h" #include "net/test/gtest_util.h" @@ -267,7 +268,7 @@ void SequencedSocketDataTest::Initialize(MockRead* reads, EXPECT_EQ(OK, connection_.Init( - endpoint_.ToString(), tcp_params_, LOWEST, + endpoint_.ToString(), tcp_params_, LOWEST, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, CompletionCallback(), reinterpret_cast<TransportClientSocketPool*>(&socket_pool_), NetLogWithSource())); @@ -671,8 +672,8 @@ TEST_F(SequencedSocketDataTest, SingleSyncWriteTooSmall) { static const char* kExpectedFailures[] = { "Expected: (data.length()) >= (expected_data.length())", - "To be equal to: actual_data", - "To be equal to: sock_->Write(buf.get(), len, failing_callback_)"}; + "Value of: actual_data == expected_data\n Actual: false\nExpected: true", + "Expected equality of these values:\n rv"}; ASSERT_EQ(arraysize(kExpectedFailures), static_cast<size_t>(gtest_failures.size())); diff --git a/chromium/net/socket/socket.h b/chromium/net/socket/socket.h index 8f5fed6dea0..1d0ab9297d7 100644 --- a/chromium/net/socket/socket.h +++ b/chromium/net/socket/socket.h @@ -10,6 +10,7 @@ #include "base/feature_list.h" #include "net/base/completion_callback.h" #include "net/base/net_export.h" +#include "net/traffic_annotation/network_traffic_annotation.h" namespace net { @@ -62,8 +63,14 @@ class NET_EXPORT Socket { // closed. Implementations of this method should not modify the contents // of the actual buffer that is written to the socket. If the socket is // Disconnected before the write completes, the callback will not be invoked. - virtual int Write(IOBuffer* buf, int buf_len, - const CompletionCallback& callback) = 0; + // |traffic_annotation| provides the required description for auditing. Please + // refer to //docs/network_traffic_annotations.md for more details. + // TODO(crbug.com/656607): Remove default value. + virtual int Write(IOBuffer* buf, + int buf_len, + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& traffic_annotation = + NO_TRAFFIC_ANNOTATION_BUG_656607) = 0; // Set the receive buffer size (in bytes) for the socket. // Note: changing this value can affect the TCP window size on some platforms. diff --git a/chromium/net/socket/socket_posix.cc b/chromium/net/socket/socket_posix.cc index ae9bb1e3b78..91ce4e82e7a 100644 --- a/chromium/net/socket/socket_posix.cc +++ b/chromium/net/socket/socket_posix.cc @@ -20,6 +20,7 @@ #include "net/base/net_errors.h" #include "net/base/sockaddr_storage.h" #include "net/base/trace_constants.h" +#include "net/traffic_annotation/network_traffic_annotation.h" #if defined(OS_FUCHSIA) #include <poll.h> @@ -346,9 +347,11 @@ int SocketPosix::ReadIfReady(IOBuffer* buf, return ERR_IO_PENDING; } -int SocketPosix::Write(IOBuffer* buf, - int buf_len, - const CompletionCallback& callback) { +int SocketPosix::Write( + IOBuffer* buf, + int buf_len, + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& /* traffic_annotation */) { DCHECK(thread_checker_.CalledOnValidThread()); DCHECK_NE(kInvalidSocket, socket_fd_); DCHECK(!waiting_connect_); diff --git a/chromium/net/socket/socket_posix.h b/chromium/net/socket/socket_posix.h index 04ef7f6cb95..cdccc8c04bf 100644 --- a/chromium/net/socket/socket_posix.h +++ b/chromium/net/socket/socket_posix.h @@ -15,6 +15,7 @@ #include "net/base/completion_callback.h" #include "net/base/net_export.h" #include "net/socket/socket_descriptor.h" +#include "net/traffic_annotation/network_traffic_annotation.h" namespace net { @@ -75,7 +76,10 @@ class NET_EXPORT_PRIVATE SocketPosix : public base::MessageLoopForIO::Watcher { int ReadIfReady(IOBuffer* buf, int buf_len, const CompletionCallback& callback); - int Write(IOBuffer* buf, int buf_len, const CompletionCallback& callback); + int Write(IOBuffer* buf, + int buf_len, + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& traffic_annotation); // Waits for next write event. This is called by TCPSocketPosix for TCP // fastopen after sending first data. Returns ERR_IO_PENDING if it starts diff --git a/chromium/net/socket/socket_tag_unittest.cc b/chromium/net/socket/socket_tag_unittest.cc index 59b0f69db3b..93bd8b3be23 100644 --- a/chromium/net/socket/socket_tag_unittest.cc +++ b/chromium/net/socket/socket_tag_unittest.cc @@ -12,64 +12,17 @@ #include <sys/types.h> #endif -#include <inttypes.h> // For SCNx64 #include <stdint.h> -#include <stdio.h> -#include <string> - -#include "base/files/file_util.h" #include "net/base/ip_address.h" #include "net/base/ip_endpoint.h" #include "net/base/sockaddr_storage.h" +#include "net/socket/socket_test_util.h" #include "net/test/embedded_test_server/embedded_test_server.h" #include "testing/gtest/include/gtest/gtest.h" namespace net { -namespace { - -#if defined(OS_ANDROID) -// Query the system to find out how many bytes were received with tag -// |expected_tag| for our UID. Return the count of recieved bytes. -uint64_t GetTaggedBytes(int32_t expected_tag) { - // To determine how many bytes the system saw with a particular tag read - // the /proc/net/xt_qtaguid/stats file which contains the kernel's - // dump of all the UIDs and their tags sent and received bytes. - uint64_t bytes = 0; - std::string contents; - EXPECT_TRUE(base::ReadFileToString( - base::FilePath::FromUTF8Unsafe("/proc/net/xt_qtaguid/stats"), &contents)); - for (size_t i = contents.find('\n'); // Skip first line which is headers. - i != std::string::npos && i < contents.length();) { - uint64_t tag, rx_bytes; - uid_t uid; - int n; - // Parse out the numbers we care about. For reference here's the column - // headers: - // idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes - // tx_packets rx_tcp_bytes rx_tcp_packets rx_udp_bytes rx_udp_packets - // rx_other_bytes rx_other_packets tx_tcp_bytes tx_tcp_packets tx_udp_bytes - // tx_udp_packets tx_other_bytes tx_other_packets - EXPECT_EQ(sscanf(contents.c_str() + i, - "%*d %*s 0x%" SCNx64 " %d %*d %" SCNu64 - " %*d %*d %*d %*d %*d %*d %*d %*d " - "%*d %*d %*d %*d %*d %*d %*d%n", - &tag, &uid, &rx_bytes, &n), - 3); - // If this line matches our UID and |expected_tag| then add it to the total. - if (uid == getuid() && (int32_t)(tag >> 32) == expected_tag) { - bytes += rx_bytes; - } - // Move |i| to the next line. - i += n + 1; - } - return bytes; -} -#endif - -} // namespace - // Test that SocketTag's comparison function work. TEST(SocketTagTest, Compares) { SocketTag unset1; @@ -126,20 +79,24 @@ TEST(SocketTagTest, Apply) { ASSERT_EQ(connect(s, addr.addr, addr.addr_len), 0); EXPECT_GT(GetTaggedBytes(tag_val1), old_traffic); - // Verify socket can be retagged and with our UID. + // Verify socket can be retagged with a new value and the current process's + // UID. int32_t tag_val2 = 0x87654321; old_traffic = GetTaggedBytes(tag_val2); SocketTag tag2(getuid(), tag_val2); tag2.Apply(s); - const char kRequest1[] = "GET /"; - ASSERT_EQ(send(s, kRequest1, strlen(kRequest1), 0), (int)strlen(kRequest1)); + const char kRequest1[] = "GET / HTTP/1.0"; + ASSERT_EQ(send(s, kRequest1, strlen(kRequest1), 0), + static_cast<int>(strlen(kRequest1))); EXPECT_GT(GetTaggedBytes(tag_val2), old_traffic); - // Verify socket can be retagged and with our UID. + // Verify socket can be retagged with a new value and the current process's + // UID. old_traffic = GetTaggedBytes(tag_val1); tag1.Apply(s); const char kRequest2[] = "\n\n"; - ASSERT_EQ(send(s, kRequest2, strlen(kRequest2), 0), (int)strlen(kRequest2)); + ASSERT_EQ(send(s, kRequest2, strlen(kRequest2), 0), + static_cast<int>(strlen(kRequest2))); EXPECT_GT(GetTaggedBytes(tag_val1), old_traffic); ASSERT_EQ(close(s), 0); diff --git a/chromium/net/socket/socket_test_util.cc b/chromium/net/socket/socket_test_util.cc index e6b52532489..daa5a898588 100644 --- a/chromium/net/socket/socket_test_util.cc +++ b/chromium/net/socket/socket_test_util.cc @@ -4,7 +4,12 @@ #include "net/socket/socket_test_util.h" +#include <inttypes.h> // For SCNx64 +#include <stdint.h> +#include <stdio.h> + #include <algorithm> +#include <string> #include <utility> #include <vector> @@ -12,6 +17,7 @@ #include "base/bind_helpers.h" #include "base/callback_helpers.h" #include "base/compiler_specific.h" +#include "base/files/file_util.h" #include "base/location.h" #include "base/logging.h" #include "base/run_loop.h" @@ -21,6 +27,7 @@ #include "net/base/address_family.h" #include "net/base/address_list.h" #include "net/base/auth.h" +#include "net/base/hex_utils.h" #include "net/base/ip_address.h" #include "net/base/load_timing_info.h" #include "net/http/http_network_session.h" @@ -33,6 +40,7 @@ #include "net/ssl/ssl_cert_request_info.h" #include "net/ssl/ssl_connection_status_flags.h" #include "net/ssl/ssl_info.h" +#include "net/traffic_annotation/network_traffic_annotation_test_helper.h" #include "testing/gtest/include/gtest/gtest.h" #define NET_TRACE(level, s) VLOG(level) << s << __FUNCTION__ << "() " @@ -222,7 +230,9 @@ bool StaticSocketDataHelper::VerifyWriteData(const std::string& data) { std::string expected_data(next_write.data, next_write.data_len); std::string actual_data(data.substr(0, next_write.data_len)); EXPECT_GE(data.length(), expected_data.length()); - EXPECT_EQ(expected_data, actual_data); + EXPECT_TRUE(actual_data == expected_data) + << "Actual write data:\n" << HexDump(actual_data) + << "Expected write data:\n" << HexDump(expected_data); return expected_data == actual_data; } @@ -259,10 +269,10 @@ MockWriteResult StaticSocketDataProvider::OnWrite(const std::string& data) { // Not using mock writes; succeed synchronously. return MockWriteResult(SYNCHRONOUS, data.length()); } - EXPECT_FALSE(helper_.AllWriteDataConsumed()); + EXPECT_FALSE(helper_.AllWriteDataConsumed()) + << "No more mock data to match write:\n" + << HexDump(data); if (helper_.AllWriteDataConsumed()) { - // Show what the extra write actually consists of. - EXPECT_EQ("<unexpected write>", data); return MockWriteResult(SYNCHRONOUS, ERR_UNEXPECTED); } @@ -438,7 +448,9 @@ MockRead SequencedSocketData::OnRead() { MockWriteResult SequencedSocketData::OnWrite(const std::string& data) { CHECK_EQ(IDLE, write_state_); - CHECK(!helper_.AllWriteDataConsumed()); + CHECK(!helper_.AllWriteDataConsumed()) + << "\nNo more mock data to match write:\n" + << HexDump(data); NET_TRACE(1, " *** ") << "sequence_number: " << sequence_number_; const MockWrite& next_write = helper_.PeekWrite(); @@ -917,8 +929,11 @@ int MockTCPClientSocket::ReadIfReady(IOBuffer* buf, return ReadIfReadyImpl(buf, buf_len, callback); } -int MockTCPClientSocket::Write(IOBuffer* buf, int buf_len, - const CompletionCallback& callback) { +int MockTCPClientSocket::Write( + IOBuffer* buf, + int buf_len, + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& /* traffic_annotation */) { DCHECK(buf); DCHECK_GT(buf_len, 0); @@ -1189,24 +1204,24 @@ int MockSSLClientSocket::ReadIfReady(IOBuffer* buf, return transport_->socket()->ReadIfReady(buf, buf_len, callback); } -int MockSSLClientSocket::Write(IOBuffer* buf, int buf_len, - const CompletionCallback& callback) { - return transport_->socket()->Write(buf, buf_len, callback); +int MockSSLClientSocket::Write( + IOBuffer* buf, + int buf_len, + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& traffic_annotation) { + return transport_->socket()->Write(buf, buf_len, callback, + traffic_annotation); } int MockSSLClientSocket::Connect(const CompletionCallback& callback) { - int rv = transport_->socket()->Connect( - base::Bind(&ConnectCallback, base::Unretained(this), callback)); - if (rv == OK) { - if (data_->connect.result == OK) - connected_ = true; - if (data_->connect.mode == ASYNC) { - RunCallbackAsync(callback, data_->connect.result); - return ERR_IO_PENDING; - } - return data_->connect.result; + DCHECK(transport_->socket()->IsConnected()); + if (data_->connect.result == OK) + connected_ = true; + if (data_->connect.mode == ASYNC) { + RunCallbackAsync(callback, data_->connect.result); + return ERR_IO_PENDING; } - return rv; + return data_->connect.result; } void MockSSLClientSocket::Disconnect() { @@ -1245,6 +1260,10 @@ bool MockSSLClientSocket::GetSSLInfo(SSLInfo* requested_ssl_info) { return true; } +void MockSSLClientSocket::ApplySocketTag(const SocketTag& tag) { + return transport_->socket()->ApplySocketTag(tag); +} + void MockSSLClientSocket::GetSSLCertRequestInfo( SSLCertRequestInfo* cert_request_info) { DCHECK(cert_request_info); @@ -1336,8 +1355,11 @@ int MockUDPClientSocket::Read(IOBuffer* buf, return CompleteRead(); } -int MockUDPClientSocket::Write(IOBuffer* buf, int buf_len, - const CompletionCallback& callback) { +int MockUDPClientSocket::Write( + IOBuffer* buf, + int buf_len, + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& /* traffic_annotation */) { DCHECK(buf); DCHECK_GT(buf_len, 0); @@ -1427,6 +1449,8 @@ NetworkChangeNotifier::NetworkHandle MockUDPClientSocket::GetBoundNetwork() return network_; } +void MockUDPClientSocket::ApplySocketTag(const SocketTag& tag) {} + void MockUDPClientSocket::OnReadComplete(const MockRead& data) { if (!data_) return; @@ -1580,12 +1604,17 @@ void ClientSocketPoolTest::ReleaseAllConnections(KeepAlive keep_alive) { MockTransportClientSocketPool::MockConnectJob::MockConnectJob( std::unique_ptr<StreamSocket> socket, ClientSocketHandle* handle, + const SocketTag& socket_tag, const CompletionCallback& callback) - : socket_(std::move(socket)), handle_(handle), user_callback_(callback) {} + : socket_(std::move(socket)), + handle_(handle), + socket_tag_(socket_tag), + user_callback_(callback) {} MockTransportClientSocketPool::MockConnectJob::~MockConnectJob() = default; int MockTransportClientSocketPool::MockConnectJob::Connect() { + socket_->ApplySocketTag(socket_tag_); int rv = socket_->Connect(base::Bind(&MockConnectJob::OnConnect, base::Unretained(this))); if (rv != ERR_IO_PENDING) { @@ -1659,6 +1688,7 @@ int MockTransportClientSocketPool::RequestSocket( const std::string& group_name, const void* socket_params, RequestPriority priority, + const SocketTag& socket_tag, RespectLimits respect_limits, ClientSocketHandle* handle, const CompletionCallback& callback, @@ -1667,7 +1697,8 @@ int MockTransportClientSocketPool::RequestSocket( std::unique_ptr<StreamSocket> socket = client_socket_factory_->CreateTransportClientSocket( AddressList(), NULL, net_log.net_log(), NetLogSource()); - MockConnectJob* job = new MockConnectJob(std::move(socket), handle, callback); + MockConnectJob* job = + new MockConnectJob(std::move(socket), handle, socket_tag, callback); job_list_.push_back(base::WrapUnique(job)); handle->set_pool_id(1); return job->Connect(); @@ -1714,13 +1745,14 @@ MockSOCKSClientSocketPool::~MockSOCKSClientSocketPool() = default; int MockSOCKSClientSocketPool::RequestSocket(const std::string& group_name, const void* socket_params, RequestPriority priority, + const SocketTag& socket_tag, RespectLimits respect_limits, ClientSocketHandle* handle, const CompletionCallback& callback, const NetLogWithSource& net_log) { return transport_pool_->RequestSocket(group_name, socket_params, priority, - respect_limits, handle, callback, - net_log); + socket_tag, respect_limits, handle, + callback, net_log); } void MockSOCKSClientSocketPool::SetPriority(const std::string& group_name, @@ -1757,6 +1789,144 @@ ScopedWebSocketEndpointZeroUnlockDelay:: EXPECT_EQ(active_delay, base::TimeDelta()); } +WrappedStreamSocket::WrappedStreamSocket( + std::unique_ptr<StreamSocket> transport) + : transport_(std::move(transport)) {} +WrappedStreamSocket::~WrappedStreamSocket() {} + +int WrappedStreamSocket::Connect(const CompletionCallback& callback) { + return transport_->Connect(callback); +} + +void WrappedStreamSocket::Disconnect() { + transport_->Disconnect(); +} + +bool WrappedStreamSocket::IsConnected() const { + return transport_->IsConnected(); +} + +bool WrappedStreamSocket::IsConnectedAndIdle() const { + return transport_->IsConnectedAndIdle(); +} + +int WrappedStreamSocket::GetPeerAddress(IPEndPoint* address) const { + return transport_->GetPeerAddress(address); +} + +int WrappedStreamSocket::GetLocalAddress(IPEndPoint* address) const { + return transport_->GetLocalAddress(address); +} + +const NetLogWithSource& WrappedStreamSocket::NetLog() const { + return transport_->NetLog(); +} + +void WrappedStreamSocket::SetSubresourceSpeculation() { + transport_->SetSubresourceSpeculation(); +} + +void WrappedStreamSocket::SetOmniboxSpeculation() { + transport_->SetOmniboxSpeculation(); +} + +bool WrappedStreamSocket::WasEverUsed() const { + return transport_->WasEverUsed(); +} + +bool WrappedStreamSocket::WasAlpnNegotiated() const { + return transport_->WasAlpnNegotiated(); +} + +NextProto WrappedStreamSocket::GetNegotiatedProtocol() const { + return transport_->GetNegotiatedProtocol(); +} + +bool WrappedStreamSocket::GetSSLInfo(SSLInfo* ssl_info) { + return transport_->GetSSLInfo(ssl_info); +} + +void WrappedStreamSocket::GetConnectionAttempts(ConnectionAttempts* out) const { + transport_->GetConnectionAttempts(out); +} + +void WrappedStreamSocket::ClearConnectionAttempts() { + transport_->ClearConnectionAttempts(); +} + +void WrappedStreamSocket::AddConnectionAttempts( + const ConnectionAttempts& attempts) { + transport_->AddConnectionAttempts(attempts); +} + +int64_t WrappedStreamSocket::GetTotalReceivedBytes() const { + return transport_->GetTotalReceivedBytes(); +} + +void WrappedStreamSocket::ApplySocketTag(const SocketTag& tag) { + transport_->ApplySocketTag(tag); +} + +int WrappedStreamSocket::Read(IOBuffer* buf, + int buf_len, + const CompletionCallback& callback) { + return transport_->Read(buf, buf_len, callback); +} + +int WrappedStreamSocket::ReadIfReady(IOBuffer* buf, + int buf_len, + const CompletionCallback& callback) { + return transport_->ReadIfReady(buf, buf_len, callback); +} + +int WrappedStreamSocket::Write( + IOBuffer* buf, + int buf_len, + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& traffic_annotation) { + return transport_->Write(buf, buf_len, callback); +} + +int WrappedStreamSocket::SetReceiveBufferSize(int32_t size) { + return transport_->SetReceiveBufferSize(size); +} + +int WrappedStreamSocket::SetSendBufferSize(int32_t size) { + return transport_->SetSendBufferSize(size); +} + +int MockTaggingStreamSocket::Connect(const CompletionCallback& callback) { + connected_ = true; + return WrappedStreamSocket::Connect(callback); +} + +void MockTaggingStreamSocket::ApplySocketTag(const SocketTag& tag) { + tagged_before_connected_ &= !connected_ || tag == tag_; + tag_ = tag; + transport_->ApplySocketTag(tag); +} + +std::unique_ptr<StreamSocket> +MockTaggingClientSocketFactory::CreateTransportClientSocket( + const AddressList& addresses, + std::unique_ptr<SocketPerformanceWatcher> socket_performance_watcher, + NetLog* net_log, + const NetLogSource& source) { + std::unique_ptr<MockTaggingStreamSocket> socket(new MockTaggingStreamSocket( + MockClientSocketFactory::CreateTransportClientSocket( + addresses, std::move(socket_performance_watcher), net_log, source))); + socket_ = socket.get(); + return std::move(socket); +} + +const char kSOCKS4OkRequestLocalHostPort80[] = {0x04, 0x01, 0x00, 0x50, 127, + 0, 0, 1, 0}; +const int kSOCKS4OkRequestLocalHostPort80Length = + arraysize(kSOCKS4OkRequestLocalHostPort80); + +const char kSOCKS4OkReply[] = {0x00, 0x5A, 0x00, 0x00, 0, 0, 0, 0}; +const int kSOCKS4OkReplyLength = arraysize(kSOCKS4OkReply); + const char kSOCKS5GreetRequest[] = { 0x05, 0x01, 0x00 }; const int kSOCKS5GreetRequestLength = arraysize(kSOCKS5GreetRequest); @@ -1785,4 +1955,41 @@ int64_t CountWriteBytes(const MockWrite writes[], size_t writes_size) { return total; } +#if defined(OS_ANDROID) +uint64_t GetTaggedBytes(int32_t expected_tag) { + // To determine how many bytes the system saw with a particular tag read + // the /proc/net/xt_qtaguid/stats file which contains the kernel's + // dump of all the UIDs and their tags sent and received bytes. + uint64_t bytes = 0; + std::string contents; + EXPECT_TRUE(base::ReadFileToString( + base::FilePath::FromUTF8Unsafe("/proc/net/xt_qtaguid/stats"), &contents)); + for (size_t i = contents.find('\n'); // Skip first line which is headers. + i != std::string::npos && i < contents.length();) { + uint64_t tag, rx_bytes; + uid_t uid; + int n; + // Parse out the numbers we care about. For reference here's the column + // headers: + // idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes + // tx_packets rx_tcp_bytes rx_tcp_packets rx_udp_bytes rx_udp_packets + // rx_other_bytes rx_other_packets tx_tcp_bytes tx_tcp_packets tx_udp_bytes + // tx_udp_packets tx_other_bytes tx_other_packets + EXPECT_EQ(sscanf(contents.c_str() + i, + "%*d %*s 0x%" SCNx64 " %d %*d %" SCNu64 + " %*d %*d %*d %*d %*d %*d %*d %*d " + "%*d %*d %*d %*d %*d %*d %*d%n", + &tag, &uid, &rx_bytes, &n), + 3); + // If this line matches our UID and |expected_tag| then add it to the total. + if (uid == getuid() && (int32_t)(tag >> 32) == expected_tag) { + bytes += rx_bytes; + } + // Move |i| to the next line. + i += n + 1; + } + return bytes; +} +#endif + } // namespace net diff --git a/chromium/net/socket/socket_test_util.h b/chromium/net/socket/socket_test_util.h index ce0ccf58e07..1e8ea79afcb 100644 --- a/chromium/net/socket/socket_test_util.h +++ b/chromium/net/socket/socket_test_util.h @@ -21,6 +21,7 @@ #include "base/memory/weak_ptr.h" #include "base/strings/string16.h" #include "base/time/time.h" +#include "build/build_config.h" #include "net/base/address_list.h" #include "net/base/io_buffer.h" #include "net/base/net_errors.h" @@ -33,11 +34,13 @@ #include "net/socket/connection_attempts.h" #include "net/socket/datagram_client_socket.h" #include "net/socket/socket_performance_watcher.h" +#include "net/socket/socket_tag.h" #include "net/socket/socks_client_socket_pool.h" #include "net/socket/ssl_client_socket.h" #include "net/socket/ssl_client_socket_pool.h" #include "net/socket/transport_client_socket_pool.h" #include "net/ssl/ssl_config_service.h" +#include "net/traffic_annotation/network_traffic_annotation.h" #include "testing/gtest/include/gtest/gtest.h" namespace base { @@ -570,7 +573,8 @@ class MockClientSocket : public SSLClientSocket { const CompletionCallback& callback) override = 0; int Write(IOBuffer* buf, int buf_len, - const CompletionCallback& callback) override = 0; + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& traffic_annotation) override = 0; int SetReceiveBufferSize(int32_t size) override; int SetSendBufferSize(int32_t size) override; @@ -590,6 +594,7 @@ class MockClientSocket : public SSLClientSocket { void ClearConnectionAttempts() override {} void AddConnectionAttempts(const ConnectionAttempts& attempts) override {} int64_t GetTotalReceivedBytes() const override; + void ApplySocketTag(const SocketTag& tag) override {} // SSLClientSocket implementation. void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info) override; @@ -641,7 +646,8 @@ class MockTCPClientSocket : public MockClientSocket, public AsyncSocket { const CompletionCallback& callback) override; int Write(IOBuffer* buf, int buf_len, - const CompletionCallback& callback) override; + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& traffic_annotation) override; // StreamSocket implementation. int Connect(const CompletionCallback& callback) override; @@ -721,7 +727,8 @@ class MockSSLClientSocket : public MockClientSocket, public AsyncSocket { const CompletionCallback& callback) override; int Write(IOBuffer* buf, int buf_len, - const CompletionCallback& callback) override; + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& traffic_annotation) override; // StreamSocket implementation. int Connect(const CompletionCallback& callback) override; @@ -733,6 +740,7 @@ class MockSSLClientSocket : public MockClientSocket, public AsyncSocket { bool WasAlpnNegotiated() const override; NextProto GetNegotiatedProtocol() const override; bool GetSSLInfo(SSLInfo* ssl_info) override; + void ApplySocketTag(const SocketTag& tag) override; // SSLClientSocket implementation. void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info) override; @@ -772,7 +780,8 @@ class MockUDPClientSocket : public DatagramClientSocket, public AsyncSocket { const CompletionCallback& callback) override; int Write(IOBuffer* buf, int buf_len, - const CompletionCallback& callback) override; + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& traffic_annotation) override; int SetReceiveBufferSize(int32_t size) override; int SetSendBufferSize(int32_t size) override; int SetDoNotFragment() override; @@ -790,6 +799,7 @@ class MockUDPClientSocket : public DatagramClientSocket, public AsyncSocket { const IPEndPoint& address) override; int ConnectUsingDefaultNetwork(const IPEndPoint& address) override; NetworkChangeNotifier::NetworkHandle GetBoundNetwork() const override; + void ApplySocketTag(const SocketTag& tag) override; // AsyncSocket implementation. void OnReadComplete(const MockRead& data) override; @@ -879,9 +889,9 @@ class ClientSocketPoolTest { TestSocketRequest* request( new TestSocketRequest(&request_order_, &completion_count_)); requests_.push_back(base::WrapUnique(request)); - int rv = request->handle()->Init(group_name, socket_params, priority, - respect_limits, request->callback(), - socket_pool, NetLogWithSource()); + int rv = request->handle()->Init( + group_name, socket_params, priority, SocketTag(), respect_limits, + request->callback(), socket_pool, NetLogWithSource()); if (rv != ERR_IO_PENDING) request_order_.push_back(request); return rv; @@ -935,6 +945,7 @@ class MockTransportClientSocketPool : public TransportClientSocketPool { public: MockConnectJob(std::unique_ptr<StreamSocket> socket, ClientSocketHandle* handle, + const SocketTag& socket_tag, const CompletionCallback& callback); ~MockConnectJob(); @@ -946,6 +957,7 @@ class MockTransportClientSocketPool : public TransportClientSocketPool { std::unique_ptr<StreamSocket> socket_; ClientSocketHandle* handle_; + const SocketTag socket_tag_; CompletionCallback user_callback_; DISALLOW_COPY_AND_ASSIGN(MockConnectJob); @@ -967,6 +979,7 @@ class MockTransportClientSocketPool : public TransportClientSocketPool { int RequestSocket(const std::string& group_name, const void* socket_params, RequestPriority priority, + const SocketTag& socket_tag, RespectLimits respect_limits, ClientSocketHandle* handle, const CompletionCallback& callback, @@ -1002,6 +1015,7 @@ class MockSOCKSClientSocketPool : public SOCKSClientSocketPool { int RequestSocket(const std::string& group_name, const void* socket_params, RequestPriority priority, + const SocketTag& socket_tag, RespectLimits respect_limits, ClientSocketHandle* handle, const CompletionCallback& callback, @@ -1033,6 +1047,113 @@ class ScopedWebSocketEndpointZeroUnlockDelay { base::TimeDelta old_delay_; }; +// WrappedStreamSocket is a base class that wraps an existing StreamSocket, +// forwarding the Socket and StreamSocket interfaces to the underlying +// transport. +// This is to provide a common base class for subclasses to override specific +// StreamSocket methods for testing, while still communicating with a 'real' +// StreamSocket. +class WrappedStreamSocket : public StreamSocket { + public: + explicit WrappedStreamSocket(std::unique_ptr<StreamSocket> transport); + ~WrappedStreamSocket() override; + + // StreamSocket implementation: + int Connect(const CompletionCallback& callback) override; + void Disconnect() override; + bool IsConnected() const override; + bool IsConnectedAndIdle() const override; + int GetPeerAddress(IPEndPoint* address) const override; + int GetLocalAddress(IPEndPoint* address) const override; + const NetLogWithSource& NetLog() const override; + void SetSubresourceSpeculation() override; + void SetOmniboxSpeculation() override; + bool WasEverUsed() const override; + bool WasAlpnNegotiated() const override; + NextProto GetNegotiatedProtocol() const override; + bool GetSSLInfo(SSLInfo* ssl_info) override; + void GetConnectionAttempts(ConnectionAttempts* out) const override; + void ClearConnectionAttempts() override; + void AddConnectionAttempts(const ConnectionAttempts& attempts) override; + int64_t GetTotalReceivedBytes() const override; + void ApplySocketTag(const SocketTag& tag) override; + + // Socket implementation: + int Read(IOBuffer* buf, + int buf_len, + const CompletionCallback& callback) override; + int ReadIfReady(IOBuffer* buf, + int buf_len, + const CompletionCallback& callback) override; + int Write(IOBuffer* buf, + int buf_len, + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& traffic_annotation = + NO_TRAFFIC_ANNOTATION_BUG_656607) override; + int SetReceiveBufferSize(int32_t size) override; + int SetSendBufferSize(int32_t size) override; + + protected: + std::unique_ptr<StreamSocket> transport_; +}; + +// StreamSocket that wraps another StreamSocket, but keeps track of any +// SocketTag applied to the socket. +class MockTaggingStreamSocket : public WrappedStreamSocket { + public: + explicit MockTaggingStreamSocket(std::unique_ptr<StreamSocket> transport) + : WrappedStreamSocket(std::move(transport)) {} + ~MockTaggingStreamSocket() override {} + + // StreamSocket implementation. + int Connect(const CompletionCallback& callback) override; + void ApplySocketTag(const SocketTag& tag) override; + + // Returns false if socket's tag was changed after the socket was connected, + // otherwise returns true. + bool tagged_before_connected() const { return tagged_before_connected_; } + + // Returns last tag applied to socket. + SocketTag tag() const { return tag_; } + + private: + bool connected_ = false; + bool tagged_before_connected_ = true; + SocketTag tag_; + + DISALLOW_COPY_AND_ASSIGN(MockTaggingStreamSocket); +}; + +// Extend MockClientSocketFactory to return MockTaggingStreamSockets and +// keep track of last socket produced for test inspection. +class MockTaggingClientSocketFactory : public MockClientSocketFactory { + public: + MockTaggingClientSocketFactory() = default; + + std::unique_ptr<StreamSocket> CreateTransportClientSocket( + const AddressList& addresses, + std::unique_ptr<SocketPerformanceWatcher> socket_performance_watcher, + NetLog* net_log, + const NetLogSource& source) override; + + // Returns a pointer to last socket produced by this factory. + // NOTE: Socket must still exist, or pointer will be to freed memory. + MockTaggingStreamSocket* GetLastProducedSocket() { return socket_; } + + private: + MockTaggingStreamSocket* socket_ = nullptr; + + DISALLOW_COPY_AND_ASSIGN(MockTaggingClientSocketFactory); +}; + +// Constants for a successful SOCKS v4 handshake (connecting to localhost on +// port 80, for the request). +extern const char kSOCKS4OkRequestLocalHostPort80[]; +extern const int kSOCKS4OkRequestLocalHostPort80Length; + +extern const char kSOCKS4OkReply[]; +extern const int kSOCKS4OkReplyLength; + // Constants for a successful SOCKS v5 handshake. extern const char kSOCKS5GreetRequest[]; extern const int kSOCKS5GreetRequestLength; @@ -1052,6 +1173,12 @@ int64_t CountReadBytes(const MockRead reads[], size_t reads_size); // Helper function to get the total data size of the MockWrites in |writes|. int64_t CountWriteBytes(const MockWrite writes[], size_t writes_size); +#if defined(OS_ANDROID) +// Query the system to find out how many bytes were received with tag +// |expected_tag| for our UID. Return the count of recieved bytes. +uint64_t GetTaggedBytes(int32_t expected_tag); +#endif + } // namespace net #endif // NET_SOCKET_SOCKET_TEST_UTIL_H_ diff --git a/chromium/net/socket/socks5_client_socket.cc b/chromium/net/socket/socks5_client_socket.cc index 19cdfddbe0c..6b436878f78 100644 --- a/chromium/net/socket/socks5_client_socket.cc +++ b/chromium/net/socket/socks5_client_socket.cc @@ -16,6 +16,7 @@ #include "net/log/net_log.h" #include "net/log/net_log_event_type.h" #include "net/socket/client_socket_handle.h" +#include "net/traffic_annotation/network_traffic_annotation.h" namespace net { @@ -31,7 +32,8 @@ static_assert(sizeof(struct in6_addr) == 16, "incorrect system size of IPv6"); SOCKS5ClientSocket::SOCKS5ClientSocket( std::unique_ptr<ClientSocketHandle> transport_socket, - const HostResolver::RequestInfo& req_info) + const HostResolver::RequestInfo& req_info, + const NetworkTrafficAnnotationTag& traffic_annotation) : io_callback_(base::Bind(&SOCKS5ClientSocket::OnIOComplete, base::Unretained(this))), transport_(std::move(transport_socket)), @@ -42,7 +44,8 @@ SOCKS5ClientSocket::SOCKS5ClientSocket( read_header_size(kReadHeaderSize), was_ever_used_(false), host_request_info_(req_info), - net_log_(transport_->socket()->NetLog()) {} + net_log_(transport_->socket()->NetLog()), + traffic_annotation_(traffic_annotation) {} SOCKS5ClientSocket::~SOCKS5ClientSocket() { Disconnect(); @@ -146,6 +149,10 @@ int64_t SOCKS5ClientSocket::GetTotalReceivedBytes() const { return transport_->socket()->GetTotalReceivedBytes(); } +void SOCKS5ClientSocket::ApplySocketTag(const SocketTag& tag) { + return transport_->socket()->ApplySocketTag(tag); +} + // Read is called by the transport layer above to read. This can only be done // if the SOCKS handshake is complete. int SOCKS5ClientSocket::Read(IOBuffer* buf, int buf_len, @@ -166,8 +173,11 @@ int SOCKS5ClientSocket::Read(IOBuffer* buf, int buf_len, // Write is called by the transport layer. This can only be done if the // SOCKS handshake is complete. -int SOCKS5ClientSocket::Write(IOBuffer* buf, int buf_len, - const CompletionCallback& callback) { +int SOCKS5ClientSocket::Write( + IOBuffer* buf, + int buf_len, + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& traffic_annotation) { DCHECK(completed_handshake_); DCHECK_EQ(STATE_NONE, next_state_); DCHECK(user_callback_.is_null()); @@ -176,7 +186,8 @@ int SOCKS5ClientSocket::Write(IOBuffer* buf, int buf_len, int rv = transport_->socket()->Write( buf, buf_len, base::Bind(&SOCKS5ClientSocket::OnReadWriteComplete, - base::Unretained(this), callback)); + base::Unretained(this), callback), + traffic_annotation); if (rv > 0) was_ever_used_ = true; return rv; @@ -295,8 +306,8 @@ int SOCKS5ClientSocket::DoGreetWrite() { handshake_buf_ = new IOBuffer(handshake_buf_len); memcpy(handshake_buf_->data(), &buffer_.data()[bytes_sent_], handshake_buf_len); - return transport_->socket() - ->Write(handshake_buf_.get(), handshake_buf_len, io_callback_); + return transport_->socket()->Write(handshake_buf_.get(), handshake_buf_len, + io_callback_, traffic_annotation_); } int SOCKS5ClientSocket::DoGreetWriteComplete(int result) { @@ -394,8 +405,8 @@ int SOCKS5ClientSocket::DoHandshakeWrite() { handshake_buf_ = new IOBuffer(handshake_buf_len); memcpy(handshake_buf_->data(), &buffer_[bytes_sent_], handshake_buf_len); - return transport_->socket() - ->Write(handshake_buf_.get(), handshake_buf_len, io_callback_); + return transport_->socket()->Write(handshake_buf_.get(), handshake_buf_len, + io_callback_, traffic_annotation_); } int SOCKS5ClientSocket::DoHandshakeWriteComplete(int result) { diff --git a/chromium/net/socket/socks5_client_socket.h b/chromium/net/socket/socks5_client_socket.h index afef312d001..364ac53391d 100644 --- a/chromium/net/socket/socks5_client_socket.h +++ b/chromium/net/socket/socks5_client_socket.h @@ -20,6 +20,7 @@ #include "net/dns/host_resolver.h" #include "net/log/net_log_with_source.h" #include "net/socket/stream_socket.h" +#include "net/traffic_annotation/network_traffic_annotation.h" #include "url/gurl.h" namespace net { @@ -37,7 +38,8 @@ class NET_EXPORT_PRIVATE SOCKS5ClientSocket : public StreamSocket { // always pass it a hostname. This means the DNS resolving is done // proxy side. SOCKS5ClientSocket(std::unique_ptr<ClientSocketHandle> transport_socket, - const HostResolver::RequestInfo& req_info); + const HostResolver::RequestInfo& req_info, + const NetworkTrafficAnnotationTag& traffic_annotation); // On destruction Disconnect() is called. ~SOCKS5ClientSocket() override; @@ -60,6 +62,7 @@ class NET_EXPORT_PRIVATE SOCKS5ClientSocket : public StreamSocket { void ClearConnectionAttempts() override {} void AddConnectionAttempts(const ConnectionAttempts& attempts) override {} int64_t GetTotalReceivedBytes() const override; + void ApplySocketTag(const SocketTag& tag) override; // Socket implementation. int Read(IOBuffer* buf, @@ -67,7 +70,8 @@ class NET_EXPORT_PRIVATE SOCKS5ClientSocket : public StreamSocket { const CompletionCallback& callback) override; int Write(IOBuffer* buf, int buf_len, - const CompletionCallback& callback) override; + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& traffic_annotation) override; int SetReceiveBufferSize(int32_t size) override; int SetSendBufferSize(int32_t size) override; @@ -155,6 +159,9 @@ class NET_EXPORT_PRIVATE SOCKS5ClientSocket : public StreamSocket { NetLogWithSource net_log_; + // Traffic annotation for socket control. + NetworkTrafficAnnotationTag traffic_annotation_; + DISALLOW_COPY_AND_ASSIGN(SOCKS5ClientSocket); }; diff --git a/chromium/net/socket/socks5_client_socket_fuzzer.cc b/chromium/net/socket/socks5_client_socket_fuzzer.cc index 272e37dfdea..fb9c7b5528a 100644 --- a/chromium/net/socket/socks5_client_socket_fuzzer.cc +++ b/chromium/net/socket/socks5_client_socket_fuzzer.cc @@ -16,6 +16,7 @@ #include "net/socket/client_socket_handle.h" #include "net/socket/fuzzed_socket.h" #include "net/socket/socks5_client_socket.h" +#include "net/traffic_annotation/network_traffic_annotation_test_helper.h" // Fuzzer for Socks5ClientSocket. Only covers the SOCKS5 greeet and // handshake. @@ -38,7 +39,8 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { socket_handle->SetSocket(std::move(fuzzed_socket)); net::HostResolver::RequestInfo request_info(net::HostPortPair("foo", 80)); - net::SOCKS5ClientSocket socket(std::move(socket_handle), request_info); + net::SOCKS5ClientSocket socket(std::move(socket_handle), request_info, + TRAFFIC_ANNOTATION_FOR_TESTS); int result = socket.Connect(callback.callback()); callback.GetResult(result); return 0; diff --git a/chromium/net/socket/socks5_client_socket_unittest.cc b/chromium/net/socket/socks5_client_socket_unittest.cc index 4cf98cffe42..fea734f67ea 100644 --- a/chromium/net/socket/socks5_client_socket_unittest.cc +++ b/chromium/net/socket/socks5_client_socket_unittest.cc @@ -11,6 +11,7 @@ #include "base/macros.h" #include "base/sys_byteorder.h" +#include "build/build_config.h" #include "net/base/address_list.h" #include "net/base/test_completion_callback.h" #include "net/base/winsock_init.h" @@ -23,6 +24,7 @@ #include "net/socket/socket_test_util.h" #include "net/socket/tcp_client_socket.h" #include "net/test/gtest_util.h" +#include "net/traffic_annotation/network_traffic_annotation_test_helper.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/platform_test.h" @@ -116,7 +118,8 @@ std::unique_ptr<SOCKS5ClientSocket> SOCKS5ClientSocketTest::BuildMockSocket( connection->SetSocket(std::unique_ptr<StreamSocket>(tcp_sock_)); return std::unique_ptr<SOCKS5ClientSocket>(new SOCKS5ClientSocket( std::move(connection), - HostResolver::RequestInfo(HostPortPair(hostname, port)))); + HostResolver::RequestInfo(HostPortPair(hostname, port)), + TRAFFIC_ANNOTATION_FOR_TESTS)); } // Tests a complete SOCKS5 handshake and the disconnection. @@ -172,8 +175,8 @@ TEST_F(SOCKS5ClientSocketTest, CompleteHandshake) { scoped_refptr<IOBuffer> buffer(new IOBuffer(payload_write.size())); memcpy(buffer->data(), payload_write.data(), payload_write.size()); - rv = user_sock_->Write( - buffer.get(), payload_write.size(), callback_.callback()); + rv = user_sock_->Write(buffer.get(), payload_write.size(), + callback_.callback(), TRAFFIC_ANNOTATION_FOR_TESTS); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); rv = callback_.WaitForResult(); EXPECT_EQ(static_cast<int>(payload_write.size()), rv); @@ -384,6 +387,30 @@ TEST_F(SOCKS5ClientSocketTest, PartialReadWrites) { } } +TEST_F(SOCKS5ClientSocketTest, Tag) { + StaticSocketDataProvider data; + TestNetLog log; + MockTaggingStreamSocket* tagging_sock = + new MockTaggingStreamSocket(std::unique_ptr<StreamSocket>( + new MockTCPClientSocket(address_list_, &log, &data))); + + std::unique_ptr<ClientSocketHandle> connection(new ClientSocketHandle); + // |connection| takes ownership of |tagging_sock|, but keep a + // non-owning pointer to it. + connection->SetSocket(std::unique_ptr<StreamSocket>(tagging_sock)); + SOCKS5ClientSocket socket( + std::move(connection), + HostResolver::RequestInfo(HostPortPair("localhost", 80)), + TRAFFIC_ANNOTATION_FOR_TESTS); + + EXPECT_EQ(tagging_sock->tag(), SocketTag()); +#if defined(OS_ANDROID) + SocketTag tag(0x12345678, 0x87654321); + socket.ApplySocketTag(tag); + EXPECT_EQ(tagging_sock->tag(), tag); +#endif // OS_ANDROID +} + } // namespace } // namespace net diff --git a/chromium/net/socket/socks_client_socket.cc b/chromium/net/socket/socks_client_socket.cc index 027d18ab7c1..3e5d6eb0aa4 100644 --- a/chromium/net/socket/socks_client_socket.cc +++ b/chromium/net/socket/socks_client_socket.cc @@ -14,6 +14,7 @@ #include "net/log/net_log.h" #include "net/log/net_log_event_type.h" #include "net/socket/client_socket_handle.h" +#include "net/traffic_annotation/network_traffic_annotation.h" namespace net { @@ -61,7 +62,8 @@ SOCKSClientSocket::SOCKSClientSocket( std::unique_ptr<ClientSocketHandle> transport_socket, const HostResolver::RequestInfo& req_info, RequestPriority priority, - HostResolver* host_resolver) + HostResolver* host_resolver, + const NetworkTrafficAnnotationTag& traffic_annotation) : transport_(std::move(transport_socket)), next_state_(STATE_NONE), completed_handshake_(false), @@ -71,7 +73,8 @@ SOCKSClientSocket::SOCKSClientSocket( host_resolver_(host_resolver), host_request_info_(req_info), priority_(priority), - net_log_(transport_->socket()->NetLog()) {} + net_log_(transport_->socket()->NetLog()), + traffic_annotation_(traffic_annotation) {} SOCKSClientSocket::~SOCKSClientSocket() { Disconnect(); @@ -175,6 +178,10 @@ int64_t SOCKSClientSocket::GetTotalReceivedBytes() const { return transport_->socket()->GetTotalReceivedBytes(); } +void SOCKSClientSocket::ApplySocketTag(const SocketTag& tag) { + return transport_->socket()->ApplySocketTag(tag); +} + // Read is called by the transport layer above to read. This can only be done // if the SOCKS handshake is complete. int SOCKSClientSocket::Read(IOBuffer* buf, int buf_len, @@ -195,8 +202,11 @@ int SOCKSClientSocket::Read(IOBuffer* buf, int buf_len, // Write is called by the transport layer. This can only be done if the // SOCKS handshake is complete. -int SOCKSClientSocket::Write(IOBuffer* buf, int buf_len, - const CompletionCallback& callback) { +int SOCKSClientSocket::Write( + IOBuffer* buf, + int buf_len, + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& traffic_annotation) { DCHECK(completed_handshake_); DCHECK_EQ(STATE_NONE, next_state_); DCHECK(user_callback_.is_null()); @@ -205,7 +215,8 @@ int SOCKSClientSocket::Write(IOBuffer* buf, int buf_len, int rv = transport_->socket()->Write( buf, buf_len, base::Bind(&SOCKSClientSocket::OnReadWriteComplete, - base::Unretained(this), callback)); + base::Unretained(this), callback), + traffic_annotation); if (rv > 0) was_ever_used_ = true; return rv; @@ -352,9 +363,9 @@ int SOCKSClientSocket::DoHandshakeWrite() { memcpy(handshake_buf_->data(), &buffer_[bytes_sent_], handshake_buf_len); return transport_->socket()->Write( - handshake_buf_.get(), - handshake_buf_len, - base::Bind(&SOCKSClientSocket::OnIOComplete, base::Unretained(this))); + handshake_buf_.get(), handshake_buf_len, + base::Bind(&SOCKSClientSocket::OnIOComplete, base::Unretained(this)), + traffic_annotation_); } int SOCKSClientSocket::DoHandshakeWriteComplete(int result) { diff --git a/chromium/net/socket/socks_client_socket.h b/chromium/net/socket/socks_client_socket.h index c2999ffa17b..f39f2646579 100644 --- a/chromium/net/socket/socks_client_socket.h +++ b/chromium/net/socket/socks_client_socket.h @@ -21,6 +21,7 @@ #include "net/dns/host_resolver.h" #include "net/log/net_log_with_source.h" #include "net/socket/stream_socket.h" +#include "net/traffic_annotation/network_traffic_annotation.h" namespace net { @@ -34,7 +35,8 @@ class NET_EXPORT_PRIVATE SOCKSClientSocket : public StreamSocket { SOCKSClientSocket(std::unique_ptr<ClientSocketHandle> transport_socket, const HostResolver::RequestInfo& req_info, RequestPriority priority, - HostResolver* host_resolver); + HostResolver* host_resolver, + const NetworkTrafficAnnotationTag& traffic_annotation); // On destruction Disconnect() is called. ~SOCKSClientSocket() override; @@ -57,6 +59,7 @@ class NET_EXPORT_PRIVATE SOCKSClientSocket : public StreamSocket { void ClearConnectionAttempts() override {} void AddConnectionAttempts(const ConnectionAttempts& attempts) override {} int64_t GetTotalReceivedBytes() const override; + void ApplySocketTag(const SocketTag& tag) override; // Socket implementation. int Read(IOBuffer* buf, @@ -64,7 +67,8 @@ class NET_EXPORT_PRIVATE SOCKSClientSocket : public StreamSocket { const CompletionCallback& callback) override; int Write(IOBuffer* buf, int buf_len, - const CompletionCallback& callback) override; + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& traffic_annotation) override; int SetReceiveBufferSize(int32_t size) override; int SetSendBufferSize(int32_t size) override; @@ -138,6 +142,9 @@ class NET_EXPORT_PRIVATE SOCKSClientSocket : public StreamSocket { NetLogWithSource net_log_; + // Traffic annotation for socket control. + NetworkTrafficAnnotationTag traffic_annotation_; + DISALLOW_COPY_AND_ASSIGN(SOCKSClientSocket); }; diff --git a/chromium/net/socket/socks_client_socket_fuzzer.cc b/chromium/net/socket/socks_client_socket_fuzzer.cc index dd02f51fe67..feaa18282d1 100644 --- a/chromium/net/socket/socks_client_socket_fuzzer.cc +++ b/chromium/net/socket/socks_client_socket_fuzzer.cc @@ -18,6 +18,7 @@ #include "net/socket/client_socket_handle.h" #include "net/socket/fuzzed_socket.h" #include "net/socket/socks_client_socket.h" +#include "net/traffic_annotation/network_traffic_annotation_test_helper.h" // Fuzzer for SocksClientSocket. Only covers the SOCKS4 handshake. // @@ -58,8 +59,10 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { socket_handle->SetSocket(std::move(fuzzed_socket)); net::HostResolver::RequestInfo request_info(net::HostPortPair("foo", 80)); + net::SOCKSClientSocket socket(std::move(socket_handle), request_info, - net::DEFAULT_PRIORITY, &mock_host_resolver); + net::DEFAULT_PRIORITY, &mock_host_resolver, + TRAFFIC_ANNOTATION_FOR_TESTS); int result = socket.Connect(callback.callback()); callback.GetResult(result); return 0; diff --git a/chromium/net/socket/socks_client_socket_pool.cc b/chromium/net/socket/socks_client_socket_pool.cc index 86b4ac0d109..0e16d7eecb8 100644 --- a/chromium/net/socket/socks_client_socket_pool.cc +++ b/chromium/net/socket/socks_client_socket_pool.cc @@ -27,11 +27,12 @@ class NetLog; SOCKSSocketParams::SOCKSSocketParams( const scoped_refptr<TransportSocketParams>& proxy_server, bool socks_v5, - const HostPortPair& host_port_pair) + const HostPortPair& host_port_pair, + const NetworkTrafficAnnotationTag& traffic_annotation) : transport_params_(proxy_server), destination_(host_port_pair), - socks_v5_(socks_v5) { -} + socks_v5_(socks_v5), + traffic_annotation_(traffic_annotation) {} SOCKSSocketParams::~SOCKSSocketParams() = default; @@ -42,6 +43,7 @@ static const int kSOCKSConnectJobTimeoutInSeconds = 30; SOCKSConnectJob::SOCKSConnectJob( const std::string& group_name, RequestPriority priority, + const SocketTag& socket_tag, ClientSocketPool::RespectLimits respect_limits, const scoped_refptr<SOCKSSocketParams>& socks_params, const base::TimeDelta& timeout_duration, @@ -53,6 +55,7 @@ SOCKSConnectJob::SOCKSConnectJob( group_name, timeout_duration, priority, + socket_tag, respect_limits, delegate, NetLogWithSource::Make(net_log, NetLogSourceType::SOCKS_CONNECT_JOB)), @@ -125,7 +128,7 @@ int SOCKSConnectJob::DoTransportConnect() { next_state_ = STATE_TRANSPORT_CONNECT_COMPLETE; transport_socket_handle_.reset(new ClientSocketHandle()); return transport_socket_handle_->Init( - group_name(), socks_params_->transport_params(), priority(), + group_name(), socks_params_->transport_params(), priority(), socket_tag(), respect_limits(), callback_, transport_pool_, net_log()); } @@ -147,11 +150,12 @@ int SOCKSConnectJob::DoSOCKSConnect() { // Add a SOCKS connection on top of the tcp socket. if (socks_params_->is_socks_v5()) { socket_.reset(new SOCKS5ClientSocket(std::move(transport_socket_handle_), - socks_params_->destination())); + socks_params_->destination(), + socks_params_->traffic_annotation())); } else { - socket_.reset(new SOCKSClientSocket(std::move(transport_socket_handle_), - socks_params_->destination(), - priority(), resolver_)); + socket_.reset(new SOCKSClientSocket( + std::move(transport_socket_handle_), socks_params_->destination(), + priority(), resolver_, socks_params_->traffic_annotation())); } return socket_->Connect( base::Bind(&SOCKSConnectJob::OnIOComplete, base::Unretained(this))); @@ -178,9 +182,9 @@ SOCKSClientSocketPool::SOCKSConnectJobFactory::NewConnectJob( const PoolBase::Request& request, ConnectJob::Delegate* delegate) const { return std::unique_ptr<ConnectJob>(new SOCKSConnectJob( - group_name, request.priority(), request.respect_limits(), - request.params(), ConnectionTimeout(), transport_pool_, host_resolver_, - delegate, net_log_)); + group_name, request.priority(), request.socket_tag(), + request.respect_limits(), request.params(), ConnectionTimeout(), + transport_pool_, host_resolver_, delegate, net_log_)); } base::TimeDelta @@ -214,6 +218,7 @@ SOCKSClientSocketPool::~SOCKSClientSocketPool() = default; int SOCKSClientSocketPool::RequestSocket(const std::string& group_name, const void* socket_params, RequestPriority priority, + const SocketTag& socket_tag, RespectLimits respect_limits, ClientSocketHandle* handle, const CompletionCallback& callback, @@ -222,7 +227,8 @@ int SOCKSClientSocketPool::RequestSocket(const std::string& group_name, static_cast<const scoped_refptr<SOCKSSocketParams>*>(socket_params); return base_.RequestSocket(group_name, *casted_socket_params, priority, - respect_limits, handle, callback, net_log); + socket_tag, respect_limits, handle, callback, + net_log); } void SOCKSClientSocketPool::RequestSockets( diff --git a/chromium/net/socket/socks_client_socket_pool.h b/chromium/net/socket/socks_client_socket_pool.h index 4eb72e8e4fe..d67e0d480f2 100644 --- a/chromium/net/socket/socks_client_socket_pool.h +++ b/chromium/net/socket/socks_client_socket_pool.h @@ -17,6 +17,7 @@ #include "net/dns/host_resolver.h" #include "net/socket/client_socket_pool.h" #include "net/socket/client_socket_pool_base.h" +#include "net/traffic_annotation/network_traffic_annotation.h" namespace net { @@ -29,7 +30,9 @@ class NET_EXPORT_PRIVATE SOCKSSocketParams : public base::RefCounted<SOCKSSocketParams> { public: SOCKSSocketParams(const scoped_refptr<TransportSocketParams>& proxy_server, - bool socks_v5, const HostPortPair& host_port_pair); + bool socks_v5, + const HostPortPair& host_port_pair, + const NetworkTrafficAnnotationTag& traffic_annotation); const scoped_refptr<TransportSocketParams>& transport_params() const { return transport_params_; @@ -37,6 +40,10 @@ class NET_EXPORT_PRIVATE SOCKSSocketParams const HostResolver::RequestInfo& destination() const { return destination_; } bool is_socks_v5() const { return socks_v5_; } + const NetworkTrafficAnnotationTag traffic_annotation() { + return traffic_annotation_; + } + private: friend class base::RefCounted<SOCKSSocketParams>; ~SOCKSSocketParams(); @@ -47,6 +54,8 @@ class NET_EXPORT_PRIVATE SOCKSSocketParams HostResolver::RequestInfo destination_; const bool socks_v5_; + NetworkTrafficAnnotationTag traffic_annotation_; + DISALLOW_COPY_AND_ASSIGN(SOCKSSocketParams); }; @@ -56,6 +65,7 @@ class SOCKSConnectJob : public ConnectJob { public: SOCKSConnectJob(const std::string& group_name, RequestPriority priority, + const SocketTag& socket_tag, ClientSocketPool::RespectLimits respect_limits, const scoped_refptr<SOCKSSocketParams>& params, const base::TimeDelta& timeout_duration, @@ -122,6 +132,7 @@ class NET_EXPORT_PRIVATE SOCKSClientSocketPool int RequestSocket(const std::string& group_name, const void* connect_params, RequestPriority priority, + const SocketTag& socket_tag, RespectLimits respect_limits, ClientSocketHandle* handle, const CompletionCallback& callback, diff --git a/chromium/net/socket/socks_client_socket_pool_unittest.cc b/chromium/net/socket/socks_client_socket_pool_unittest.cc index eaafb9d9f7e..8836d0b762b 100644 --- a/chromium/net/socket/socks_client_socket_pool_unittest.cc +++ b/chromium/net/socket/socks_client_socket_pool_unittest.cc @@ -8,6 +8,7 @@ #include "base/compiler_specific.h" #include "base/run_loop.h" #include "base/time/time.h" +#include "build/build_config.h" #include "net/base/load_timing_info.h" #include "net/base/load_timing_info_test_util.h" #include "net/base/net_errors.h" @@ -17,8 +18,10 @@ #include "net/log/net_log_with_source.h" #include "net/socket/client_socket_factory.h" #include "net/socket/client_socket_handle.h" +#include "net/socket/socket_tag.h" #include "net/socket/socket_test_util.h" #include "net/test/gtest_util.h" +#include "net/traffic_annotation/network_traffic_annotation_test_helper.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -56,15 +59,15 @@ scoped_refptr<TransportSocketParams> CreateProxyHostParams() { } scoped_refptr<SOCKSSocketParams> CreateSOCKSv4Params() { - return new SOCKSSocketParams( - CreateProxyHostParams(), false /* socks_v5 */, - HostPortPair("host", 80)); + return new SOCKSSocketParams(CreateProxyHostParams(), false /* socks_v5 */, + HostPortPair("host", 80), + TRAFFIC_ANNOTATION_FOR_TESTS); } scoped_refptr<SOCKSSocketParams> CreateSOCKSv5Params() { - return new SOCKSSocketParams( - CreateProxyHostParams(), true /* socks_v5 */, - HostPortPair("host", 80)); + return new SOCKSSocketParams(CreateProxyHostParams(), true /* socks_v5 */, + HostPortPair("host", 80), + TRAFFIC_ANNOTATION_FOR_TESTS); } class SOCKSClientSocketPoolTest : public testing::Test { @@ -137,7 +140,7 @@ TEST_F(SOCKSClientSocketPoolTest, Simple) { transport_client_socket_factory_.AddSocketDataProvider(data.data_provider()); ClientSocketHandle handle; - int rv = handle.Init("a", CreateSOCKSv5Params(), LOW, + int rv = handle.Init("a", CreateSOCKSv5Params(), LOW, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, CompletionCallback(), &pool_, NetLogWithSource()); EXPECT_THAT(rv, IsOk()); @@ -158,7 +161,7 @@ TEST_F(SOCKSClientSocketPoolTest, SetSocketRequestPriorityOnInit) { ClientSocketHandle handle; EXPECT_EQ(OK, - handle.Init("a", CreateSOCKSv5Params(), priority, + handle.Init("a", CreateSOCKSv5Params(), priority, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, CompletionCallback(), &pool_, NetLogWithSource())); EXPECT_EQ(priority, transport_socket_pool_.last_request_priority()); @@ -178,7 +181,7 @@ TEST_F(SOCKSClientSocketPoolTest, SetResolvePriorityOnInit) { ClientSocketHandle handle; EXPECT_EQ(ERR_IO_PENDING, - handle.Init("a", CreateSOCKSv4Params(), priority, + handle.Init("a", CreateSOCKSv4Params(), priority, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, CompletionCallback(), &pool_, NetLogWithSource())); EXPECT_EQ(priority, transport_socket_pool_.last_request_priority()); @@ -193,7 +196,7 @@ TEST_F(SOCKSClientSocketPoolTest, Async) { TestCompletionCallback callback; ClientSocketHandle handle; - int rv = handle.Init("a", CreateSOCKSv5Params(), LOW, + int rv = handle.Init("a", CreateSOCKSv5Params(), LOW, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), &pool_, NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); @@ -213,7 +216,7 @@ TEST_F(SOCKSClientSocketPoolTest, TransportConnectError) { transport_client_socket_factory_.AddSocketDataProvider(&socket_data); ClientSocketHandle handle; - int rv = handle.Init("a", CreateSOCKSv5Params(), LOW, + int rv = handle.Init("a", CreateSOCKSv5Params(), LOW, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, CompletionCallback(), &pool_, NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_PROXY_CONNECTION_FAILED)); @@ -228,7 +231,7 @@ TEST_F(SOCKSClientSocketPoolTest, AsyncTransportConnectError) { TestCompletionCallback callback; ClientSocketHandle handle; - int rv = handle.Init("a", CreateSOCKSv5Params(), LOW, + int rv = handle.Init("a", CreateSOCKSv5Params(), LOW, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), &pool_, NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); @@ -251,7 +254,7 @@ TEST_F(SOCKSClientSocketPoolTest, SOCKSConnectError) { ClientSocketHandle handle; EXPECT_EQ(0, transport_socket_pool_.release_count()); - int rv = handle.Init("a", CreateSOCKSv5Params(), LOW, + int rv = handle.Init("a", CreateSOCKSv5Params(), LOW, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, CompletionCallback(), &pool_, NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_SOCKS_CONNECTION_FAILED)); @@ -272,7 +275,7 @@ TEST_F(SOCKSClientSocketPoolTest, AsyncSOCKSConnectError) { TestCompletionCallback callback; ClientSocketHandle handle; EXPECT_EQ(0, transport_socket_pool_.release_count()); - int rv = handle.Init("a", CreateSOCKSv5Params(), LOW, + int rv = handle.Init("a", CreateSOCKSv5Params(), LOW, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), &pool_, NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); @@ -356,6 +359,82 @@ TEST_F(SOCKSClientSocketPoolTest, CancelDuringSOCKSConnect) { // It would be nice to also test the timeouts in SOCKSClientSocketPool. +// Test that SocketTag passed into SOCKSClientSocketPool is applied to returned +// sockets. +#if defined(OS_ANDROID) +TEST_F(SOCKSClientSocketPoolTest, Tag) { + MockTaggingClientSocketFactory socket_factory; + MockTransportClientSocketPool transport_socket_pool( + kMaxSockets, kMaxSocketsPerGroup, &socket_factory); + SOCKSClientSocketPool pool(kMaxSockets, kMaxSocketsPerGroup, &host_resolver_, + &transport_socket_pool, NULL, NULL); + SocketTag tag1(SocketTag::UNSET_UID, 0x12345678); + SocketTag tag2(getuid(), 0x87654321); + scoped_refptr<TransportSocketParams> tcp_params(new TransportSocketParams( + HostPortPair("proxy", 80), false, OnHostResolutionCallback(), + TransportSocketParams::COMBINE_CONNECT_AND_WRITE_DEFAULT)); + scoped_refptr<SOCKSSocketParams> params(new SOCKSSocketParams( + tcp_params, true /* socks_v5 */, HostPortPair("host", 80), + TRAFFIC_ANNOTATION_FOR_TESTS)); + + // Test socket is tagged when created synchronously. + SOCKS5MockData data_sync(SYNCHRONOUS); + data_sync.data_provider()->set_connect_data(MockConnect(SYNCHRONOUS, OK)); + socket_factory.AddSocketDataProvider(data_sync.data_provider()); + ClientSocketHandle handle; + int rv = handle.Init("a", params, LOW, tag1, + ClientSocketPool::RespectLimits::ENABLED, + CompletionCallback(), &pool, NetLogWithSource()); + EXPECT_THAT(rv, IsOk()); + EXPECT_TRUE(handle.is_initialized()); + EXPECT_TRUE(handle.socket()); + EXPECT_EQ(socket_factory.GetLastProducedSocket()->tag(), tag1); + EXPECT_TRUE( + socket_factory.GetLastProducedSocket()->tagged_before_connected()); + + // Test socket is tagged when reused synchronously. + StreamSocket* socket = handle.socket(); + handle.Reset(); + rv = handle.Init("a", params, LOW, tag2, + ClientSocketPool::RespectLimits::ENABLED, + CompletionCallback(), &pool, NetLogWithSource()); + EXPECT_THAT(rv, IsOk()); + EXPECT_TRUE(handle.socket()); + EXPECT_TRUE(handle.socket()->IsConnected()); + EXPECT_EQ(handle.socket(), socket); + EXPECT_EQ(socket_factory.GetLastProducedSocket()->tag(), tag2); + handle.socket()->Disconnect(); + handle.Reset(); + + // Test socket is tagged when created asynchronously. + SOCKS5MockData data_async(ASYNC); + socket_factory.AddSocketDataProvider(data_async.data_provider()); + TestCompletionCallback callback; + rv = handle.Init("a", params, LOW, tag1, + ClientSocketPool::RespectLimits::ENABLED, + callback.callback(), &pool, NetLogWithSource()); + EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); + EXPECT_THAT(callback.WaitForResult(), IsOk()); + EXPECT_TRUE(handle.is_initialized()); + EXPECT_TRUE(handle.socket()); + EXPECT_EQ(socket_factory.GetLastProducedSocket()->tag(), tag1); + EXPECT_TRUE( + socket_factory.GetLastProducedSocket()->tagged_before_connected()); + + // Test socket is tagged when reused after being created asynchronously. + socket = handle.socket(); + handle.Reset(); + rv = handle.Init("a", params, LOW, tag2, + ClientSocketPool::RespectLimits::ENABLED, + CompletionCallback(), &pool, NetLogWithSource()); + EXPECT_THAT(rv, IsOk()); + EXPECT_TRUE(handle.socket()); + EXPECT_TRUE(handle.socket()->IsConnected()); + EXPECT_EQ(handle.socket(), socket); + EXPECT_EQ(socket_factory.GetLastProducedSocket()->tag(), tag2); +} +#endif + } // namespace } // namespace net diff --git a/chromium/net/socket/socks_client_socket_unittest.cc b/chromium/net/socket/socks_client_socket_unittest.cc index 63183845e69..63b82c0ad74 100644 --- a/chromium/net/socket/socks_client_socket_unittest.cc +++ b/chromium/net/socket/socks_client_socket_unittest.cc @@ -8,6 +8,7 @@ #include <utility> #include "base/macros.h" +#include "build/build_config.h" #include "net/base/address_list.h" #include "net/base/test_completion_callback.h" #include "net/base/winsock_init.h" @@ -21,6 +22,7 @@ #include "net/socket/socket_test_util.h" #include "net/socket/tcp_client_socket.h" #include "net/test/gtest_util.h" +#include "net/traffic_annotation/network_traffic_annotation_test_helper.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/platform_test.h" @@ -34,9 +36,6 @@ namespace net { class NetLog; -const char kSOCKSOkRequest[] = { 0x04, 0x01, 0x00, 0x50, 127, 0, 0, 1, 0 }; -const char kSOCKSOkReply[] = { 0x00, 0x5A, 0x00, 0x00, 0, 0, 0, 0 }; - class SOCKSClientSocketTest : public PlatformTest { public: SOCKSClientSocketTest(); @@ -99,7 +98,7 @@ std::unique_ptr<SOCKSClientSocket> SOCKSClientSocketTest::BuildMockSocket( return std::unique_ptr<SOCKSClientSocket>(new SOCKSClientSocket( std::move(connection), HostResolver::RequestInfo(HostPortPair(hostname, port)), DEFAULT_PRIORITY, - host_resolver)); + host_resolver, TRAFFIC_ANNOTATION_FOR_TESTS)); } // Implementation of HostResolver that never completes its resolve request. @@ -130,6 +129,21 @@ class HangingHostResolverWithCancel : public HostResolver { return ERR_UNEXPECTED; } + int ResolveStaleFromCache(const RequestInfo& info, + AddressList* addresses, + HostCache::EntryStaleness* stale_info, + const NetLogWithSource& net_log) override { + NOTIMPLEMENTED(); + return ERR_UNEXPECTED; + } + + bool HasCached(base::StringPiece hostname, + HostCache::Entry::Source* source_out, + HostCache::EntryStaleness* stale_out) const override { + NOTIMPLEMENTED(); + return false; + } + void RemoveRequest(Request* req) { EXPECT_TRUE(HasOutstandingRequest()); EXPECT_EQ(outstanding_request_, req); @@ -165,11 +179,12 @@ TEST_F(SOCKSClientSocketTest, CompleteHandshake) { const std::string payload_read = "moar random data"; MockWrite data_writes[] = { - MockWrite(ASYNC, kSOCKSOkRequest, arraysize(kSOCKSOkRequest)), - MockWrite(ASYNC, payload_write.data(), payload_write.size()) }; + MockWrite(ASYNC, kSOCKS4OkRequestLocalHostPort80, + kSOCKS4OkRequestLocalHostPort80Length), + MockWrite(ASYNC, payload_write.data(), payload_write.size())}; MockRead data_reads[] = { - MockRead(ASYNC, kSOCKSOkReply, arraysize(kSOCKSOkReply)), - MockRead(ASYNC, payload_read.data(), payload_read.size()) }; + MockRead(ASYNC, kSOCKS4OkReply, kSOCKS4OkReplyLength), + MockRead(ASYNC, payload_read.data(), payload_read.size())}; TestNetLog log; user_sock_ = BuildMockSocket(data_reads, arraysize(data_reads), @@ -199,8 +214,8 @@ TEST_F(SOCKSClientSocketTest, CompleteHandshake) { scoped_refptr<IOBuffer> buffer(new IOBuffer(payload_write.size())); memcpy(buffer->data(), payload_write.data(), payload_write.size()); - rv = user_sock_->Write( - buffer.get(), payload_write.size(), callback_.callback()); + rv = user_sock_->Write(buffer.get(), payload_write.size(), + callback_.callback(), TRAFFIC_ANNOTATION_FOR_TESTS); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); rv = callback_.WaitForResult(); EXPECT_EQ(static_cast<int>(payload_write.size()), rv); @@ -241,7 +256,8 @@ TEST_F(SOCKSClientSocketTest, HandshakeFailures) { for (size_t i = 0; i < arraysize(tests); ++i) { MockWrite data_writes[] = { - MockWrite(SYNCHRONOUS, kSOCKSOkRequest, arraysize(kSOCKSOkRequest)) }; + MockWrite(SYNCHRONOUS, kSOCKS4OkRequestLocalHostPort80, + kSOCKS4OkRequestLocalHostPort80Length)}; MockRead data_reads[] = { MockRead(SYNCHRONOUS, tests[i].fail_reply, arraysize(tests[i].fail_reply)) }; @@ -277,8 +293,8 @@ TEST_F(SOCKSClientSocketTest, PartialServerReads) { const char kSOCKSPartialReply1[] = { 0x00 }; const char kSOCKSPartialReply2[] = { 0x5A, 0x00, 0x00, 0, 0, 0, 0 }; - MockWrite data_writes[] = { - MockWrite(ASYNC, kSOCKSOkRequest, arraysize(kSOCKSOkRequest)) }; + MockWrite data_writes[] = {MockWrite(ASYNC, kSOCKS4OkRequestLocalHostPort80, + kSOCKS4OkRequestLocalHostPort80Length)}; MockRead data_reads[] = { MockRead(ASYNC, kSOCKSPartialReply1, arraysize(kSOCKSPartialReply1)), MockRead(ASYNC, kSOCKSPartialReply2, arraysize(kSOCKSPartialReply2)) }; @@ -318,7 +334,7 @@ TEST_F(SOCKSClientSocketTest, PartialClientWrites) { MockWrite(ASYNC, kSOCKSPartialRequest2, arraysize(kSOCKSPartialRequest2)), }; MockRead data_reads[] = { - MockRead(ASYNC, kSOCKSOkReply, arraysize(kSOCKSOkReply)) }; + MockRead(ASYNC, kSOCKS4OkReply, kSOCKS4OkReplyLength)}; TestNetLog log; user_sock_ = BuildMockSocket(data_reads, arraysize(data_reads), @@ -344,12 +360,12 @@ TEST_F(SOCKSClientSocketTest, PartialClientWrites) { // Tests the case when the server sends a smaller sized handshake data // and closes the connection. TEST_F(SOCKSClientSocketTest, FailedSocketRead) { - MockWrite data_writes[] = { - MockWrite(ASYNC, kSOCKSOkRequest, arraysize(kSOCKSOkRequest)) }; + MockWrite data_writes[] = {MockWrite(ASYNC, kSOCKS4OkRequestLocalHostPort80, + kSOCKS4OkRequestLocalHostPort80Length)}; MockRead data_reads[] = { - MockRead(ASYNC, kSOCKSOkReply, arraysize(kSOCKSOkReply) - 2), + MockRead(ASYNC, kSOCKS4OkReply, kSOCKS4OkReplyLength - 2), // close connection unexpectedly - MockRead(SYNCHRONOUS, 0) }; + MockRead(SYNCHRONOUS, 0)}; TestNetLog log; user_sock_ = BuildMockSocket(data_reads, arraysize(data_reads), @@ -468,4 +484,29 @@ TEST_F(SOCKSClientSocketTest, NoIPv6RealResolver) { callback_.GetResult(user_sock_->Connect(callback_.callback()))); } +TEST_F(SOCKSClientSocketTest, Tag) { + StaticSocketDataProvider data; + TestNetLog log; + MockTaggingStreamSocket* tagging_sock = + new MockTaggingStreamSocket(std::unique_ptr<StreamSocket>( + new MockTCPClientSocket(address_list_, &log, &data))); + + std::unique_ptr<ClientSocketHandle> connection(new ClientSocketHandle); + // |connection| takes ownership of |tagging_sock|, but keep a + // non-owning pointer to it. + connection->SetSocket(std::unique_ptr<StreamSocket>(tagging_sock)); + MockHostResolver host_resolver; + SOCKSClientSocket socket( + std::move(connection), + HostResolver::RequestInfo(HostPortPair("localhost", 80)), + DEFAULT_PRIORITY, &host_resolver, TRAFFIC_ANNOTATION_FOR_TESTS); + + EXPECT_EQ(tagging_sock->tag(), SocketTag()); +#if defined(OS_ANDROID) + SocketTag tag(0x12345678, 0x87654321); + socket.ApplySocketTag(tag); + EXPECT_EQ(tagging_sock->tag(), tag); +#endif // OS_ANDROID +} + } // namespace net diff --git a/chromium/net/socket/ssl_client_socket_impl.cc b/chromium/net/socket/ssl_client_socket_impl.cc index 54c0c560c96..c584e8e0f77 100644 --- a/chromium/net/socket/ssl_client_socket_impl.cc +++ b/chromium/net/socket/ssl_client_socket_impl.cc @@ -8,6 +8,7 @@ #include <string.h> #include <algorithm> +#include <map> #include <utility> #include "base/bind.h" @@ -17,8 +18,9 @@ #include "base/macros.h" #include "base/memory/singleton.h" #include "base/metrics/field_trial.h" +#include "base/metrics/field_trial_params.h" +#include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" -#include "base/metrics/sparse_histogram.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_piece.h" #include "base/strings/stringprintf.h" @@ -36,8 +38,10 @@ #include "net/cert/ct_policy_enforcer.h" #include "net/cert/ct_policy_status.h" #include "net/cert/ct_verifier.h" +#include "net/cert/internal/parse_certificate.h" #include "net/cert/x509_certificate_net_log_param.h" #include "net/cert/x509_util.h" +#include "net/der/parse_values.h" #include "net/http/transport_security_state.h" #include "net/log/net_log.h" #include "net/log/net_log_event_type.h" @@ -49,6 +53,7 @@ #include "net/ssl/ssl_info.h" #include "net/ssl/ssl_private_key.h" #include "net/ssl/token_binding.h" +#include "net/traffic_annotation/network_traffic_annotation.h" #include "third_party/boringssl/src/include/openssl/bio.h" #include "third_party/boringssl/src/include/openssl/bytestring.h" #include "third_party/boringssl/src/include/openssl/err.h" @@ -84,6 +89,9 @@ const uint8_t kTbProtocolVersionMinor = 13; const uint8_t kTbMinProtocolVersionMajor = 0; const uint8_t kTbMinProtocolVersionMinor = 10; +const base::Feature kPostQuantumPadding{"PostQuantumPadding", + base::FEATURE_DISABLED_BY_DEFAULT}; + std::unique_ptr<base::Value> NetLogPrivateKeyOperationCallback( uint16_t algorithm, NetLogCaptureMode mode) { @@ -195,6 +203,95 @@ std::unique_ptr<base::Value> NetLogSSLMessageCallback( return std::move(dict); } +// This enum is used in histograms, so values may not be reused. +enum class RSAKeyUsage { + // The TLS cipher suite was not RSA or ECDHE_RSA. + kNotRSA = 0, + // The Key Usage extension is not present, which is consistent with TLS usage. + kOKNoExtension = 1, + // The Key Usage extension has both the digitalSignature and keyEncipherment + // bits, which is consistent with TLS usage. + kOKHaveBoth = 2, + // The Key Usage extension contains only the digitalSignature bit, which is + // consistent with TLS usage. + kOKHaveDigitalSignature = 3, + // The Key Usage extension contains only the keyEncipherment bit, which is + // consistent with TLS usage. + kOKHaveKeyEncipherment = 4, + // The Key Usage extension is missing the digitalSignature bit. + kMissingDigitalSignature = 5, + // The Key Usage extension is missing the keyEncipherment bit. + kMissingKeyEncipherment = 6, + // There was an error processing the certificate. + kError = 7, + + kLastValue = kError, +}; + +RSAKeyUsage CheckRSAKeyUsage(const X509Certificate* cert, + const SSL_CIPHER* cipher) { + bool need_key_encipherment = false; + switch (SSL_CIPHER_get_kx_nid(cipher)) { + case NID_kx_rsa: + need_key_encipherment = true; + break; + case NID_kx_ecdhe: + if (SSL_CIPHER_get_auth_nid(cipher) != NID_auth_rsa) { + return RSAKeyUsage::kNotRSA; + } + break; + default: + return RSAKeyUsage::kNotRSA; + } + + const CRYPTO_BUFFER* buffer = cert->cert_buffer(); + der::Input tbs_certificate_tlv; + der::Input signature_algorithm_tlv; + der::BitString signature_value; + ParsedTbsCertificate tbs; + if (!ParseCertificate( + der::Input(CRYPTO_BUFFER_data(buffer), CRYPTO_BUFFER_len(buffer)), + &tbs_certificate_tlv, &signature_algorithm_tlv, &signature_value, + nullptr) || + !ParseTbsCertificate(tbs_certificate_tlv, + x509_util::DefaultParseCertificateOptions(), &tbs, + nullptr)) { + return RSAKeyUsage::kError; + } + + if (!tbs.has_extensions) { + return RSAKeyUsage::kOKNoExtension; + } + + std::map<der::Input, ParsedExtension> extensions; + if (!ParseExtensions(tbs.extensions_tlv, &extensions)) { + return RSAKeyUsage::kError; + } + ParsedExtension key_usage_ext; + if (!ConsumeExtension(KeyUsageOid(), &extensions, &key_usage_ext)) { + return RSAKeyUsage::kOKNoExtension; + } + der::BitString key_usage; + if (!ParseKeyUsage(key_usage_ext.value, &key_usage)) { + return RSAKeyUsage::kError; + } + + bool have_digital_signature = + key_usage.AssertsBit(KEY_USAGE_BIT_DIGITAL_SIGNATURE); + bool have_key_encipherment = + key_usage.AssertsBit(KEY_USAGE_BIT_KEY_ENCIPHERMENT); + if (have_digital_signature && have_key_encipherment) { + return RSAKeyUsage::kOKHaveBoth; + } + + if (need_key_encipherment) { + return have_key_encipherment ? RSAKeyUsage::kOKHaveKeyEncipherment + : RSAKeyUsage::kMissingKeyEncipherment; + } + return have_digital_signature ? RSAKeyUsage::kOKHaveDigitalSignature + : RSAKeyUsage::kMissingDigitalSignature; +} + } // namespace class SSLClientSocketImpl::SSLContext { @@ -412,6 +509,7 @@ SSLClientSocketImpl::SSLClientSocketImpl( transport_security_state_(context.transport_security_state), policy_enforcer_(context.ct_policy_enforcer), pkp_bypassed_(false), + is_fatal_cert_error_(false), connect_error_details_(SSLErrorDetails::kOther), net_log_(transport_->socket()->NetLog()), weak_factory_(this) { @@ -673,7 +771,7 @@ bool SSLClientSocketImpl::GetSSLInfo(SSLInfo* ssl_info) { ssl_info->token_binding_key_param = tb_negotiated_param_; ssl_info->pinning_failure_log = pinning_failure_log_; ssl_info->ocsp_result = server_cert_verify_result_.ocsp_result; - + ssl_info->is_fatal_cert_error = is_fatal_cert_error_; AddCTInfoToSSLInfo(ssl_info); const SSL_CIPHER* cipher = SSL_get_current_cipher(ssl_.get()); @@ -718,6 +816,10 @@ void SSLClientSocketImpl::DumpMemoryStats(SocketMemoryStats* stats) const { stats->total_size = stats->buffer_size + stats->cert_size; } +void SSLClientSocketImpl::ApplySocketTag(const SocketTag& tag) { + return transport_->socket()->ApplySocketTag(tag); +} + // static void SSLClientSocketImpl::DumpSSLClientSessionMemoryStats( base::trace_event::ProcessMemoryDump* pmd) { @@ -749,9 +851,11 @@ int SSLClientSocketImpl::ReadIfReady(IOBuffer* buf, return rv; } -int SSLClientSocketImpl::Write(IOBuffer* buf, - int buf_len, - const CompletionCallback& callback) { +int SSLClientSocketImpl::Write( + IOBuffer* buf, + int buf_len, + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& traffic_annotation) { user_write_buf_ = buf; user_write_buf_len_ = buf_len; @@ -844,18 +948,21 @@ int SSLClientSocketImpl::Init() { } switch (ssl_config_.tls13_variant) { - case kTLS13VariantDraft: - SSL_set_tls13_variant(ssl_.get(), tls13_default); + case kTLS13VariantDraft22: + SSL_set_tls13_variant(ssl_.get(), tls13_draft22); break; - case kTLS13VariantExperiment: - SSL_set_tls13_variant(ssl_.get(), tls13_experiment); + case kTLS13VariantDraft23: + SSL_set_tls13_variant(ssl_.get(), tls13_default); break; case kTLS13VariantExperiment2: SSL_set_tls13_variant(ssl_.get(), tls13_experiment2); break; - case kTLS13VariantExperiment3: - SSL_set_tls13_variant(ssl_.get(), tls13_experiment3); - break; + } + + const int dummy_pq_padding_len = base::GetFieldTrialParamByFeatureAsInt( + kPostQuantumPadding, "length", 0 /* default value */); + if (dummy_pq_padding_len > 0 && dummy_pq_padding_len < 15000) { + SSL_set_dummy_pq_padding_size(ssl_.get(), dummy_pq_padding_len); } // OpenSSL defaults some options to on, others to off. To avoid ambiguity, @@ -1098,8 +1205,7 @@ int SSLClientSocketImpl::DoHandshakeComplete(int result) { uint16_t signature_algorithm = SSL_get_peer_signature_algorithm(ssl_.get()); if (signature_algorithm != 0) { - UMA_HISTOGRAM_SPARSE_SLOWLY("Net.SSLSignatureAlgorithm", - signature_algorithm); + base::UmaHistogramSparse("Net.SSLSignatureAlgorithm", signature_algorithm); } // Verify the certificate. @@ -1231,6 +1337,10 @@ int SSLClientSocketImpl::DoVerifyCertComplete(int result) { result = ct_result; } + is_fatal_cert_error_ = + IsCertStatusError(cert_status) && !IsCertStatusMinorError(cert_status) && + transport_security_state_->ShouldSSLErrorsBeFatal(host_and_port_.host()); + if (result == OK) { DCHECK(!certificate_verified_); certificate_verified_ = true; @@ -1247,6 +1357,22 @@ int SSLClientSocketImpl::DoVerifyCertComplete(int result) { transport_security_state_->CheckExpectStaple(host_and_port_, ssl_info, ocsp_response); + + // 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 { + UMA_HISTOGRAM_ENUMERATION( + "Net.SSLRSAKeyUsage.UnknownRoot", rsa_key_usage, + static_cast<int>(RSAKeyUsage::kLastValue) + 1); + } + } } completed_connect_ = true; @@ -1495,8 +1621,8 @@ int SSLClientSocketImpl::VerifyCT() { // gets all the data it needs for SCT verification and does not do any // external communication. cert_transparency_verifier_->Verify( - server_cert_verify_result_.verified_cert.get(), ocsp_response, sct_list, - &ct_verify_result_.scts, net_log_); + host_and_port().host(), server_cert_verify_result_.verified_cert.get(), + ocsp_response, sct_list, &ct_verify_result_.scts, net_log_); SCTList verified_scts = ct::SCTsMatchingStatus(ct_verify_result_.scts, ct::SCT_STATUS_OK); @@ -1613,7 +1739,7 @@ int SSLClientSocketImpl::ClientCertRequestCallback(SSL* ssl) { NetLogEventType::SSL_CLIENT_CERT_PROVIDED, NetLog::IntCallback( "cert_count", - 1 + ssl_config_.client_cert->GetIntermediateCertificates().size())); + 1 + ssl_config_.client_cert->intermediate_buffers().size())); return 1; } #endif // defined(OS_IOS) diff --git a/chromium/net/socket/ssl_client_socket_impl.h b/chromium/net/socket/ssl_client_socket_impl.h index 0d162d37879..40b5d9763ea 100644 --- a/chromium/net/socket/ssl_client_socket_impl.h +++ b/chromium/net/socket/ssl_client_socket_impl.h @@ -32,6 +32,7 @@ #include "net/ssl/openssl_ssl_util.h" #include "net/ssl/ssl_client_cert_type.h" #include "net/ssl/ssl_config_service.h" +#include "net/traffic_annotation/network_traffic_annotation.h" #include "third_party/boringssl/src/include/openssl/base.h" #include "third_party/boringssl/src/include/openssl/ssl.h" @@ -116,6 +117,7 @@ class SSLClientSocketImpl : public SSLClientSocket, void AddConnectionAttempts(const ConnectionAttempts& attempts) override {} int64_t GetTotalReceivedBytes() const override; void DumpMemoryStats(SocketMemoryStats* stats) const override; + void ApplySocketTag(const SocketTag& tag) override; // Dumps memory allocation stats. |pmd| is the browser process memory dump. static void DumpSSLClientSessionMemoryStats( @@ -130,7 +132,8 @@ class SSLClientSocketImpl : public SSLClientSocket, const CompletionCallback& callback) override; int Write(IOBuffer* buf, int buf_len, - const CompletionCallback& callback) override; + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& traffic_annotation) override; int SetReceiveBufferSize(int32_t size) override; int SetSendBufferSize(int32_t size) override; @@ -349,6 +352,10 @@ class SSLClientSocketImpl : public SSLClientSocket, // True if PKP is bypassed due to a local trust anchor. bool pkp_bypassed_; + // True if there was a certificate error which should be treated as fatal, + // and false otherwise. + bool is_fatal_cert_error_; + SSLErrorDetails connect_error_details_; NetLogWithSource net_log_; diff --git a/chromium/net/socket/ssl_client_socket_pool.cc b/chromium/net/socket/ssl_client_socket_pool.cc index 8eb860fafe4..b6a45f509a7 100644 --- a/chromium/net/socket/ssl_client_socket_pool.cc +++ b/chromium/net/socket/ssl_client_socket_pool.cc @@ -10,8 +10,8 @@ #include "base/bind.h" #include "base/bind_helpers.h" #include "base/metrics/field_trial.h" +#include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" -#include "base/metrics/sparse_histogram.h" #include "base/trace_event/trace_event.h" #include "base/values.h" #include "net/base/host_port_pair.h" @@ -100,6 +100,7 @@ static const int kSSLHandshakeTimeoutInSeconds = 30; SSLConnectJob::SSLConnectJob(const std::string& group_name, RequestPriority priority, + const SocketTag& socket_tag, ClientSocketPool::RespectLimits respect_limits, const scoped_refptr<SSLSocketParams>& params, const base::TimeDelta& timeout_duration, @@ -114,6 +115,7 @@ SSLConnectJob::SSLConnectJob(const std::string& group_name, group_name, timeout_duration, priority, + socket_tag, respect_limits, delegate, NetLogWithSource::Make(net_log, NetLogSourceType::SSL_CONNECT_JOB)), @@ -236,8 +238,8 @@ int SSLConnectJob::DoTransportConnect() { scoped_refptr<TransportSocketParams> direct_params = params_->GetDirectConnectionParams(); return transport_socket_handle_->Init(group_name(), direct_params, priority(), - respect_limits(), callback_, - transport_pool_, net_log()); + socket_tag(), respect_limits(), + callback_, transport_pool_, net_log()); } int SSLConnectJob::DoTransportConnectComplete(int result) { @@ -259,9 +261,9 @@ int SSLConnectJob::DoSOCKSConnect() { transport_socket_handle_.reset(new ClientSocketHandle()); scoped_refptr<SOCKSSocketParams> socks_proxy_params = params_->GetSocksProxyConnectionParams(); - return transport_socket_handle_->Init(group_name(), socks_proxy_params, - priority(), respect_limits(), callback_, - socks_pool_, net_log()); + return transport_socket_handle_->Init( + group_name(), socks_proxy_params, priority(), socket_tag(), + respect_limits(), callback_, socks_pool_, net_log()); } int SSLConnectJob::DoSOCKSConnectComplete(int result) { @@ -278,9 +280,9 @@ int SSLConnectJob::DoTunnelConnect() { transport_socket_handle_.reset(new ClientSocketHandle()); scoped_refptr<HttpProxySocketParams> http_proxy_params = params_->GetHttpProxyConnectionParams(); - return transport_socket_handle_->Init(group_name(), http_proxy_params, - priority(), respect_limits(), callback_, - http_proxy_pool_, net_log()); + return transport_socket_handle_->Init( + group_name(), http_proxy_params, priority(), socket_tag(), + respect_limits(), callback_, http_proxy_pool_, net_log()); } int SSLConnectJob::DoTunnelConnectComplete(int result) { @@ -366,8 +368,8 @@ int SSLConnectJob::DoSSLConnectComplete(int result) { result == ERR_SSL_BAD_RECORD_MAC_ALERT) { // Report the error code for each time a version interference probe is // triggered. - UMA_HISTOGRAM_SPARSE_SLOWLY("Net.SSLVersionInterferenceProbeTrigger", - std::abs(result)); + base::UmaHistogramSparse("Net.SSLVersionInterferenceProbeTrigger", + std::abs(result)); net_log().AddEventWithNetErrorCode( NetLogEventType::SSL_VERSION_INTERFERENCE_PROBE, result); SSLErrorDetails details = ssl_socket_->GetConnectErrorDetails(); @@ -417,11 +419,11 @@ int SSLConnectJob::DoSSLConnectComplete(int result) { uint16_t cipher_suite = SSLConnectionStatusToCipherSuite(ssl_info.connection_status); - UMA_HISTOGRAM_SPARSE_SLOWLY("Net.SSL_CipherSuite", cipher_suite); + base::UmaHistogramSparse("Net.SSL_CipherSuite", cipher_suite); if (ssl_info.key_exchange_group != 0) { - UMA_HISTOGRAM_SPARSE_SLOWLY("Net.SSL_KeyExchange.ECDHE", - ssl_info.key_exchange_group); + base::UmaHistogramSparse("Net.SSL_KeyExchange.ECDHE", + ssl_info.key_exchange_group); } if (ssl_info.handshake_type == SSLInfo::HANDSHAKE_RESUME) { @@ -469,24 +471,24 @@ int SSLConnectJob::DoSSLConnectComplete(int result) { } } - UMA_HISTOGRAM_SPARSE_SLOWLY("Net.SSL_Connection_Error", std::abs(result)); + base::UmaHistogramSparse("Net.SSL_Connection_Error", std::abs(result)); if (is_google) { - UMA_HISTOGRAM_SPARSE_SLOWLY("Net.SSL_Connection_Error_Google", - std::abs(result)); + base::UmaHistogramSparse("Net.SSL_Connection_Error_Google", + std::abs(result)); } if (tls13_supported) { - UMA_HISTOGRAM_SPARSE_SLOWLY("Net.SSL_Connection_Error_TLS13Experiment", - std::abs(result)); + base::UmaHistogramSparse("Net.SSL_Connection_Error_TLS13Experiment", + std::abs(result)); } if (result == ERR_SSL_VERSION_INTERFERENCE) { // Record the error code version interference was detected at. DCHECK(version_interference_probe_); DCHECK_NE(OK, version_interference_error_); - UMA_HISTOGRAM_SPARSE_SLOWLY("Net.SSLVersionInterferenceError", - std::abs(version_interference_error_)); + base::UmaHistogramSparse("Net.SSLVersionInterferenceError", + std::abs(version_interference_error_)); if (tls13_supported) { UMA_HISTOGRAM_ENUMERATION( @@ -622,9 +624,10 @@ SSLClientSocketPool::SSLConnectJobFactory::NewConnectJob( const PoolBase::Request& request, ConnectJob::Delegate* delegate) const { return std::unique_ptr<ConnectJob>(new SSLConnectJob( - group_name, request.priority(), request.respect_limits(), - request.params(), ConnectionTimeout(), transport_pool_, socks_pool_, - http_proxy_pool_, client_socket_factory_, context_, delegate, net_log_)); + group_name, request.priority(), request.socket_tag(), + request.respect_limits(), request.params(), ConnectionTimeout(), + transport_pool_, socks_pool_, http_proxy_pool_, client_socket_factory_, + context_, delegate, net_log_)); } base::TimeDelta SSLClientSocketPool::SSLConnectJobFactory::ConnectionTimeout() @@ -635,6 +638,7 @@ base::TimeDelta SSLClientSocketPool::SSLConnectJobFactory::ConnectionTimeout() int SSLClientSocketPool::RequestSocket(const std::string& group_name, const void* socket_params, RequestPriority priority, + const SocketTag& socket_tag, RespectLimits respect_limits, ClientSocketHandle* handle, const CompletionCallback& callback, @@ -643,7 +647,8 @@ int SSLClientSocketPool::RequestSocket(const std::string& group_name, static_cast<const scoped_refptr<SSLSocketParams>*>(socket_params); return base_.RequestSocket(group_name, *casted_socket_params, priority, - respect_limits, handle, callback, net_log); + socket_tag, respect_limits, handle, callback, + net_log); } void SSLClientSocketPool::RequestSockets( diff --git a/chromium/net/socket/ssl_client_socket_pool.h b/chromium/net/socket/ssl_client_socket_pool.h index 097cf6c322b..6ec5c44f1ca 100644 --- a/chromium/net/socket/ssl_client_socket_pool.h +++ b/chromium/net/socket/ssl_client_socket_pool.h @@ -98,6 +98,7 @@ class SSLConnectJob : public ConnectJob { // job. SSLConnectJob(const std::string& group_name, RequestPriority priority, + const SocketTag& socket_tag, ClientSocketPool::RespectLimits respect_limits, const scoped_refptr<SSLSocketParams>& params, const base::TimeDelta& timeout_duration, @@ -217,6 +218,7 @@ class NET_EXPORT_PRIVATE SSLClientSocketPool int RequestSocket(const std::string& group_name, const void* connect_params, RequestPriority priority, + const SocketTag& socket_tag, RespectLimits respect_limits, ClientSocketHandle* handle, const CompletionCallback& callback, diff --git a/chromium/net/socket/ssl_client_socket_pool_unittest.cc b/chromium/net/socket/ssl_client_socket_pool_unittest.cc index 2715d394c49..c9fe46058af 100644 --- a/chromium/net/socket/ssl_client_socket_pool_unittest.cc +++ b/chromium/net/socket/ssl_client_socket_pool_unittest.cc @@ -9,6 +9,7 @@ #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "base/time/time.h" +#include "build/build_config.h" #include "net/base/auth.h" #include "net/base/load_timing_info.h" #include "net/base/load_timing_info_test_util.h" @@ -29,13 +30,16 @@ #include "net/proxy/proxy_service.h" #include "net/socket/client_socket_handle.h" #include "net/socket/next_proto.h" +#include "net/socket/socket_tag.h" #include "net/socket/socket_test_util.h" #include "net/spdy/chromium/spdy_session.h" #include "net/spdy/chromium/spdy_session_pool.h" #include "net/spdy/chromium/spdy_test_util_common.h" #include "net/ssl/ssl_config_service_defaults.h" +#include "net/test/embedded_test_server/embedded_test_server.h" #include "net/test/gtest_util.h" #include "net/test/test_certificate_data.h" +#include "net/traffic_annotation/network_traffic_annotation_test_helper.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -48,6 +52,7 @@ namespace { const int kMaxSockets = 32; const int kMaxSocketsPerGroup = 6; +const char kGroupName[] = "a"; // Make sure |handle|'s load times are set correctly. DNS and connect start // times comes from mock client sockets in these tests, so primarily serves to @@ -109,7 +114,8 @@ class SSLClientSocketPoolTest : public testing::Test { socks_socket_params_( new SOCKSSocketParams(proxy_transport_socket_params_, true, - HostPortPair("sockshost", 443))), + HostPortPair("sockshost", 443), + TRAFFIC_ANNOTATION_FOR_TESTS)), socks_socket_pool_(kMaxSockets, kMaxSocketsPerGroup, &transport_socket_pool_), @@ -123,8 +129,7 @@ class SSLClientSocketPoolTest : public testing::Test { session_->http_auth_handler_factory(), session_->spdy_session_pool(), session_->quic_stream_factory(), - true, - NULL)), + true)), http_proxy_socket_pool_(kMaxSockets, kMaxSocketsPerGroup, &transport_socket_pool_, @@ -190,7 +195,7 @@ class SSLClientSocketPoolTest : public testing::Test { MockClientSocketFactory socket_factory_; MockCachingHostResolver host_resolver_; - std::unique_ptr<CertVerifier> cert_verifier_; + std::unique_ptr<MockCertVerifier> cert_verifier_; std::unique_ptr<TransportSecurityState> transport_security_state_; MultiLogCTVerifier ct_verifier_; CTPolicyEnforcer ct_policy_enforcer_; @@ -225,9 +230,9 @@ TEST_F(SSLClientSocketPoolTest, TCPFail) { false); ClientSocketHandle handle; - int rv = - handle.Init("a", params, MEDIUM, ClientSocketPool::RespectLimits::ENABLED, - CompletionCallback(), pool_.get(), NetLogWithSource()); + int rv = handle.Init(kGroupName, params, MEDIUM, SocketTag(), + ClientSocketPool::RespectLimits::ENABLED, + CompletionCallback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_CONNECTION_FAILED)); EXPECT_FALSE(handle.is_initialized()); EXPECT_FALSE(handle.socket()); @@ -248,9 +253,9 @@ TEST_F(SSLClientSocketPoolTest, TCPFailAsync) { ClientSocketHandle handle; TestCompletionCallback callback; - int rv = - handle.Init("a", params, MEDIUM, ClientSocketPool::RespectLimits::ENABLED, - callback.callback(), pool_.get(), NetLogWithSource()); + int rv = handle.Init(kGroupName, params, MEDIUM, SocketTag(), + ClientSocketPool::RespectLimits::ENABLED, + callback.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); EXPECT_FALSE(handle.is_initialized()); EXPECT_FALSE(handle.socket()); @@ -277,9 +282,9 @@ TEST_F(SSLClientSocketPoolTest, BasicDirect) { ClientSocketHandle handle; TestCompletionCallback callback; - int rv = - handle.Init("a", params, MEDIUM, ClientSocketPool::RespectLimits::ENABLED, - callback.callback(), pool_.get(), NetLogWithSource()); + int rv = handle.Init(kGroupName, params, MEDIUM, SocketTag(), + ClientSocketPool::RespectLimits::ENABLED, + callback.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsOk()); EXPECT_TRUE(handle.is_initialized()); EXPECT_TRUE(handle.socket()); @@ -305,7 +310,7 @@ TEST_F(SSLClientSocketPoolTest, SetSocketRequestPriorityOnInitDirect) { ClientSocketHandle handle; TestCompletionCallback callback; EXPECT_EQ( - OK, handle.Init("a", params, priority, + OK, handle.Init(kGroupName, params, priority, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), NetLogWithSource())); EXPECT_EQ(priority, transport_socket_pool_.last_request_priority()); @@ -325,9 +330,9 @@ TEST_F(SSLClientSocketPoolTest, BasicDirectAsync) { ClientSocketHandle handle; TestCompletionCallback callback; - int rv = - handle.Init("a", params, MEDIUM, ClientSocketPool::RespectLimits::ENABLED, - callback.callback(), pool_.get(), NetLogWithSource()); + int rv = handle.Init(kGroupName, params, MEDIUM, SocketTag(), + ClientSocketPool::RespectLimits::ENABLED, + callback.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); EXPECT_FALSE(handle.is_initialized()); EXPECT_FALSE(handle.socket()); @@ -350,9 +355,9 @@ TEST_F(SSLClientSocketPoolTest, DirectCertError) { ClientSocketHandle handle; TestCompletionCallback callback; - int rv = - handle.Init("a", params, MEDIUM, ClientSocketPool::RespectLimits::ENABLED, - callback.callback(), pool_.get(), NetLogWithSource()); + int rv = handle.Init(kGroupName, params, MEDIUM, SocketTag(), + ClientSocketPool::RespectLimits::ENABLED, + callback.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); EXPECT_FALSE(handle.is_initialized()); EXPECT_FALSE(handle.socket()); @@ -375,9 +380,9 @@ TEST_F(SSLClientSocketPoolTest, DirectSSLError) { ClientSocketHandle handle; TestCompletionCallback callback; - int rv = - handle.Init("a", params, MEDIUM, ClientSocketPool::RespectLimits::ENABLED, - callback.callback(), pool_.get(), NetLogWithSource()); + int rv = handle.Init(kGroupName, params, MEDIUM, SocketTag(), + ClientSocketPool::RespectLimits::ENABLED, + callback.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); EXPECT_FALSE(handle.is_initialized()); EXPECT_FALSE(handle.socket()); @@ -401,9 +406,9 @@ TEST_F(SSLClientSocketPoolTest, DirectWithNPN) { ClientSocketHandle handle; TestCompletionCallback callback; - int rv = - handle.Init("a", params, MEDIUM, ClientSocketPool::RespectLimits::ENABLED, - callback.callback(), pool_.get(), NetLogWithSource()); + int rv = handle.Init(kGroupName, params, MEDIUM, SocketTag(), + ClientSocketPool::RespectLimits::ENABLED, + callback.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); EXPECT_FALSE(handle.is_initialized()); EXPECT_FALSE(handle.socket()); @@ -429,9 +434,9 @@ TEST_F(SSLClientSocketPoolTest, DirectNoSPDY) { ClientSocketHandle handle; TestCompletionCallback callback; - int rv = - handle.Init("a", params, MEDIUM, ClientSocketPool::RespectLimits::ENABLED, - callback.callback(), pool_.get(), NetLogWithSource()); + int rv = handle.Init(kGroupName, params, MEDIUM, SocketTag(), + ClientSocketPool::RespectLimits::ENABLED, + callback.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); EXPECT_FALSE(handle.is_initialized()); EXPECT_FALSE(handle.socket()); @@ -455,9 +460,9 @@ TEST_F(SSLClientSocketPoolTest, DirectGotSPDY) { ClientSocketHandle handle; TestCompletionCallback callback; - int rv = - handle.Init("a", params, MEDIUM, ClientSocketPool::RespectLimits::ENABLED, - callback.callback(), pool_.get(), NetLogWithSource()); + int rv = handle.Init(kGroupName, params, MEDIUM, SocketTag(), + ClientSocketPool::RespectLimits::ENABLED, + callback.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); EXPECT_FALSE(handle.is_initialized()); EXPECT_FALSE(handle.socket()); @@ -485,9 +490,9 @@ TEST_F(SSLClientSocketPoolTest, DirectGotBonusSPDY) { ClientSocketHandle handle; TestCompletionCallback callback; - int rv = - handle.Init("a", params, MEDIUM, ClientSocketPool::RespectLimits::ENABLED, - callback.callback(), pool_.get(), NetLogWithSource()); + int rv = handle.Init(kGroupName, params, MEDIUM, SocketTag(), + ClientSocketPool::RespectLimits::ENABLED, + callback.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); EXPECT_FALSE(handle.is_initialized()); EXPECT_FALSE(handle.socket()); @@ -513,9 +518,9 @@ TEST_F(SSLClientSocketPoolTest, SOCKSFail) { ClientSocketHandle handle; TestCompletionCallback callback; - int rv = - handle.Init("a", params, MEDIUM, ClientSocketPool::RespectLimits::ENABLED, - callback.callback(), pool_.get(), NetLogWithSource()); + int rv = handle.Init(kGroupName, params, MEDIUM, SocketTag(), + ClientSocketPool::RespectLimits::ENABLED, + callback.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_CONNECTION_FAILED)); EXPECT_FALSE(handle.is_initialized()); EXPECT_FALSE(handle.socket()); @@ -533,9 +538,9 @@ TEST_F(SSLClientSocketPoolTest, SOCKSFailAsync) { ClientSocketHandle handle; TestCompletionCallback callback; - int rv = - handle.Init("a", params, MEDIUM, ClientSocketPool::RespectLimits::ENABLED, - callback.callback(), pool_.get(), NetLogWithSource()); + int rv = handle.Init(kGroupName, params, MEDIUM, SocketTag(), + ClientSocketPool::RespectLimits::ENABLED, + callback.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); EXPECT_FALSE(handle.is_initialized()); EXPECT_FALSE(handle.socket()); @@ -559,9 +564,9 @@ TEST_F(SSLClientSocketPoolTest, SOCKSBasic) { ClientSocketHandle handle; TestCompletionCallback callback; - int rv = - handle.Init("a", params, MEDIUM, ClientSocketPool::RespectLimits::ENABLED, - callback.callback(), pool_.get(), NetLogWithSource()); + int rv = handle.Init(kGroupName, params, MEDIUM, SocketTag(), + ClientSocketPool::RespectLimits::ENABLED, + callback.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsOk()); EXPECT_TRUE(handle.is_initialized()); EXPECT_TRUE(handle.socket()); @@ -586,7 +591,7 @@ TEST_F(SSLClientSocketPoolTest, SetTransportPriorityOnInitSOCKS) { ClientSocketHandle handle; TestCompletionCallback callback; EXPECT_EQ(OK, - handle.Init("a", params, HIGHEST, + handle.Init(kGroupName, params, HIGHEST, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), NetLogWithSource())); EXPECT_EQ(HIGHEST, transport_socket_pool_.last_request_priority()); @@ -604,9 +609,9 @@ TEST_F(SSLClientSocketPoolTest, SOCKSBasicAsync) { ClientSocketHandle handle; TestCompletionCallback callback; - int rv = - handle.Init("a", params, MEDIUM, ClientSocketPool::RespectLimits::ENABLED, - callback.callback(), pool_.get(), NetLogWithSource()); + int rv = handle.Init(kGroupName, params, MEDIUM, SocketTag(), + ClientSocketPool::RespectLimits::ENABLED, + callback.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); EXPECT_FALSE(handle.is_initialized()); EXPECT_FALSE(handle.socket()); @@ -630,9 +635,9 @@ TEST_F(SSLClientSocketPoolTest, HttpProxyFail) { ClientSocketHandle handle; TestCompletionCallback callback; - int rv = - handle.Init("a", params, MEDIUM, ClientSocketPool::RespectLimits::ENABLED, - callback.callback(), pool_.get(), NetLogWithSource()); + int rv = handle.Init(kGroupName, params, MEDIUM, SocketTag(), + ClientSocketPool::RespectLimits::ENABLED, + callback.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_PROXY_CONNECTION_FAILED)); EXPECT_FALSE(handle.is_initialized()); EXPECT_FALSE(handle.socket()); @@ -650,9 +655,9 @@ TEST_F(SSLClientSocketPoolTest, HttpProxyFailAsync) { ClientSocketHandle handle; TestCompletionCallback callback; - int rv = - handle.Init("a", params, MEDIUM, ClientSocketPool::RespectLimits::ENABLED, - callback.callback(), pool_.get(), NetLogWithSource()); + int rv = handle.Init(kGroupName, params, MEDIUM, SocketTag(), + ClientSocketPool::RespectLimits::ENABLED, + callback.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); EXPECT_FALSE(handle.is_initialized()); EXPECT_FALSE(handle.socket()); @@ -688,9 +693,9 @@ TEST_F(SSLClientSocketPoolTest, HttpProxyBasic) { ClientSocketHandle handle; TestCompletionCallback callback; - int rv = - handle.Init("a", params, MEDIUM, ClientSocketPool::RespectLimits::ENABLED, - callback.callback(), pool_.get(), NetLogWithSource()); + int rv = handle.Init(kGroupName, params, MEDIUM, SocketTag(), + ClientSocketPool::RespectLimits::ENABLED, + callback.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsOk()); EXPECT_TRUE(handle.is_initialized()); EXPECT_TRUE(handle.socket()); @@ -725,7 +730,7 @@ TEST_F(SSLClientSocketPoolTest, SetTransportPriorityOnInitHTTP) { ClientSocketHandle handle; TestCompletionCallback callback; EXPECT_EQ(OK, - handle.Init("a", params, HIGHEST, + handle.Init(kGroupName, params, HIGHEST, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), pool_.get(), NetLogWithSource())); EXPECT_EQ(HIGHEST, transport_socket_pool_.last_request_priority()); @@ -755,9 +760,9 @@ TEST_F(SSLClientSocketPoolTest, HttpProxyBasicAsync) { ClientSocketHandle handle; TestCompletionCallback callback; - int rv = - handle.Init("a", params, MEDIUM, ClientSocketPool::RespectLimits::ENABLED, - callback.callback(), pool_.get(), NetLogWithSource()); + int rv = handle.Init(kGroupName, params, MEDIUM, SocketTag(), + ClientSocketPool::RespectLimits::ENABLED, + callback.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); EXPECT_FALSE(handle.is_initialized()); EXPECT_FALSE(handle.socket()); @@ -793,9 +798,9 @@ TEST_F(SSLClientSocketPoolTest, NeedProxyAuth) { ClientSocketHandle handle; TestCompletionCallback callback; - int rv = - handle.Init("a", params, MEDIUM, ClientSocketPool::RespectLimits::ENABLED, - callback.callback(), pool_.get(), NetLogWithSource()); + int rv = handle.Init(kGroupName, params, MEDIUM, SocketTag(), + ClientSocketPool::RespectLimits::ENABLED, + callback.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); EXPECT_FALSE(handle.is_initialized()); EXPECT_FALSE(handle.socket()); @@ -944,6 +949,217 @@ TEST_F(SSLClientSocketPoolTest, IPPoolingChannelID) { // It would be nice to also test the timeouts in SSLClientSocketPool. +// Test that SocketTag passed into SSLClientSocketPool is applied to returned +// sockets. +#if defined(OS_ANDROID) +TEST_F(SSLClientSocketPoolTest, Tag) { + // Start test server. + EmbeddedTestServer test_server(net::EmbeddedTestServer::TYPE_HTTPS); + test_server.SetSSLConfig(net::EmbeddedTestServer::CERT_OK, SSLServerConfig()); + test_server.AddDefaultHandlers(base::FilePath()); + ASSERT_TRUE(test_server.Start()); + + TransportClientSocketPool tcp_pool( + kMaxSockets, kMaxSocketsPerGroup, &host_resolver_, + ClientSocketFactory::GetDefaultFactory(), NULL, NULL); + cert_verifier_->set_default_result(OK); + SSLClientSocketPool pool(kMaxSockets, kMaxSocketsPerGroup, + cert_verifier_.get(), NULL /* channel_id_service */, + transport_security_state_.get(), &ct_verifier_, + &ct_policy_enforcer_, + std::string() /* ssl_session_cache_shard */, + ClientSocketFactory::GetDefaultFactory(), &tcp_pool, + NULL, NULL, NULL, NULL); + TestCompletionCallback callback; + ClientSocketHandle handle; + int32_t tag_val1 = 0x12345678; + SocketTag tag1(SocketTag::UNSET_UID, tag_val1); + int32_t tag_val2 = 0x87654321; + SocketTag tag2(getuid(), tag_val2); + scoped_refptr<TransportSocketParams> tcp_params(new TransportSocketParams( + test_server.host_port_pair(), false, OnHostResolutionCallback(), + TransportSocketParams::COMBINE_CONNECT_AND_WRITE_DEFAULT)); + scoped_refptr<SSLSocketParams> params( + new SSLSocketParams(tcp_params, NULL, NULL, test_server.host_port_pair(), + ssl_config_, PRIVACY_MODE_DISABLED, 0, false)); + + // Test socket is tagged before connected. + uint64_t old_traffic = GetTaggedBytes(tag_val1); + int rv = handle.Init(kGroupName, params, LOW, tag1, + ClientSocketPool::RespectLimits::ENABLED, + callback.callback(), &pool, NetLogWithSource()); + EXPECT_THAT(callback.GetResult(rv), IsOk()); + EXPECT_TRUE(handle.socket()); + EXPECT_TRUE(handle.socket()->IsConnected()); + EXPECT_GT(GetTaggedBytes(tag_val1), old_traffic); + + // Test reused socket is retagged. + StreamSocket* socket = handle.socket(); + handle.Reset(); + old_traffic = GetTaggedBytes(tag_val2); + TestCompletionCallback callback2; + rv = handle.Init(kGroupName, params, LOW, tag2, + ClientSocketPool::RespectLimits::ENABLED, + callback2.callback(), &pool, NetLogWithSource()); + EXPECT_THAT(rv, IsOk()); + EXPECT_TRUE(handle.socket()); + EXPECT_TRUE(handle.socket()->IsConnected()); + EXPECT_EQ(handle.socket(), socket); + const char kRequest[] = "GET / HTTP/1.1\r\n\r\n"; + scoped_refptr<IOBuffer> write_buffer(new StringIOBuffer(kRequest)); + rv = + handle.socket()->Write(write_buffer.get(), strlen(kRequest), + callback.callback(), TRAFFIC_ANNOTATION_FOR_TESTS); + EXPECT_EQ(static_cast<int>(strlen(kRequest)), callback.GetResult(rv)); + scoped_refptr<IOBufferWithSize> read_buffer(new IOBufferWithSize(1)); + rv = handle.socket()->Read(read_buffer.get(), read_buffer->size(), + callback.callback()); + EXPECT_EQ(read_buffer->size(), callback.GetResult(rv)); + EXPECT_GT(GetTaggedBytes(tag_val2), old_traffic); + // Disconnect socket to prevent reuse. + handle.socket()->Disconnect(); + handle.Reset(); +} + +TEST_F(SSLClientSocketPoolTest, TagTwoSockets) { + // Start test server. + EmbeddedTestServer test_server(net::EmbeddedTestServer::TYPE_HTTPS); + test_server.SetSSLConfig(net::EmbeddedTestServer::CERT_OK, SSLServerConfig()); + test_server.AddDefaultHandlers(base::FilePath()); + ASSERT_TRUE(test_server.Start()); + + TransportClientSocketPool tcp_pool( + kMaxSockets, kMaxSocketsPerGroup, &host_resolver_, + ClientSocketFactory::GetDefaultFactory(), NULL, NULL); + cert_verifier_->set_default_result(OK); + SSLClientSocketPool pool(kMaxSockets, kMaxSocketsPerGroup, + cert_verifier_.get(), NULL /* channel_id_service */, + transport_security_state_.get(), &ct_verifier_, + &ct_policy_enforcer_, + std::string() /* ssl_session_cache_shard */, + ClientSocketFactory::GetDefaultFactory(), &tcp_pool, + NULL, NULL, NULL, NULL); + ClientSocketHandle handle; + int32_t tag_val1 = 0x12345678; + SocketTag tag1(SocketTag::UNSET_UID, tag_val1); + int32_t tag_val2 = 0x87654321; + SocketTag tag2(getuid(), tag_val2); + scoped_refptr<TransportSocketParams> tcp_params(new TransportSocketParams( + test_server.host_port_pair(), false, OnHostResolutionCallback(), + TransportSocketParams::COMBINE_CONNECT_AND_WRITE_DEFAULT)); + scoped_refptr<SSLSocketParams> params( + new SSLSocketParams(tcp_params, NULL, NULL, test_server.host_port_pair(), + ssl_config_, PRIVACY_MODE_DISABLED, 0, false)); + + // Test connect jobs that are orphaned and then adopted, appropriately apply + // new tag. Request socket with |tag1|. + TestCompletionCallback callback; + int rv = handle.Init(kGroupName, params, LOW, tag1, + ClientSocketPool::RespectLimits::ENABLED, + callback.callback(), &pool, NetLogWithSource()); + EXPECT_TRUE(rv == OK || rv == ERR_IO_PENDING) << "Result: " << rv; + // Abort and request socket with |tag2|. + handle.Reset(); + TestCompletionCallback callback2; + rv = handle.Init(kGroupName, params, LOW, tag2, + ClientSocketPool::RespectLimits::ENABLED, + callback2.callback(), &pool, NetLogWithSource()); + EXPECT_THAT(callback2.GetResult(rv), IsOk()); + EXPECT_TRUE(handle.socket()); + EXPECT_TRUE(handle.socket()->IsConnected()); + // Verify socket has |tag2| applied. + uint64_t old_traffic = GetTaggedBytes(tag_val2); + const char kRequest[] = "GET / HTTP/1.1\r\n\r\n"; + scoped_refptr<IOBuffer> write_buffer(new StringIOBuffer(kRequest)); + rv = handle.socket()->Write(write_buffer.get(), strlen(kRequest), + callback2.callback(), + TRAFFIC_ANNOTATION_FOR_TESTS); + EXPECT_EQ(static_cast<int>(strlen(kRequest)), callback2.GetResult(rv)); + scoped_refptr<IOBufferWithSize> read_buffer(new IOBufferWithSize(1)); + rv = handle.socket()->Read(read_buffer.get(), read_buffer->size(), + callback2.callback()); + EXPECT_EQ(read_buffer->size(), callback2.GetResult(rv)); + EXPECT_GT(GetTaggedBytes(tag_val2), old_traffic); +} + +TEST_F(SSLClientSocketPoolTest, TagTwoSocketsFullPool) { + // Start test server. + EmbeddedTestServer test_server(net::EmbeddedTestServer::TYPE_HTTPS); + test_server.SetSSLConfig(net::EmbeddedTestServer::CERT_OK, SSLServerConfig()); + test_server.AddDefaultHandlers(base::FilePath()); + ASSERT_TRUE(test_server.Start()); + + TransportClientSocketPool tcp_pool( + kMaxSockets, kMaxSocketsPerGroup, &host_resolver_, + ClientSocketFactory::GetDefaultFactory(), NULL, NULL); + cert_verifier_->set_default_result(OK); + SSLClientSocketPool pool(kMaxSockets, kMaxSocketsPerGroup, + cert_verifier_.get(), NULL /* channel_id_service */, + transport_security_state_.get(), &ct_verifier_, + &ct_policy_enforcer_, + std::string() /* ssl_session_cache_shard */, + ClientSocketFactory::GetDefaultFactory(), &tcp_pool, + NULL, NULL, NULL, NULL); + TestCompletionCallback callback; + ClientSocketHandle handle; + int32_t tag_val1 = 0x12345678; + SocketTag tag1(SocketTag::UNSET_UID, tag_val1); + int32_t tag_val2 = 0x87654321; + SocketTag tag2(getuid(), tag_val2); + scoped_refptr<TransportSocketParams> tcp_params(new TransportSocketParams( + test_server.host_port_pair(), false, OnHostResolutionCallback(), + TransportSocketParams::COMBINE_CONNECT_AND_WRITE_DEFAULT)); + scoped_refptr<SSLSocketParams> params( + new SSLSocketParams(tcp_params, NULL, NULL, test_server.host_port_pair(), + ssl_config_, PRIVACY_MODE_DISABLED, 0, false)); + + // Test that sockets paused by a full underlying socket pool are properly + // connected and tagged when underlying pool is freed up. + // Fill up all slots in TCP pool. + ClientSocketHandle tcp_handles[kMaxSocketsPerGroup]; + int rv; + for (auto& tcp_handle : tcp_handles) { + rv = tcp_handle.Init(kGroupName, tcp_params, LOW, tag1, + ClientSocketPool::RespectLimits::ENABLED, + callback.callback(), &tcp_pool, NetLogWithSource()); + EXPECT_THAT(callback.GetResult(rv), IsOk()); + EXPECT_TRUE(tcp_handle.socket()); + EXPECT_TRUE(tcp_handle.socket()->IsConnected()); + } + // Request two SSL sockets. + ClientSocketHandle handle_to_be_canceled; + rv = handle_to_be_canceled.Init( + kGroupName, params, LOW, tag1, ClientSocketPool::RespectLimits::ENABLED, + callback.callback(), &pool, NetLogWithSource()); + EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); + rv = handle.Init(kGroupName, params, LOW, tag2, + ClientSocketPool::RespectLimits::ENABLED, + callback.callback(), &pool, NetLogWithSource()); + EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); + // Cancel first request. + handle_to_be_canceled.Reset(); + // Disconnect a TCP socket to free up a slot. + tcp_handles[0].socket()->Disconnect(); + tcp_handles[0].Reset(); + // Verify |handle| gets a valid tagged socket. + EXPECT_THAT(callback.WaitForResult(), IsOk()); + EXPECT_TRUE(handle.socket()); + EXPECT_TRUE(handle.socket()->IsConnected()); + uint64_t old_traffic = GetTaggedBytes(tag_val2); + const char kRequest[] = "GET / HTTP/1.1\r\n\r\n"; + scoped_refptr<IOBuffer> write_buffer(new StringIOBuffer(kRequest)); + rv = + handle.socket()->Write(write_buffer.get(), strlen(kRequest), + callback.callback(), TRAFFIC_ANNOTATION_FOR_TESTS); + EXPECT_EQ(static_cast<int>(strlen(kRequest)), callback.GetResult(rv)); + scoped_refptr<IOBufferWithSize> read_buffer(new IOBufferWithSize(1)); + EXPECT_EQ(handle.socket()->Read(read_buffer.get(), read_buffer->size(), + callback.callback()), + ERR_IO_PENDING); + EXPECT_THAT(callback.WaitForResult(), read_buffer->size()); + EXPECT_GT(GetTaggedBytes(tag_val2), old_traffic); +} +#endif } // namespace } // namespace net diff --git a/chromium/net/socket/ssl_client_socket_unittest.cc b/chromium/net/socket/ssl_client_socket_unittest.cc index d0527eea2b3..19576f43903 100644 --- a/chromium/net/socket/ssl_client_socket_unittest.cc +++ b/chromium/net/socket/ssl_client_socket_unittest.cc @@ -22,6 +22,7 @@ #include "base/threading/thread_task_runner_handle.h" #include "base/time/time.h" #include "base/values.h" +#include "build/build_config.h" #include "crypto/rsa_private_key.h" #include "net/base/address_list.h" #include "net/base/io_buffer.h" @@ -37,6 +38,7 @@ #include "net/cert/mock_cert_verifier.h" #include "net/cert/signed_certificate_timestamp_and_status.h" #include "net/cert/test_root_certs.h" +#include "net/cert/x509_util.h" #include "net/der/input.h" #include "net/der/parser.h" #include "net/der/tag.h" @@ -66,6 +68,7 @@ #include "net/test/gtest_util.h" #include "net/test/spawned_test_server/spawned_test_server.h" #include "net/test/test_data_directory.h" +#include "net/traffic_annotation/network_traffic_annotation.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/platform_test.h" @@ -87,90 +90,6 @@ class NetLogWithSource; namespace { -// WrappedStreamSocket is a base class that wraps an existing StreamSocket, -// forwarding the Socket and StreamSocket interfaces to the underlying -// transport. -// This is to provide a common base class for subclasses to override specific -// StreamSocket methods for testing, while still communicating with a 'real' -// StreamSocket. -class WrappedStreamSocket : public StreamSocket { - public: - explicit WrappedStreamSocket(std::unique_ptr<StreamSocket> transport) - : transport_(std::move(transport)) {} - ~WrappedStreamSocket() override = default; - - // StreamSocket implementation: - int Connect(const CompletionCallback& callback) override { - return transport_->Connect(callback); - } - void Disconnect() override { transport_->Disconnect(); } - bool IsConnected() const override { return transport_->IsConnected(); } - bool IsConnectedAndIdle() const override { - return transport_->IsConnectedAndIdle(); - } - int GetPeerAddress(IPEndPoint* address) const override { - return transport_->GetPeerAddress(address); - } - int GetLocalAddress(IPEndPoint* address) const override { - return transport_->GetLocalAddress(address); - } - const NetLogWithSource& NetLog() const override { - return transport_->NetLog(); - } - void SetSubresourceSpeculation() override { - transport_->SetSubresourceSpeculation(); - } - void SetOmniboxSpeculation() override { transport_->SetOmniboxSpeculation(); } - bool WasEverUsed() const override { return transport_->WasEverUsed(); } - bool WasAlpnNegotiated() const override { - return transport_->WasAlpnNegotiated(); - } - NextProto GetNegotiatedProtocol() const override { - return transport_->GetNegotiatedProtocol(); - } - bool GetSSLInfo(SSLInfo* ssl_info) override { - return transport_->GetSSLInfo(ssl_info); - } - void GetConnectionAttempts(ConnectionAttempts* out) const override { - transport_->GetConnectionAttempts(out); - } - void ClearConnectionAttempts() override { - transport_->ClearConnectionAttempts(); - } - void AddConnectionAttempts(const ConnectionAttempts& attempts) override { - transport_->AddConnectionAttempts(attempts); - } - int64_t GetTotalReceivedBytes() const override { - return transport_->GetTotalReceivedBytes(); - } - - // Socket implementation: - int Read(IOBuffer* buf, - int buf_len, - const CompletionCallback& callback) override { - return transport_->Read(buf, buf_len, callback); - } - int ReadIfReady(IOBuffer* buf, - int buf_len, - const CompletionCallback& callback) override { - return transport_->ReadIfReady(buf, buf_len, callback); - } - int Write(IOBuffer* buf, - int buf_len, - const CompletionCallback& callback) override { - return transport_->Write(buf, buf_len, callback); - } - int SetReceiveBufferSize(int32_t size) override { - return transport_->SetReceiveBufferSize(size); - } - int SetSendBufferSize(int32_t size) override { - return transport_->SetSendBufferSize(size); - } - - protected: - std::unique_ptr<StreamSocket> transport_; -}; - // ReadBufferingStreamSocket is a wrapper for an existing StreamSocket that // will ensure a certain amount of data is internally buffered before // satisfying a Read() request. It exists to mimic OS-level internal @@ -349,7 +268,8 @@ class SynchronousErrorStreamSocket : public WrappedStreamSocket { const CompletionCallback& callback) override; int Write(IOBuffer* buf, int buf_len, - const CompletionCallback& callback) override; + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& traffic_annotation) override; // Sets the next Read() call and all future calls to return |error|. // If there is already a pending asynchronous read, the configured error @@ -398,9 +318,11 @@ int SynchronousErrorStreamSocket::ReadIfReady( return transport_->ReadIfReady(buf, buf_len, callback); } -int SynchronousErrorStreamSocket::Write(IOBuffer* buf, - int buf_len, - const CompletionCallback& callback) { +int SynchronousErrorStreamSocket::Write( + IOBuffer* buf, + int buf_len, + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& traffic_annotation) { if (have_write_error_) return pending_write_error_; return transport_->Write(buf, buf_len, callback); @@ -425,7 +347,8 @@ class FakeBlockingStreamSocket : public WrappedStreamSocket { const CompletionCallback& callback) override; int Write(IOBuffer* buf, int buf_len, - const CompletionCallback& callback) override; + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& traffic_annotation) override; int pending_read_result() const { return pending_read_result_; } IOBuffer* pending_read_buf() const { return pending_read_buf_.get(); } @@ -559,9 +482,11 @@ int FakeBlockingStreamSocket::ReadIfReady(IOBuffer* buf, return rv; } -int FakeBlockingStreamSocket::Write(IOBuffer* buf, - int len, - const CompletionCallback& callback) { +int FakeBlockingStreamSocket::Write( + IOBuffer* buf, + int len, + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& traffic_annotation) { DCHECK(buf); DCHECK_LE(0, len); @@ -713,7 +638,8 @@ class CountingStreamSocket : public WrappedStreamSocket { } int Write(IOBuffer* buf, int buf_len, - const CompletionCallback& callback) override { + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& traffic_annotation) override { write_count_++; return transport_->Write(buf, buf_len, callback); } @@ -855,13 +781,15 @@ class MockExpectCTReporter : public TransportSecurityState::ExpectCTReporter { // anything. class MockCTVerifier : public CTVerifier { public: - MOCK_METHOD5(Verify, - void(X509Certificate*, + MOCK_METHOD6(Verify, + void(base::StringPiece, + X509Certificate*, base::StringPiece, base::StringPiece, SignedCertificateTimestampAndStatusList*, const NetLogWithSource&)); MOCK_METHOD1(SetObserver, void(CTVerifier::Observer*)); + MOCK_CONST_METHOD0(GetObserver, CTVerifier::Observer*()); }; // A mock CTPolicyEnforcer that returns a custom verification result. @@ -2325,24 +2253,23 @@ TEST_F(SSLClientSocketTest, VerifyServerChainProperlyOrdered) { scoped_refptr<X509Certificate> server_certificate = ssl_info.unverified_cert; // Get the intermediates as received client side. - const X509Certificate::OSCertHandles& server_intermediates = - server_certificate->GetIntermediateCertificates(); + const auto& server_intermediates = server_certificate->intermediate_buffers(); // Check that the unverified server certificate chain is properly retrieved // from the underlying ssl stack. ASSERT_EQ(4U, server_certs.size()); - EXPECT_TRUE(X509Certificate::IsSameOSCert( - server_certificate->os_cert_handle(), server_certs[0]->os_cert_handle())); + EXPECT_TRUE(x509_util::CryptoBufferEqual(server_certificate->cert_buffer(), + server_certs[0]->cert_buffer())); ASSERT_EQ(3U, server_intermediates.size()); - EXPECT_TRUE(X509Certificate::IsSameOSCert(server_intermediates[0], - server_certs[1]->os_cert_handle())); - EXPECT_TRUE(X509Certificate::IsSameOSCert(server_intermediates[1], - server_certs[2]->os_cert_handle())); - EXPECT_TRUE(X509Certificate::IsSameOSCert(server_intermediates[2], - server_certs[3]->os_cert_handle())); + EXPECT_TRUE(x509_util::CryptoBufferEqual(server_intermediates[0].get(), + server_certs[1]->cert_buffer())); + EXPECT_TRUE(x509_util::CryptoBufferEqual(server_intermediates[1].get(), + server_certs[2]->cert_buffer())); + EXPECT_TRUE(x509_util::CryptoBufferEqual(server_intermediates[2].get(), + server_certs[3]->cert_buffer())); sock_->Disconnect(); EXPECT_FALSE(sock_->IsConnected()); @@ -2379,13 +2306,16 @@ TEST_F(SSLClientSocketTest, VerifyReturnChainProperlyOrdered) { ASSERT_TRUE(certs[0]->Equals(unverified_certs[0].get())); - X509Certificate::OSCertHandles temp_intermediates; - temp_intermediates.push_back(certs[1]->os_cert_handle()); - temp_intermediates.push_back(certs[2]->os_cert_handle()); + std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> temp_intermediates; + temp_intermediates.push_back( + x509_util::DupCryptoBuffer(certs[1]->cert_buffer())); + temp_intermediates.push_back( + x509_util::DupCryptoBuffer(certs[2]->cert_buffer())); CertVerifyResult verify_result; - verify_result.verified_cert = X509Certificate::CreateFromHandle( - certs[0]->os_cert_handle(), temp_intermediates); + verify_result.verified_cert = X509Certificate::CreateFromBuffer( + x509_util::DupCryptoBuffer(certs[0]->cert_buffer()), + std::move(temp_intermediates)); ASSERT_TRUE(verify_result.verified_cert); // Add a rule that maps the server cert (A) to the chain of A->B->C2 @@ -2418,29 +2348,28 @@ TEST_F(SSLClientSocketTest, VerifyReturnChainProperlyOrdered) { // Verify that SSLInfo contains the corrected re-constructed chain A -> B // -> C2. ASSERT_TRUE(ssl_info.cert); - const X509Certificate::OSCertHandles& intermediates = - ssl_info.cert->GetIntermediateCertificates(); + const auto& intermediates = ssl_info.cert->intermediate_buffers(); ASSERT_EQ(2U, intermediates.size()); - EXPECT_TRUE(X509Certificate::IsSameOSCert(ssl_info.cert->os_cert_handle(), - certs[0]->os_cert_handle())); - EXPECT_TRUE(X509Certificate::IsSameOSCert(intermediates[0], - certs[1]->os_cert_handle())); - EXPECT_TRUE(X509Certificate::IsSameOSCert(intermediates[1], - certs[2]->os_cert_handle())); + EXPECT_TRUE(x509_util::CryptoBufferEqual(ssl_info.cert->cert_buffer(), + certs[0]->cert_buffer())); + EXPECT_TRUE(x509_util::CryptoBufferEqual(intermediates[0].get(), + certs[1]->cert_buffer())); + EXPECT_TRUE(x509_util::CryptoBufferEqual(intermediates[1].get(), + certs[2]->cert_buffer())); // Verify that SSLInfo also contains the chain as received from the server. ASSERT_TRUE(ssl_info.unverified_cert); - const X509Certificate::OSCertHandles& served_intermediates = - ssl_info.unverified_cert->GetIntermediateCertificates(); + const auto& served_intermediates = + ssl_info.unverified_cert->intermediate_buffers(); ASSERT_EQ(3U, served_intermediates.size()); - EXPECT_TRUE(X509Certificate::IsSameOSCert( - ssl_info.cert->os_cert_handle(), unverified_certs[0]->os_cert_handle())); - EXPECT_TRUE(X509Certificate::IsSameOSCert( - served_intermediates[0], unverified_certs[1]->os_cert_handle())); - EXPECT_TRUE(X509Certificate::IsSameOSCert( - served_intermediates[1], unverified_certs[2]->os_cert_handle())); - EXPECT_TRUE(X509Certificate::IsSameOSCert( - served_intermediates[2], unverified_certs[3]->os_cert_handle())); + EXPECT_TRUE(x509_util::CryptoBufferEqual(ssl_info.cert->cert_buffer(), + unverified_certs[0]->cert_buffer())); + EXPECT_TRUE(x509_util::CryptoBufferEqual(served_intermediates[0].get(), + unverified_certs[1]->cert_buffer())); + EXPECT_TRUE(x509_util::CryptoBufferEqual(served_intermediates[1].get(), + unverified_certs[2]->cert_buffer())); + EXPECT_TRUE(x509_util::CryptoBufferEqual(served_intermediates[2].get(), + unverified_certs[3]->cert_buffer())); sock_->Disconnect(); EXPECT_FALSE(sock_->IsConnected()); @@ -2526,8 +2455,8 @@ TEST_F(SSLClientSocketTest, ConnectSignedCertTimestampsEnabledTLSExtension) { // Check that the SCT list is extracted from the TLS extension as expected, // while also simulating that it was an unparsable response. SignedCertificateTimestampAndStatusList sct_list; - EXPECT_CALL(ct_verifier, Verify(_, _, sct_ext, _, _)) - .WillOnce(testing::SetArgPointee<3>(sct_list)); + EXPECT_CALL(ct_verifier, Verify(_, _, _, sct_ext, _, _)) + .WillOnce(testing::SetArgPointee<4>(sct_list)); int rv; ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv)); @@ -2743,6 +2672,40 @@ TEST_F(SSLClientSocketTest, ReuseStates) { // buffer. Call SSL_pending. } +// Tests that |is_fatal_cert_error| does not get set for a certificate error, +// on a non-HSTS host. +TEST_F(SSLClientSocketTest, IsFatalErrorNotSetOnNonFatalError) { + cert_verifier_->set_default_result(ERR_CERT_DATE_INVALID); + SpawnedTestServer::SSLOptions ssl_options( + SpawnedTestServer::SSLOptions::CERT_CHAIN_WRONG_ROOT); + ASSERT_TRUE(StartTestServer(ssl_options)); + SSLConfig ssl_config; + int rv; + ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv)); + SSLInfo ssl_info; + ASSERT_TRUE(sock_->GetSSLInfo(&ssl_info)); + EXPECT_FALSE(ssl_info.is_fatal_cert_error); +} + +// Tests that |is_fatal_cert_error| gets set for a certificate error on an +// HSTS host. +TEST_F(SSLClientSocketTest, IsFatalErrorSetOnFatalError) { + cert_verifier_->set_default_result(ERR_CERT_DATE_INVALID); + SpawnedTestServer::SSLOptions ssl_options( + SpawnedTestServer::SSLOptions::CERT_CHAIN_WRONG_ROOT); + ASSERT_TRUE(StartTestServer(ssl_options)); + SSLConfig ssl_config; + int rv; + const base::Time expiry = + base::Time::Now() + base::TimeDelta::FromSeconds(1000); + context_.transport_security_state->AddHSTS( + spawned_test_server()->host_port_pair().host(), expiry, true); + ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv)); + SSLInfo ssl_info; + ASSERT_TRUE(sock_->GetSSLInfo(&ssl_info)); + EXPECT_TRUE(ssl_info.is_fatal_cert_error); +} + // Tests that IsConnectedAndIdle treats a socket as idle even if a Write hasn't // been flushed completely out of SSLClientSocket's internal buffers. This is a // regression test for https://crbug.com/466147. @@ -4420,4 +4383,28 @@ TEST_F(SSLClientSocketTest, SessionCacheShard) { EXPECT_EQ(SSLInfo::HANDSHAKE_FULL, ssl_info.handshake_type); } +TEST_F(SSLClientSocketTest, Tag) { + ASSERT_TRUE(StartTestServer(SpawnedTestServer::SSLOptions())); + + TestNetLog log; + std::unique_ptr<StreamSocket> transport( + new TCPClientSocket(addr(), NULL, &log, NetLogSource())); + + MockTaggingStreamSocket* tagging_sock = + new MockTaggingStreamSocket(std::move(transport)); + + // |sock| takes ownership of |tagging_sock|, but keep a + // non-owning pointer to it. + std::unique_ptr<SSLClientSocket> sock(CreateSSLClientSocket( + std::unique_ptr<StreamSocket>(tagging_sock), + spawned_test_server()->host_port_pair(), SSLConfig())); + + EXPECT_EQ(tagging_sock->tag(), SocketTag()); +#if defined(OS_ANDROID) + SocketTag tag(0x12345678, 0x87654321); + sock->ApplySocketTag(tag); + EXPECT_EQ(tagging_sock->tag(), tag); +#endif // OS_ANDROID +} + } // namespace net diff --git a/chromium/net/socket/ssl_server_socket.h b/chromium/net/socket/ssl_server_socket.h index b61e6631761..92d2185305f 100644 --- a/chromium/net/socket/ssl_server_socket.h +++ b/chromium/net/socket/ssl_server_socket.h @@ -30,6 +30,7 @@ class RSAPrivateKey; namespace net { struct SSLServerConfig; +class SSLPrivateKey; class X509Certificate; // A server socket that uses SSL as the transport layer. @@ -70,6 +71,11 @@ NET_EXPORT std::unique_ptr<SSLServerContext> CreateSSLServerContext( const crypto::RSAPrivateKey& key, const SSLServerConfig& ssl_config); +NET_EXPORT std::unique_ptr<SSLServerContext> CreateSSLServerContext( + X509Certificate* certificate, + scoped_refptr<SSLPrivateKey> key, + const SSLServerConfig& ssl_config); + } // namespace net #endif // NET_SOCKET_SSL_SERVER_SOCKET_H_ diff --git a/chromium/net/socket/ssl_server_socket_impl.cc b/chromium/net/socket/ssl_server_socket_impl.cc index cba12a6b80a..198f1650024 100644 --- a/chromium/net/socket/ssl_server_socket_impl.cc +++ b/chromium/net/socket/ssl_server_socket_impl.cc @@ -7,7 +7,9 @@ #include <utility> #include "base/callback_helpers.h" +#include "base/lazy_instance.h" #include "base/logging.h" +#include "base/memory/weak_ptr.h" #include "base/strings/string_util.h" #include "crypto/openssl_util.h" #include "crypto/rsa_private_key.h" @@ -21,6 +23,7 @@ #include "net/ssl/openssl_ssl_util.h" #include "net/ssl/ssl_connection_status_flags.h" #include "net/ssl/ssl_info.h" +#include "net/traffic_annotation/network_traffic_annotation.h" #include "third_party/boringssl/src/include/openssl/err.h" #include "third_party/boringssl/src/include/openssl/pool.h" #include "third_party/boringssl/src/include/openssl/ssl.h" @@ -29,6 +32,34 @@ namespace net { +namespace { + +// This constant can be any non-negative/non-zero value (eg: it does not +// overlap with any value of the net::Error range, including net::OK). +const int kNoPendingResult = 1; + +class SocketDataIndex { + public: + static SocketDataIndex* GetInstance(); + SocketDataIndex() { + ssl_socket_data_index_ = SSL_get_ex_new_index(0, 0, 0, 0, 0); + } + + // This is the index used with SSL_get_ex_data to retrieve the owner + // SSLServerSocketImpl object from an SSL instance. + int ssl_socket_data_index_; +}; + +base::LazyInstance<SocketDataIndex>::Leaky g_ssl_socket_data_index_ = + LAZY_INSTANCE_INITIALIZER; + +// static +SocketDataIndex* SocketDataIndex::GetInstance() { + return g_ssl_socket_data_index_.Pointer(); +} + +} // namespace + class SSLServerContextImpl::SocketImpl : public SSLServerSocket, public SocketBIOAdapter::Delegate { public: @@ -52,7 +83,8 @@ class SSLServerContextImpl::SocketImpl : public SSLServerSocket, const CompletionCallback& callback) override; int Write(IOBuffer* buf, int buf_len, - const CompletionCallback& callback) override; + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& traffic_annotation) override; int SetReceiveBufferSize(int32_t size) override; int SetSendBufferSize(int32_t size) override; @@ -74,9 +106,41 @@ class SSLServerContextImpl::SocketImpl : public SSLServerSocket, void ClearConnectionAttempts() override {} void AddConnectionAttempts(const ConnectionAttempts& attempts) override {} int64_t GetTotalReceivedBytes() const override; + void ApplySocketTag(const SocketTag& tag) override; + static ssl_verify_result_t CertVerifyCallback(SSL* ssl, uint8_t* out_alert); ssl_verify_result_t CertVerifyCallbackImpl(uint8_t* out_alert); + static const SSL_PRIVATE_KEY_METHOD kPrivateKeyMethod; + static ssl_private_key_result_t PrivateKeySignCallback(SSL* ssl, + uint8_t* out, + size_t* out_len, + size_t max_out, + uint16_t algorithm, + const uint8_t* in, + size_t in_len); + static ssl_private_key_result_t PrivateKeyDecryptCallback(SSL* ssl, + uint8_t* out, + size_t* out_len, + size_t max_out, + const uint8_t* in, + size_t in_len); + static ssl_private_key_result_t PrivateKeyCompleteCallback(SSL* ssl, + uint8_t* out, + size_t* out_len, + size_t max_out); + + ssl_private_key_result_t PrivateKeySignCallback(uint8_t* out, + size_t* out_len, + size_t max_out, + uint16_t algorithm, + const uint8_t* in, + size_t in_len); + ssl_private_key_result_t PrivateKeyCompleteCallback(uint8_t* out, + size_t* out_len, + size_t max_out); + void OnPrivateKeyComplete(Error error, const std::vector<uint8_t>& signature); + // SocketBIOAdapter::Delegate implementation. void OnReadReady() override; void OnWriteReady() override; @@ -109,6 +173,10 @@ class SSLServerContextImpl::SocketImpl : public SSLServerSocket, CompletionCallback user_read_callback_; CompletionCallback user_write_callback_; + // SSLPrivateKey signature. + int signature_result_; + std::vector<uint8_t> signature_; + // Used by Read function. scoped_refptr<IOBuffer> user_read_buf_; int user_read_buf_len_; @@ -130,6 +198,8 @@ class SSLServerContextImpl::SocketImpl : public SSLServerSocket, State next_handshake_state_; bool completed_handshake_; + base::WeakPtrFactory<SocketImpl> weak_factory_; + DISALLOW_COPY_AND_ASSIGN(SocketImpl); }; @@ -137,11 +207,13 @@ SSLServerContextImpl::SocketImpl::SocketImpl( SSLServerContextImpl* context, std::unique_ptr<StreamSocket> transport_socket) : context_(context), + signature_result_(kNoPendingResult), user_read_buf_len_(0), user_write_buf_len_(0), transport_socket_(std::move(transport_socket)), next_handshake_state_(STATE_NONE), - completed_handshake_(false) { + completed_handshake_(false), + weak_factory_(this) { ssl_.reset(SSL_new(context_->ssl_ctx_.get())); SSL_set_app_data(ssl_.get(), this); } @@ -155,6 +227,108 @@ SSLServerContextImpl::SocketImpl::~SocketImpl() { } } +// static +const SSL_PRIVATE_KEY_METHOD + SSLServerContextImpl::SocketImpl::kPrivateKeyMethod = { + &SSLServerContextImpl::SocketImpl::PrivateKeySignCallback, + &SSLServerContextImpl::SocketImpl::PrivateKeyDecryptCallback, + &SSLServerContextImpl::SocketImpl::PrivateKeyCompleteCallback, +}; + +// static +ssl_private_key_result_t +SSLServerContextImpl::SocketImpl::PrivateKeySignCallback(SSL* ssl, + uint8_t* out, + size_t* out_len, + size_t max_out, + uint16_t algorithm, + const uint8_t* in, + size_t in_len) { + DCHECK(ssl); + SSLServerContextImpl::SocketImpl* socket = + static_cast<SSLServerContextImpl::SocketImpl*>(SSL_get_ex_data( + ssl, SocketDataIndex::GetInstance()->ssl_socket_data_index_)); + DCHECK(socket); + return socket->PrivateKeySignCallback(out, out_len, max_out, algorithm, in, + in_len); +} + +// static +ssl_private_key_result_t +SSLServerContextImpl::SocketImpl::PrivateKeyDecryptCallback(SSL* ssl, + uint8_t* out, + size_t* out_len, + size_t max_out, + const uint8_t* in, + size_t in_len) { + // Decrypt is not supported. + return ssl_private_key_failure; +} + +// static +ssl_private_key_result_t +SSLServerContextImpl::SocketImpl::PrivateKeyCompleteCallback(SSL* ssl, + uint8_t* out, + size_t* out_len, + size_t max_out) { + DCHECK(ssl); + SSLServerContextImpl::SocketImpl* socket = + static_cast<SSLServerContextImpl::SocketImpl*>(SSL_get_ex_data( + ssl, SocketDataIndex::GetInstance()->ssl_socket_data_index_)); + DCHECK(socket); + return socket->PrivateKeyCompleteCallback(out, out_len, max_out); +} + +ssl_private_key_result_t +SSLServerContextImpl::SocketImpl::PrivateKeySignCallback(uint8_t* out, + size_t* out_len, + size_t max_out, + uint16_t algorithm, + const uint8_t* in, + size_t in_len) { + DCHECK(context_); + DCHECK(context_->private_key_); + signature_result_ = ERR_IO_PENDING; + context_->private_key_->Sign( + algorithm, base::make_span(in, in_len), + base::BindRepeating( + &SSLServerContextImpl::SocketImpl::OnPrivateKeyComplete, + weak_factory_.GetWeakPtr())); + return ssl_private_key_retry; +} + +ssl_private_key_result_t +SSLServerContextImpl::SocketImpl::PrivateKeyCompleteCallback(uint8_t* out, + size_t* out_len, + size_t max_out) { + if (signature_result_ == ERR_IO_PENDING) + return ssl_private_key_retry; + if (signature_result_ != OK) { + OpenSSLPutNetError(FROM_HERE, signature_result_); + return ssl_private_key_failure; + } + if (signature_.size() > max_out) { + OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED); + return ssl_private_key_failure; + } + memcpy(out, signature_.data(), signature_.size()); + *out_len = signature_.size(); + signature_.clear(); + return ssl_private_key_success; +} + +void SSLServerContextImpl::SocketImpl::OnPrivateKeyComplete( + Error error, + const std::vector<uint8_t>& signature) { + DCHECK_EQ(ERR_IO_PENDING, signature_result_); + DCHECK(signature_.empty()); + + signature_result_ = error; + if (signature_result_ == OK) + signature_ = signature; + DoHandshakeLoop(ERR_IO_PENDING); +} + int SSLServerContextImpl::SocketImpl::Handshake( const CompletionCallback& callback) { net_log_.BeginEvent(NetLogEventType::SSL_SERVER_HANDSHAKE); @@ -236,7 +410,8 @@ int SSLServerContextImpl::SocketImpl::Read(IOBuffer* buf, int SSLServerContextImpl::SocketImpl::Write( IOBuffer* buf, int buf_len, - const CompletionCallback& callback) { + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& traffic_annotation) { DCHECK(user_write_callback_.is_null()); DCHECK(!user_write_buf_); DCHECK(!callback.is_null()); @@ -356,6 +531,10 @@ int64_t SSLServerContextImpl::SocketImpl::GetTotalReceivedBytes() const { return transport_socket_->GetTotalReceivedBytes(); } +void SSLServerContextImpl::SocketImpl::ApplySocketTag(const SocketTag& tag) { + NOTIMPLEMENTED(); +} + void SSLServerContextImpl::SocketImpl::OnReadReady() { if (next_handshake_state_ == STATE_HANDSHAKE) { // In handshake phase. The parameter to OnHandshakeIOComplete is unused. @@ -471,7 +650,6 @@ int SSLServerContextImpl::SocketImpl::DoHandshake() { crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); int net_error = OK; int rv = SSL_do_handshake(ssl_.get()); - if (rv == 1) { completed_handshake_ = true; STACK_OF(CRYPTO_BUFFER)* certs = SSL_get0_peer_certificates(ssl_.get()); @@ -482,6 +660,13 @@ int SSLServerContextImpl::SocketImpl::DoHandshake() { } } else { int ssl_error = SSL_get_error(ssl_.get(), rv); + + if (ssl_error == SSL_ERROR_WANT_PRIVATE_KEY_OPERATION) { + DCHECK(context_->private_key_); + GotoState(STATE_HANDSHAKE); + return ERR_IO_PENDING; + } + OpenSSLErrorInfo error_info; net_error = MapOpenSSLErrorWithDetails(ssl_error, err_tracer, &error_info); @@ -535,15 +720,30 @@ int SSLServerContextImpl::SocketImpl::Init() { crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); - if (!ssl_) + if (!ssl_ || + !SSL_set_ex_data(ssl_.get(), + SocketDataIndex::GetInstance()->ssl_socket_data_index_, + this)) return ERR_UNEXPECTED; // Set certificate and private key. - DCHECK(context_->cert_->os_cert_handle()); - DCHECK(context_->key_->key()); - if (!SetSSLChainAndKey(ssl_.get(), context_->cert_.get(), - context_->key_->key(), nullptr)) { - return ERR_UNEXPECTED; + if (context_->key_) { + DCHECK(context_->cert_->cert_buffer()); + DCHECK(context_->key_->key()); + if (!SetSSLChainAndKey(ssl_.get(), context_->cert_.get(), + context_->key_->key(), nullptr)) { + return ERR_UNEXPECTED; + } + } else { + DCHECK(context_->private_key_); + if (!SetSSLChainAndKey(ssl_.get(), context_->cert_.get(), nullptr, + &kPrivateKeyMethod)) { + return ERR_UNEXPECTED; + } + std::vector<uint16_t> preferences = + context_->private_key_->GetAlgorithmPreferences(); + SSL_set_signing_algorithm_prefs(ssl_.get(), preferences.data(), + preferences.size()); } transport_adapter_.reset(new SocketBIOAdapter( @@ -601,8 +801,26 @@ std::unique_ptr<SSLServerContext> CreateSSLServerContext( X509Certificate* certificate, const crypto::RSAPrivateKey& key, const SSLServerConfig& ssl_server_config) { - return std::unique_ptr<SSLServerContext>( - new SSLServerContextImpl(certificate, key, ssl_server_config)); + return std::make_unique<SSLServerContextImpl>(certificate, key, + ssl_server_config); +} + +std::unique_ptr<SSLServerContext> CreateSSLServerContext( + X509Certificate* certificate, + scoped_refptr<SSLPrivateKey> key, + const SSLServerConfig& ssl_config) { + return std::make_unique<SSLServerContextImpl>(certificate, key, ssl_config); +} + +SSLServerContextImpl::SSLServerContextImpl( + X509Certificate* certificate, + scoped_refptr<net::SSLPrivateKey> key, + const SSLServerConfig& ssl_server_config) + : ssl_server_config_(ssl_server_config), + cert_(certificate), + private_key_(key) { + CHECK(private_key_); + Init(); } SSLServerContextImpl::SSLServerContextImpl( @@ -613,6 +831,10 @@ SSLServerContextImpl::SSLServerContextImpl( cert_(certificate), key_(key.Copy()) { CHECK(key_); + Init(); +} + +void SSLServerContextImpl::Init() { crypto::EnsureOpenSSLInit(); ssl_ctx_.reset(SSL_CTX_new(TLS_with_buffers_method())); SSL_CTX_set_session_cache_mode(ssl_ctx_.get(), SSL_SESS_CACHE_SERVER); @@ -665,7 +887,8 @@ SSLServerContextImpl::SSLServerContextImpl( // as the handshake hash. std::string command("DEFAULT:!SHA256:!SHA384:!AESGCM+AES256:!aPSK"); - if (ssl_server_config_.require_ecdhe) + // SSLPrivateKey only supports ECDHE-based ciphers because it lacks decrypt. + if (ssl_server_config_.require_ecdhe || (!key_ && private_key_)) command.append(":!kRSA"); // Remove any disabled ciphers. @@ -695,8 +918,7 @@ SSLServerContextImpl::~SSLServerContextImpl() = default; std::unique_ptr<SSLServerSocket> SSLServerContextImpl::CreateSSLServerSocket( std::unique_ptr<StreamSocket> socket) { - return std::unique_ptr<SSLServerSocket>( - new SocketImpl(this, std::move(socket))); + return std::make_unique<SocketImpl>(this, std::move(socket)); } } // namespace net diff --git a/chromium/net/socket/ssl_server_socket_impl.h b/chromium/net/socket/ssl_server_socket_impl.h index 7e9ca967d48..74ffbfa1429 100644 --- a/chromium/net/socket/ssl_server_socket_impl.h +++ b/chromium/net/socket/ssl_server_socket_impl.h @@ -23,6 +23,9 @@ class SSLServerContextImpl : public SSLServerContext { SSLServerContextImpl(X509Certificate* certificate, const crypto::RSAPrivateKey& key, const SSLServerConfig& ssl_server_config); + SSLServerContextImpl(X509Certificate* certificate, + scoped_refptr<SSLPrivateKey> key, + const SSLServerConfig& ssl_server_config); ~SSLServerContextImpl() override; std::unique_ptr<SSLServerSocket> CreateSSLServerSocket( @@ -31,6 +34,8 @@ class SSLServerContextImpl : public SSLServerContext { private: class SocketImpl; + void Init(); + bssl::UniquePtr<SSL_CTX> ssl_ctx_; // Options for the SSL socket. @@ -40,7 +45,9 @@ class SSLServerContextImpl : public SSLServerContext { scoped_refptr<X509Certificate> cert_; // Private key used by the server. + // Only one representation should be set at any time. std::unique_ptr<crypto::RSAPrivateKey> key_; + const scoped_refptr<SSLPrivateKey> private_key_; }; } // namespace net diff --git a/chromium/net/socket/ssl_server_socket_unittest.cc b/chromium/net/socket/ssl_server_socket_unittest.cc index 73a038d61cc..b4465f77eab 100644 --- a/chromium/net/socket/ssl_server_socket_unittest.cc +++ b/chromium/net/socket/ssl_server_socket_unittest.cc @@ -66,6 +66,7 @@ #include "net/test/cert_test_util.h" #include "net/test/gtest_util.h" #include "net/test/test_data_directory.h" +#include "net/traffic_annotation/network_traffic_annotation_test_helper.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/platform_test.h" @@ -119,7 +120,10 @@ class FakeDataChannel { return PropagateData(buf, buf_len); } - int Write(IOBuffer* buf, int buf_len, const CompletionCallback& callback) { + int Write(IOBuffer* buf, + int buf_len, + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& traffic_annotation) { DCHECK(write_callback_.is_null()); if (closed_) { if (write_called_after_close_) @@ -234,10 +238,12 @@ class FakeSocket : public StreamSocket { int Write(IOBuffer* buf, int buf_len, - const CompletionCallback& callback) override { + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& traffic_annotation) override { // Write random number of bytes. buf_len = rand() % buf_len + 1; - return outgoing_->Write(buf, buf_len, callback); + return outgoing_->Write(buf, buf_len, callback, + TRAFFIC_ANNOTATION_FOR_TESTS); } int SetReceiveBufferSize(int32_t size) override { return OK; } @@ -291,6 +297,8 @@ class FakeSocket : public StreamSocket { return 0; } + void ApplySocketTag(const SocketTag& tag) override {} + private: NetLogWithSource net_log_; FakeDataChannel* incoming_; @@ -317,7 +325,8 @@ TEST(FakeSocketTest, DataTransfer) { // Write then read. int written = - server.Write(write_buf.get(), kTestDataSize, CompletionCallback()); + server.Write(write_buf.get(), kTestDataSize, CompletionCallback(), + TRAFFIC_ANNOTATION_FOR_TESTS); EXPECT_GT(written, 0); EXPECT_LE(written, kTestDataSize); @@ -331,7 +340,8 @@ TEST(FakeSocketTest, DataTransfer) { EXPECT_EQ(ERR_IO_PENDING, server.Read(read_buf.get(), kReadBufSize, callback.callback())); - written = client.Write(write_buf.get(), kTestDataSize, CompletionCallback()); + written = client.Write(write_buf.get(), kTestDataSize, CompletionCallback(), + TRAFFIC_ANNOTATION_FOR_TESTS); EXPECT_GT(written, 0); EXPECT_LE(written, kTestDataSize); @@ -363,6 +373,13 @@ class SSLServerSocketTest : public PlatformTest { server_private_key_ = ReadTestKey("unittest.key.bin"); ASSERT_TRUE(server_private_key_); + std::unique_ptr<crypto::RSAPrivateKey> key = + ReadTestKey("unittest.key.bin"); + ASSERT_TRUE(key); + EVP_PKEY_up_ref(key->key()); + server_ssl_private_key_ = + WrapOpenSSLPrivateKey(bssl::UniquePtr<EVP_PKEY>(key->key())); + client_ssl_config_.false_start_enabled = false; client_ssl_config_.channel_id_enabled = false; @@ -382,6 +399,16 @@ class SSLServerSocketTest : public PlatformTest { server_cert_.get(), *server_private_key_, server_ssl_config_); } + void CreateContextSSLPrivateKey() { + client_socket_.reset(); + server_socket_.reset(); + channel_1_.reset(); + channel_2_.reset(); + server_context_.reset(); + server_context_ = CreateSSLServerContext( + server_cert_.get(), server_ssl_private_key_, server_ssl_config_); + } + void CreateSockets() { client_socket_.reset(); server_socket_.reset(); @@ -479,6 +506,7 @@ class SSLServerSocketTest : public PlatformTest { std::unique_ptr<MockCTPolicyEnforcer> ct_policy_enforcer_; std::unique_ptr<SSLServerContext> server_context_; std::unique_ptr<crypto::RSAPrivateKey> server_private_key_; + scoped_refptr<SSLPrivateKey> server_ssl_private_key_; scoped_refptr<X509Certificate> server_cert_; }; @@ -1088,4 +1116,80 @@ TEST_F(SSLServerSocketTest, RequireEcdheFlag) { ASSERT_THAT(server_ret, IsError(ERR_SSL_VERSION_OR_CIPHER_MISMATCH)); } +// This test executes Connect() on SSLClientSocket and Handshake() on +// SSLServerSocket to make sure handshaking between the two sockets is +// completed successfully. The server key is represented by SSLPrivateKey. +TEST_F(SSLServerSocketTest, HandshakeServerSSLPrivateKey) { + ASSERT_NO_FATAL_FAILURE(CreateContextSSLPrivateKey()); + ASSERT_NO_FATAL_FAILURE(CreateSockets()); + + TestCompletionCallback handshake_callback; + int server_ret = server_socket_->Handshake(handshake_callback.callback()); + + TestCompletionCallback connect_callback; + int client_ret = client_socket_->Connect(connect_callback.callback()); + + client_ret = connect_callback.GetResult(client_ret); + server_ret = handshake_callback.GetResult(server_ret); + + ASSERT_THAT(client_ret, IsOk()); + ASSERT_THAT(server_ret, IsOk()); + + // Make sure the cert status is expected. + SSLInfo ssl_info; + ASSERT_TRUE(client_socket_->GetSSLInfo(&ssl_info)); + EXPECT_EQ(CERT_STATUS_AUTHORITY_INVALID, ssl_info.cert_status); + + // The default cipher suite should be ECDHE and an AEAD. + uint16_t cipher_suite = + SSLConnectionStatusToCipherSuite(ssl_info.connection_status); + const char* key_exchange; + const char* cipher; + const char* mac; + bool is_aead; + bool is_tls13; + SSLCipherSuiteToStrings(&key_exchange, &cipher, &mac, &is_aead, &is_tls13, + cipher_suite); + EXPECT_TRUE(is_aead); + ASSERT_FALSE(is_tls13); + EXPECT_STREQ("ECDHE_RSA", key_exchange); +} + +// Verifies that non-ECDHE ciphers are disabled when using SSLPrivateKey as the +// server key. +TEST_F(SSLServerSocketTest, HandshakeServerSSLPrivateKeyRequireEcdhe) { + // Disable all ECDHE suites on the client side. + uint16_t kEcdheCiphers[] = { + 0xc007, // ECDHE_ECDSA_WITH_RC4_128_SHA + 0xc009, // ECDHE_ECDSA_WITH_AES_128_CBC_SHA + 0xc00a, // ECDHE_ECDSA_WITH_AES_256_CBC_SHA + 0xc011, // ECDHE_RSA_WITH_RC4_128_SHA + 0xc013, // ECDHE_RSA_WITH_AES_128_CBC_SHA + 0xc014, // ECDHE_RSA_WITH_AES_256_CBC_SHA + 0xc02b, // ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + 0xc02f, // ECDHE_RSA_WITH_AES_128_GCM_SHA256 + 0xcca8, // ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 + 0xcca9, // ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 + }; + client_ssl_config_.disabled_cipher_suites.assign( + kEcdheCiphers, kEcdheCiphers + arraysize(kEcdheCiphers)); + // TLS 1.3 always works with SSLPrivateKey. + client_ssl_config_.version_max = SSL_PROTOCOL_VERSION_TLS1_2; + + ASSERT_NO_FATAL_FAILURE(CreateContextSSLPrivateKey()); + ASSERT_NO_FATAL_FAILURE(CreateSockets()); + + TestCompletionCallback connect_callback; + int client_ret = client_socket_->Connect(connect_callback.callback()); + + TestCompletionCallback handshake_callback; + int server_ret = server_socket_->Handshake(handshake_callback.callback()); + + client_ret = connect_callback.GetResult(client_ret); + server_ret = handshake_callback.GetResult(server_ret); + + ASSERT_THAT(client_ret, IsError(ERR_SSL_VERSION_OR_CIPHER_MISMATCH)); + ASSERT_THAT(server_ret, IsError(ERR_SSL_VERSION_OR_CIPHER_MISMATCH)); +} + } // namespace net diff --git a/chromium/net/socket/stream_socket.h b/chromium/net/socket/stream_socket.h index 6ee0e40adcb..ddec9993b4e 100644 --- a/chromium/net/socket/stream_socket.h +++ b/chromium/net/socket/stream_socket.h @@ -18,6 +18,7 @@ namespace net { class IPEndPoint; class NetLogWithSource; class SSLInfo; +class SocketTag; class NET_EXPORT_PRIVATE StreamSocket : public Socket { public: @@ -136,6 +137,18 @@ class NET_EXPORT_PRIVATE StreamSocket : public Socket { // |stats|. Default implementation does nothing. virtual void DumpMemoryStats(SocketMemoryStats* stats) const {} + // Apply |tag| to this socket. If socket isn't yet connected, tag will be + // applied when socket is later connected. If Connect() fails or socket + // is closed, tag is cleared. If this socket is layered upon or wraps an + // underlying socket, |tag| will be applied to the underlying socket in the + // same manner as if ApplySocketTag() was called on the underlying socket. + // The tag can be applied at any time, in other words active sockets can be + // retagged with a different tag. Sockets wrapping multiplexed sockets + // (e.g. sockets who proxy through a QUIC or Spdy stream) cannot be tagged as + // the tag would inadvertently affect other streams; calling ApplySocketTag() + // in this case will result in CHECK(false). + virtual void ApplySocketTag(const SocketTag& tag) = 0; + protected: // The following class is only used to gather statistics about the history of // a socket. It is only instantiated and used in basic sockets, such as diff --git a/chromium/net/socket/tcp_client_socket.cc b/chromium/net/socket/tcp_client_socket.cc index d6dce18f6b9..1b1831b625f 100644 --- a/chromium/net/socket/tcp_client_socket.cc +++ b/chromium/net/socket/tcp_client_socket.cc @@ -14,6 +14,7 @@ #include "net/base/ip_endpoint.h" #include "net/base/net_errors.h" #include "net/socket/socket_performance_watcher.h" +#include "net/traffic_annotation/network_traffic_annotation.h" namespace net { @@ -294,16 +295,18 @@ int TCPClientSocket::ReadIfReady(IOBuffer* buf, return ReadCommon(buf, buf_len, callback, /*read_if_ready=*/true); } -int TCPClientSocket::Write(IOBuffer* buf, - int buf_len, - const CompletionCallback& callback) { +int TCPClientSocket::Write( + IOBuffer* buf, + int buf_len, + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& traffic_annotation) { DCHECK(!callback.is_null()); // |socket_| is owned by this class and the callback won't be run once // |socket_| is gone. Therefore, it is safe to use base::Unretained() here. CompletionCallback write_callback = base::Bind( &TCPClientSocket::DidCompleteWrite, base::Unretained(this), callback); - int result = socket_->Write(buf, buf_len, write_callback); + int result = socket_->Write(buf, buf_len, write_callback, traffic_annotation); if (result > 0) use_history_.set_was_used_to_convey_data(); @@ -344,6 +347,10 @@ int64_t TCPClientSocket::GetTotalReceivedBytes() const { return total_received_bytes_; } +void TCPClientSocket::ApplySocketTag(const SocketTag& tag) { + socket_->ApplySocketTag(tag); +} + void TCPClientSocket::DidCompleteConnect(int result) { DCHECK_EQ(next_connect_state_, CONNECT_STATE_CONNECT_COMPLETE); DCHECK_NE(result, ERR_IO_PENDING); diff --git a/chromium/net/socket/tcp_client_socket.h b/chromium/net/socket/tcp_client_socket.h index 8981fb066f5..cda599b52a4 100644 --- a/chromium/net/socket/tcp_client_socket.h +++ b/chromium/net/socket/tcp_client_socket.h @@ -17,6 +17,7 @@ #include "net/socket/connection_attempts.h" #include "net/socket/stream_socket.h" #include "net/socket/tcp_socket.h" +#include "net/traffic_annotation/network_traffic_annotation.h" namespace net { @@ -61,6 +62,11 @@ class NET_EXPORT TCPClientSocket : public StreamSocket { bool WasAlpnNegotiated() const override; NextProto GetNegotiatedProtocol() const override; bool GetSSLInfo(SSLInfo* ssl_info) override; + void GetConnectionAttempts(ConnectionAttempts* out) const override; + void ClearConnectionAttempts() override; + void AddConnectionAttempts(const ConnectionAttempts& attempts) override; + int64_t GetTotalReceivedBytes() const override; + void ApplySocketTag(const SocketTag& tag) override; // Socket implementation. // Multiple outstanding requests are not supported. @@ -73,18 +79,14 @@ class NET_EXPORT TCPClientSocket : public StreamSocket { const CompletionCallback& callback) override; int Write(IOBuffer* buf, int buf_len, - const CompletionCallback& callback) override; + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& traffic_annotation) override; int SetReceiveBufferSize(int32_t size) override; int SetSendBufferSize(int32_t size) override; virtual bool SetKeepAlive(bool enable, int delay); virtual bool SetNoDelay(bool no_delay); - void GetConnectionAttempts(ConnectionAttempts* out) const override; - void ClearConnectionAttempts() override; - void AddConnectionAttempts(const ConnectionAttempts& attempts) override; - int64_t GetTotalReceivedBytes() const override; - private: // State machine for connecting the socket. enum ConnectState { diff --git a/chromium/net/socket/tcp_client_socket_unittest.cc b/chromium/net/socket/tcp_client_socket_unittest.cc index 1766d7f70ff..5a95bf9bd8c 100644 --- a/chromium/net/socket/tcp_client_socket_unittest.cc +++ b/chromium/net/socket/tcp_client_socket_unittest.cc @@ -10,14 +10,18 @@ #include <stddef.h> +#include "build/build_config.h" #include "net/base/ip_address.h" #include "net/base/ip_endpoint.h" #include "net/base/net_errors.h" #include "net/base/test_completion_callback.h" #include "net/log/net_log_source.h" #include "net/socket/socket_performance_watcher.h" +#include "net/socket/socket_test_util.h" #include "net/socket/tcp_server_socket.h" +#include "net/test/embedded_test_server/embedded_test_server.h" #include "net/test/gtest_util.h" +#include "net/traffic_annotation/network_traffic_annotation_test_helper.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -164,6 +168,107 @@ TEST(TCPClientSocketTest, MAYBE_TestSocketPerformanceWatcher) { EXPECT_EQ(kNumIPs - 1, watcher_ptr->connection_changed_count()); } +// On Android, where socket tagging is supported, verify that +// TCPClientSocket::Tag works as expected. +#if defined(OS_ANDROID) +TEST(TCPClientSocketTest, Tag) { + // Start test server. + EmbeddedTestServer test_server; + test_server.AddDefaultHandlers(base::FilePath()); + ASSERT_TRUE(test_server.Start()); + + AddressList addr_list; + ASSERT_TRUE(test_server.GetAddressList(&addr_list)); + TCPClientSocket s(addr_list, NULL, NULL, NetLogSource()); + + // Verify TCP connect packets are tagged and counted properly. + int32_t tag_val1 = 0x12345678; + uint64_t old_traffic = GetTaggedBytes(tag_val1); + SocketTag tag1(SocketTag::UNSET_UID, tag_val1); + s.ApplySocketTag(tag1); + TestCompletionCallback connect_callback; + int connect_result = s.Connect(connect_callback.callback()); + EXPECT_THAT(connect_callback.GetResult(connect_result), IsOk()); + EXPECT_GT(GetTaggedBytes(tag_val1), old_traffic); + + // Verify socket can be retagged with a new value and the current process's + // UID. + int32_t tag_val2 = 0x87654321; + old_traffic = GetTaggedBytes(tag_val2); + SocketTag tag2(getuid(), tag_val2); + s.ApplySocketTag(tag2); + const char kRequest1[] = "GET / HTTP/1.0"; + scoped_refptr<IOBuffer> write_buffer1(new StringIOBuffer(kRequest1)); + TestCompletionCallback write_callback1; + EXPECT_EQ(s.Write(write_buffer1.get(), strlen(kRequest1), + write_callback1.callback(), TRAFFIC_ANNOTATION_FOR_TESTS), + static_cast<int>(strlen(kRequest1))); + EXPECT_GT(GetTaggedBytes(tag_val2), old_traffic); + + // Verify socket can be retagged with a new value and the current process's + // UID. + old_traffic = GetTaggedBytes(tag_val1); + s.ApplySocketTag(tag1); + const char kRequest2[] = "\n\n"; + scoped_refptr<IOBufferWithSize> write_buffer2( + new IOBufferWithSize(strlen(kRequest2))); + memmove(write_buffer2->data(), kRequest2, strlen(kRequest2)); + TestCompletionCallback write_callback2; + EXPECT_EQ(s.Write(write_buffer2.get(), strlen(kRequest2), + write_callback2.callback(), TRAFFIC_ANNOTATION_FOR_TESTS), + static_cast<int>(strlen(kRequest2))); + EXPECT_GT(GetTaggedBytes(tag_val1), old_traffic); + + s.Disconnect(); +} + +TEST(TCPClientSocketTest, TagAfterConnect) { + // Start test server. + EmbeddedTestServer test_server; + test_server.AddDefaultHandlers(base::FilePath()); + ASSERT_TRUE(test_server.Start()); + + AddressList addr_list; + ASSERT_TRUE(test_server.GetAddressList(&addr_list)); + TCPClientSocket s(addr_list, NULL, NULL, NetLogSource()); + + // Connect socket. + TestCompletionCallback connect_callback; + int connect_result = s.Connect(connect_callback.callback()); + EXPECT_THAT(connect_callback.GetResult(connect_result), IsOk()); + + // Verify socket can be tagged with a new value and the current process's + // UID. + int32_t tag_val2 = 0x87654321; + uint64_t old_traffic = GetTaggedBytes(tag_val2); + SocketTag tag2(getuid(), tag_val2); + s.ApplySocketTag(tag2); + const char kRequest1[] = "GET / HTTP/1.0"; + scoped_refptr<IOBuffer> write_buffer1(new StringIOBuffer(kRequest1)); + TestCompletionCallback write_callback1; + EXPECT_EQ(s.Write(write_buffer1.get(), strlen(kRequest1), + write_callback1.callback(), TRAFFIC_ANNOTATION_FOR_TESTS), + static_cast<int>(strlen(kRequest1))); + EXPECT_GT(GetTaggedBytes(tag_val2), old_traffic); + + // Verify socket can be retagged with a new value and the current process's + // UID. + int32_t tag_val1 = 0x12345678; + old_traffic = GetTaggedBytes(tag_val1); + SocketTag tag1(SocketTag::UNSET_UID, tag_val1); + s.ApplySocketTag(tag1); + const char kRequest2[] = "\n\n"; + scoped_refptr<IOBuffer> write_buffer2(new StringIOBuffer(kRequest2)); + TestCompletionCallback write_callback2; + EXPECT_EQ(s.Write(write_buffer2.get(), strlen(kRequest2), + write_callback2.callback(), TRAFFIC_ANNOTATION_FOR_TESTS), + static_cast<int>(strlen(kRequest2))); + EXPECT_GT(GetTaggedBytes(tag_val1), old_traffic); + + s.Disconnect(); +} +#endif + } // namespace } // namespace net diff --git a/chromium/net/socket/tcp_socket_posix.cc b/chromium/net/socket/tcp_socket_posix.cc index b46ccadb5af..600462077b2 100644 --- a/chromium/net/socket/tcp_socket_posix.cc +++ b/chromium/net/socket/tcp_socket_posix.cc @@ -36,6 +36,8 @@ #include "net/socket/socket_net_log_params.h" #include "net/socket/socket_options.h" #include "net/socket/socket_posix.h" +#include "net/socket/socket_tag.h" +#include "net/traffic_annotation/network_traffic_annotation.h" // If we don't have a definition for TCPI_OPT_SYN_DATA, create one. #if !defined(TCPI_OPT_SYN_DATA) @@ -148,11 +150,57 @@ base::LazyInstance<FastOpenProbe>::Leaky g_fast_open_probe = #endif // defined(OS_LINUX) || defined(OS_ANDROID) #if defined(HAVE_TCP_INFO) -bool GetTcpInfo(SocketDescriptor fd, tcp_info* info) { +// Returns a zero value if the transport RTT is unavailable. +base::TimeDelta GetTransportRtt(SocketDescriptor fd) { + tcp_info info; + // Reset |tcpi_rtt| to verify if getsockopt() actually updates |tcpi_rtt|. + info.tcpi_rtt = 0; + socklen_t info_len = sizeof(tcp_info); - return getsockopt(fd, IPPROTO_TCP, TCP_INFO, info, &info_len) == 0 && - info_len == sizeof(tcp_info); + if (getsockopt(fd, IPPROTO_TCP, TCP_INFO, &info, &info_len) != 0) + return base::TimeDelta(); + + // Verify that |tcpi_rtt| in tcp_info struct was updated. Note that it's + // possible that |info_len| is shorter than |sizeof(tcp_info)| which implies + // that only a subset of values in |info| may have been updated by + // getsockopt(). + if (info_len < static_cast<socklen_t>(offsetof(tcp_info, tcpi_rtt) + + sizeof(info.tcpi_rtt))) { + return base::TimeDelta(); + } + + return base::TimeDelta::FromMicroseconds(info.tcpi_rtt); +} + +// Returns true if getsockopt() call was successful. Sets +// |server_acked_syn_data| to true if SYN-ACK acked data in SYN sent or +// received. +bool GetServerAckedDataInSyn(SocketDescriptor fd, bool* server_acked_syn_data) { + tcp_info info; + // Reset |tcpi_options| to verify if getsockopt() actually updates + // |tcpi_options|. + info.tcpi_options = 0; + + socklen_t info_len = sizeof(tcp_info); + if (getsockopt(fd, IPPROTO_TCP, TCP_INFO, &info, &info_len) != 0) { + *server_acked_syn_data = false; + return false; + } + + // Verify that |tcpi_options| in tcp_info struct was updated. Note that it's + // possible that |info_len| is shorter than |sizeof(tcp_info)| which implies + // that only a subset of values in |info| may have been updated by + // getsockopt(). + if (info_len < static_cast<socklen_t>(offsetof(tcp_info, tcpi_options) + + sizeof(info.tcpi_options))) { + *server_acked_syn_data = false; + return false; + } + + *server_acked_syn_data = (info.tcpi_options & TCPI_OPT_SYN_DATA); + return true; } + #endif // defined(TCP_INFO) } // namespace @@ -193,6 +241,8 @@ int TCPSocketPosix::Open(AddressFamily family) { int rv = socket_->Open(ConvertAddressFamily(family)); if (rv != OK) socket_.reset(); + if (rv == OK && tag_ != SocketTag()) + tag_.Apply(socket_->socket_fd()); return rv; } @@ -211,6 +261,8 @@ int TCPSocketPosix::AdoptConnectedSocket(SocketDescriptor socket, int rv = socket_->AdoptConnectedSocket(socket, storage); if (rv != OK) socket_.reset(); + if (rv == OK && tag_ != SocketTag()) + tag_.Apply(socket_->socket_fd()); return rv; } @@ -221,6 +273,8 @@ int TCPSocketPosix::AdoptUnconnectedSocket(SocketDescriptor socket) { int rv = socket_->AdoptUnconnectedSocket(socket); if (rv != OK) socket_.reset(); + if (rv == OK && tag_ != SocketTag()) + tag_.Apply(socket_->socket_fd()); return rv; } @@ -340,9 +394,11 @@ int TCPSocketPosix::ReadIfReady(IOBuffer* buf, return rv; } -int TCPSocketPosix::Write(IOBuffer* buf, - int buf_len, - const CompletionCallback& callback) { +int TCPSocketPosix::Write( + IOBuffer* buf, + int buf_len, + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& traffic_annotation) { DCHECK(socket_); DCHECK(!callback.is_null()); @@ -357,7 +413,7 @@ int TCPSocketPosix::Write(IOBuffer* buf, if (use_tcp_fastopen_ && !tcp_fastopen_write_attempted_) { rv = TcpFastOpenWrite(buf, buf_len, write_callback); } else { - rv = socket_->Write(buf, buf_len, write_callback); + rv = socket_->Write(buf, buf_len, write_callback, traffic_annotation); } if (rv != ERR_IO_PENDING) @@ -476,6 +532,7 @@ void TCPSocketPosix::Close() { tcp_fastopen_connected_ = false; tcp_fastopen_write_attempted_ = false; tcp_fastopen_status_ = TCP_FASTOPEN_STATUS_UNKNOWN; + tag_ = SocketTag(); } void TCPSocketPosix::EnableTCPFastOpenIfSupported() { @@ -525,6 +582,13 @@ SocketDescriptor TCPSocketPosix::ReleaseSocketDescriptorForTesting() { return socket_descriptor; } +void TCPSocketPosix::ApplySocketTag(const SocketTag& tag) { + if (IsValid() && tag != tag_) { + tag.Apply(socket_->socket_fd()); + } + tag_ = tag; +} + void TCPSocketPosix::AcceptCompleted( std::unique_ptr<TCPSocketPosix>* tcp_socket, IPEndPoint* address, @@ -580,6 +644,7 @@ int TCPSocketPosix::HandleConnectCompleted(int rv) { if (rv != OK) { net_log_.EndEvent(NetLogEventType::TCP_CONNECT_ATTEMPT, NetLog::IntCallback("os_error", errno)); + tag_ = SocketTag(); } else { net_log_.EndEvent(NetLogEventType::TCP_CONNECT_ATTEMPT); NotifySocketPerformanceWatcher(); @@ -783,20 +848,11 @@ void TCPSocketPosix::NotifySocketPerformanceWatcher() { return; } - tcp_info info; - if (!GetTcpInfo(socket_->socket_fd(), &info)) + base::TimeDelta rtt = GetTransportRtt(socket_->socket_fd()); + if (rtt.is_zero()) return; - // Only notify the |socket_performance_watcher_| if the RTT in |tcp_info| - // struct was populated. A value of 0 may be valid in certain cases - // (on very fast networks), but it is discarded. This means that - // some of the RTT values may be missed, but the values that are kept are - // guaranteed to be correct. - if (info.tcpi_rtt == 0 && info.tcpi_rttvar == 0) - return; - - socket_performance_watcher_->OnUpdatedRTTAvailable( - base::TimeDelta::FromMicroseconds(info.tcpi_rtt)); + socket_performance_watcher_->OnUpdatedRTTAvailable(rtt); #endif // defined(TCP_INFO) } @@ -814,24 +870,22 @@ void TCPSocketPosix::UpdateTCPFastOpenStatusAfterRead() { } bool getsockopt_success = false; - bool server_acked_data = false; + bool server_acked_syn_data = false; #if defined(HAVE_TCP_INFO) // Probe to see the if the socket used TCP FastOpen. - tcp_info info; - getsockopt_success = GetTcpInfo(socket_->socket_fd(), &info); - server_acked_data = - getsockopt_success && (info.tcpi_options & TCPI_OPT_SYN_DATA); + getsockopt_success = + GetServerAckedDataInSyn(socket_->socket_fd(), &server_acked_syn_data); #endif // defined(TCP_INFO) if (getsockopt_success) { if (tcp_fastopen_status_ == TCP_FASTOPEN_FAST_CONNECT_RETURN) { - tcp_fastopen_status_ = (server_acked_data ? - TCP_FASTOPEN_SYN_DATA_ACK : - TCP_FASTOPEN_SYN_DATA_NACK); + tcp_fastopen_status_ = + (server_acked_syn_data ? TCP_FASTOPEN_SYN_DATA_ACK + : TCP_FASTOPEN_SYN_DATA_NACK); } else { - tcp_fastopen_status_ = (server_acked_data ? - TCP_FASTOPEN_NO_SYN_DATA_ACK : - TCP_FASTOPEN_NO_SYN_DATA_NACK); + tcp_fastopen_status_ = + (server_acked_syn_data ? TCP_FASTOPEN_NO_SYN_DATA_ACK + : TCP_FASTOPEN_NO_SYN_DATA_NACK); } } else { tcp_fastopen_status_ = @@ -847,15 +901,11 @@ bool TCPSocketPosix::GetEstimatedRoundTripTime(base::TimeDelta* out_rtt) const { return false; #if defined(HAVE_TCP_INFO) - tcp_info info; - if (GetTcpInfo(socket_->socket_fd(), &info)) { - // tcpi_rtt is zero when the kernel doesn't have an RTT estimate, - // and possibly in other cases such as connections to localhost. - if (info.tcpi_rtt > 0) { - *out_rtt = base::TimeDelta::FromMicroseconds(info.tcpi_rtt); - return true; - } - } + base::TimeDelta rtt = GetTransportRtt(socket_->socket_fd()); + if (rtt.is_zero()) + return false; + *out_rtt = rtt; + return true; #endif // defined(TCP_INFO) return false; } diff --git a/chromium/net/socket/tcp_socket_posix.h b/chromium/net/socket/tcp_socket_posix.h index 031dd8cc97e..4e00fd9893c 100644 --- a/chromium/net/socket/tcp_socket_posix.h +++ b/chromium/net/socket/tcp_socket_posix.h @@ -18,6 +18,8 @@ #include "net/log/net_log_with_source.h" #include "net/socket/socket_descriptor.h" #include "net/socket/socket_performance_watcher.h" +#include "net/socket/socket_tag.h" +#include "net/traffic_annotation/network_traffic_annotation.h" namespace base { class TimeDelta; @@ -31,6 +33,7 @@ class IPEndPoint; class SocketPosix; class NetLog; struct NetLogSource; +class SocketTag; class NET_EXPORT TCPSocketPosix { public: @@ -91,7 +94,10 @@ class NET_EXPORT TCPSocketPosix { // Writes to the socket. // Returns a net error code. - int Write(IOBuffer* buf, int buf_len, const CompletionCallback& callback); + int Write(IOBuffer* buf, + int buf_len, + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& traffic_annotation); // Copies the local tcp address into |address| and returns a net error code. int GetLocalAddress(IPEndPoint* address) const; @@ -150,6 +156,9 @@ class NET_EXPORT TCPSocketPosix { // write, or accept operations should be pending. SocketDescriptor ReleaseSocketDescriptorForTesting(); + // Apply |tag| to this socket. + void ApplySocketTag(const SocketTag& tag); + private: // States that using a socket with TCP FastOpen can lead to. enum TCPFastOpenStatus { @@ -280,6 +289,10 @@ class NET_EXPORT TCPSocketPosix { NetLogWithSource net_log_; + // Current socket tag if |socket_| is valid, otherwise the tag to apply when + // |socket_| is opened. + SocketTag tag_; + DISALLOW_COPY_AND_ASSIGN(TCPSocketPosix); }; diff --git a/chromium/net/socket/tcp_socket_unittest.cc b/chromium/net/socket/tcp_socket_unittest.cc index e170f3b5a5b..c9d4c716455 100644 --- a/chromium/net/socket/tcp_socket_unittest.cc +++ b/chromium/net/socket/tcp_socket_unittest.cc @@ -13,6 +13,7 @@ #include "base/memory/ref_counted.h" #include "base/time/time.h" +#include "build/build_config.h" #include "net/base/address_list.h" #include "net/base/io_buffer.h" #include "net/base/ip_endpoint.h" @@ -21,8 +22,11 @@ #include "net/base/test_completion_callback.h" #include "net/log/net_log_source.h" #include "net/socket/socket_performance_watcher.h" +#include "net/socket/socket_test_util.h" #include "net/socket/tcp_client_socket.h" +#include "net/test/embedded_test_server/embedded_test_server.h" #include "net/test/gtest_util.h" +#include "net/traffic_annotation/network_traffic_annotation_test_helper.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/platform_test.h" @@ -168,7 +172,8 @@ class TCPSocketTest : public PlatformTest { TestCompletionCallback write_callback; int write_result = accepted_socket->Write( - write_buffer.get(), write_buffer->size(), write_callback.callback()); + write_buffer.get(), write_buffer->size(), write_callback.callback(), + TRAFFIC_ANNOTATION_FOR_TESTS); scoped_refptr<IOBufferWithSize> read_buffer( new IOBufferWithSize(message.size())); @@ -388,7 +393,8 @@ TEST_F(TCPSocketTest, ReadWrite) { TestCompletionCallback write_callback; int write_result = accepted_socket->Write( - write_buffer.get(), write_buffer->size(), write_callback.callback()); + write_buffer.get(), write_buffer->size(), write_callback.callback(), + TRAFFIC_ANNOTATION_FOR_TESTS); write_result = write_callback.GetResult(write_result); ASSERT_TRUE(write_result >= 0); bytes_written += write_result; @@ -429,5 +435,110 @@ TEST_F(TCPSocketTest, SPWNoAdvance) { } #endif // defined(TCP_INFO) || defined(OS_LINUX) +// On Android, where socket tagging is supported, verify that TCPSocket::Tag +// works as expected. +#if defined(OS_ANDROID) +TEST_F(TCPSocketTest, Tag) { + // Start test server. + EmbeddedTestServer test_server; + test_server.AddDefaultHandlers(base::FilePath()); + ASSERT_TRUE(test_server.Start()); + + AddressList addr_list; + ASSERT_TRUE(test_server.GetAddressList(&addr_list)); + EXPECT_EQ(socket_.Open(addr_list[0].GetFamily()), OK); + + // Verify TCP connect packets are tagged and counted properly. + int32_t tag_val1 = 0x12345678; + uint64_t old_traffic = GetTaggedBytes(tag_val1); + SocketTag tag1(SocketTag::UNSET_UID, tag_val1); + socket_.ApplySocketTag(tag1); + TestCompletionCallback connect_callback; + int connect_result = + socket_.Connect(addr_list[0], connect_callback.callback()); + EXPECT_THAT(connect_callback.GetResult(connect_result), IsOk()); + EXPECT_GT(GetTaggedBytes(tag_val1), old_traffic); + + // Verify socket can be retagged with a new value and the current process's + // UID. + int32_t tag_val2 = 0x87654321; + old_traffic = GetTaggedBytes(tag_val2); + SocketTag tag2(getuid(), tag_val2); + socket_.ApplySocketTag(tag2); + const char kRequest1[] = "GET / HTTP/1.0"; + scoped_refptr<IOBuffer> write_buffer1(new StringIOBuffer(kRequest1)); + TestCompletionCallback write_callback1; + EXPECT_EQ( + socket_.Write(write_buffer1.get(), strlen(kRequest1), + write_callback1.callback(), TRAFFIC_ANNOTATION_FOR_TESTS), + static_cast<int>(strlen(kRequest1))); + EXPECT_GT(GetTaggedBytes(tag_val2), old_traffic); + + // Verify socket can be retagged with a new value and the current process's + // UID. + old_traffic = GetTaggedBytes(tag_val1); + socket_.ApplySocketTag(tag1); + const char kRequest2[] = "\n\n"; + scoped_refptr<IOBuffer> write_buffer2(new StringIOBuffer(kRequest2)); + TestCompletionCallback write_callback2; + EXPECT_EQ( + socket_.Write(write_buffer2.get(), strlen(kRequest2), + write_callback2.callback(), TRAFFIC_ANNOTATION_FOR_TESTS), + static_cast<int>(strlen(kRequest2))); + EXPECT_GT(GetTaggedBytes(tag_val1), old_traffic); + + socket_.Close(); +} + +TEST_F(TCPSocketTest, TagAfterConnect) { + // Start test server. + EmbeddedTestServer test_server; + test_server.AddDefaultHandlers(base::FilePath()); + ASSERT_TRUE(test_server.Start()); + + AddressList addr_list; + ASSERT_TRUE(test_server.GetAddressList(&addr_list)); + EXPECT_EQ(socket_.Open(addr_list[0].GetFamily()), OK); + + // Connect socket. + TestCompletionCallback connect_callback; + int connect_result = + socket_.Connect(addr_list[0], connect_callback.callback()); + EXPECT_THAT(connect_callback.GetResult(connect_result), IsOk()); + + // Verify socket can be tagged with a new value and the current process's + // UID. + int32_t tag_val2 = 0x87654321; + uint64_t old_traffic = GetTaggedBytes(tag_val2); + SocketTag tag2(getuid(), tag_val2); + socket_.ApplySocketTag(tag2); + const char kRequest1[] = "GET / HTTP/1.0"; + scoped_refptr<IOBuffer> write_buffer1(new StringIOBuffer(kRequest1)); + TestCompletionCallback write_callback1; + EXPECT_EQ( + socket_.Write(write_buffer1.get(), strlen(kRequest1), + write_callback1.callback(), TRAFFIC_ANNOTATION_FOR_TESTS), + static_cast<int>(strlen(kRequest1))); + EXPECT_GT(GetTaggedBytes(tag_val2), old_traffic); + + // Verify socket can be retagged with a new value and the current process's + // UID. + int32_t tag_val1 = 0x12345678; + old_traffic = GetTaggedBytes(tag_val1); + SocketTag tag1(SocketTag::UNSET_UID, tag_val1); + socket_.ApplySocketTag(tag1); + const char kRequest2[] = "\n\n"; + scoped_refptr<IOBuffer> write_buffer2(new StringIOBuffer(kRequest2)); + TestCompletionCallback write_callback2; + EXPECT_EQ( + socket_.Write(write_buffer2.get(), strlen(kRequest2), + write_callback2.callback(), TRAFFIC_ANNOTATION_FOR_TESTS), + static_cast<int>(strlen(kRequest2))); + EXPECT_GT(GetTaggedBytes(tag_val1), old_traffic); + + socket_.Close(); +} +#endif + } // namespace } // namespace net diff --git a/chromium/net/socket/tcp_socket_win.cc b/chromium/net/socket/tcp_socket_win.cc index 7612291cb75..4ecab0b6061 100644 --- a/chromium/net/socket/tcp_socket_win.cc +++ b/chromium/net/socket/tcp_socket_win.cc @@ -30,6 +30,7 @@ #include "net/socket/socket_descriptor.h" #include "net/socket/socket_net_log_params.h" #include "net/socket/socket_options.h" +#include "net/socket/socket_tag.h" namespace net { @@ -517,9 +518,11 @@ int TCPSocketWin::ReadIfReady(IOBuffer* buf, return ERR_IO_PENDING; } -int TCPSocketWin::Write(IOBuffer* buf, - int buf_len, - const CompletionCallback& callback) { +int TCPSocketWin::Write( + IOBuffer* buf, + int buf_len, + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& /* traffic_annotation */) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK_NE(socket_, INVALID_SOCKET); DCHECK(!waiting_write_); @@ -1016,4 +1019,10 @@ bool TCPSocketWin::GetEstimatedRoundTripTime(base::TimeDelta* out_rtt) const { return false; } +void TCPSocketWin::ApplySocketTag(const SocketTag& tag) { + // Windows does not support any specific SocketTags so fail if any non-default + // tag is applied. + CHECK(tag == SocketTag()); +} + } // namespace net diff --git a/chromium/net/socket/tcp_socket_win.h b/chromium/net/socket/tcp_socket_win.h index 1c1b548490e..1cb2675a369 100644 --- a/chromium/net/socket/tcp_socket_win.h +++ b/chromium/net/socket/tcp_socket_win.h @@ -21,6 +21,7 @@ #include "net/log/net_log_with_source.h" #include "net/socket/socket_descriptor.h" #include "net/socket/socket_performance_watcher.h" +#include "net/traffic_annotation/network_traffic_annotation.h" namespace net { @@ -29,6 +30,7 @@ class IOBuffer; class IPEndPoint; class NetLog; struct NetLogSource; +class SocketTag; class NET_EXPORT TCPSocketWin : public base::win::ObjectWatcher::Delegate { public: @@ -68,7 +70,10 @@ class NET_EXPORT TCPSocketWin : public base::win::ObjectWatcher::Delegate { int ReadIfReady(IOBuffer* buf, int buf_len, const CompletionCallback& callback); - int Write(IOBuffer* buf, int buf_len, const CompletionCallback& callback); + int Write(IOBuffer* buf, + int buf_len, + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& traffic_annotation); int GetLocalAddress(IPEndPoint* address) const; int GetPeerAddress(IPEndPoint* address) const; @@ -124,6 +129,9 @@ class NET_EXPORT TCPSocketWin : public base::win::ObjectWatcher::Delegate { // write, or accept operations should be pending. SocketDescriptor ReleaseSocketDescriptorForTesting(); + // Apply |tag| to this socket. + void ApplySocketTag(const SocketTag& tag); + private: class Core; diff --git a/chromium/net/socket/transport_client_socket_pool.cc b/chromium/net/socket/transport_client_socket_pool.cc index 53f2c154392..a7299062335 100644 --- a/chromium/net/socket/transport_client_socket_pool.cc +++ b/chromium/net/socket/transport_client_socket_pool.cc @@ -80,6 +80,7 @@ const int TransportConnectJob::kIPv6FallbackTimerInMs = 300; TransportConnectJob::TransportConnectJob( const std::string& group_name, RequestPriority priority, + const SocketTag& socket_tag, ClientSocketPool::RespectLimits respect_limits, const scoped_refptr<TransportSocketParams>& params, base::TimeDelta timeout_duration, @@ -92,6 +93,7 @@ TransportConnectJob::TransportConnectJob( group_name, timeout_duration, priority, + socket_tag, respect_limits, delegate, NetLogWithSource::Make(net_log, @@ -307,6 +309,8 @@ int TransportConnectJob::DoTransportConnect() { transport_socket_->EnableTCPFastOpenIfSupported(); } + transport_socket_->ApplySocketTag(socket_tag()); + int rv = transport_socket_->Connect( base::Bind(&TransportConnectJob::OnIOComplete, base::Unretained(this))); if (rv == ERR_IO_PENDING && try_ipv6_connect_with_ipv4_fallback) { @@ -453,9 +457,10 @@ TransportClientSocketPool::TransportConnectJobFactory::NewConnectJob( const PoolBase::Request& request, ConnectJob::Delegate* delegate) const { return std::unique_ptr<ConnectJob>(new TransportConnectJob( - group_name, request.priority(), request.respect_limits(), - request.params(), ConnectionTimeout(), client_socket_factory_, - socket_performance_watcher_factory_, host_resolver_, delegate, net_log_)); + group_name, request.priority(), request.socket_tag(), + request.respect_limits(), request.params(), ConnectionTimeout(), + client_socket_factory_, socket_performance_watcher_factory_, + host_resolver_, delegate, net_log_)); } base::TimeDelta @@ -488,6 +493,7 @@ TransportClientSocketPool::~TransportClientSocketPool() = default; int TransportClientSocketPool::RequestSocket(const std::string& group_name, const void* params, RequestPriority priority, + const SocketTag& socket_tag, RespectLimits respect_limits, ClientSocketHandle* handle, const CompletionCallback& callback, @@ -497,7 +503,7 @@ int TransportClientSocketPool::RequestSocket(const std::string& group_name, NetLogTcpClientSocketPoolRequestedSocket(net_log, casted_params); - return base_.RequestSocket(group_name, *casted_params, priority, + return base_.RequestSocket(group_name, *casted_params, priority, socket_tag, respect_limits, handle, callback, net_log); } diff --git a/chromium/net/socket/transport_client_socket_pool.h b/chromium/net/socket/transport_client_socket_pool.h index 7633977779c..0df8883c311 100644 --- a/chromium/net/socket/transport_client_socket_pool.h +++ b/chromium/net/socket/transport_client_socket_pool.h @@ -18,6 +18,7 @@ #include "net/socket/client_socket_pool.h" #include "net/socket/client_socket_pool_base.h" #include "net/socket/connection_attempts.h" +#include "net/socket/socket_tag.h" namespace net { @@ -102,6 +103,7 @@ class NET_EXPORT_PRIVATE TransportConnectJob : public ConnectJob { TransportConnectJob( const std::string& group_name, RequestPriority priority, + const SocketTag& socket_tag, ClientSocketPool::RespectLimits respect_limits, const scoped_refptr<TransportSocketParams>& params, base::TimeDelta timeout_duration, @@ -201,6 +203,7 @@ class NET_EXPORT_PRIVATE TransportClientSocketPool : public ClientSocketPool { int RequestSocket(const std::string& group_name, const void* resolve_info, RequestPriority priority, + const SocketTag& socket_tag, RespectLimits respect_limits, ClientSocketHandle* handle, const CompletionCallback& callback, diff --git a/chromium/net/socket/transport_client_socket_pool_test_util.cc b/chromium/net/socket/transport_client_socket_pool_test_util.cc index 361d7f8508a..7f872c6ea18 100644 --- a/chromium/net/socket/transport_client_socket_pool_test_util.cc +++ b/chromium/net/socket/transport_client_socket_pool_test_util.cc @@ -25,6 +25,7 @@ #include "net/socket/client_socket_handle.h" #include "net/socket/datagram_client_socket.h" #include "net/socket/ssl_client_socket.h" +#include "net/traffic_annotation/network_traffic_annotation_test_helper.h" #include "testing/gtest/include/gtest/gtest.h" namespace net { @@ -85,6 +86,7 @@ class MockConnectClientSocket : public StreamSocket { NOTIMPLEMENTED(); return 0; } + void ApplySocketTag(const SocketTag& tag) override {} // Socket implementation. int Read(IOBuffer* buf, @@ -94,7 +96,8 @@ class MockConnectClientSocket : public StreamSocket { } int Write(IOBuffer* buf, int buf_len, - const CompletionCallback& callback) override { + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& traffic_annotation) override { return ERR_FAILED; } int SetReceiveBufferSize(int32_t size) override { return OK; } @@ -149,6 +152,7 @@ class MockFailingClientSocket : public StreamSocket { NOTIMPLEMENTED(); return 0; } + void ApplySocketTag(const SocketTag& tag) override {} // Socket implementation. int Read(IOBuffer* buf, @@ -159,7 +163,8 @@ class MockFailingClientSocket : public StreamSocket { int Write(IOBuffer* buf, int buf_len, - const CompletionCallback& callback) override { + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& traffic_annotation) override { return ERR_FAILED; } int SetReceiveBufferSize(int32_t size) override { return OK; } @@ -276,6 +281,7 @@ class MockTriggerableClientSocket : public StreamSocket { NOTIMPLEMENTED(); return 0; } + void ApplySocketTag(const SocketTag& tag) override {} // Socket implementation. int Read(IOBuffer* buf, @@ -286,7 +292,8 @@ class MockTriggerableClientSocket : public StreamSocket { int Write(IOBuffer* buf, int buf_len, - const CompletionCallback& callback) override { + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& traffic_annotation) override { return ERR_FAILED; } int SetReceiveBufferSize(int32_t size) override { return OK; } diff --git a/chromium/net/socket/transport_client_socket_pool_unittest.cc b/chromium/net/socket/transport_client_socket_pool_unittest.cc index 313c5ba1a2d..bdd5df5e738 100644 --- a/chromium/net/socket/transport_client_socket_pool_unittest.cc +++ b/chromium/net/socket/transport_client_socket_pool_unittest.cc @@ -11,6 +11,7 @@ #include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "base/threading/platform_thread.h" +#include "build/build_config.h" #include "net/base/ip_address.h" #include "net/base/ip_endpoint.h" #include "net/base/load_timing_info.h" @@ -21,10 +22,13 @@ #include "net/log/net_log_with_source.h" #include "net/log/test_net_log.h" #include "net/socket/client_socket_handle.h" +#include "net/socket/socket_tag.h" #include "net/socket/socket_test_util.h" #include "net/socket/stream_socket.h" #include "net/socket/transport_client_socket_pool_test_util.h" +#include "net/test/embedded_test_server/embedded_test_server.h" #include "net/test/gtest_util.h" +#include "net/traffic_annotation/network_traffic_annotation_test_helper.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -181,9 +185,9 @@ TEST(TransportConnectJobTest, MakeAddrListStartWithIPv4) { TEST_F(TransportClientSocketPoolTest, Basic) { TestCompletionCallback callback; ClientSocketHandle handle; - int rv = - handle.Init("a", params_, LOW, ClientSocketPool::RespectLimits::ENABLED, - callback.callback(), &pool_, NetLogWithSource()); + int rv = handle.Init("a", params_, LOW, SocketTag(), + ClientSocketPool::RespectLimits::ENABLED, + callback.callback(), &pool_, NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); EXPECT_FALSE(handle.is_initialized()); EXPECT_FALSE(handle.socket()); @@ -203,7 +207,7 @@ TEST_F(TransportClientSocketPoolTest, SetResolvePriorityOnInit) { TestCompletionCallback callback; ClientSocketHandle handle; EXPECT_EQ(ERR_IO_PENDING, - handle.Init("a", params_, priority, + handle.Init("a", params_, priority, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), &pool_, NetLogWithSource())); EXPECT_EQ(priority, host_resolver_->last_request_priority()); @@ -219,7 +223,7 @@ TEST_F(TransportClientSocketPoolTest, InitHostResolutionFailure) { host_port_pair, false, OnHostResolutionCallback(), TransportSocketParams::COMBINE_CONNECT_AND_WRITE_DEFAULT)); EXPECT_EQ(ERR_IO_PENDING, - handle.Init("a", dest, kDefaultPriority, + handle.Init("a", dest, kDefaultPriority, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), &pool_, NetLogWithSource())); EXPECT_THAT(callback.WaitForResult(), IsError(ERR_NAME_NOT_RESOLVED)); @@ -235,7 +239,7 @@ TEST_F(TransportClientSocketPoolTest, InitConnectionFailure) { TestCompletionCallback callback; ClientSocketHandle handle; EXPECT_EQ(ERR_IO_PENDING, - handle.Init("a", params_, kDefaultPriority, + handle.Init("a", params_, kDefaultPriority, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), &pool_, NetLogWithSource())); EXPECT_THAT(callback.WaitForResult(), IsError(ERR_CONNECTION_FAILED)); @@ -248,7 +252,7 @@ TEST_F(TransportClientSocketPoolTest, InitConnectionFailure) { // Make the host resolutions complete synchronously this time. host_resolver_->set_synchronous_mode(true); EXPECT_EQ(ERR_CONNECTION_FAILED, - handle.Init("a", params_, kDefaultPriority, + handle.Init("a", params_, kDefaultPriority, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), &pool_, NetLogWithSource())); ASSERT_EQ(1u, handle.connection_attempts().size()); @@ -361,7 +365,7 @@ TEST_F(TransportClientSocketPoolTest, CancelRequestClearGroup) { TestCompletionCallback callback; ClientSocketHandle handle; EXPECT_EQ(ERR_IO_PENDING, - handle.Init("a", params_, kDefaultPriority, + handle.Init("a", params_, kDefaultPriority, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), &pool_, NetLogWithSource())); handle.Reset(); @@ -374,11 +378,11 @@ TEST_F(TransportClientSocketPoolTest, TwoRequestsCancelOne) { TestCompletionCallback callback2; EXPECT_EQ(ERR_IO_PENDING, - handle.Init("a", params_, kDefaultPriority, + handle.Init("a", params_, kDefaultPriority, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), &pool_, NetLogWithSource())); EXPECT_EQ(ERR_IO_PENDING, - handle2.Init("a", params_, kDefaultPriority, + handle2.Init("a", params_, kDefaultPriority, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback2.callback(), &pool_, NetLogWithSource())); @@ -394,7 +398,7 @@ TEST_F(TransportClientSocketPoolTest, ConnectCancelConnect) { ClientSocketHandle handle; TestCompletionCallback callback; EXPECT_EQ(ERR_IO_PENDING, - handle.Init("a", params_, kDefaultPriority, + handle.Init("a", params_, kDefaultPriority, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), &pool_, NetLogWithSource())); @@ -402,7 +406,7 @@ TEST_F(TransportClientSocketPoolTest, ConnectCancelConnect) { TestCompletionCallback callback2; EXPECT_EQ(ERR_IO_PENDING, - handle.Init("a", params_, kDefaultPriority, + handle.Init("a", params_, kDefaultPriority, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback2.callback(), &pool_, NetLogWithSource())); @@ -515,7 +519,7 @@ class RequestSocketCallback : public TestCompletionCallbackBase { scoped_refptr<TransportSocketParams> dest(new TransportSocketParams( HostPortPair("www.google.com", 80), false, OnHostResolutionCallback(), TransportSocketParams::COMBINE_CONNECT_AND_WRITE_DEFAULT)); - int rv = handle_->Init("a", dest, LOWEST, + int rv = handle_->Init("a", dest, LOWEST, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback(), pool_, NetLogWithSource()); EXPECT_THAT(rv, IsOk()); @@ -536,9 +540,9 @@ TEST_F(TransportClientSocketPoolTest, RequestTwice) { scoped_refptr<TransportSocketParams> dest(new TransportSocketParams( HostPortPair("www.google.com", 80), false, OnHostResolutionCallback(), TransportSocketParams::COMBINE_CONNECT_AND_WRITE_DEFAULT)); - int rv = - handle.Init("a", dest, LOWEST, ClientSocketPool::RespectLimits::ENABLED, - callback.callback(), &pool_, NetLogWithSource()); + int rv = handle.Init("a", dest, LOWEST, SocketTag(), + ClientSocketPool::RespectLimits::ENABLED, + callback.callback(), &pool_, NetLogWithSource()); ASSERT_THAT(rv, IsError(ERR_IO_PENDING)); // The callback is going to request "www.google.com". We want it to complete @@ -601,9 +605,9 @@ TEST_F(TransportClientSocketPoolTest, FailingActiveRequestWithPendingRequests) { TEST_F(TransportClientSocketPoolTest, IdleSocketLoadTiming) { TestCompletionCallback callback; ClientSocketHandle handle; - int rv = - handle.Init("a", params_, LOW, ClientSocketPool::RespectLimits::ENABLED, - callback.callback(), &pool_, NetLogWithSource()); + int rv = handle.Init("a", params_, LOW, SocketTag(), + ClientSocketPool::RespectLimits::ENABLED, + callback.callback(), &pool_, NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); EXPECT_FALSE(handle.is_initialized()); EXPECT_FALSE(handle.socket()); @@ -620,7 +624,8 @@ TEST_F(TransportClientSocketPoolTest, IdleSocketLoadTiming) { // Now we should have 1 idle socket. EXPECT_EQ(1, pool_.IdleSocketCount()); - rv = handle.Init("a", params_, LOW, ClientSocketPool::RespectLimits::ENABLED, + rv = handle.Init("a", params_, LOW, SocketTag(), + ClientSocketPool::RespectLimits::ENABLED, callback.callback(), &pool_, NetLogWithSource()); EXPECT_THAT(rv, IsOk()); EXPECT_EQ(0, pool_.IdleSocketCount()); @@ -630,9 +635,9 @@ TEST_F(TransportClientSocketPoolTest, IdleSocketLoadTiming) { TEST_F(TransportClientSocketPoolTest, ResetIdleSocketsOnIPAddressChange) { TestCompletionCallback callback; ClientSocketHandle handle; - int rv = - handle.Init("a", params_, LOW, ClientSocketPool::RespectLimits::ENABLED, - callback.callback(), &pool_, NetLogWithSource()); + int rv = handle.Init("a", params_, LOW, SocketTag(), + ClientSocketPool::RespectLimits::ENABLED, + callback.callback(), &pool_, NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); EXPECT_FALSE(handle.is_initialized()); EXPECT_FALSE(handle.socket()); @@ -687,9 +692,9 @@ TEST_F(TransportClientSocketPoolTest, BackupSocketConnect) { TestCompletionCallback callback; ClientSocketHandle handle; - int rv = - handle.Init("b", params_, LOW, ClientSocketPool::RespectLimits::ENABLED, - callback.callback(), &pool_, NetLogWithSource()); + int rv = handle.Init("b", params_, LOW, SocketTag(), + ClientSocketPool::RespectLimits::ENABLED, + callback.callback(), &pool_, NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); EXPECT_FALSE(handle.is_initialized()); EXPECT_FALSE(handle.socket()); @@ -730,9 +735,9 @@ TEST_F(TransportClientSocketPoolTest, BackupSocketCancel) { TestCompletionCallback callback; ClientSocketHandle handle; - int rv = - handle.Init("c", params_, LOW, ClientSocketPool::RespectLimits::ENABLED, - callback.callback(), &pool_, NetLogWithSource()); + int rv = handle.Init("c", params_, LOW, SocketTag(), + ClientSocketPool::RespectLimits::ENABLED, + callback.callback(), &pool_, NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); EXPECT_FALSE(handle.is_initialized()); EXPECT_FALSE(handle.socket()); @@ -777,9 +782,9 @@ TEST_F(TransportClientSocketPoolTest, BackupSocketFailAfterStall) { TestCompletionCallback callback; ClientSocketHandle handle; - int rv = - handle.Init("b", params_, LOW, ClientSocketPool::RespectLimits::ENABLED, - callback.callback(), &pool_, NetLogWithSource()); + int rv = handle.Init("b", params_, LOW, SocketTag(), + ClientSocketPool::RespectLimits::ENABLED, + callback.callback(), &pool_, NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); EXPECT_FALSE(handle.is_initialized()); EXPECT_FALSE(handle.socket()); @@ -829,9 +834,9 @@ TEST_F(TransportClientSocketPoolTest, BackupSocketFailAfterDelay) { TestCompletionCallback callback; ClientSocketHandle handle; - int rv = - handle.Init("b", params_, LOW, ClientSocketPool::RespectLimits::ENABLED, - callback.callback(), &pool_, NetLogWithSource()); + int rv = handle.Init("b", params_, LOW, SocketTag(), + ClientSocketPool::RespectLimits::ENABLED, + callback.callback(), &pool_, NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); EXPECT_FALSE(handle.is_initialized()); EXPECT_FALSE(handle.socket()); @@ -886,9 +891,9 @@ TEST_F(TransportClientSocketPoolTest, IPv6FallbackSocketIPv4FinishesFirst) { TestCompletionCallback callback; ClientSocketHandle handle; - int rv = - handle.Init("a", params_, LOW, ClientSocketPool::RespectLimits::ENABLED, - callback.callback(), &pool, NetLogWithSource()); + int rv = handle.Init("a", params_, LOW, SocketTag(), + ClientSocketPool::RespectLimits::ENABLED, + callback.callback(), &pool, NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); EXPECT_FALSE(handle.is_initialized()); EXPECT_FALSE(handle.socket()); @@ -937,9 +942,9 @@ TEST_F(TransportClientSocketPoolTest, IPv6FallbackSocketIPv6FinishesFirst) { TestCompletionCallback callback; ClientSocketHandle handle; - int rv = - handle.Init("a", params_, LOW, ClientSocketPool::RespectLimits::ENABLED, - callback.callback(), &pool, NetLogWithSource()); + int rv = handle.Init("a", params_, LOW, SocketTag(), + ClientSocketPool::RespectLimits::ENABLED, + callback.callback(), &pool, NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); EXPECT_FALSE(handle.is_initialized()); EXPECT_FALSE(handle.socket()); @@ -978,9 +983,9 @@ TEST_F(TransportClientSocketPoolTest, IPv6NoIPv4AddressesToFallbackTo) { TestCompletionCallback callback; ClientSocketHandle handle; - int rv = - handle.Init("a", params_, LOW, ClientSocketPool::RespectLimits::ENABLED, - callback.callback(), &pool, NetLogWithSource()); + int rv = handle.Init("a", params_, LOW, SocketTag(), + ClientSocketPool::RespectLimits::ENABLED, + callback.callback(), &pool, NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); EXPECT_FALSE(handle.is_initialized()); EXPECT_FALSE(handle.socket()); @@ -1010,9 +1015,9 @@ TEST_F(TransportClientSocketPoolTest, IPv4HasNoFallback) { TestCompletionCallback callback; ClientSocketHandle handle; - int rv = - handle.Init("a", params_, LOW, ClientSocketPool::RespectLimits::ENABLED, - callback.callback(), &pool, NetLogWithSource()); + int rv = handle.Init("a", params_, LOW, SocketTag(), + ClientSocketPool::RespectLimits::ENABLED, + callback.callback(), &pool, NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); EXPECT_FALSE(handle.is_initialized()); EXPECT_FALSE(handle.socket()); @@ -1044,8 +1049,9 @@ TEST_F(TransportClientSocketPoolTest, TCPFastOpenOnIPv4WithNoFallback) { ClientSocketHandle handle; // Enable TCP FastOpen in TransportSocketParams. scoped_refptr<TransportSocketParams> params = CreateParamsForTCPFastOpen(); - handle.Init("a", params, LOW, ClientSocketPool::RespectLimits::ENABLED, - callback.callback(), &pool, NetLogWithSource()); + handle.Init("a", params, LOW, SocketTag(), + ClientSocketPool::RespectLimits::ENABLED, callback.callback(), + &pool, NetLogWithSource()); EXPECT_THAT(callback.WaitForResult(), IsOk()); EXPECT_TRUE(socket_data.IsUsingTCPFastOpen()); } @@ -1070,8 +1076,9 @@ TEST_F(TransportClientSocketPoolTest, TCPFastOpenOnIPv6WithNoFallback) { ClientSocketHandle handle; // Enable TCP FastOpen in TransportSocketParams. scoped_refptr<TransportSocketParams> params = CreateParamsForTCPFastOpen(); - handle.Init("a", params, LOW, ClientSocketPool::RespectLimits::ENABLED, - callback.callback(), &pool, NetLogWithSource()); + handle.Init("a", params, LOW, SocketTag(), + ClientSocketPool::RespectLimits::ENABLED, callback.callback(), + &pool, NetLogWithSource()); EXPECT_THAT(callback.WaitForResult(), IsOk()); EXPECT_TRUE(socket_data.IsUsingTCPFastOpen()); } @@ -1100,8 +1107,9 @@ TEST_F(TransportClientSocketPoolTest, ClientSocketHandle handle; // Enable TCP FastOpen in TransportSocketParams. scoped_refptr<TransportSocketParams> params = CreateParamsForTCPFastOpen(); - handle.Init("a", params, LOW, ClientSocketPool::RespectLimits::ENABLED, - callback.callback(), &pool, NetLogWithSource()); + handle.Init("a", params, LOW, SocketTag(), + ClientSocketPool::RespectLimits::ENABLED, callback.callback(), + &pool, NetLogWithSource()); EXPECT_THAT(callback.WaitForResult(), IsOk()); // Verify that the socket used is connected to the fallback IPv4 address. IPEndPoint endpoint; @@ -1132,8 +1140,9 @@ TEST_F(TransportClientSocketPoolTest, ClientSocketHandle handle; // Enable TCP FastOpen in TransportSocketParams. scoped_refptr<TransportSocketParams> params = CreateParamsForTCPFastOpen(); - handle.Init("a", params, LOW, ClientSocketPool::RespectLimits::ENABLED, - callback.callback(), &pool, NetLogWithSource()); + handle.Init("a", params, LOW, SocketTag(), + ClientSocketPool::RespectLimits::ENABLED, callback.callback(), + &pool, NetLogWithSource()); EXPECT_THAT(callback.WaitForResult(), IsOk()); IPEndPoint endpoint; handle.socket()->GetPeerAddress(&endpoint); @@ -1143,6 +1152,129 @@ TEST_F(TransportClientSocketPoolTest, EXPECT_FALSE(socket_data.IsUsingTCPFastOpen()); } +// Test that SocketTag passed into TransportClientSocketPool is applied to +// returned sockets. +#if defined(OS_ANDROID) +TEST_F(TransportClientSocketPoolTest, Tag) { + // Start test server. + EmbeddedTestServer test_server; + test_server.AddDefaultHandlers(base::FilePath()); + ASSERT_TRUE(test_server.Start()); + + TransportClientSocketPool pool( + kMaxSockets, kMaxSocketsPerGroup, host_resolver_.get(), + ClientSocketFactory::GetDefaultFactory(), NULL, NULL); + ClientSocketHandle handle; + int32_t tag_val1 = 0x12345678; + SocketTag tag1(SocketTag::UNSET_UID, tag_val1); + int32_t tag_val2 = 0x87654321; + SocketTag tag2(getuid(), tag_val2); + + // Test socket is tagged before connected. + uint64_t old_traffic = GetTaggedBytes(tag_val1); + scoped_refptr<TransportSocketParams> params(new TransportSocketParams( + test_server.host_port_pair(), false, OnHostResolutionCallback(), + TransportSocketParams::COMBINE_CONNECT_AND_WRITE_DEFAULT)); + TestCompletionCallback callback; + int rv = handle.Init("a", params, LOW, tag1, + ClientSocketPool::RespectLimits::ENABLED, + callback.callback(), &pool, NetLogWithSource()); + EXPECT_THAT(callback.GetResult(rv), IsOk()); + EXPECT_TRUE(handle.socket()); + EXPECT_TRUE(handle.socket()->IsConnected()); + EXPECT_GT(GetTaggedBytes(tag_val1), old_traffic); + + // Test reused socket is retagged. + StreamSocket* socket = handle.socket(); + handle.Reset(); + old_traffic = GetTaggedBytes(tag_val2); + rv = handle.Init("a", params, LOW, tag2, + ClientSocketPool::RespectLimits::ENABLED, + callback.callback(), &pool, NetLogWithSource()); + EXPECT_THAT(rv, IsOk()); + EXPECT_TRUE(handle.socket()); + EXPECT_TRUE(handle.socket()->IsConnected()); + EXPECT_EQ(handle.socket(), socket); + const char kRequest[] = "GET / HTTP/1.0\n\n"; + scoped_refptr<IOBuffer> write_buffer(new StringIOBuffer(kRequest)); + rv = + handle.socket()->Write(write_buffer.get(), strlen(kRequest), + callback.callback(), TRAFFIC_ANNOTATION_FOR_TESTS); + EXPECT_EQ(static_cast<int>(strlen(kRequest)), callback.GetResult(rv)); + EXPECT_GT(GetTaggedBytes(tag_val2), old_traffic); + // Disconnect socket to prevent reuse. + handle.socket()->Disconnect(); + handle.Reset(); + + // Test connect jobs that are orphaned and then adopted, appropriately apply + // new tag. Request socket with |tag1|. + TestCompletionCallback callback2; + rv = handle.Init("a", params, LOW, tag1, + ClientSocketPool::RespectLimits::ENABLED, + callback2.callback(), &pool, NetLogWithSource()); + EXPECT_TRUE(rv == OK || rv == ERR_IO_PENDING) << "Result: " << rv; + // Abort and request socket with |tag2|. + handle.Reset(); + rv = handle.Init("a", params, LOW, tag2, + ClientSocketPool::RespectLimits::ENABLED, + callback.callback(), &pool, NetLogWithSource()); + EXPECT_THAT(callback.GetResult(rv), IsOk()); + EXPECT_TRUE(handle.socket()); + EXPECT_TRUE(handle.socket()->IsConnected()); + // Verify socket has |tag2| applied. + old_traffic = GetTaggedBytes(tag_val2); + rv = + handle.socket()->Write(write_buffer.get(), strlen(kRequest), + callback.callback(), TRAFFIC_ANNOTATION_FOR_TESTS); + EXPECT_EQ(static_cast<int>(strlen(kRequest)), callback.GetResult(rv)); + EXPECT_GT(GetTaggedBytes(tag_val2), old_traffic); + // Disconnect socket to prevent reuse. + handle.socket()->Disconnect(); + handle.Reset(); + // Eat the left over connect job from the second request. + // TODO(pauljensen): remove when crbug.com/800731 fixed. + rv = handle.Init("a", params, LOW, tag1, + ClientSocketPool::RespectLimits::ENABLED, + callback.callback(), &pool, NetLogWithSource()); + EXPECT_THAT(rv, IsOk()); + // Disconnect socket to prevent reuse. + handle.socket()->Disconnect(); + handle.Reset(); + + // Test two connect jobs of differing priorities. Start the lower priority one + // first but expect its socket to get vended to the higher priority request. + ClientSocketHandle handle_high_pri; + TestCompletionCallback callback_high_pri; + rv = handle.Init("a", params, LOW, tag1, + ClientSocketPool::RespectLimits::ENABLED, + callback.callback(), &pool, NetLogWithSource()); + EXPECT_TRUE(rv == OK || rv == ERR_IO_PENDING) << "Result: " << rv; + int rv_high_pri = handle_high_pri.Init( + "a", params, HIGHEST, tag2, ClientSocketPool::RespectLimits::ENABLED, + callback_high_pri.callback(), &pool, NetLogWithSource()); + EXPECT_THAT(callback_high_pri.GetResult(rv_high_pri), IsOk()); + EXPECT_TRUE(handle_high_pri.socket()); + EXPECT_TRUE(handle_high_pri.socket()->IsConnected()); + EXPECT_THAT(callback.GetResult(rv), IsOk()); + EXPECT_TRUE(handle.socket()); + EXPECT_TRUE(handle.socket()->IsConnected()); + // Verify |handle_high_pri| has |tag2| applied. + old_traffic = GetTaggedBytes(tag_val2); + rv = handle_high_pri.socket()->Write(write_buffer.get(), strlen(kRequest), + callback.callback(), + TRAFFIC_ANNOTATION_FOR_TESTS); + EXPECT_EQ(static_cast<int>(strlen(kRequest)), callback.GetResult(rv)); + EXPECT_GT(GetTaggedBytes(tag_val2), old_traffic); + // Verify |handle| has |tag1| applied. + old_traffic = GetTaggedBytes(tag_val1); + rv = + handle.socket()->Write(write_buffer.get(), strlen(kRequest), + callback.callback(), TRAFFIC_ANNOTATION_FOR_TESTS); + EXPECT_EQ(static_cast<int>(strlen(kRequest)), callback.GetResult(rv)); + EXPECT_GT(GetTaggedBytes(tag_val1), old_traffic); +} +#endif + } // namespace } // namespace net diff --git a/chromium/net/socket/udp_client_socket.cc b/chromium/net/socket/udp_client_socket.cc index aac8ae06054..e2eccbb148c 100644 --- a/chromium/net/socket/udp_client_socket.cc +++ b/chromium/net/socket/udp_client_socket.cc @@ -5,6 +5,7 @@ #include "net/socket/udp_client_socket.h" #include "net/base/net_errors.h" +#include "net/traffic_annotation/network_traffic_annotation.h" namespace net { @@ -75,16 +76,22 @@ NetworkChangeNotifier::NetworkHandle UDPClientSocket::GetBoundNetwork() const { return network_; } +void UDPClientSocket::ApplySocketTag(const SocketTag& tag) { + socket_.ApplySocketTag(tag); +} + int UDPClientSocket::Read(IOBuffer* buf, int buf_len, const CompletionCallback& callback) { return socket_.Read(buf, buf_len, callback); } -int UDPClientSocket::Write(IOBuffer* buf, - int buf_len, - const CompletionCallback& callback) { - return socket_.Write(buf, buf_len, callback); +int UDPClientSocket::Write( + IOBuffer* buf, + int buf_len, + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& traffic_annotation) { + return socket_.Write(buf, buf_len, callback, traffic_annotation); } void UDPClientSocket::Close() { diff --git a/chromium/net/socket/udp_client_socket.h b/chromium/net/socket/udp_client_socket.h index 1a7adc43123..986898c51ba 100644 --- a/chromium/net/socket/udp_client_socket.h +++ b/chromium/net/socket/udp_client_socket.h @@ -12,6 +12,7 @@ #include "net/base/rand_callback.h" #include "net/socket/datagram_client_socket.h" #include "net/socket/udp_socket.h" +#include "net/traffic_annotation/network_traffic_annotation.h" namespace net { @@ -33,12 +34,14 @@ class NET_EXPORT_PRIVATE UDPClientSocket : public DatagramClientSocket { const IPEndPoint& address) override; int ConnectUsingDefaultNetwork(const IPEndPoint& address) override; NetworkChangeNotifier::NetworkHandle GetBoundNetwork() const override; + void ApplySocketTag(const SocketTag& tag) override; int Read(IOBuffer* buf, int buf_len, const CompletionCallback& callback) override; int Write(IOBuffer* buf, int buf_len, - const CompletionCallback& callback) override; + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& traffic_annotation) override; void Close() override; int GetPeerAddress(IPEndPoint* address) const override; int GetLocalAddress(IPEndPoint* address) const override; diff --git a/chromium/net/socket/udp_socket_perftest.cc b/chromium/net/socket/udp_socket_perftest.cc index 190e157caac..25f0ba349a3 100644 --- a/chromium/net/socket/udp_socket_perftest.cc +++ b/chromium/net/socket/udp_socket_perftest.cc @@ -17,6 +17,7 @@ #include "net/socket/udp_socket.h" #include "net/test/gtest_util.h" #include "net/test/net_test_suite.h" +#include "net/traffic_annotation/network_traffic_annotation_test_helper.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/platform_test.h" @@ -75,7 +76,8 @@ void UDPSocketPerfTest::WritePacketsToSocket(UDPClientSocket* socket, socket->Write(io_buffer.get(), io_buffer->size(), base::Bind(&UDPSocketPerfTest::DoneWritePacketsToSocket, weak_factory_.GetWeakPtr(), socket, - num_of_packets - 1, done_callback)); + num_of_packets - 1, done_callback), + TRAFFIC_ANNOTATION_FOR_TESTS); if (rv == ERR_IO_PENDING) break; --num_of_packets; diff --git a/chromium/net/socket/udp_socket_posix.cc b/chromium/net/socket/udp_socket_posix.cc index b0dfc16e883..f67eff8201d 100644 --- a/chromium/net/socket/udp_socket_posix.cc +++ b/chromium/net/socket/udp_socket_posix.cc @@ -17,7 +17,7 @@ #include "base/files/file_util.h" #include "base/logging.h" #include "base/message_loop/message_loop.h" -#include "base/metrics/histogram_macros.h" +#include "base/metrics/histogram_functions.h" #include "base/posix/eintr_wrapper.h" #include "base/rand_util.h" #include "base/trace_event/trace_event.h" @@ -35,12 +35,12 @@ #include "net/log/net_log_source_type.h" #include "net/socket/socket_descriptor.h" #include "net/socket/socket_options.h" +#include "net/socket/socket_tag.h" #include "net/socket/udp_net_log_parameters.h" +#include "net/traffic_annotation/network_traffic_annotation.h" #if defined(OS_ANDROID) #include <dlfcn.h> -// This was added in Lollipop to dlfcn.h -#define RTLD_NOLOAD 4 #include "base/android/build_info.h" #include "base/native_library.h" #include "base/strings/utf_string_conversions.h" @@ -235,6 +235,8 @@ int UDPSocketPosix::Open(AddressFamily address_family) { Close(); return err; } + if (tag_ != SocketTag()) + tag_.Apply(socket_); return OK; } @@ -323,6 +325,7 @@ void UDPSocketPosix::Close() { socket_ = kInvalidSocket; addr_family_ = 0; is_connected_ = false; + tag_ = SocketTag(); sent_activity_monitor_.OnClose(); received_activity_monitor_.OnClose(); @@ -408,9 +411,11 @@ int UDPSocketPosix::RecvFrom(IOBuffer* buf, return ERR_IO_PENDING; } -int UDPSocketPosix::Write(IOBuffer* buf, - int buf_len, - const CompletionCallback& callback) { +int UDPSocketPosix::Write( + IOBuffer* buf, + int buf_len, + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& traffic_annotation) { return SendToOrWrite(buf, buf_len, NULL, callback); } @@ -461,6 +466,8 @@ int UDPSocketPosix::Connect(const IPEndPoint& address) { int rv = InternalConnect(address); net_log_.EndEventWithNetErrorCode(NetLogEventType::UDP_CONNECT, rv); is_connected_ = (rv == OK); + if (rv != OK) + tag_ = SocketTag(); return rv; } @@ -481,7 +488,7 @@ int UDPSocketPosix::InternalConnect(const IPEndPoint& address) { // else connect() does the DatagramSocket::DEFAULT_BIND if (rv < 0) { - UMA_HISTOGRAM_SPARSE_SLOWLY("Net.UdpSocketRandomBindErrorCode", -rv); + base::UmaHistogramSparse("Net.UdpSocketRandomBindErrorCode", -rv); return rv; } @@ -1077,4 +1084,12 @@ void UDPSocketPosix::DetachFromThread() { DETACH_FROM_THREAD(thread_checker_); } +void UDPSocketPosix::ApplySocketTag(const SocketTag& tag) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + if (socket_ != kInvalidSocket && tag != tag_) { + tag.Apply(socket_); + } + tag_ = tag; +} + } // namespace net diff --git a/chromium/net/socket/udp_socket_posix.h b/chromium/net/socket/udp_socket_posix.h index e094c434317..fac8d127c80 100644 --- a/chromium/net/socket/udp_socket_posix.h +++ b/chromium/net/socket/udp_socket_posix.h @@ -25,12 +25,15 @@ #include "net/socket/datagram_socket.h" #include "net/socket/diff_serv_code_point.h" #include "net/socket/socket_descriptor.h" +#include "net/socket/socket_tag.h" +#include "net/traffic_annotation/network_traffic_annotation.h" namespace net { class IPAddress; class NetLog; struct NetLogSource; +class SocketTag; class NET_EXPORT UDPSocketPosix { public: @@ -126,7 +129,10 @@ class NET_EXPORT UDPSocketPosix { // Writes to the socket. // Only usable from the client-side of a UDP socket, after the socket // has been connected. - int Write(IOBuffer* buf, int buf_len, const CompletionCallback& callback); + int Write(IOBuffer* buf, + int buf_len, + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& traffic_annotation); // Reads from a socket and receive sender address information. // |buf| is the buffer to read data into. @@ -238,6 +244,9 @@ class NET_EXPORT UDPSocketPosix { // Resets the thread to be used for thread-safety checks. void DetachFromThread(); + // Apply |tag| to this socket. + void ApplySocketTag(const SocketTag& tag); + private: enum SocketOptions { SOCKET_OPTION_MULTICAST_LOOP = 1 << 0 @@ -370,6 +379,10 @@ class NET_EXPORT UDPSocketPosix { SentActivityMonitor sent_activity_monitor_; ReceivedActivityMonitor received_activity_monitor_; + // Current socket tag if |socket_| is valid, otherwise the tag to apply when + // |socket_| is opened. + SocketTag tag_; + THREAD_CHECKER(thread_checker_); DISALLOW_COPY_AND_ASSIGN(UDPSocketPosix); diff --git a/chromium/net/socket/udp_socket_unittest.cc b/chromium/net/socket/udp_socket_unittest.cc index 100d94b087e..82423090bd6 100644 --- a/chromium/net/socket/udp_socket_unittest.cc +++ b/chromium/net/socket/udp_socket_unittest.cc @@ -24,16 +24,20 @@ #include "net/log/test_net_log.h" #include "net/log/test_net_log_entry.h" #include "net/log/test_net_log_util.h" +#include "net/socket/socket_test_util.h" #include "net/socket/udp_client_socket.h" #include "net/socket/udp_server_socket.h" #include "net/test/gtest_util.h" #include "net/test/net_test_suite.h" +#include "net/traffic_annotation/network_traffic_annotation_test_helper.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/platform_test.h" #if defined(OS_ANDROID) #include "base/android/build_info.h" +#include "net/android/network_change_notifier_factory_android.h" +#include "net/base/network_change_notifier.h" #endif #if defined(OS_IOS) @@ -95,8 +99,8 @@ class UDPSocketTest : public PlatformTest { int WriteSocket(UDPClientSocket* socket, const std::string& msg) { scoped_refptr<StringIOBuffer> io_buffer(new StringIOBuffer(msg)); TestCompletionCallback callback; - int rv = - socket->Write(io_buffer.get(), io_buffer->size(), callback.callback()); + int rv = socket->Write(io_buffer.get(), io_buffer->size(), + callback.callback(), TRAFFIC_ANNOTATION_FOR_TESTS); return callback.GetResult(rv); } @@ -734,6 +738,11 @@ TEST_F(UDPSocketTest, SetDSCP) { TEST_F(UDPSocketTest, TestBindToNetwork) { UDPSocket socket(DatagramSocket::RANDOM_BIND, base::Bind(&PrivilegedRand), NULL, NetLogSource()); +#if defined(OS_ANDROID) + NetworkChangeNotifierFactoryAndroid ncn_factory; + NetworkChangeNotifier::DisableForTest ncn_disable_for_test; + std::unique_ptr<NetworkChangeNotifier> ncn(ncn_factory.CreateInstance()); +#endif ASSERT_EQ(OK, socket.Open(ADDRESS_FAMILY_IPV4)); // Test unsuccessful binding, by attempting to bind to a bogus NetworkHandle. int rv = socket.BindToNetwork(65536); @@ -767,12 +776,11 @@ TEST_F(UDPSocketTest, TestBindToNetwork) { socket.BindToNetwork(NetworkChangeNotifier::kInvalidNetworkHandle)); // Test successful binding, if possible. - if (NetworkChangeNotifier::AreNetworkHandlesSupported()) { - NetworkChangeNotifier::NetworkHandle network_handle = - NetworkChangeNotifier::GetDefaultNetwork(); - if (network_handle != NetworkChangeNotifier::kInvalidNetworkHandle) { - EXPECT_EQ(OK, socket.BindToNetwork(network_handle)); - } + EXPECT_TRUE(NetworkChangeNotifier::AreNetworkHandlesSupported()); + NetworkChangeNotifier::NetworkHandle network_handle = + NetworkChangeNotifier::GetDefaultNetwork(); + if (network_handle != NetworkChangeNotifier::kInvalidNetworkHandle) { + EXPECT_EQ(OK, socket.BindToNetwork(network_handle)); } } #endif @@ -903,4 +911,77 @@ TEST_F(UDPSocketTest, SetDSCPFake) { } #endif +// On Android, where socket tagging is supported, verify that UDPSocket::Tag +// works as expected. +#if defined(OS_ANDROID) +TEST_F(UDPSocketTest, Tag) { + UDPServerSocket server(nullptr, NetLogSource()); + ASSERT_THAT(server.Listen(IPEndPoint(IPAddress::IPv4Localhost(), 0)), IsOk()); + IPEndPoint server_address; + ASSERT_THAT(server.GetLocalAddress(&server_address), IsOk()); + + UDPClientSocket client(DatagramSocket::DEFAULT_BIND, RandIntCallback(), + nullptr, NetLogSource()); + ASSERT_THAT(client.Connect(server_address), IsOk()); + + // Verify UDP packets are tagged and counted properly. + int32_t tag_val1 = 0x12345678; + uint64_t old_traffic = GetTaggedBytes(tag_val1); + SocketTag tag1(SocketTag::UNSET_UID, tag_val1); + client.ApplySocketTag(tag1); + // Client sends to the server. + std::string simple_message("hello world!"); + int rv = WriteSocket(&client, simple_message); + EXPECT_EQ(simple_message.length(), static_cast<size_t>(rv)); + // Server waits for message. + std::string str = RecvFromSocket(&server); + EXPECT_EQ(simple_message, str); + // Server echoes reply. + rv = SendToSocket(&server, simple_message); + EXPECT_EQ(simple_message.length(), static_cast<size_t>(rv)); + // Client waits for response. + str = ReadSocket(&client); + EXPECT_EQ(simple_message, str); + EXPECT_GT(GetTaggedBytes(tag_val1), old_traffic); + + // Verify socket can be retagged with a new value and the current process's + // UID. + int32_t tag_val2 = 0x87654321; + old_traffic = GetTaggedBytes(tag_val2); + SocketTag tag2(getuid(), tag_val2); + client.ApplySocketTag(tag2); + // Client sends to the server. + rv = WriteSocket(&client, simple_message); + EXPECT_EQ(simple_message.length(), static_cast<size_t>(rv)); + // Server waits for message. + str = RecvFromSocket(&server); + EXPECT_EQ(simple_message, str); + // Server echoes reply. + rv = SendToSocket(&server, simple_message); + EXPECT_EQ(simple_message.length(), static_cast<size_t>(rv)); + // Client waits for response. + str = ReadSocket(&client); + EXPECT_EQ(simple_message, str); + EXPECT_GT(GetTaggedBytes(tag_val2), old_traffic); + + // Verify socket can be retagged with a new value and the current process's + // UID. + old_traffic = GetTaggedBytes(tag_val1); + client.ApplySocketTag(tag1); + // Client sends to the server. + rv = WriteSocket(&client, simple_message); + EXPECT_EQ(simple_message.length(), static_cast<size_t>(rv)); + // Server waits for message. + str = RecvFromSocket(&server); + EXPECT_EQ(simple_message, str); + // Server echoes reply. + rv = SendToSocket(&server, simple_message); + EXPECT_EQ(simple_message.length(), static_cast<size_t>(rv)); + // Client waits for response. + str = ReadSocket(&client); + EXPECT_EQ(simple_message, str); + EXPECT_GT(GetTaggedBytes(tag_val1), old_traffic); +} +#endif + } // namespace net diff --git a/chromium/net/socket/udp_socket_win.cc b/chromium/net/socket/udp_socket_win.cc index e030cdc91ca..7790d6a4176 100644 --- a/chromium/net/socket/udp_socket_win.cc +++ b/chromium/net/socket/udp_socket_win.cc @@ -11,8 +11,8 @@ #include "base/logging.h" #include "base/macros.h" #include "base/message_loop/message_loop.h" +#include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" -#include "base/metrics/sparse_histogram.h" #include "base/rand_util.h" #include "net/base/io_buffer.h" #include "net/base/ip_address.h" @@ -29,7 +29,9 @@ #include "net/log/net_log_source_type.h" #include "net/socket/socket_descriptor.h" #include "net/socket/socket_options.h" +#include "net/socket/socket_tag.h" #include "net/socket/udp_net_log_parameters.h" +#include "net/traffic_annotation/network_traffic_annotation.h" namespace { @@ -405,9 +407,11 @@ int UDPSocketWin::RecvFrom(IOBuffer* buf, return ERR_IO_PENDING; } -int UDPSocketWin::Write(IOBuffer* buf, - int buf_len, - const CompletionCallback& callback) { +int UDPSocketWin::Write( + IOBuffer* buf, + int buf_len, + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& /* traffic_annotation */) { return SendToOrWrite(buf, buf_len, remote_address_.get(), callback); } @@ -468,7 +472,7 @@ int UDPSocketWin::InternalConnect(const IPEndPoint& address) { // else connect() does the DatagramSocket::DEFAULT_BIND if (rv < 0) { - UMA_HISTOGRAM_SPARSE_SLOWLY("Net.UdpSocketRandomBindErrorCode", -rv); + base::UmaHistogramSparse("Net.UdpSocketRandomBindErrorCode", -rv); return rv; } @@ -1215,4 +1219,10 @@ void UDPSocketWin::UseNonBlockingIO() { use_non_blocking_io_ = true; } +void UDPSocketWin::ApplySocketTag(const SocketTag& tag) { + // Windows does not support any specific SocketTags so fail if any non-default + // tag is applied. + CHECK(tag == SocketTag()); +} + } // namespace net diff --git a/chromium/net/socket/udp_socket_win.h b/chromium/net/socket/udp_socket_win.h index 8af9850d82b..71094d4dbde 100644 --- a/chromium/net/socket/udp_socket_win.h +++ b/chromium/net/socket/udp_socket_win.h @@ -28,12 +28,14 @@ #include "net/log/net_log_with_source.h" #include "net/socket/datagram_socket.h" #include "net/socket/diff_serv_code_point.h" +#include "net/traffic_annotation/network_traffic_annotation.h" namespace net { class IPAddress; class NetLog; struct NetLogSource; +class SocketTag; class NET_EXPORT UDPSocketWin : public base::win::ObjectWatcher::Delegate { public: @@ -87,7 +89,10 @@ class NET_EXPORT UDPSocketWin : public base::win::ObjectWatcher::Delegate { // Writes to the socket. // Only usable from the client-side of a UDP socket, after the socket // has been connected. - int Write(IOBuffer* buf, int buf_len, const CompletionCallback& callback); + int Write(IOBuffer* buf, + int buf_len, + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& traffic_annotation); // Reads from a socket and receive sender address information. // |buf| is the buffer to read data into. @@ -200,6 +205,9 @@ class NET_EXPORT UDPSocketWin : public base::win::ObjectWatcher::Delegate { // to switch to non-blocking IO. void UseNonBlockingIO(); + // Apply |tag| to this socket. + void ApplySocketTag(const SocketTag& tag); + private: enum SocketOptions { SOCKET_OPTION_MULTICAST_LOOP = 1 << 0 diff --git a/chromium/net/socket/unix_domain_client_socket_posix.cc b/chromium/net/socket/unix_domain_client_socket_posix.cc index 037b0728dbc..72bf717bd3f 100644 --- a/chromium/net/socket/unix_domain_client_socket_posix.cc +++ b/chromium/net/socket/unix_domain_client_socket_posix.cc @@ -12,6 +12,7 @@ #include "net/base/net_errors.h" #include "net/base/sockaddr_storage.h" #include "net/socket/socket_posix.h" +#include "net/traffic_annotation/network_traffic_annotation.h" namespace net { @@ -154,16 +155,23 @@ int64_t UnixDomainClientSocket::GetTotalReceivedBytes() const { return 0; } +void UnixDomainClientSocket::ApplySocketTag(const SocketTag& tag) { + // Ignore socket tags as Unix domain sockets are local only. +} + int UnixDomainClientSocket::Read(IOBuffer* buf, int buf_len, const CompletionCallback& callback) { DCHECK(socket_); return socket_->Read(buf, buf_len, callback); } -int UnixDomainClientSocket::Write(IOBuffer* buf, int buf_len, - const CompletionCallback& callback) { +int UnixDomainClientSocket::Write( + IOBuffer* buf, + int buf_len, + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& traffic_annotation) { DCHECK(socket_); - return socket_->Write(buf, buf_len, callback); + return socket_->Write(buf, buf_len, callback, traffic_annotation); } int UnixDomainClientSocket::SetReceiveBufferSize(int32_t size) { diff --git a/chromium/net/socket/unix_domain_client_socket_posix.h b/chromium/net/socket/unix_domain_client_socket_posix.h index 47fb4fe2e8d..dbc513c3f9d 100644 --- a/chromium/net/socket/unix_domain_client_socket_posix.h +++ b/chromium/net/socket/unix_domain_client_socket_posix.h @@ -16,6 +16,7 @@ #include "net/log/net_log_with_source.h" #include "net/socket/socket_descriptor.h" #include "net/socket/stream_socket.h" +#include "net/traffic_annotation/network_traffic_annotation.h" namespace net { @@ -59,6 +60,7 @@ class NET_EXPORT UnixDomainClientSocket : public StreamSocket { void ClearConnectionAttempts() override {} void AddConnectionAttempts(const ConnectionAttempts& attempts) override {} int64_t GetTotalReceivedBytes() const override; + void ApplySocketTag(const SocketTag& tag) override; // Socket implementation. int Read(IOBuffer* buf, @@ -66,7 +68,8 @@ class NET_EXPORT UnixDomainClientSocket : public StreamSocket { const CompletionCallback& callback) override; int Write(IOBuffer* buf, int buf_len, - const CompletionCallback& callback) override; + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& traffic_annotation) override; int SetReceiveBufferSize(int32_t size) override; int SetSendBufferSize(int32_t size) override; diff --git a/chromium/net/socket/websocket_endpoint_lock_manager_unittest.cc b/chromium/net/socket/websocket_endpoint_lock_manager_unittest.cc index e7143ce3895..c80e780f3c1 100644 --- a/chromium/net/socket/websocket_endpoint_lock_manager_unittest.cc +++ b/chromium/net/socket/websocket_endpoint_lock_manager_unittest.cc @@ -16,6 +16,7 @@ #include "net/socket/socket_test_util.h" #include "net/socket/stream_socket.h" #include "net/test/gtest_util.h" +#include "net/traffic_annotation/network_traffic_annotation.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -73,6 +74,8 @@ class FakeStreamSocket : public StreamSocket { return 0; } + void ApplySocketTag(const SocketTag& tag) override {} + // Socket implementation int Read(IOBuffer* buf, int buf_len, @@ -82,7 +85,8 @@ class FakeStreamSocket : public StreamSocket { int Write(IOBuffer* buf, int buf_len, - const CompletionCallback& callback) override { + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& traffic_annotation) override { return ERR_FAILED; } diff --git a/chromium/net/socket/websocket_transport_client_socket_pool.cc b/chromium/net/socket/websocket_transport_client_socket_pool.cc index 3eb1bfc8a3c..5ef8809159a 100644 --- a/chromium/net/socket/websocket_transport_client_socket_pool.cc +++ b/chromium/net/socket/websocket_transport_client_socket_pool.cc @@ -45,6 +45,7 @@ WebSocketTransportConnectJob::WebSocketTransportConnectJob( : ConnectJob(group_name, timeout_duration, priority, + SocketTag(), respect_limits, delegate, NetLogWithSource::Make( @@ -324,6 +325,7 @@ int WebSocketTransportClientSocketPool::RequestSocket( const std::string& group_name, const void* params, RequestPriority priority, + const SocketTag& socket_tag, RespectLimits respect_limits, ClientSocketHandle* handle, const CompletionCallback& callback, @@ -339,6 +341,8 @@ int WebSocketTransportClientSocketPool::RequestSocket( request_net_log.BeginEvent(NetLogEventType::SOCKET_POOL); + DCHECK(socket_tag == SocketTag()); + if (ReachedMaxSocketsLimit() && respect_limits == ClientSocketPool::RespectLimits::ENABLED) { request_net_log.AddEvent(NetLogEventType::SOCKET_POOL_STALLED_MAX_SOCKETS); @@ -666,11 +670,12 @@ void WebSocketTransportClientSocketPool::ActivateStalledRequest() { stalled_request_queue_.pop_front(); stalled_request_map_.erase(request.handle); - int rv = RequestSocket("ignored", &request.params, request.priority, - // Stalled requests can't have |respect_limits| - // DISABLED. - RespectLimits::ENABLED, request.handle, - request.callback, request.net_log); + int rv = + RequestSocket("ignored", &request.params, request.priority, SocketTag(), + // Stalled requests can't have |respect_limits| + // DISABLED. + RespectLimits::ENABLED, request.handle, request.callback, + request.net_log); // ActivateStalledRequest() never returns synchronously, so it is never // called re-entrantly. diff --git a/chromium/net/socket/websocket_transport_client_socket_pool.h b/chromium/net/socket/websocket_transport_client_socket_pool.h index b6d73928937..c8248812f81 100644 --- a/chromium/net/socket/websocket_transport_client_socket_pool.h +++ b/chromium/net/socket/websocket_transport_client_socket_pool.h @@ -155,6 +155,7 @@ class NET_EXPORT_PRIVATE WebSocketTransportClientSocketPool int RequestSocket(const std::string& group_name, const void* resolve_info, RequestPriority priority, + const SocketTag& socket_tag, RespectLimits respect_limits, ClientSocketHandle* handle, const CompletionCallback& callback, diff --git a/chromium/net/socket/websocket_transport_client_socket_pool_unittest.cc b/chromium/net/socket/websocket_transport_client_socket_pool_unittest.cc index e8f78794a0e..65a51cfec93 100644 --- a/chromium/net/socket/websocket_transport_client_socket_pool_unittest.cc +++ b/chromium/net/socket/websocket_transport_client_socket_pool_unittest.cc @@ -24,6 +24,7 @@ #include "net/dns/mock_host_resolver.h" #include "net/log/test_net_log.h" #include "net/socket/client_socket_handle.h" +#include "net/socket/socket_tag.h" #include "net/socket/socket_test_util.h" #include "net/socket/stream_socket.h" #include "net/socket/transport_client_socket_pool_test_util.h" @@ -79,12 +80,9 @@ class WebSocketTransportClientSocketPoolTest : public ::testing::Test { static void RunUntilIdle() { base::RunLoop().RunUntilIdle(); } int StartRequest(const std::string& group_name, RequestPriority priority) { - scoped_refptr<TransportSocketParams> params( - new TransportSocketParams( - HostPortPair("www.google.com", 80), - false, - OnHostResolutionCallback(), - TransportSocketParams::COMBINE_CONNECT_AND_WRITE_DEFAULT)); + scoped_refptr<TransportSocketParams> params(new TransportSocketParams( + HostPortPair("www.google.com", 80), false, OnHostResolutionCallback(), + TransportSocketParams::COMBINE_CONNECT_AND_WRITE_DEFAULT)); return test_base_.StartRequestUsingPool( &pool_, group_name, priority, ClientSocketPool::RespectLimits::ENABLED, params); @@ -124,9 +122,9 @@ class WebSocketTransportClientSocketPoolTest : public ::testing::Test { TEST_F(WebSocketTransportClientSocketPoolTest, Basic) { TestCompletionCallback callback; ClientSocketHandle handle; - int rv = - handle.Init("a", params_, LOW, ClientSocketPool::RespectLimits::ENABLED, - callback.callback(), &pool_, NetLogWithSource()); + int rv = handle.Init("a", params_, LOW, SocketTag(), + ClientSocketPool::RespectLimits::ENABLED, + callback.callback(), &pool_, NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); EXPECT_FALSE(handle.is_initialized()); EXPECT_FALSE(handle.socket()); @@ -145,7 +143,7 @@ TEST_F(WebSocketTransportClientSocketPoolTest, SetResolvePriorityOnInit) { TestCompletionCallback callback; ClientSocketHandle handle; EXPECT_EQ(ERR_IO_PENDING, - handle.Init("a", params_, priority, + handle.Init("a", params_, priority, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), &pool_, NetLogWithSource())); EXPECT_EQ(priority, host_resolver_->last_request_priority()); @@ -161,7 +159,7 @@ TEST_F(WebSocketTransportClientSocketPoolTest, InitHostResolutionFailure) { host_port_pair, false, OnHostResolutionCallback(), TransportSocketParams::COMBINE_CONNECT_AND_WRITE_DEFAULT)); EXPECT_EQ(ERR_IO_PENDING, - handle.Init("a", dest, kDefaultPriority, + handle.Init("a", dest, kDefaultPriority, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), &pool_, NetLogWithSource())); EXPECT_THAT(callback.WaitForResult(), IsError(ERR_NAME_NOT_RESOLVED)); @@ -173,7 +171,7 @@ TEST_F(WebSocketTransportClientSocketPoolTest, InitConnectionFailure) { TestCompletionCallback callback; ClientSocketHandle handle; EXPECT_EQ(ERR_IO_PENDING, - handle.Init("a", params_, kDefaultPriority, + handle.Init("a", params_, kDefaultPriority, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), &pool_, NetLogWithSource())); EXPECT_THAT(callback.WaitForResult(), IsError(ERR_CONNECTION_FAILED)); @@ -181,7 +179,7 @@ TEST_F(WebSocketTransportClientSocketPoolTest, InitConnectionFailure) { // Make the host resolutions complete synchronously this time. host_resolver_->set_synchronous_mode(true); EXPECT_EQ(ERR_CONNECTION_FAILED, - handle.Init("a", params_, kDefaultPriority, + handle.Init("a", params_, kDefaultPriority, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), &pool_, NetLogWithSource())); } @@ -258,7 +256,7 @@ TEST_F(WebSocketTransportClientSocketPoolTest, CancelRequestClearGroup) { TestCompletionCallback callback; ClientSocketHandle handle; EXPECT_EQ(ERR_IO_PENDING, - handle.Init("a", params_, kDefaultPriority, + handle.Init("a", params_, kDefaultPriority, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), &pool_, NetLogWithSource())); handle.Reset(); @@ -271,11 +269,11 @@ TEST_F(WebSocketTransportClientSocketPoolTest, TwoRequestsCancelOne) { TestCompletionCallback callback2; EXPECT_EQ(ERR_IO_PENDING, - handle.Init("a", params_, kDefaultPriority, + handle.Init("a", params_, kDefaultPriority, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), &pool_, NetLogWithSource())); EXPECT_EQ(ERR_IO_PENDING, - handle2.Init("a", params_, kDefaultPriority, + handle2.Init("a", params_, kDefaultPriority, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback2.callback(), &pool_, NetLogWithSource())); @@ -291,7 +289,7 @@ TEST_F(WebSocketTransportClientSocketPoolTest, ConnectCancelConnect) { ClientSocketHandle handle; TestCompletionCallback callback; EXPECT_EQ(ERR_IO_PENDING, - handle.Init("a", params_, kDefaultPriority, + handle.Init("a", params_, kDefaultPriority, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), &pool_, NetLogWithSource())); @@ -299,7 +297,7 @@ TEST_F(WebSocketTransportClientSocketPoolTest, ConnectCancelConnect) { TestCompletionCallback callback2; EXPECT_EQ(ERR_IO_PENDING, - handle.Init("a", params_, kDefaultPriority, + handle.Init("a", params_, kDefaultPriority, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback2.callback(), &pool_, NetLogWithSource())); @@ -373,9 +371,9 @@ void RequestSocketOnComplete(ClientSocketHandle* handle, scoped_refptr<TransportSocketParams> dest(new TransportSocketParams( HostPortPair("www.google.com", 80), false, OnHostResolutionCallback(), TransportSocketParams::COMBINE_CONNECT_AND_WRITE_DEFAULT)); - int rv = - handle->Init("a", dest, LOWEST, ClientSocketPool::RespectLimits::ENABLED, - nested_callback, pool, NetLogWithSource()); + int rv = handle->Init("a", dest, LOWEST, SocketTag(), + ClientSocketPool::RespectLimits::ENABLED, + nested_callback, pool, NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); if (ERR_IO_PENDING != rv) nested_callback.Run(rv); @@ -386,18 +384,15 @@ void RequestSocketOnComplete(ClientSocketHandle* handle, // ClientSocketHandle for the second socket, after disconnecting the first. TEST_F(WebSocketTransportClientSocketPoolTest, RequestTwice) { ClientSocketHandle handle; - scoped_refptr<TransportSocketParams> dest( - new TransportSocketParams( - HostPortPair("www.google.com", 80), - false, - OnHostResolutionCallback(), - TransportSocketParams::COMBINE_CONNECT_AND_WRITE_DEFAULT)); + scoped_refptr<TransportSocketParams> dest(new TransportSocketParams( + HostPortPair("www.google.com", 80), false, OnHostResolutionCallback(), + TransportSocketParams::COMBINE_CONNECT_AND_WRITE_DEFAULT)); TestCompletionCallback second_result_callback; - int rv = - handle.Init("a", dest, LOWEST, ClientSocketPool::RespectLimits::ENABLED, - base::Bind(&RequestSocketOnComplete, &handle, &pool_, - second_result_callback.callback()), - &pool_, NetLogWithSource()); + int rv = handle.Init("a", dest, LOWEST, SocketTag(), + ClientSocketPool::RespectLimits::ENABLED, + base::Bind(&RequestSocketOnComplete, &handle, &pool_, + second_result_callback.callback()), + &pool_, NetLogWithSource()); ASSERT_THAT(rv, IsError(ERR_IO_PENDING)); EXPECT_THAT(second_result_callback.WaitForResult(), IsOk()); @@ -468,9 +463,9 @@ TEST_F(WebSocketTransportClientSocketPoolTest, LockReleasedOnHandleReset) { TEST_F(WebSocketTransportClientSocketPoolTest, LockReleasedOnHandleDelete) { TestCompletionCallback callback; std::unique_ptr<ClientSocketHandle> handle(new ClientSocketHandle); - int rv = - handle->Init("a", params_, LOW, ClientSocketPool::RespectLimits::ENABLED, - callback.callback(), &pool_, NetLogWithSource()); + int rv = handle->Init("a", params_, LOW, SocketTag(), + ClientSocketPool::RespectLimits::ENABLED, + callback.callback(), &pool_, NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING)); @@ -534,9 +529,9 @@ TEST_F(WebSocketTransportClientSocketPoolTest, TestCompletionCallback callback; ClientSocketHandle handle; - int rv = - handle.Init("a", params_, LOW, ClientSocketPool::RespectLimits::ENABLED, - callback.callback(), &pool, NetLogWithSource()); + int rv = handle.Init("a", params_, LOW, SocketTag(), + ClientSocketPool::RespectLimits::ENABLED, + callback.callback(), &pool, NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); EXPECT_FALSE(handle.is_initialized()); EXPECT_FALSE(handle.socket()); @@ -575,9 +570,9 @@ TEST_F(WebSocketTransportClientSocketPoolTest, TestCompletionCallback callback; ClientSocketHandle handle; - int rv = - handle.Init("a", params_, LOW, ClientSocketPool::RespectLimits::ENABLED, - callback.callback(), &pool, NetLogWithSource()); + int rv = handle.Init("a", params_, LOW, SocketTag(), + ClientSocketPool::RespectLimits::ENABLED, + callback.callback(), &pool, NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); EXPECT_FALSE(handle.is_initialized()); EXPECT_FALSE(handle.socket()); @@ -606,9 +601,9 @@ TEST_F(WebSocketTransportClientSocketPoolTest, TestCompletionCallback callback; ClientSocketHandle handle; - int rv = - handle.Init("a", params_, LOW, ClientSocketPool::RespectLimits::ENABLED, - callback.callback(), &pool, NetLogWithSource()); + int rv = handle.Init("a", params_, LOW, SocketTag(), + ClientSocketPool::RespectLimits::ENABLED, + callback.callback(), &pool, NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); EXPECT_FALSE(handle.is_initialized()); EXPECT_FALSE(handle.socket()); @@ -635,9 +630,9 @@ TEST_F(WebSocketTransportClientSocketPoolTest, IPv4HasNoFallback) { TestCompletionCallback callback; ClientSocketHandle handle; - int rv = - handle.Init("a", params_, LOW, ClientSocketPool::RespectLimits::ENABLED, - callback.callback(), &pool, NetLogWithSource()); + int rv = handle.Init("a", params_, LOW, SocketTag(), + ClientSocketPool::RespectLimits::ENABLED, + callback.callback(), &pool, NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); EXPECT_FALSE(handle.is_initialized()); EXPECT_FALSE(handle.socket()); @@ -675,9 +670,9 @@ TEST_F(WebSocketTransportClientSocketPoolTest, IPv6InstantFail) { host_resolver_->set_synchronous_mode(true); TestCompletionCallback callback; ClientSocketHandle handle; - int rv = - handle.Init("a", params_, LOW, ClientSocketPool::RespectLimits::ENABLED, - callback.callback(), &pool, NetLogWithSource()); + int rv = handle.Init("a", params_, LOW, SocketTag(), + ClientSocketPool::RespectLimits::ENABLED, + callback.callback(), &pool, NetLogWithSource()); EXPECT_THAT(rv, IsOk()); ASSERT_TRUE(handle.socket()); @@ -710,9 +705,9 @@ TEST_F(WebSocketTransportClientSocketPoolTest, IPv6RapidFail) { TestCompletionCallback callback; ClientSocketHandle handle; - int rv = - handle.Init("a", params_, LOW, ClientSocketPool::RespectLimits::ENABLED, - callback.callback(), &pool, NetLogWithSource()); + int rv = handle.Init("a", params_, LOW, SocketTag(), + ClientSocketPool::RespectLimits::ENABLED, + callback.callback(), &pool, NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); EXPECT_FALSE(handle.socket()); @@ -745,9 +740,9 @@ TEST_F(WebSocketTransportClientSocketPoolTest, FirstSuccessWins) { TestCompletionCallback callback; ClientSocketHandle handle; - int rv = - handle.Init("a", params_, LOW, ClientSocketPool::RespectLimits::ENABLED, - callback.callback(), &pool, NetLogWithSource()); + int rv = handle.Init("a", params_, LOW, SocketTag(), + ClientSocketPool::RespectLimits::ENABLED, + callback.callback(), &pool, NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); ASSERT_FALSE(handle.socket()); @@ -796,9 +791,9 @@ TEST_F(WebSocketTransportClientSocketPoolTest, LastFailureWins) { TestCompletionCallback callback; ClientSocketHandle handle; base::TimeTicks start(base::TimeTicks::Now()); - int rv = - handle.Init("a", params_, LOW, ClientSocketPool::RespectLimits::ENABLED, - callback.callback(), &pool, NetLogWithSource()); + int rv = handle.Init("a", params_, LOW, SocketTag(), + ClientSocketPool::RespectLimits::ENABLED, + callback.callback(), &pool, NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); EXPECT_THAT(callback.WaitForResult(), IsError(ERR_CONNECTION_FAILED)); @@ -832,9 +827,9 @@ TEST_F(WebSocketTransportClientSocketPoolTest, DISABLED_OverallTimeoutApplies) { TestCompletionCallback callback; ClientSocketHandle handle; - int rv = - handle.Init("a", params_, LOW, ClientSocketPool::RespectLimits::ENABLED, - callback.callback(), &pool, NetLogWithSource()); + int rv = handle.Init("a", params_, LOW, SocketTag(), + ClientSocketPool::RespectLimits::ENABLED, + callback.callback(), &pool, NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); EXPECT_THAT(callback.WaitForResult(), IsError(ERR_TIMED_OUT)); diff --git a/chromium/net/spdy/chromium/bidirectional_stream_spdy_impl_unittest.cc b/chromium/net/spdy/chromium/bidirectional_stream_spdy_impl_unittest.cc index c6f5d42c573..a92c30472e3 100644 --- a/chromium/net/spdy/chromium/bidirectional_stream_spdy_impl_unittest.cc +++ b/chromium/net/spdy/chromium/bidirectional_stream_spdy_impl_unittest.cc @@ -79,7 +79,7 @@ class TestDelegateBase : public BidirectionalStreamImpl::Delegate { not_expect_callback_(false), on_failed_called_(false) {} - ~TestDelegateBase() override {} + ~TestDelegateBase() override = default; void OnStreamReady(bool request_headers_sent) override { CHECK(!on_failed_called_); diff --git a/chromium/net/spdy/chromium/buffered_spdy_framer.cc b/chromium/net/spdy/chromium/buffered_spdy_framer.cc index 8da2d1080af..71a0eb36147 100644 --- a/chromium/net/spdy/chromium/buffered_spdy_framer.cc +++ b/chromium/net/spdy/chromium/buffered_spdy_framer.cc @@ -9,6 +9,7 @@ #include "base/logging.h" #include "base/strings/string_util.h" +#include "net/spdy/chromium/spdy_flags.h" #include "net/spdy/platform/api/spdy_estimate_memory_usage.h" namespace net { @@ -23,6 +24,7 @@ size_t kGoAwayDebugDataMaxSize = 1024; BufferedSpdyFramer::BufferedSpdyFramer(uint32_t max_header_list_size, const NetLogWithSource& net_log) : spdy_framer_(SpdyFramer::ENABLE_COMPRESSION), + deframer_(FLAGS_chromium_http2_flag_h2_on_stream_pad_length), visitor_(NULL), frames_received_(0), max_header_list_size_(max_header_list_size), @@ -32,8 +34,7 @@ BufferedSpdyFramer::BufferedSpdyFramer(uint32_t max_header_list_size, max_header_list_size_); } -BufferedSpdyFramer::~BufferedSpdyFramer() { -} +BufferedSpdyFramer::~BufferedSpdyFramer() = default; void BufferedSpdyFramer::set_visitor( BufferedSpdyFramerVisitorInterface* visitor) { @@ -90,6 +91,12 @@ void BufferedSpdyFramer::OnStreamEnd(SpdyStreamId stream_id) { visitor_->OnStreamEnd(stream_id); } +void BufferedSpdyFramer::OnStreamPadLength(SpdyStreamId stream_id, + size_t value) { + // Deliver the stream pad length byte for flow control handling. + visitor_->OnStreamPadding(stream_id, 1); +} + void BufferedSpdyFramer::OnStreamPadding(SpdyStreamId stream_id, size_t len) { visitor_->OnStreamPadding(stream_id, len); } diff --git a/chromium/net/spdy/chromium/buffered_spdy_framer.h b/chromium/net/spdy/chromium/buffered_spdy_framer.h index bdc15203a6e..84604467826 100644 --- a/chromium/net/spdy/chromium/buffered_spdy_framer.h +++ b/chromium/net/spdy/chromium/buffered_spdy_framer.h @@ -152,6 +152,7 @@ class NET_EXPORT_PRIVATE BufferedSpdyFramer const char* data, size_t len) override; void OnStreamEnd(SpdyStreamId stream_id) override; + void OnStreamPadLength(SpdyStreamId stream_id, size_t value) override; void OnStreamPadding(SpdyStreamId stream_id, size_t len) override; SpdyHeadersHandlerInterface* OnHeaderFrameStart( SpdyStreamId stream_id) override; diff --git a/chromium/net/spdy/chromium/http2_priority_dependencies.cc b/chromium/net/spdy/chromium/http2_priority_dependencies.cc index 991924e4908..5874511ea6e 100644 --- a/chromium/net/spdy/chromium/http2_priority_dependencies.cc +++ b/chromium/net/spdy/chromium/http2_priority_dependencies.cc @@ -7,16 +7,17 @@ namespace net { -Http2PriorityDependencies::Http2PriorityDependencies() {} +Http2PriorityDependencies::Http2PriorityDependencies() = default; -Http2PriorityDependencies::~Http2PriorityDependencies() {} +Http2PriorityDependencies::~Http2PriorityDependencies() = default; void Http2PriorityDependencies::OnStreamCreation( SpdyStreamId id, SpdyPriority priority, SpdyStreamId* dependent_stream_id, bool* exclusive) { - DCHECK(entry_by_stream_id_.find(id) == entry_by_stream_id_.end()); + if (entry_by_stream_id_.find(id) != entry_by_stream_id_.end()) + return; *dependent_stream_id = 0ul; *exclusive = true; @@ -97,6 +98,10 @@ Http2PriorityDependencies::OnStreamUpdate(SpdyStreamId id, result.reserve(2); EntryMap::iterator curr_entry = entry_by_stream_id_.find(id); + if (curr_entry == entry_by_stream_id_.end()) { + return result; + } + SpdyPriority old_priority = curr_entry->second->second; if (old_priority == new_priority) { return result; @@ -151,7 +156,8 @@ Http2PriorityDependencies::OnStreamUpdate(SpdyStreamId id, void Http2PriorityDependencies::OnStreamDestruction(SpdyStreamId id) { EntryMap::iterator emit = entry_by_stream_id_.find(id); - DCHECK(emit != entry_by_stream_id_.end()); + if (emit == entry_by_stream_id_.end()) + return; IdList::iterator it = emit->second; id_priority_lists_[it->second].erase(it); diff --git a/chromium/net/spdy/chromium/http2_push_promise_index.cc b/chromium/net/spdy/chromium/http2_push_promise_index.cc index 876b1ca9804..f0f280c6a95 100644 --- a/chromium/net/spdy/chromium/http2_push_promise_index.cc +++ b/chromium/net/spdy/chromium/http2_push_promise_index.cc @@ -3,91 +3,151 @@ // found in the LICENSE file. #include "net/spdy/chromium/http2_push_promise_index.h" +#include "base/trace_event/memory_usage_estimator.h" +#include <algorithm> #include <utility> -#include "net/spdy/chromium/spdy_session.h" - namespace net { -Http2PushPromiseIndex::Http2PushPromiseIndex() {} +Http2PushPromiseIndex::Http2PushPromiseIndex() = default; Http2PushPromiseIndex::~Http2PushPromiseIndex() { DCHECK(unclaimed_pushed_streams_.empty()); } -base::WeakPtr<SpdySession> Http2PushPromiseIndex::Find( - const SpdySessionKey& key, - const GURL& url) const { +bool Http2PushPromiseIndex::RegisterUnclaimedPushedStream( + const GURL& url, + SpdyStreamId stream_id, + Delegate* delegate) { DCHECK(!url.is_empty()); - - UnclaimedPushedStreamMap::const_iterator url_it = - unclaimed_pushed_streams_.find(url); - - if (url_it == unclaimed_pushed_streams_.end()) { - return base::WeakPtr<SpdySession>(); + DCHECK_GT(stream_id, kNoPushedStreamFound); + DCHECK(delegate); + + // Find the entry with |url| for |delegate| if such exists (there can be at + // most one such entry). It is okay to cast away const from |delegate|, + // because it is only used for lookup. + auto it = unclaimed_pushed_streams_.lower_bound(UnclaimedPushedStream{ + url, const_cast<Delegate*>(delegate), kNoPushedStreamFound}); + // If such entry is found, do not allow registering another one. + if (it != unclaimed_pushed_streams_.end() && it->url == url && + it->delegate == delegate) { + return false; } - DCHECK(url.SchemeIsCryptographic()); - for (const auto& session : url_it->second) { - const SpdySessionKey& spdy_session_key = session->spdy_session_key(); - if (spdy_session_key.proxy_server() != key.proxy_server() || - spdy_session_key.privacy_mode() != key.privacy_mode()) { - continue; - } - if (!session->VerifyDomainAuthentication(key.host_port_pair().host())) { - continue; - } - return session; - } + unclaimed_pushed_streams_.insert( + it, UnclaimedPushedStream{url, delegate, stream_id}); - return base::WeakPtr<SpdySession>(); + return true; } -void Http2PushPromiseIndex::RegisterUnclaimedPushedStream( +bool Http2PushPromiseIndex::UnregisterUnclaimedPushedStream( const GURL& url, - base::WeakPtr<SpdySession> spdy_session) { + SpdyStreamId stream_id, + Delegate* delegate) { DCHECK(!url.is_empty()); - DCHECK(url.SchemeIsCryptographic()); - - // Use lower_bound() so that if key does not exists, then insertion can use - // its return value as a hint. - UnclaimedPushedStreamMap::iterator url_it = - unclaimed_pushed_streams_.lower_bound(url); - if (url_it == unclaimed_pushed_streams_.end() || url_it->first != url) { - WeakSessionList list; - list.push_back(std::move(spdy_session)); - UnclaimedPushedStreamMap::value_type value(url, std::move(list)); - unclaimed_pushed_streams_.insert(url_it, std::move(value)); - return; + DCHECK_GT(stream_id, kNoPushedStreamFound); + DCHECK(delegate); + + size_t result = unclaimed_pushed_streams_.erase( + UnclaimedPushedStream{url, delegate, stream_id}); + + return result == 1; +} + +// The runtime of this method is linear in unclaimed_pushed_streams_.size(), +// which is acceptable, because it is only used in NetLog, tests, and DCHECKs. +size_t Http2PushPromiseIndex::CountStreamsForSession( + const Delegate* delegate) const { + DCHECK(delegate); + + return std::count_if(unclaimed_pushed_streams_.begin(), + unclaimed_pushed_streams_.end(), + [&delegate](const UnclaimedPushedStream& entry) { + return entry.delegate == delegate; + }); +} + +SpdyStreamId Http2PushPromiseIndex::FindStream(const GURL& url, + const Delegate* delegate) const { + // Find the entry with |url| for |delegate| if such exists (there can be at + // most one such entry). It is okay to cast away const from |delegate|, + // because it is only used for lookup. + auto it = unclaimed_pushed_streams_.lower_bound(UnclaimedPushedStream{ + url, const_cast<Delegate*>(delegate), kNoPushedStreamFound}); + + if (it == unclaimed_pushed_streams_.end() || it->url != url || + it->delegate != delegate) { + return kNoPushedStreamFound; } - url_it->second.push_back(spdy_session); + + return it->stream_id; } -void Http2PushPromiseIndex::UnregisterUnclaimedPushedStream( +void Http2PushPromiseIndex::ClaimPushedStream( + const SpdySessionKey& key, const GURL& url, - SpdySession* spdy_session) { + const HttpRequestInfo& request_info, + base::WeakPtr<SpdySession>* session, + SpdyStreamId* stream_id) { DCHECK(!url.is_empty()); - DCHECK(url.SchemeIsCryptographic()); - UnclaimedPushedStreamMap::iterator url_it = - unclaimed_pushed_streams_.find(url); - if (url_it == unclaimed_pushed_streams_.end()) { - NOTREACHED(); - return; - } - for (WeakSessionList::iterator it = url_it->second.begin(); - it != url_it->second.end();) { - if (it->get() == spdy_session) { - url_it->second.erase(it); - if (url_it->second.empty()) { - unclaimed_pushed_streams_.erase(url_it); - } + *session = nullptr; + *stream_id = kNoPushedStreamFound; + + // Find the first entry for |url|, if such exists. + auto it = unclaimed_pushed_streams_.lower_bound( + UnclaimedPushedStream{url, nullptr, kNoPushedStreamFound}); + + while (it != unclaimed_pushed_streams_.end() && it->url == url) { + if (it->delegate->ValidatePushedStream(it->stream_id, url, request_info, + key)) { + *session = it->delegate->GetWeakPtrToSession(); + *stream_id = it->stream_id; + unclaimed_pushed_streams_.erase(it); return; } ++it; } - NOTREACHED(); +} + +size_t Http2PushPromiseIndex::EstimateMemoryUsage() const { + return base::trace_event::EstimateMemoryUsage(unclaimed_pushed_streams_); +} + +size_t Http2PushPromiseIndex::UnclaimedPushedStream::EstimateMemoryUsage() + const { + return base::trace_event::EstimateMemoryUsage(url) + sizeof(SpdyStreamId) + + sizeof(Delegate*); +} + +bool Http2PushPromiseIndex::CompareByUrl::operator()( + const UnclaimedPushedStream& a, + const UnclaimedPushedStream& b) const { + // Compare by URL first. + if (a.url < b.url) + return true; + if (a.url > b.url) + return false; + // For identical URL, put an entry with delegate == nullptr first. + // The C++ standard dictates that comparisons between |nullptr| and other + // pointers are unspecified, hence the need to handle this case separately. + if (a.delegate == nullptr && b.delegate != nullptr) { + return true; + } + if (a.delegate != nullptr && b.delegate == nullptr) { + return false; + } + // Then compare by Delegate. + // The C++ standard guarantees that both |nullptr < nullptr| and + // |nullptr > nullptr| are false, so there is no need to handle that case + // separately. + if (a.delegate < b.delegate) + return true; + if (a.delegate > b.delegate) + return false; + // If URL and Delegate are identical, then compare by stream ID. + return a.stream_id < b.stream_id; } } // namespace net diff --git a/chromium/net/spdy/chromium/http2_push_promise_index.h b/chromium/net/spdy/chromium/http2_push_promise_index.h index a50ef42044b..e9f8f2e66db 100644 --- a/chromium/net/spdy/chromium/http2_push_promise_index.h +++ b/chromium/net/spdy/chromium/http2_push_promise_index.h @@ -5,53 +5,128 @@ #ifndef NET_SPDY_CHROMIUM_HTTP2_PUSH_PROMISE_INDEX_H_ #define NET_SPDY_CHROMIUM_HTTP2_PUSH_PROMISE_INDEX_H_ -#include <map> -#include <vector> +#include <set> +#include "base/compiler_specific.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "net/base/net_export.h" +#include "net/http/http_request_info.h" #include "net/spdy/chromium/spdy_session_key.h" +#include "net/spdy/core/spdy_protocol.h" #include "url/gurl.h" namespace net { class SpdySession; -// This class manages cross-origin unclaimed pushed streams (push promises) from -// the receipt of PUSH_PROMISE frame until they are matched to a request. Each -// SpdySessionPool owns one instance of this class, which then allows requests -// to be matched with a pushed stream regardless of which HTTP/2 connection the -// stream is on. -// Only pushed streams with cryptographic schemes (for example, https) are -// allowed to be shared across connections. Non-cryptographic scheme pushes -// (for example, http) are fully managed within each SpdySession. +namespace test { + +class Http2PushPromiseIndexPeer; + +} // namespace test + +// Value returned by ClaimPushedStream() and FindStream() if no stream is found. +const SpdyStreamId kNoPushedStreamFound = 0; + +// This class manages unclaimed pushed streams (push promises) from the receipt +// of PUSH_PROMISE frame until they are matched to a request. +// Each SpdySessionPool owns one instance of this class. +// SpdySession uses this class to register, unregister and query pushed streams. +// HttpStreamFactoryImpl::Job uses this class to find a SpdySession with a +// pushed stream matching the request, if such exists. class NET_EXPORT Http2PushPromiseIndex { public: + // Interface for validating pushed streams, signaling when a pushed stream is + // claimed, and generating SpdySession weak pointer. + class NET_EXPORT Delegate { + public: + Delegate() {} + virtual ~Delegate() {} + + // Return true if a pushed stream with |url| can be used for a request with + // |key|. + virtual bool ValidatePushedStream(SpdyStreamId stream_id, + const GURL& url, + const HttpRequestInfo& request_info, + const SpdySessionKey& key) const = 0; + + // Generate weak pointer. Guaranateed to be called synchronously after + // ValidatePushedStream() is called and returns true. + virtual base::WeakPtr<SpdySession> GetWeakPtrToSession() = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(Delegate); + }; + Http2PushPromiseIndex(); ~Http2PushPromiseIndex(); - // Returns a session with |key| that has an unclaimed push stream for |url| if - // such exists. Returns nullptr otherwise. - base::WeakPtr<SpdySession> Find(const SpdySessionKey& key, - const GURL& url) const; + // Tries to register a Delegate with an unclaimed pushed stream for |url|. + // Caller must make sure |delegate| stays valid by unregistering the exact + // same entry before |delegate| is destroyed. + // Returns true if there is no unclaimed pushed stream with the same URL for + // the same Delegate, in which case the stream is registered. + bool RegisterUnclaimedPushedStream(const GURL& url, + SpdyStreamId stream_id, + Delegate* delegate) WARN_UNUSED_RESULT; - // (Un)registers a SpdySession with an unclaimed pushed stream for |url|. - void RegisterUnclaimedPushedStream(const GURL& url, - base::WeakPtr<SpdySession> spdy_session); - void UnregisterUnclaimedPushedStream(const GURL& url, - SpdySession* spdy_session); + // Tries to unregister a Delegate with an unclaimed pushed stream for |url| + // with given |stream_id|. + // Returns true if this exact entry is found, in which case it is removed. + bool UnregisterUnclaimedPushedStream(const GURL& url, + SpdyStreamId stream_id, + Delegate* delegate) WARN_UNUSED_RESULT; + + // Returns the number of pushed streams registered for |delegate|. + size_t CountStreamsForSession(const Delegate* delegate) const; + + // Returns the stream ID of the entry registered for |delegate| with |url|, + // or kNoPushedStreamFound if no such entry exists. + SpdyStreamId FindStream(const GURL& url, const Delegate* delegate) const; + + // If there exists a session compatible with |key| that has an unclaimed push + // stream for |url|, then sets |*session| and |*stream| to one such session + // and stream, and removes entry from index. Makes no guarantee on which + // (session, stream_id) pair is claimed if there are multiple matches. Sets + // |*session| to nullptr and |*stream| to kNoPushedStreamFound if no such + // session exists. + void ClaimPushedStream(const SpdySessionKey& key, + const GURL& url, + const HttpRequestInfo& request_info, + base::WeakPtr<SpdySession>* session, + SpdyStreamId* stream_id); + + // Return the estimate of dynamically allocated memory in bytes. + size_t EstimateMemoryUsage() const; private: - typedef std::vector<base::WeakPtr<SpdySession>> WeakSessionList; - typedef std::map<GURL, WeakSessionList> UnclaimedPushedStreamMap; - - // A multimap of all SpdySessions that have an unclaimed pushed stream for a - // GURL. SpdySession must unregister its streams before destruction, - // therefore all weak pointers must be valid. A single SpdySession can only - // have at most one pushed stream for each GURL, but it is possible that - // multiple SpdySessions have pushed streams for the same GURL. - UnclaimedPushedStreamMap unclaimed_pushed_streams_; + friend test::Http2PushPromiseIndexPeer; + + // An unclaimed pushed stream entry. + struct NET_EXPORT UnclaimedPushedStream { + GURL url; + Delegate* delegate; + SpdyStreamId stream_id; + size_t EstimateMemoryUsage() const; + }; + + // Function object satisfying the requirements of "Compare", see + // http://en.cppreference.com/w/cpp/concept/Compare. + // A set ordered by this function object supports O(log n) lookup + // of the first entry with a given URL, by calling lower_bound() with an entry + // with that URL and with delegate = nullptr. + struct NET_EXPORT CompareByUrl { + bool operator()(const UnclaimedPushedStream& a, + const UnclaimedPushedStream& b) const; + }; + + // Collection of all unclaimed pushed streams. Delegate must unregister + // its streams before destruction, so that all pointers remain valid. + // Each Delegate can have at most one pushed stream for each URL (but each + // Delegate can have pushed streams for different URLs, and different + // Delegates can have pushed streams for the same GURL). + std::set<UnclaimedPushedStream, CompareByUrl> unclaimed_pushed_streams_; DISALLOW_COPY_AND_ASSIGN(Http2PushPromiseIndex); }; diff --git a/chromium/net/spdy/chromium/http2_push_promise_index_test.cc b/chromium/net/spdy/chromium/http2_push_promise_index_test.cc index d1cd077f3ff..6777cb50b37 100644 --- a/chromium/net/spdy/chromium/http2_push_promise_index_test.cc +++ b/chromium/net/spdy/chromium/http2_push_promise_index_test.cc @@ -4,175 +4,463 @@ #include "net/spdy/chromium/http2_push_promise_index.h" -#include "base/run_loop.h" #include "net/base/host_port_pair.h" #include "net/base/privacy_mode.h" -#include "net/log/test_net_log.h" -#include "net/socket/socket_test_util.h" -#include "net/spdy/chromium/spdy_session.h" -#include "net/spdy/chromium/spdy_test_util_common.h" -#include "net/test/cert_test_util.h" -#include "net/test/test_data_directory.h" +#include "net/test/gtest_util.h" #include "testing/gtest/include/gtest/gtest.h" #include "url/gurl.h" +// For simplicity, these tests do not create SpdySession instances +// (necessary for a non-null WeakPtr<SpdySession>), instead they use nullptr. +// Streams are identified by SpdyStreamId only. + +using ::testing::Return; +using ::testing::_; + namespace net { namespace test { +namespace { + +// Delegate implementation for tests that requires exact match of SpdySessionKey +// in ValidatePushedStream(). Note that SpdySession, unlike TestDelegate, +// allows cross-origin pooling. +class TestDelegate : public Http2PushPromiseIndex::Delegate { + public: + TestDelegate() = delete; + TestDelegate(const SpdySessionKey& key) : key_(key) {} + ~TestDelegate() override {} + + bool ValidatePushedStream(SpdyStreamId stream_id, + const GURL& url, + const HttpRequestInfo& request_info, + const SpdySessionKey& key) const override { + return key == key_; + } + + base::WeakPtr<SpdySession> GetWeakPtrToSession() override { return nullptr; } + + private: + SpdySessionKey key_; +}; + +} // namespace + +class Http2PushPromiseIndexPeer { + public: + using UnclaimedPushedStream = Http2PushPromiseIndex::UnclaimedPushedStream; + using CompareByUrl = Http2PushPromiseIndex::CompareByUrl; +}; class Http2PushPromiseIndexTest : public testing::Test { protected: Http2PushPromiseIndexTest() : url1_("https://www.example.org"), url2_("https://mail.example.com"), - host_port_pair1_(HostPortPair::FromURL(url1_)), - host_port_pair2_(HostPortPair::FromURL(url2_)), - key1_(host_port_pair1_, ProxyServer::Direct(), PRIVACY_MODE_ENABLED), - key2_(host_port_pair2_, ProxyServer::Direct(), PRIVACY_MODE_ENABLED), - http_network_session_( - SpdySessionDependencies::SpdyCreateSession(&session_deps_)) {} - - NetLogWithSource log_; + key1_(HostPortPair::FromURL(url1_), + ProxyServer::Direct(), + PRIVACY_MODE_ENABLED), + key2_(HostPortPair::FromURL(url2_), + ProxyServer::Direct(), + PRIVACY_MODE_ENABLED) {} + const GURL url1_; const GURL url2_; - const HostPortPair host_port_pair1_; - const HostPortPair host_port_pair2_; const SpdySessionKey key1_; const SpdySessionKey key2_; - SpdySessionDependencies session_deps_; - std::unique_ptr<HttpNetworkSession> http_network_session_; Http2PushPromiseIndex index_; }; -TEST_F(Http2PushPromiseIndexTest, Empty) { - EXPECT_FALSE(index_.Find(key1_, url1_)); - EXPECT_FALSE(index_.Find(key2_, url2_)); +// RegisterUnclaimedPushedStream() returns false +// if there is already a registered entry with same delegate and URL. +TEST_F(Http2PushPromiseIndexTest, CannotRegisterSameEntryTwice) { + TestDelegate delegate(key1_); + EXPECT_TRUE(index_.RegisterUnclaimedPushedStream(url1_, 2, &delegate)); + EXPECT_FALSE(index_.RegisterUnclaimedPushedStream(url1_, 4, &delegate)); + // Unregister first entry so that DCHECK() does not fail in destructor. + EXPECT_TRUE(index_.UnregisterUnclaimedPushedStream(url1_, 2, &delegate)); } -TEST_F(Http2PushPromiseIndexTest, FindMultipleSessionsWithDifferentUrl) { - MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)}; - SSLSocketDataProvider ssl(SYNCHRONOUS, OK); - ssl.ssl_info.cert = - ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem"); - ASSERT_TRUE(ssl.ssl_info.cert); - // For first session. - SequencedSocketData data1(reads, arraysize(reads), nullptr, 0); - session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); - session_deps_.socket_factory->AddSocketDataProvider(&data1); - // For second session. - SequencedSocketData data2(reads, arraysize(reads), nullptr, 0); - session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); - session_deps_.socket_factory->AddSocketDataProvider(&data2); +// UnregisterUnclaimedPushedStream() returns false +// if there is no identical entry registered. +// Case 1: no streams for the given URL. +TEST_F(Http2PushPromiseIndexTest, CannotUnregisterNonexistingEntry) { + TestDelegate delegate(key1_); + EXPECT_FALSE(index_.UnregisterUnclaimedPushedStream(url1_, 2, &delegate)); +} - base::WeakPtr<SpdySession> spdy_session1 = - CreateSpdySession(http_network_session_.get(), key1_, log_); - base::WeakPtr<SpdySession> spdy_session2 = - CreateSpdySession(http_network_session_.get(), key2_, log_); - // Read hanging socket data. - base::RunLoop().RunUntilIdle(); +// UnregisterUnclaimedPushedStream() returns false +// if there is no identical entry registered. +// Case 2: there is a stream for the given URL with the same Delegate, +// but the stream ID does not match. +TEST_F(Http2PushPromiseIndexTest, CannotUnregisterEntryIfStreamIdDoesNotMatch) { + TestDelegate delegate(key1_); + EXPECT_TRUE(index_.RegisterUnclaimedPushedStream(url1_, 2, &delegate)); + EXPECT_FALSE(index_.UnregisterUnclaimedPushedStream(url1_, 4, &delegate)); + // Unregister first entry so that DCHECK() does not fail in destructor. + EXPECT_TRUE(index_.UnregisterUnclaimedPushedStream(url1_, 2, &delegate)); +} - EXPECT_FALSE(index_.Find(key1_, url1_)); - EXPECT_FALSE(index_.Find(key2_, url2_)); +// UnregisterUnclaimedPushedStream() returns false +// if there is no identical entry registered. +// Case 3: there is a stream for the given URL with the same stream ID, +// but the delegate does not match. +TEST_F(Http2PushPromiseIndexTest, CannotUnregisterEntryIfDelegateDoesNotMatch) { + TestDelegate delegate1(key1_); + TestDelegate delegate2(key2_); + EXPECT_TRUE(index_.RegisterUnclaimedPushedStream(url1_, 2, &delegate1)); + EXPECT_FALSE(index_.UnregisterUnclaimedPushedStream(url1_, 2, &delegate2)); + // Unregister first entry so that DCHECK() does not fail in destructor. + EXPECT_TRUE(index_.UnregisterUnclaimedPushedStream(url1_, 2, &delegate1)); +} - index_.RegisterUnclaimedPushedStream(url1_, spdy_session1); +TEST_F(Http2PushPromiseIndexTest, CountStreamsForSession) { + TestDelegate delegate1(key1_); + TestDelegate delegate2(key2_); - EXPECT_EQ(spdy_session1.get(), index_.Find(key1_, url1_).get()); - EXPECT_FALSE(index_.Find(key2_, url2_)); + EXPECT_EQ(0u, index_.CountStreamsForSession(&delegate1)); + EXPECT_EQ(0u, index_.CountStreamsForSession(&delegate2)); - index_.RegisterUnclaimedPushedStream(url2_, spdy_session2); + EXPECT_TRUE(index_.RegisterUnclaimedPushedStream(url1_, 2, &delegate1)); - EXPECT_EQ(spdy_session1.get(), index_.Find(key1_, url1_).get()); - EXPECT_EQ(spdy_session2.get(), index_.Find(key2_, url2_).get()); + EXPECT_EQ(1u, index_.CountStreamsForSession(&delegate1)); + EXPECT_EQ(0u, index_.CountStreamsForSession(&delegate2)); - index_.UnregisterUnclaimedPushedStream(url1_, spdy_session1.get()); + EXPECT_TRUE(index_.RegisterUnclaimedPushedStream(url2_, 4, &delegate1)); - EXPECT_FALSE(index_.Find(key1_, url1_)); - EXPECT_EQ(spdy_session2.get(), index_.Find(key2_, url2_).get()); + EXPECT_EQ(2u, index_.CountStreamsForSession(&delegate1)); + EXPECT_EQ(0u, index_.CountStreamsForSession(&delegate2)); - index_.UnregisterUnclaimedPushedStream(url2_, spdy_session2.get()); + EXPECT_TRUE(index_.RegisterUnclaimedPushedStream(url1_, 6, &delegate2)); - EXPECT_FALSE(index_.Find(key1_, url1_)); - EXPECT_FALSE(index_.Find(key2_, url2_)); + EXPECT_EQ(2u, index_.CountStreamsForSession(&delegate1)); + EXPECT_EQ(1u, index_.CountStreamsForSession(&delegate2)); - // SpdySession weak pointers must still be valid, - // otherwise comparisons above are not meaningful. - EXPECT_TRUE(spdy_session1); - EXPECT_TRUE(spdy_session2); + EXPECT_TRUE(index_.UnregisterUnclaimedPushedStream(url1_, 2, &delegate1)); - EXPECT_TRUE(data1.AllReadDataConsumed()); - EXPECT_TRUE(data1.AllWriteDataConsumed()); - EXPECT_TRUE(data2.AllReadDataConsumed()); - EXPECT_TRUE(data2.AllWriteDataConsumed()); + EXPECT_EQ(1u, index_.CountStreamsForSession(&delegate1)); + EXPECT_EQ(1u, index_.CountStreamsForSession(&delegate2)); + + EXPECT_TRUE(index_.UnregisterUnclaimedPushedStream(url2_, 4, &delegate1)); + + EXPECT_EQ(0u, index_.CountStreamsForSession(&delegate1)); + EXPECT_EQ(1u, index_.CountStreamsForSession(&delegate2)); + + EXPECT_TRUE(index_.UnregisterUnclaimedPushedStream(url1_, 6, &delegate2)); + + EXPECT_EQ(0u, index_.CountStreamsForSession(&delegate1)); + EXPECT_EQ(0u, index_.CountStreamsForSession(&delegate2)); } -TEST_F(Http2PushPromiseIndexTest, MultipleSessionsForSingleUrl) { - MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)}; - SSLSocketDataProvider ssl(SYNCHRONOUS, OK); - ssl.ssl_info.cert = - ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem"); - ASSERT_TRUE(ssl.ssl_info.cert); - // For first session. - SequencedSocketData data1(reads, arraysize(reads), nullptr, 0); - session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); - session_deps_.socket_factory->AddSocketDataProvider(&data1); - // For second session. - SequencedSocketData data2(reads, arraysize(reads), nullptr, 0); - session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); - session_deps_.socket_factory->AddSocketDataProvider(&data2); - - base::WeakPtr<SpdySession> spdy_session1 = - CreateSpdySession(http_network_session_.get(), key1_, log_); - base::WeakPtr<SpdySession> spdy_session2 = - CreateSpdySession(http_network_session_.get(), key2_, log_); - // Read hanging socket data. - base::RunLoop().RunUntilIdle(); - - EXPECT_FALSE(index_.Find(key1_, url1_)); - EXPECT_FALSE(index_.Find(key2_, url1_)); - EXPECT_FALSE(index_.Find(key1_, url2_)); - EXPECT_FALSE(index_.Find(key2_, url2_)); - - index_.RegisterUnclaimedPushedStream(url1_, spdy_session1); - - // Note that Find() only uses its SpdySessionKey argument to verify proxy and - // privacy mode. Cross-origin pooling is supported, therefore HostPortPair of - // SpdySessionKey does not matter. - EXPECT_EQ(spdy_session1.get(), index_.Find(key1_, url1_).get()); - EXPECT_EQ(spdy_session1.get(), index_.Find(key2_, url1_).get()); - EXPECT_FALSE(index_.Find(key1_, url2_)); - EXPECT_FALSE(index_.Find(key2_, url2_)); - - index_.RegisterUnclaimedPushedStream(url1_, spdy_session2); - - // Find returns the first SpdySession if there are multiple for the same URL. - EXPECT_EQ(spdy_session1.get(), index_.Find(key1_, url1_).get()); - EXPECT_EQ(spdy_session1.get(), index_.Find(key2_, url1_).get()); - EXPECT_FALSE(index_.Find(key1_, url2_)); - EXPECT_FALSE(index_.Find(key2_, url2_)); - - index_.UnregisterUnclaimedPushedStream(url1_, spdy_session1.get()); - - EXPECT_EQ(spdy_session2.get(), index_.Find(key1_, url1_).get()); - EXPECT_EQ(spdy_session2.get(), index_.Find(key2_, url1_).get()); - EXPECT_FALSE(index_.Find(key1_, url2_)); - EXPECT_FALSE(index_.Find(key2_, url2_)); - - index_.UnregisterUnclaimedPushedStream(url1_, spdy_session2.get()); - - EXPECT_FALSE(index_.Find(key1_, url1_)); - EXPECT_FALSE(index_.Find(key2_, url1_)); - EXPECT_FALSE(index_.Find(key1_, url2_)); - EXPECT_FALSE(index_.Find(key2_, url2_)); - - // SpdySession weak pointers must still be valid, - // otherwise comparisons above are not meaningful. - EXPECT_TRUE(spdy_session1); - EXPECT_TRUE(spdy_session2); - - EXPECT_TRUE(data1.AllReadDataConsumed()); - EXPECT_TRUE(data1.AllWriteDataConsumed()); - EXPECT_TRUE(data2.AllReadDataConsumed()); - EXPECT_TRUE(data2.AllWriteDataConsumed()); +TEST_F(Http2PushPromiseIndexTest, FindStream) { + TestDelegate delegate1(key1_); + TestDelegate delegate2(key2_); + + EXPECT_EQ(kNoPushedStreamFound, index_.FindStream(url1_, &delegate1)); + EXPECT_EQ(kNoPushedStreamFound, index_.FindStream(url2_, &delegate1)); + EXPECT_EQ(kNoPushedStreamFound, index_.FindStream(url1_, &delegate2)); + EXPECT_EQ(kNoPushedStreamFound, index_.FindStream(url2_, &delegate2)); + + EXPECT_TRUE(index_.RegisterUnclaimedPushedStream(url1_, 2, &delegate1)); + + EXPECT_EQ(2u, index_.FindStream(url1_, &delegate1)); + EXPECT_EQ(kNoPushedStreamFound, index_.FindStream(url2_, &delegate1)); + EXPECT_EQ(kNoPushedStreamFound, index_.FindStream(url1_, &delegate2)); + EXPECT_EQ(kNoPushedStreamFound, index_.FindStream(url2_, &delegate2)); + + EXPECT_TRUE(index_.RegisterUnclaimedPushedStream(url2_, 4, &delegate1)); + + EXPECT_EQ(2u, index_.FindStream(url1_, &delegate1)); + EXPECT_EQ(4u, index_.FindStream(url2_, &delegate1)); + EXPECT_EQ(kNoPushedStreamFound, index_.FindStream(url1_, &delegate2)); + EXPECT_EQ(kNoPushedStreamFound, index_.FindStream(url2_, &delegate2)); + + EXPECT_TRUE(index_.RegisterUnclaimedPushedStream(url1_, 6, &delegate2)); + + EXPECT_EQ(2u, index_.FindStream(url1_, &delegate1)); + EXPECT_EQ(4u, index_.FindStream(url2_, &delegate1)); + EXPECT_EQ(6u, index_.FindStream(url1_, &delegate2)); + EXPECT_EQ(kNoPushedStreamFound, index_.FindStream(url2_, &delegate2)); + + EXPECT_TRUE(index_.UnregisterUnclaimedPushedStream(url1_, 2, &delegate1)); + + EXPECT_EQ(kNoPushedStreamFound, index_.FindStream(url1_, &delegate1)); + EXPECT_EQ(4u, index_.FindStream(url2_, &delegate1)); + EXPECT_EQ(6u, index_.FindStream(url1_, &delegate2)); + EXPECT_EQ(kNoPushedStreamFound, index_.FindStream(url2_, &delegate2)); + + EXPECT_TRUE(index_.UnregisterUnclaimedPushedStream(url2_, 4, &delegate1)); + + EXPECT_EQ(kNoPushedStreamFound, index_.FindStream(url1_, &delegate1)); + EXPECT_EQ(kNoPushedStreamFound, index_.FindStream(url2_, &delegate1)); + EXPECT_EQ(6u, index_.FindStream(url1_, &delegate2)); + EXPECT_EQ(kNoPushedStreamFound, index_.FindStream(url2_, &delegate2)); + + EXPECT_TRUE(index_.UnregisterUnclaimedPushedStream(url1_, 6, &delegate2)); + + EXPECT_EQ(kNoPushedStreamFound, index_.FindStream(url1_, &delegate1)); + EXPECT_EQ(kNoPushedStreamFound, index_.FindStream(url2_, &delegate1)); + EXPECT_EQ(kNoPushedStreamFound, index_.FindStream(url1_, &delegate2)); + EXPECT_EQ(kNoPushedStreamFound, index_.FindStream(url2_, &delegate2)); +} + +// If |index_| is empty, then ClaimPushedStream() should set its |stream_id| +// outparam to kNoPushedStreamFound for any values of inparams. +TEST_F(Http2PushPromiseIndexTest, Empty) { + base::WeakPtr<SpdySession> session; + SpdyStreamId stream_id = 2; + index_.ClaimPushedStream(key1_, url1_, HttpRequestInfo(), &session, + &stream_id); + EXPECT_EQ(kNoPushedStreamFound, stream_id); + + stream_id = 2; + index_.ClaimPushedStream(key1_, url2_, HttpRequestInfo(), &session, + &stream_id); + EXPECT_EQ(kNoPushedStreamFound, stream_id); + + stream_id = 2; + index_.ClaimPushedStream(key1_, url2_, HttpRequestInfo(), &session, + &stream_id); + EXPECT_EQ(kNoPushedStreamFound, stream_id); + + stream_id = 2; + index_.ClaimPushedStream(key2_, url2_, HttpRequestInfo(), &session, + &stream_id); + EXPECT_EQ(kNoPushedStreamFound, stream_id); } +// Create two entries, both with a delegate that requires |key| to be equal to +// |key1_|. Register the two entries with different URLs. Check that they can +// be found by their respective URLs. +TEST_F(Http2PushPromiseIndexTest, FindMultipleStreamsWithDifferentUrl) { + // Register first entry. + TestDelegate delegate1(key1_); + EXPECT_TRUE(index_.RegisterUnclaimedPushedStream(url1_, 2, &delegate1)); + + // No entry found for |url2_|. + base::WeakPtr<SpdySession> session; + SpdyStreamId stream_id = 2; + index_.ClaimPushedStream(key1_, url2_, HttpRequestInfo(), &session, + &stream_id); + EXPECT_EQ(kNoPushedStreamFound, stream_id); + + // Claim first entry. + stream_id = kNoPushedStreamFound; + index_.ClaimPushedStream(key1_, url1_, HttpRequestInfo(), &session, + &stream_id); + EXPECT_EQ(2u, stream_id); + + // ClaimPushedStream() unregistered first entry, cannot claim it again. + stream_id = 2; + index_.ClaimPushedStream(key1_, url1_, HttpRequestInfo(), &session, + &stream_id); + EXPECT_EQ(kNoPushedStreamFound, stream_id); + + // Register two entries. Second entry uses same key. + EXPECT_TRUE(index_.RegisterUnclaimedPushedStream(url1_, 2, &delegate1)); + TestDelegate delegate2(key1_); + EXPECT_TRUE(index_.RegisterUnclaimedPushedStream(url2_, 4, &delegate2)); + + // Retrieve each entry by their respective URLs. + stream_id = kNoPushedStreamFound; + index_.ClaimPushedStream(key1_, url1_, HttpRequestInfo(), &session, + &stream_id); + EXPECT_EQ(2u, stream_id); + + stream_id = kNoPushedStreamFound; + index_.ClaimPushedStream(key1_, url2_, HttpRequestInfo(), &session, + &stream_id); + EXPECT_EQ(4u, stream_id); + + // ClaimPushedStream() calls unregistered both entries, + // cannot claim them again. + stream_id = 2; + index_.ClaimPushedStream(key1_, url1_, HttpRequestInfo(), &session, + &stream_id); + EXPECT_EQ(kNoPushedStreamFound, stream_id); + + stream_id = 2; + index_.ClaimPushedStream(key1_, url2_, HttpRequestInfo(), &session, + &stream_id); + EXPECT_EQ(kNoPushedStreamFound, stream_id); + + EXPECT_FALSE(index_.UnregisterUnclaimedPushedStream(url1_, 2, &delegate1)); + EXPECT_FALSE(index_.UnregisterUnclaimedPushedStream(url2_, 4, &delegate2)); +} + +// Create two entries with delegates that validate different SpdySessionKeys. +// Register the two entries with the same URL. Check that they can be found by +// their respective SpdySessionKeys. +TEST_F(Http2PushPromiseIndexTest, MultipleStreamsWithDifferentKeys) { + // Register first entry. + TestDelegate delegate1(key1_); + EXPECT_TRUE(index_.RegisterUnclaimedPushedStream(url1_, 2, &delegate1)); + + // No entry found for |key2_|. + base::WeakPtr<SpdySession> session; + SpdyStreamId stream_id = 2; + index_.ClaimPushedStream(key2_, url1_, HttpRequestInfo(), &session, + &stream_id); + EXPECT_EQ(kNoPushedStreamFound, stream_id); + + // Claim first entry. + stream_id = kNoPushedStreamFound; + index_.ClaimPushedStream(key1_, url1_, HttpRequestInfo(), &session, + &stream_id); + EXPECT_EQ(2u, stream_id); + + // ClaimPushedStream() unregistered first entry, cannot claim it again. + stream_id = 2; + index_.ClaimPushedStream(key1_, url1_, HttpRequestInfo(), &session, + &stream_id); + EXPECT_EQ(kNoPushedStreamFound, stream_id); + + // Register two entries. Second entry uses same URL. + EXPECT_TRUE(index_.RegisterUnclaimedPushedStream(url1_, 2, &delegate1)); + TestDelegate delegate2(key2_); + EXPECT_TRUE(index_.RegisterUnclaimedPushedStream(url1_, 4, &delegate2)); + + // Retrieve each entry by their respective SpdySessionKeys. + stream_id = kNoPushedStreamFound; + index_.ClaimPushedStream(key1_, url1_, HttpRequestInfo(), &session, + &stream_id); + EXPECT_EQ(2u, stream_id); + + stream_id = kNoPushedStreamFound; + index_.ClaimPushedStream(key2_, url1_, HttpRequestInfo(), &session, + &stream_id); + EXPECT_EQ(4u, stream_id); + + // ClaimPushedStream() calls unregistered both entries, + // cannot claim them again. + stream_id = 2; + index_.ClaimPushedStream(key1_, url1_, HttpRequestInfo(), &session, + &stream_id); + EXPECT_EQ(kNoPushedStreamFound, stream_id); + + stream_id = 2; + index_.ClaimPushedStream(key2_, url1_, HttpRequestInfo(), &session, + &stream_id); + EXPECT_EQ(kNoPushedStreamFound, stream_id); + + EXPECT_FALSE(index_.UnregisterUnclaimedPushedStream(url1_, 2, &delegate1)); + EXPECT_FALSE(index_.UnregisterUnclaimedPushedStream(url1_, 4, &delegate2)); +} + +TEST_F(Http2PushPromiseIndexTest, MultipleMatchingStreams) { + // Register two entries with identical URLs that have delegates that accept + // the same SpdySessionKey. + TestDelegate delegate1(key1_); + TestDelegate delegate2(key1_); + EXPECT_TRUE(index_.RegisterUnclaimedPushedStream(url1_, 2, &delegate1)); + EXPECT_TRUE(index_.RegisterUnclaimedPushedStream(url1_, 4, &delegate2)); + + // Test that ClaimPushedStream() returns one of the two entries. + // ClaimPushedStream() makes no guarantee about which entry it returns if + // there are multiple matches. + base::WeakPtr<SpdySession> session; + SpdyStreamId stream_id1 = kNoPushedStreamFound; + index_.ClaimPushedStream(key1_, url1_, HttpRequestInfo(), &session, + &stream_id1); + EXPECT_NE(kNoPushedStreamFound, stream_id1); + + // First call to ClaimPushedStream() unregistered one of the entries. + // Second call to ClaimPushedStream() must return the other entry. + SpdyStreamId stream_id2 = kNoPushedStreamFound; + index_.ClaimPushedStream(key1_, url1_, HttpRequestInfo(), &session, + &stream_id2); + EXPECT_NE(kNoPushedStreamFound, stream_id2); + EXPECT_NE(stream_id1, stream_id2); + + // Two calls to ClaimPushedStream() unregistered both entries. + SpdyStreamId stream_id3 = 2; + index_.ClaimPushedStream(key1_, url1_, HttpRequestInfo(), &session, + &stream_id3); + EXPECT_EQ(kNoPushedStreamFound, stream_id3); + + EXPECT_FALSE(index_.UnregisterUnclaimedPushedStream(url1_, 2, &delegate1)); + EXPECT_FALSE(index_.UnregisterUnclaimedPushedStream(url1_, 4, &delegate2)); +} + +// Test that an entry is equivalent to itself. +TEST(Http2PushPromiseIndexCompareByUrlTest, Reflexivity) { + // Test with two entries: with and without a pushed stream. + Http2PushPromiseIndexPeer::UnclaimedPushedStream entry1{GURL(), nullptr, 2}; + Http2PushPromiseIndexPeer::UnclaimedPushedStream entry2{GURL(), nullptr, + kNoPushedStreamFound}; + + // For "Compare", it is a requirement that comp(A, A) == false, see + // http://en.cppreference.com/w/cpp/concept/Compare. This will in fact imply + // that equiv(A, A) == true. + EXPECT_FALSE(Http2PushPromiseIndexPeer::CompareByUrl()(entry1, entry1)); + EXPECT_FALSE(Http2PushPromiseIndexPeer::CompareByUrl()(entry2, entry2)); + + std::set<Http2PushPromiseIndexPeer::UnclaimedPushedStream, + Http2PushPromiseIndexPeer::CompareByUrl> + entries; + bool success; + std::tie(std::ignore, success) = entries.insert(entry1); + EXPECT_TRUE(success); + + // Test that |entry1| is considered equivalent to itself by ensuring that + // a second insertion fails. + std::tie(std::ignore, success) = entries.insert(entry1); + EXPECT_FALSE(success); + + // Test that |entry1| and |entry2| are not equivalent. + std::tie(std::ignore, success) = entries.insert(entry2); + EXPECT_TRUE(success); + + // Test that |entry2| is equivalent to an existing entry + // (which then must be |entry2|). + std::tie(std::ignore, success) = entries.insert(entry2); + EXPECT_FALSE(success); +}; + +TEST(Http2PushPromiseIndexCompareByUrlTest, LookupByURL) { + const GURL url1("https://example.com:1"); + const GURL url2("https://example.com:2"); + const GURL url3("https://example.com:3"); + // This test relies on the order of these GURLs. + ASSERT_LT(url1, url2); + ASSERT_LT(url2, url3); + + // Create four entries, two for the middle URL, with distinct stream IDs not + // in ascending order. + Http2PushPromiseIndexPeer::UnclaimedPushedStream entry1{url1, nullptr, 8}; + Http2PushPromiseIndexPeer::UnclaimedPushedStream entry2{url2, nullptr, 4}; + Http2PushPromiseIndexPeer::UnclaimedPushedStream entry3{url2, nullptr, 6}; + Http2PushPromiseIndexPeer::UnclaimedPushedStream entry4{url3, nullptr, 2}; + + // Fill up a set. + std::set<Http2PushPromiseIndexPeer::UnclaimedPushedStream, + Http2PushPromiseIndexPeer::CompareByUrl> + entries; + entries.insert(entry1); + entries.insert(entry2); + entries.insert(entry3); + entries.insert(entry4); + ASSERT_EQ(4u, entries.size()); + + // Test that entries are ordered by URL first, not stream ID. + std::set<Http2PushPromiseIndexPeer::UnclaimedPushedStream, + Http2PushPromiseIndexPeer::CompareByUrl>::iterator it = + entries.begin(); + EXPECT_EQ(8u, it->stream_id); + ++it; + EXPECT_EQ(4u, it->stream_id); + ++it; + EXPECT_EQ(6u, it->stream_id); + ++it; + EXPECT_EQ(2u, it->stream_id); + ++it; + EXPECT_TRUE(it == entries.end()); + + // Test that kNoPushedStreamFound can be used to look up the first entry for a + // given URL. In particular, the first entry with |url2| is |entry2|. + EXPECT_TRUE( + entries.lower_bound(Http2PushPromiseIndexPeer::UnclaimedPushedStream{ + url2, nullptr, kNoPushedStreamFound}) == entries.find(entry2)); +}; + } // namespace test } // namespace net diff --git a/chromium/net/spdy/chromium/multiplexed_http_stream.cc b/chromium/net/spdy/chromium/multiplexed_http_stream.cc index 3148fed8d4c..0a685946f68 100644 --- a/chromium/net/spdy/chromium/multiplexed_http_stream.cc +++ b/chromium/net/spdy/chromium/multiplexed_http_stream.cc @@ -14,7 +14,7 @@ MultiplexedHttpStream::MultiplexedHttpStream( std::unique_ptr<MultiplexedSessionHandle> session) : session_(std::move(session)) {} -MultiplexedHttpStream::~MultiplexedHttpStream() {} +MultiplexedHttpStream::~MultiplexedHttpStream() = default; bool MultiplexedHttpStream::GetRemoteEndpoint(IPEndPoint* endpoint) { return session_->GetRemoteEndpoint(endpoint); diff --git a/chromium/net/spdy/chromium/multiplexed_session.cc b/chromium/net/spdy/chromium/multiplexed_session.cc index e49e69ba0e5..8b380265952 100644 --- a/chromium/net/spdy/chromium/multiplexed_session.cc +++ b/chromium/net/spdy/chromium/multiplexed_session.cc @@ -12,7 +12,7 @@ MultiplexedSessionHandle::MultiplexedSessionHandle( SaveSSLInfo(); } -MultiplexedSessionHandle::~MultiplexedSessionHandle() {} +MultiplexedSessionHandle::~MultiplexedSessionHandle() = default; bool MultiplexedSessionHandle::GetRemoteEndpoint(IPEndPoint* endpoint) { if (!session_) diff --git a/chromium/net/spdy/chromium/spdy_buffer_producer.cc b/chromium/net/spdy/chromium/spdy_buffer_producer.cc index 08847ecc523..294d826c1dc 100644 --- a/chromium/net/spdy/chromium/spdy_buffer_producer.cc +++ b/chromium/net/spdy/chromium/spdy_buffer_producer.cc @@ -13,14 +13,14 @@ namespace net { -SpdyBufferProducer::SpdyBufferProducer() {} +SpdyBufferProducer::SpdyBufferProducer() = default; -SpdyBufferProducer::~SpdyBufferProducer() {} +SpdyBufferProducer::~SpdyBufferProducer() = default; SimpleBufferProducer::SimpleBufferProducer(std::unique_ptr<SpdyBuffer> buffer) : buffer_(std::move(buffer)) {} -SimpleBufferProducer::~SimpleBufferProducer() {} +SimpleBufferProducer::~SimpleBufferProducer() = default; std::unique_ptr<SpdyBuffer> SimpleBufferProducer::ProduceBuffer() { DCHECK(buffer_); diff --git a/chromium/net/spdy/chromium/spdy_flags.cc b/chromium/net/spdy/chromium/spdy_flags.cc index a1d57cb1105..fd4a669fcf9 100644 --- a/chromium/net/spdy/chromium/spdy_flags.cc +++ b/chromium/net/spdy/chromium/spdy_flags.cc @@ -6,4 +6,7 @@ namespace net { +// Deliver OnPaddingLength separately from OnPadding. +bool FLAGS_chromium_http2_flag_h2_on_stream_pad_length = true; + } // namespace net diff --git a/chromium/net/spdy/chromium/spdy_flags.h b/chromium/net/spdy/chromium/spdy_flags.h index 7006618e388..5b188d3b8df 100644 --- a/chromium/net/spdy/chromium/spdy_flags.h +++ b/chromium/net/spdy/chromium/spdy_flags.h @@ -9,6 +9,9 @@ namespace net { +NET_EXPORT_PRIVATE extern bool + FLAGS_chromium_http2_flag_h2_on_stream_pad_length; + } // namespace net #endif // NET_SPDY_CHROMIUM_SPDY_FLAGS_H_ diff --git a/chromium/net/spdy/chromium/spdy_http_stream.cc b/chromium/net/spdy/chromium/spdy_http_stream.cc index 17a12834348..c8207afd236 100644 --- a/chromium/net/spdy/chromium/spdy_http_stream.cc +++ b/chromium/net/spdy/chromium/spdy_http_stream.cc @@ -33,11 +33,13 @@ namespace net { const size_t SpdyHttpStream::kRequestBodyBufferSize = 1 << 14; // 16KB SpdyHttpStream::SpdyHttpStream(const base::WeakPtr<SpdySession>& spdy_session, + SpdyStreamId pushed_stream_id, bool direct, NetLogSource source_dependency) : MultiplexedHttpStream( std::make_unique<MultiplexedSessionHandle>(spdy_session)), spdy_session_(spdy_session), + pushed_stream_id_(pushed_stream_id), is_reused_(spdy_session_->IsReused()), source_dependency_(source_dependency), stream_(nullptr), @@ -68,6 +70,7 @@ SpdyHttpStream::~SpdyHttpStream() { } int SpdyHttpStream::InitializeStream(const HttpRequestInfo* request_info, + bool can_send_early, RequestPriority priority, const NetLogWithSource& stream_net_log, const CompletionCallback& callback) { @@ -76,11 +79,10 @@ int SpdyHttpStream::InitializeStream(const HttpRequestInfo* request_info, return ERR_CONNECTION_CLOSED; request_info_ = request_info; - // TODO(bnc): Remove this condition once pushed headers are properly - // validated. https://crbug.com/554220. - if (request_info_->method == "GET") { - int error = spdy_session_->GetPushStream(request_info_->url, priority, - &stream_, stream_net_log); + if (pushed_stream_id_ != kNoPushedStreamFound) { + int error = + spdy_session_->GetPushedStream(request_info_->url, pushed_stream_id_, + priority, &stream_, stream_net_log); if (error != OK) return error; diff --git a/chromium/net/spdy/chromium/spdy_http_stream.h b/chromium/net/spdy/chromium/spdy_http_stream.h index fabdbaa8a2d..4eb48c522e6 100644 --- a/chromium/net/spdy/chromium/spdy_http_stream.h +++ b/chromium/net/spdy/chromium/spdy_http_stream.h @@ -36,6 +36,7 @@ class NET_EXPORT_PRIVATE SpdyHttpStream : public SpdyStream::Delegate, static const size_t kRequestBodyBufferSize; // |spdy_session| must not be NULL. SpdyHttpStream(const base::WeakPtr<SpdySession>& spdy_session, + SpdyStreamId pushed_stream_id, bool direct, NetLogSource source_dependency); ~SpdyHttpStream() override; @@ -48,6 +49,7 @@ class NET_EXPORT_PRIVATE SpdyHttpStream : public SpdyStream::Delegate, // HttpStream implementation. int InitializeStream(const HttpRequestInfo* request_info, + bool can_send_early, RequestPriority priority, const NetLogWithSource& net_log, const CompletionCallback& callback) override; @@ -133,6 +135,12 @@ class NET_EXPORT_PRIVATE SpdyHttpStream : public SpdyStream::Delegate, bool ShouldWaitForMoreBufferedData() const; const base::WeakPtr<SpdySession> spdy_session_; + + // The ID of the pushed stream if one is claimed by this request. + // In this case, the request fails if it cannot use that pushed stream. + // Otherwise set to kNoPushedStreamFound. + const SpdyStreamId pushed_stream_id_; + bool is_reused_; SpdyStreamRequest stream_request_; const NetLogSource source_dependency_; diff --git a/chromium/net/spdy/chromium/spdy_http_stream_unittest.cc b/chromium/net/spdy/chromium/spdy_http_stream_unittest.cc index 1db24232eb2..83f92b9580a 100644 --- a/chromium/net/spdy/chromium/spdy_http_stream_unittest.cc +++ b/chromium/net/spdy/chromium/spdy_http_stream_unittest.cc @@ -130,7 +130,7 @@ class SpdyHttpStreamTest : public testing::Test { session_deps_.net_log = &net_log_; } - ~SpdyHttpStreamTest() override {} + ~SpdyHttpStreamTest() override = default; protected: void TearDown() override { @@ -197,14 +197,14 @@ TEST_F(SpdyHttpStreamTest, SendRequest) { HttpResponseInfo response; HttpRequestHeaders headers; NetLogWithSource net_log; - auto http_stream = - std::make_unique<SpdyHttpStream>(session_, true, net_log.source()); + auto http_stream = std::make_unique<SpdyHttpStream>( + session_, kNoPushedStreamFound, true, net_log.source()); // Make sure getting load timing information the stream early does not crash. LoadTimingInfo load_timing_info; EXPECT_FALSE(http_stream->GetLoadTimingInfo(&load_timing_info)); - ASSERT_THAT(http_stream->InitializeStream(&request, DEFAULT_PRIORITY, net_log, - CompletionCallback()), + ASSERT_THAT(http_stream->InitializeStream(&request, true, DEFAULT_PRIORITY, + net_log, CompletionCallback()), IsOk()); EXPECT_FALSE(http_stream->GetLoadTimingInfo(&load_timing_info)); @@ -254,12 +254,13 @@ TEST_F(SpdyHttpStreamTest, RequestInfoDestroyedBeforeRead) { HttpResponseInfo response; HttpRequestHeaders headers; NetLogWithSource net_log; - auto http_stream = - std::make_unique<SpdyHttpStream>(session_, true, net_log.source()); + auto http_stream = std::make_unique<SpdyHttpStream>( + session_, kNoPushedStreamFound, true, net_log.source()); - ASSERT_THAT(http_stream->InitializeStream(request.get(), DEFAULT_PRIORITY, - net_log, CompletionCallback()), - IsOk()); + ASSERT_THAT( + http_stream->InitializeStream(request.get(), true, DEFAULT_PRIORITY, + net_log, CompletionCallback()), + IsOk()); EXPECT_THAT(http_stream->SendRequest(headers, &response, callback.callback()), IsError(ERR_IO_PENDING)); EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key_)); @@ -316,8 +317,8 @@ TEST_F(SpdyHttpStreamTest, LoadTimingTwoRequests) { HttpResponseInfo response1; HttpRequestHeaders headers1; NetLogWithSource net_log; - auto http_stream1 = - std::make_unique<SpdyHttpStream>(session_, true, net_log.source()); + auto http_stream1 = std::make_unique<SpdyHttpStream>( + session_, kNoPushedStreamFound, true, net_log.source()); HttpRequestInfo request2; request2.method = "GET"; @@ -325,11 +326,11 @@ TEST_F(SpdyHttpStreamTest, LoadTimingTwoRequests) { TestCompletionCallback callback2; HttpResponseInfo response2; HttpRequestHeaders headers2; - auto http_stream2 = - std::make_unique<SpdyHttpStream>(session_, true, net_log.source()); + auto http_stream2 = std::make_unique<SpdyHttpStream>( + session_, kNoPushedStreamFound, true, net_log.source()); // First write. - ASSERT_THAT(http_stream1->InitializeStream(&request1, DEFAULT_PRIORITY, + ASSERT_THAT(http_stream1->InitializeStream(&request1, true, DEFAULT_PRIORITY, net_log, CompletionCallback()), IsOk()); EXPECT_THAT( @@ -346,7 +347,7 @@ TEST_F(SpdyHttpStreamTest, LoadTimingTwoRequests) { EXPECT_FALSE(http_stream2->GetLoadTimingInfo(&load_timing_info2)); // Second write. - ASSERT_THAT(http_stream2->InitializeStream(&request2, DEFAULT_PRIORITY, + ASSERT_THAT(http_stream2->InitializeStream(&request2, true, DEFAULT_PRIORITY, net_log, CompletionCallback()), IsOk()); EXPECT_THAT( @@ -423,9 +424,10 @@ TEST_F(SpdyHttpStreamTest, SendChunkedPost) { HttpResponseInfo response; HttpRequestHeaders headers; NetLogWithSource net_log; - SpdyHttpStream http_stream(session_, true, net_log.source()); - ASSERT_THAT(http_stream.InitializeStream(&request, DEFAULT_PRIORITY, net_log, - CompletionCallback()), + SpdyHttpStream http_stream(session_, kNoPushedStreamFound, true, + net_log.source()); + ASSERT_THAT(http_stream.InitializeStream(&request, false, DEFAULT_PRIORITY, + net_log, CompletionCallback()), IsOk()); EXPECT_THAT(http_stream.SendRequest(headers, &response, callback.callback()), @@ -478,9 +480,10 @@ TEST_F(SpdyHttpStreamTest, SendChunkedPostLastEmpty) { HttpResponseInfo response; HttpRequestHeaders headers; NetLogWithSource net_log; - SpdyHttpStream http_stream(session_, true, net_log.source()); - ASSERT_THAT(http_stream.InitializeStream(&request, DEFAULT_PRIORITY, net_log, - CompletionCallback()), + SpdyHttpStream http_stream(session_, kNoPushedStreamFound, true, + net_log.source()); + ASSERT_THAT(http_stream.InitializeStream(&request, false, DEFAULT_PRIORITY, + net_log, CompletionCallback()), IsOk()); EXPECT_THAT(http_stream.SendRequest(headers, &response, callback.callback()), IsError(ERR_IO_PENDING)); @@ -532,9 +535,10 @@ TEST_F(SpdyHttpStreamTest, ConnectionClosedDuringChunkedPost) { HttpResponseInfo response; HttpRequestHeaders headers; NetLogWithSource net_log; - SpdyHttpStream http_stream(session_, true, net_log.source()); - ASSERT_THAT(http_stream.InitializeStream(&request, DEFAULT_PRIORITY, net_log, - CompletionCallback()), + SpdyHttpStream http_stream(session_, kNoPushedStreamFound, true, + net_log.source()); + ASSERT_THAT(http_stream.InitializeStream(&request, false, DEFAULT_PRIORITY, + net_log, CompletionCallback()), IsOk()); EXPECT_THAT(http_stream.SendRequest(headers, &response, callback.callback()), @@ -600,10 +604,10 @@ TEST_F(SpdyHttpStreamTest, DelayedSendChunkedPost) { upload_stream.AppendData(kUploadData, kUploadDataSize, false); NetLogWithSource net_log; - auto http_stream = - std::make_unique<SpdyHttpStream>(session_, true, net_log.source()); - ASSERT_THAT(http_stream->InitializeStream(&request, DEFAULT_PRIORITY, net_log, - CompletionCallback()), + auto http_stream = std::make_unique<SpdyHttpStream>( + session_, kNoPushedStreamFound, true, net_log.source()); + ASSERT_THAT(http_stream->InitializeStream(&request, false, DEFAULT_PRIORITY, + net_log, CompletionCallback()), IsOk()); TestCompletionCallback callback; @@ -695,10 +699,10 @@ TEST_F(SpdyHttpStreamTest, DelayedSendChunkedPostWithEmptyFinalDataFrame) { upload_stream.AppendData(kUploadData, kUploadDataSize, false); NetLogWithSource net_log; - auto http_stream = - std::make_unique<SpdyHttpStream>(session_, true, net_log.source()); - ASSERT_THAT(http_stream->InitializeStream(&request, DEFAULT_PRIORITY, net_log, - CompletionCallback()), + auto http_stream = std::make_unique<SpdyHttpStream>( + session_, kNoPushedStreamFound, true, net_log.source()); + ASSERT_THAT(http_stream->InitializeStream(&request, false, DEFAULT_PRIORITY, + net_log, CompletionCallback()), IsOk()); TestCompletionCallback callback; @@ -779,10 +783,10 @@ TEST_F(SpdyHttpStreamTest, ChunkedPostWithEmptyPayload) { upload_stream.AppendData("", 0, true); NetLogWithSource net_log; - auto http_stream = - std::make_unique<SpdyHttpStream>(session_, true, net_log.source()); - ASSERT_THAT(http_stream->InitializeStream(&request, DEFAULT_PRIORITY, net_log, - CompletionCallback()), + auto http_stream = std::make_unique<SpdyHttpStream>( + session_, kNoPushedStreamFound, true, net_log.source()); + ASSERT_THAT(http_stream->InitializeStream(&request, false, DEFAULT_PRIORITY, + net_log, CompletionCallback()), IsOk()); TestCompletionCallback callback; @@ -839,10 +843,10 @@ TEST_F(SpdyHttpStreamTest, SpdyURLTest) { HttpResponseInfo response; HttpRequestHeaders headers; NetLogWithSource net_log; - auto http_stream = - std::make_unique<SpdyHttpStream>(session_, true, net_log.source()); - ASSERT_THAT(http_stream->InitializeStream(&request, DEFAULT_PRIORITY, net_log, - CompletionCallback()), + auto http_stream = std::make_unique<SpdyHttpStream>( + session_, kNoPushedStreamFound, true, net_log.source()); + ASSERT_THAT(http_stream->InitializeStream(&request, true, DEFAULT_PRIORITY, + net_log, CompletionCallback()), IsOk()); EXPECT_THAT(http_stream->SendRequest(headers, &response, callback.callback()), @@ -892,10 +896,10 @@ TEST_F(SpdyHttpStreamTest, DelayedSendChunkedPostWithWindowUpdate) { IsOk()); NetLogWithSource net_log; - auto http_stream = - std::make_unique<SpdyHttpStream>(session_, true, net_log.source()); - ASSERT_THAT(http_stream->InitializeStream(&request, DEFAULT_PRIORITY, net_log, - CompletionCallback()), + auto http_stream = std::make_unique<SpdyHttpStream>( + session_, kNoPushedStreamFound, true, net_log.source()); + ASSERT_THAT(http_stream->InitializeStream(&request, false, DEFAULT_PRIORITY, + net_log, CompletionCallback()), IsOk()); HttpRequestHeaders headers; @@ -997,9 +1001,10 @@ TEST_F(SpdyHttpStreamTest, DataReadErrorSynchronous) { HttpResponseInfo response; HttpRequestHeaders headers; NetLogWithSource net_log; - SpdyHttpStream http_stream(session_, true, net_log.source()); - ASSERT_THAT(http_stream.InitializeStream(&request, DEFAULT_PRIORITY, net_log, - CompletionCallback()), + SpdyHttpStream http_stream(session_, kNoPushedStreamFound, true, + net_log.source()); + ASSERT_THAT(http_stream.InitializeStream(&request, false, DEFAULT_PRIORITY, + net_log, CompletionCallback()), IsOk()); int result = http_stream.SendRequest(headers, &response, callback.callback()); @@ -1050,9 +1055,10 @@ TEST_F(SpdyHttpStreamTest, DataReadErrorAsynchronous) { HttpResponseInfo response; HttpRequestHeaders headers; NetLogWithSource net_log; - SpdyHttpStream http_stream(session_, true, net_log.source()); - ASSERT_THAT(http_stream.InitializeStream(&request, DEFAULT_PRIORITY, net_log, - CompletionCallback()), + SpdyHttpStream http_stream(session_, kNoPushedStreamFound, true, + net_log.source()); + ASSERT_THAT(http_stream.InitializeStream(&request, false, DEFAULT_PRIORITY, + net_log, CompletionCallback()), IsOk()); int result = http_stream.SendRequest(headers, &response, callback.callback()); @@ -1092,9 +1098,10 @@ TEST_F(SpdyHttpStreamTest, RequestCallbackCancelsStream) { upload_stream.AppendData("", 0, true); NetLogWithSource net_log; - SpdyHttpStream http_stream(session_, true, net_log.source()); - ASSERT_THAT(http_stream.InitializeStream(&request, DEFAULT_PRIORITY, net_log, - CompletionCallback()), + SpdyHttpStream http_stream(session_, kNoPushedStreamFound, true, + net_log.source()); + ASSERT_THAT(http_stream.InitializeStream(&request, false, DEFAULT_PRIORITY, + net_log, CompletionCallback()), IsOk()); CancelStreamCallback callback(&http_stream); diff --git a/chromium/net/spdy/chromium/spdy_network_transaction_unittest.cc b/chromium/net/spdy/chromium/spdy_network_transaction_unittest.cc index 6d4e16fded3..0da92cf6a27 100644 --- a/chromium/net/spdy/chromium/spdy_network_transaction_unittest.cc +++ b/chromium/net/spdy/chromium/spdy_network_transaction_unittest.cc @@ -22,6 +22,7 @@ #include "net/base/test_proxy_delegate.h" #include "net/base/upload_bytes_element_reader.h" #include "net/base/upload_file_element_reader.h" +#include "net/dns/mock_host_resolver.h" #include "net/http/http_auth_scheme.h" #include "net/http/http_network_session.h" #include "net/http/http_network_session_peer.h" @@ -392,8 +393,8 @@ class SpdyNetworkTransactionTest : public ::testing::Test { session->spdy_session_pool()->FindAvailableSession( key, /* enable_ip_based_pooling = */ true, log_); ASSERT_TRUE(spdy_session); - EXPECT_EQ(0u, spdy_session->num_active_streams()); - EXPECT_EQ(0u, spdy_session->num_unclaimed_pushed_streams()); + EXPECT_EQ(0u, num_active_streams(spdy_session)); + EXPECT_EQ(0u, num_unclaimed_pushed_streams(spdy_session)); } void RunServerPushTest(SequencedSocketData* data, @@ -518,6 +519,28 @@ class SpdyNetworkTransactionTest : public ::testing::Test { return SpdyString(kDefaultUrl) + path; } + size_t num_active_streams(base::WeakPtr<SpdySession> session) { + return session->active_streams_.size(); + } + + static size_t num_unclaimed_pushed_streams( + base::WeakPtr<SpdySession> session) { + return session->pool_->push_promise_index()->CountStreamsForSession( + session.get()); + } + + static bool has_unclaimed_pushed_stream_for_url( + base::WeakPtr<SpdySession> session, + const GURL& url) { + return session->pool_->push_promise_index()->FindStream( + url, session.get()) != kNoPushedStreamFound; + } + + static SpdyStreamId spdy_stream_hi_water_mark( + base::WeakPtr<SpdySession> session) { + return session->stream_hi_water_mark_; + } + const GURL default_url_; const HostPortPair host_port_pair_; HttpRequestInfo request_; @@ -1237,7 +1260,7 @@ class KillerCallback : public TestCompletionCallbackBase { base::Unretained(this))) { } - ~KillerCallback() override {} + ~KillerCallback() override = default; const CompletionCallback& callback() const { return callback_; } @@ -2114,7 +2137,7 @@ TEST_F(SpdyNetworkTransactionTest, &push_headers); SpdySerializedFrame push_init_frame( - spdy_util_.ConstructInitialSpdyPushFrame(std::move(push_headers), 2, 1)); + spdy_util_.ConstructSpdyPushPromise(1, 2, std::move(push_headers))); SpdySerializedFrame push_headers_frame( spdy_util_.ConstructSpdyPushHeaders(2, nullptr, 0)); @@ -2372,6 +2395,138 @@ TEST_F(SpdyNetworkTransactionTest, ServerPushSingleDataFrame) { EXPECT_EQ("HTTP/1.1 200", response2.headers->GetStatusLine()); } +TEST_F(SpdyNetworkTransactionTest, ServerPushHeadMethod) { + SpdySerializedFrame req( + spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true)); + SpdySerializedFrame priority( + spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true)); + MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(priority, 2)}; + + SpdyHeaderBlock push_promise_header_block; + push_promise_header_block[kHttp2MethodHeader] = "HEAD"; + spdy_util_.AddUrlToHeaderBlock(GetDefaultUrlWithPath("/foo.dat"), + &push_promise_header_block); + SpdySerializedFrame push_promise(spdy_util_.ConstructSpdyPushPromise( + 1, 2, std::move(push_promise_header_block))); + + SpdyHeaderBlock push_response_headers; + push_response_headers[kHttp2StatusHeader] = "200"; + push_response_headers["foo"] = "bar"; + SpdyHeadersIR headers_ir(2, std::move(push_response_headers)); + SpdySerializedFrame push_headers(spdy_util_.SerializeFrame(headers_ir)); + + SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); + SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true)); + MockRead reads[] = { + CreateMockRead(push_promise, 1), CreateMockRead(push_headers, 3), + CreateMockRead(resp, 4), CreateMockRead(body, 5), + // Do not close the connection after first request is done. + MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6)}; + + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); + + NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr); + helper.RunPreTestSetup(); + helper.AddData(&data); + + // Run first request. This reads PUSH_PROMISE. + helper.RunDefaultTest(); + + // Request the pushed resource. + HttpNetworkTransaction trans(DEFAULT_PRIORITY, helper.session()); + HttpRequestInfo request = CreateGetPushRequest(); + request.method = "HEAD"; + TestCompletionCallback callback; + int rv = trans.Start(&request, callback.callback(), log_); + EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); + rv = callback.WaitForResult(); + EXPECT_THAT(rv, IsOk()); + + const HttpResponseInfo* response = trans.GetResponseInfo(); + ASSERT_TRUE(response); + EXPECT_TRUE(response->was_fetched_via_spdy); + EXPECT_TRUE(response->was_alpn_negotiated); + ASSERT_TRUE(response->headers); + EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine()); + std::string value; + EXPECT_TRUE(response->headers->GetNormalizedHeader("foo", &value)); + EXPECT_EQ("bar", value); + + helper.VerifyDataConsumed(); +} + +TEST_F(SpdyNetworkTransactionTest, ServerPushHeadDoesNotMatchGetRequest) { + SpdySerializedFrame req1( + spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true)); + SpdySerializedFrame priority( + spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true)); + spdy_util_.UpdateWithStreamDestruction(1); + SpdySerializedFrame req2(spdy_util_.ConstructSpdyGet( + GetDefaultUrlWithPath("/foo.dat").c_str(), 3, LOWEST)); + MockWrite writes[] = {CreateMockWrite(req1, 0), CreateMockWrite(priority, 2), + CreateMockWrite(req2, 6)}; + + SpdyHeaderBlock push_promise_header_block; + push_promise_header_block[kHttp2MethodHeader] = "HEAD"; + spdy_util_.AddUrlToHeaderBlock(GetDefaultUrlWithPath("/foo.dat"), + &push_promise_header_block); + SpdySerializedFrame push_promise(spdy_util_.ConstructSpdyPushPromise( + 1, 2, std::move(push_promise_header_block))); + + SpdyHeaderBlock push_response_headers; + push_response_headers[kHttp2StatusHeader] = "200"; + push_response_headers["foo"] = "bar"; + SpdyHeadersIR headers_ir(2, std::move(push_response_headers)); + SpdySerializedFrame push_headers(spdy_util_.SerializeFrame(headers_ir)); + + SpdySerializedFrame resp1(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); + SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true)); + SpdySerializedFrame resp2(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3)); + SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, true)); + MockRead reads[] = {CreateMockRead(push_promise, 1), + CreateMockRead(push_headers, 3), + CreateMockRead(resp1, 4), + CreateMockRead(body1, 5), + CreateMockRead(resp2, 7), + CreateMockRead(body2, 8), + MockRead(ASYNC, 0, 9)}; + + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); + + NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr); + helper.RunPreTestSetup(); + helper.AddData(&data); + + // Run first request. This reads PUSH_PROMISE. + helper.RunDefaultTest(); + + // Request the pushed resource. + HttpNetworkTransaction trans(DEFAULT_PRIORITY, helper.session()); + HttpRequestInfo request = CreateGetPushRequest(); + TestCompletionCallback callback; + int rv = trans.Start(&request, callback.callback(), log_); + EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); + rv = callback.WaitForResult(); + EXPECT_THAT(rv, IsOk()); + + const HttpResponseInfo* response = trans.GetResponseInfo(); + ASSERT_TRUE(response); + EXPECT_TRUE(response->was_fetched_via_spdy); + EXPECT_TRUE(response->was_alpn_negotiated); + ASSERT_TRUE(response->headers); + EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine()); + std::string value; + EXPECT_FALSE(response->headers->GetNormalizedHeader("foo", &value)); + std::string result; + ReadResult(&trans, &result); + EXPECT_EQ("hello!", result); + + // Read EOF. + base::RunLoop().RunUntilIdle(); + + helper.VerifyDataConsumed(); +} + TEST_F(SpdyNetworkTransactionTest, ServerPushBeforeHeaders) { SpdySerializedFrame stream1_syn( spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true)); @@ -2780,15 +2935,13 @@ TEST_F(SpdyNetworkTransactionTest, ServerPushInvalidUrl) { // Can't use ConstructSpdyPush here since it wants to parse a URL and // split it into the appropriate :header pieces. So we have to hand-fill // those pieces in. - SpdyFramer response_spdy_framer(SpdyFramer::ENABLE_COMPRESSION); SpdyHeaderBlock push_promise_header_block; push_promise_header_block[kHttp2AuthorityHeader] = ""; push_promise_header_block[kHttp2SchemeHeader] = ""; push_promise_header_block[kHttp2PathHeader] = "/index.html"; - SpdyPushPromiseIR push_promise(1, 2, std::move(push_promise_header_block)); - SpdySerializedFrame push_promise_frame( - response_spdy_framer.SerializeFrame(push_promise)); + SpdySerializedFrame push_promise(spdy_util_.ConstructSpdyPushPromise( + 1, 2, std::move(push_promise_header_block))); SpdySerializedFrame stream2_rst( spdy_util_.ConstructSpdyRstStream(2, ERROR_CODE_REFUSED_STREAM)); @@ -2796,7 +2949,7 @@ TEST_F(SpdyNetworkTransactionTest, ServerPushInvalidUrl) { MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(stream2_rst, 2)}; MockRead reads[] = { - CreateMockRead(push_promise_frame, 1), MockRead(ASYNC, 0, 3) /* EOF */ + CreateMockRead(push_promise, 1), MockRead(ASYNC, 0, 3) /* EOF */ }; SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); RunBrokenPushTest(&data, ERR_CONNECTION_CLOSED); @@ -2861,8 +3014,8 @@ TEST_F(SpdyNetworkTransactionTest, ServerPushNoURL) { SpdyHeaderBlock incomplete_headers; incomplete_headers[kHttp2StatusHeader] = "200 OK"; incomplete_headers["hello"] = "bye"; - SpdySerializedFrame stream2_syn(spdy_util_.ConstructInitialSpdyPushFrame( - std::move(incomplete_headers), 2, 1)); + SpdySerializedFrame stream2_syn( + spdy_util_.ConstructSpdyPushPromise(1, 2, std::move(incomplete_headers))); MockRead reads[] = { CreateMockRead(stream1_reply, 1), CreateMockRead(stream2_syn, 2), CreateMockRead(stream1_body, 4), @@ -2957,15 +3110,14 @@ TEST_F(SpdyNetworkTransactionTest, ServerPushOnClosedPushedStream) { SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway( 2, ERROR_CODE_PROTOCOL_ERROR, "Received pushed stream id 4 on invalid stream id 2 (must be odd).")); - MockWrite writes[] = { - CreateMockWrite(stream1_syn, 0), CreateMockWrite(stream2_priority, 3), - CreateMockWrite(goaway, 8), - }; + MockWrite writes[] = {CreateMockWrite(stream1_syn, 0), + CreateMockWrite(stream2_priority, 3), + CreateMockWrite(goaway, 8)}; - SpdySerializedFrame stream1_reply( - spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); SpdySerializedFrame stream2_syn(spdy_util_.ConstructSpdyPush( nullptr, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str())); + SpdySerializedFrame stream1_reply( + spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); SpdySerializedFrame stream1_body(spdy_util_.ConstructSpdyDataFrame(1, true)); const char kPushedData[] = "pushed"; SpdySerializedFrame stream2_body(spdy_util_.ConstructSpdyDataFrame( @@ -2974,10 +3126,9 @@ TEST_F(SpdyNetworkTransactionTest, ServerPushOnClosedPushedStream) { nullptr, 0, 4, 2, GetDefaultUrlWithPath("/bar.dat").c_str())); MockRead reads[] = { - CreateMockRead(stream1_reply, 1), CreateMockRead(stream2_syn, 2), + CreateMockRead(stream2_syn, 1), CreateMockRead(stream1_reply, 2), CreateMockRead(stream1_body, 4), CreateMockRead(stream2_body, 5), - MockRead(ASYNC, ERR_IO_PENDING, 6), CreateMockRead(stream3_syn, 7), - }; + MockRead(ASYNC, ERR_IO_PENDING, 6), CreateMockRead(stream3_syn, 7)}; SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr); @@ -3013,6 +3164,216 @@ TEST_F(SpdyNetworkTransactionTest, ServerPushOnClosedPushedStream) { EXPECT_TRUE(data.AllWriteDataConsumed()); } +TEST_F(SpdyNetworkTransactionTest, ServerCancelsPush) { + SpdySerializedFrame req1( + spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true)); + SpdySerializedFrame priority( + spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true)); + spdy_util_.UpdateWithStreamDestruction(1); + SpdySerializedFrame req2(spdy_util_.ConstructSpdyGet( + GetDefaultUrlWithPath("/foo.dat").c_str(), 3, LOWEST)); + MockWrite writes1[] = {CreateMockWrite(req1, 0), CreateMockWrite(priority, 3), + CreateMockWrite(req2, 6)}; + + SpdySerializedFrame reply1(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); + SpdySerializedFrame push(spdy_util_.ConstructSpdyPush( + nullptr, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str())); + SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true)); + SpdySerializedFrame rst( + spdy_util_.ConstructSpdyRstStream(2, ERROR_CODE_INTERNAL_ERROR)); + SpdySerializedFrame reply2(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3)); + SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, true)); + MockRead reads1[] = {CreateMockRead(reply1, 1), CreateMockRead(push, 2), + CreateMockRead(body1, 4), CreateMockRead(rst, 5), + CreateMockRead(reply2, 7), CreateMockRead(body2, 8), + MockRead(ASYNC, 0, 9)}; + + SequencedSocketData data(reads1, arraysize(reads1), writes1, + arraysize(writes1)); + + NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr); + helper.RunPreTestSetup(); + helper.AddData(&data); + + // First request opens up connection. + HttpNetworkTransaction* trans1 = helper.trans(); + TestCompletionCallback callback1; + int rv = trans1->Start(&request_, callback1.callback(), log_); + EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); + + // Read until response body arrives. PUSH_PROMISE comes earlier. + rv = callback1.WaitForResult(); + EXPECT_THAT(rv, IsOk()); + const HttpResponseInfo* response = trans1->GetResponseInfo(); + EXPECT_TRUE(response->headers); + EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine()); + std::string result1; + ReadResult(trans1, &result1); + EXPECT_EQ("hello!", result1); + + SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool(); + SpdySessionKey key(host_port_pair_, ProxyServer::Direct(), + PRIVACY_MODE_DISABLED); + base::WeakPtr<SpdySession> spdy_session = + spdy_session_pool->FindAvailableSession( + key, /* enable_ip_based_pooling = */ true, log_); + EXPECT_EQ(1u, num_unclaimed_pushed_streams(spdy_session)); + + // Create request matching pushed stream. + HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session()); + HttpRequestInfo request2 = CreateGetPushRequest(); + TestCompletionCallback callback2; + rv = trans2.Start(&request2, callback2.callback(), log_); + EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); + + // Pushed stream is now claimed by second request. + EXPECT_EQ(0u, num_unclaimed_pushed_streams(spdy_session)); + + // Second request receives RST_STREAM and is retried on the same connection. + rv = callback2.WaitForResult(); + EXPECT_THAT(rv, IsOk()); + response = trans2.GetResponseInfo(); + EXPECT_TRUE(response->headers); + EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine()); + std::string result2; + ReadResult(&trans2, &result2); + EXPECT_EQ("hello!", result2); + + // Read EOF. + base::RunLoop().RunUntilIdle(); + + helper.VerifyDataConsumed(); +} + +// Regression test for https://crbug.com/776415. +// A client-initiated request can only pool to an existing HTTP/2 connection if +// the IP address matches. However, a resource can be pushed by the server on a +// connection even if the IP address does not match. This test verifies that if +// the request binds to such a pushed stream, and after that the server resets +// the stream before SpdySession::GetPushedStream() is called, then the retry +// (using a client-initiated stream) does not pool to this connection. +TEST_F(SpdyNetworkTransactionTest, ServerCancelsCrossOriginPush) { + const char* kUrl1 = "https://www.example.org"; + const char* kUrl2 = "https://mail.example.org"; + + auto resolver = std::make_unique<MockHostResolver>(); + resolver->rules()->ClearRules(); + resolver->rules()->AddRule("www.example.org", "127.0.0.1"); + resolver->rules()->AddRule("mail.example.org", "127.0.0.2"); + + auto session_deps = std::make_unique<SpdySessionDependencies>(); + session_deps->host_resolver = std::move(resolver); + NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, + std::move(session_deps)); + + SpdySerializedFrame req1(spdy_util_.ConstructSpdyGet(kUrl1, 1, LOWEST)); + SpdySerializedFrame priority( + spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true)); + MockWrite writes1[] = {CreateMockWrite(req1, 0), + CreateMockWrite(priority, 3)}; + + SpdySerializedFrame reply1(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); + SpdySerializedFrame push( + spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kUrl2)); + SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true)); + SpdySerializedFrame rst( + spdy_util_.ConstructSpdyRstStream(2, ERROR_CODE_INTERNAL_ERROR)); + MockRead reads1[] = { + CreateMockRead(reply1, 1), CreateMockRead(push, 2), + CreateMockRead(body1, 4), CreateMockRead(rst, 5), + MockRead(ASYNC, ERR_IO_PENDING, 6), MockRead(ASYNC, 0, 7)}; + + SequencedSocketData data1(reads1, arraysize(reads1), writes1, + arraysize(writes1)); + + SpdyTestUtil spdy_util2; + SpdySerializedFrame req2(spdy_util2.ConstructSpdyGet(kUrl2, 1, LOWEST)); + MockWrite writes2[] = {CreateMockWrite(req2, 0)}; + + SpdySerializedFrame reply2(spdy_util2.ConstructSpdyGetReply(nullptr, 0, 1)); + base::StringPiece kData("Response on the second connection."); + SpdySerializedFrame body2( + spdy_util2.ConstructSpdyDataFrame(1, kData.data(), kData.size(), true)); + MockRead reads2[] = {CreateMockRead(reply2, 1), CreateMockRead(body2, 2), + MockRead(ASYNC, 0, 3)}; + + SequencedSocketData data2(reads2, arraysize(reads2), writes2, + arraysize(writes2)); + + helper.RunPreTestSetup(); + helper.AddData(&data1); + helper.AddData(&data2); + + // First request opens up connection to www.example.org. + HttpNetworkTransaction* trans1 = helper.trans(); + HttpRequestInfo request1; + request1.method = "GET"; + request1.url = GURL(kUrl1); + TestCompletionCallback callback1; + int rv = trans1->Start(&request1, callback1.callback(), log_); + EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); + + // Read until response body arrives. PUSH_PROMISE comes earlier. + rv = callback1.WaitForResult(); + EXPECT_THAT(rv, IsOk()); + const HttpResponseInfo* response = trans1->GetResponseInfo(); + EXPECT_TRUE(response->headers); + EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine()); + std::string result1; + ReadResult(trans1, &result1); + EXPECT_EQ("hello!", result1); + + SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool(); + SpdySessionKey key1(HostPortPair::FromURL(GURL(kUrl1)), ProxyServer::Direct(), + PRIVACY_MODE_DISABLED); + base::WeakPtr<SpdySession> spdy_session1 = + spdy_session_pool->FindAvailableSession( + key1, /* enable_ip_based_pooling = */ true, log_); + EXPECT_EQ(1u, num_unclaimed_pushed_streams(spdy_session1)); + + // While cross-origin push for kUrl2 is allowed on spdy_session1, + // a client-initiated request would not pool to this connection, + // because the IP address does not match. + SpdySessionKey key2(HostPortPair::FromURL(GURL(kUrl2)), ProxyServer::Direct(), + PRIVACY_MODE_DISABLED); + EXPECT_FALSE(spdy_session_pool->FindAvailableSession( + key2, /* enable_ip_based_pooling = */ true, log_)); + + // Create request matching pushed stream. + HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session()); + HttpRequestInfo request2; + request2.method = "GET"; + request2.url = GURL(kUrl2); + TestCompletionCallback callback2; + rv = trans2.Start(&request2, callback2.callback(), log_); + EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); + + // Pushed stream is now claimed by second request. + EXPECT_EQ(0u, num_unclaimed_pushed_streams(spdy_session1)); + + // Second request receives RST_STREAM and is retried on a new connection. + rv = callback2.WaitForResult(); + EXPECT_THAT(rv, IsOk()); + response = trans2.GetResponseInfo(); + EXPECT_TRUE(response->headers); + EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine()); + std::string result2; + ReadResult(&trans2, &result2); + EXPECT_EQ("Response on the second connection.", result2); + + // Make sure that the first connection is still open. This is important in + // order to test that the retry created its own connection (because the IP + // address does not match), instead of using the connection of the cancelled + // pushed stream. + EXPECT_TRUE(spdy_session1); + + // Read EOF. + data1.Resume(); + base::RunLoop().RunUntilIdle(); + + helper.VerifyDataConsumed(); +} + // Regression test for https://crbug.com/727653. TEST_F(SpdyNetworkTransactionTest, RejectServerPushWithNoMethod) { SpdySerializedFrame req( @@ -3024,16 +3385,15 @@ TEST_F(SpdyNetworkTransactionTest, RejectServerPushWithNoMethod) { SpdySerializedFrame reply(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); SpdyHeaderBlock push_promise_header_block; - spdy_util_.AddUrlToHeaderBlock(GetDefaultUrlWithPath("/foo.dat").c_str(), + spdy_util_.AddUrlToHeaderBlock(GetDefaultUrlWithPath("/foo.dat"), &push_promise_header_block); - SpdyPushPromiseIR push_promise(1, 2, std::move(push_promise_header_block)); - SpdySerializedFrame push_promise_frame( - spdy_util_.SerializeFrame(push_promise)); + SpdySerializedFrame push_promise(spdy_util_.ConstructSpdyPushPromise( + 1, 2, std::move(push_promise_header_block))); SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true)); - MockRead reads[] = { - CreateMockRead(reply, 1), CreateMockRead(push_promise_frame, 2), - CreateMockRead(body, 4), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5)}; + MockRead reads[] = {CreateMockRead(reply, 1), CreateMockRead(push_promise, 2), + CreateMockRead(body, 4), + MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5)}; SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr); @@ -3052,16 +3412,15 @@ TEST_F(SpdyNetworkTransactionTest, RejectServerPushWithInvalidMethod) { SpdyHeaderBlock push_promise_header_block; push_promise_header_block[":method"] = "POST"; - spdy_util_.AddUrlToHeaderBlock(GetDefaultUrlWithPath("/foo.dat").c_str(), + spdy_util_.AddUrlToHeaderBlock(GetDefaultUrlWithPath("/foo.dat"), &push_promise_header_block); - SpdyPushPromiseIR push_promise(1, 2, std::move(push_promise_header_block)); - SpdySerializedFrame push_promise_frame( - spdy_util_.SerializeFrame(push_promise)); + SpdySerializedFrame push_promise(spdy_util_.ConstructSpdyPushPromise( + 1, 2, std::move(push_promise_header_block))); SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true)); - MockRead reads[] = { - CreateMockRead(reply, 1), CreateMockRead(push_promise_frame, 2), - CreateMockRead(body, 4), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5)}; + MockRead reads[] = {CreateMockRead(reply, 1), CreateMockRead(push_promise, 2), + CreateMockRead(body, 4), + MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5)}; SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr); @@ -4607,8 +4966,8 @@ TEST_F(SpdyNetworkTransactionTest, ServerPushWithHeaders) { initial_headers[":method"] = "GET"; spdy_util_.AddUrlToHeaderBlock(GetDefaultUrlWithPath("/foo.dat"), &initial_headers); - SpdySerializedFrame stream2_syn(spdy_util_.ConstructInitialSpdyPushFrame( - std::move(initial_headers), 2, 1)); + SpdySerializedFrame stream2_syn( + spdy_util_.ConstructSpdyPushPromise(1, 2, std::move(initial_headers))); SpdyHeaderBlock late_headers; late_headers[kHttp2StatusHeader] = "200"; @@ -4666,8 +5025,8 @@ TEST_F(SpdyNetworkTransactionTest, ServerPushClaimBeforeHeaders) { initial_headers[":method"] = "GET"; spdy_util_.AddUrlToHeaderBlock(GetDefaultUrlWithPath("/foo.dat"), &initial_headers); - SpdySerializedFrame stream2_syn(spdy_util_.ConstructInitialSpdyPushFrame( - std::move(initial_headers), 2, 1)); + SpdySerializedFrame stream2_syn( + spdy_util_.ConstructSpdyPushPromise(1, 2, std::move(initial_headers))); SpdySerializedFrame stream1_body(spdy_util_.ConstructSpdyDataFrame(1, true)); SpdyHeaderBlock late_headers; late_headers[kHttp2StatusHeader] = "200"; @@ -4973,9 +5332,9 @@ TEST_F(SpdyNetworkTransactionTest, ServerPushValidCrossOrigin) { spdy_session_pool->FindAvailableSession( key, /* enable_ip_based_pooling = */ true, log_); - EXPECT_EQ(1u, spdy_session->unclaimed_pushed_streams_.size()); - EXPECT_EQ(1u, - spdy_session->unclaimed_pushed_streams_.count(GURL(url_to_push))); + EXPECT_EQ(1u, num_unclaimed_pushed_streams(spdy_session)); + EXPECT_TRUE( + has_unclaimed_pushed_stream_for_url(spdy_session, GURL(url_to_push))); HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session()); HttpRequestInfo push_request; @@ -4986,7 +5345,7 @@ TEST_F(SpdyNetworkTransactionTest, ServerPushValidCrossOrigin) { rv = callback1.GetResult(rv); EXPECT_THAT(rv, IsOk()); - EXPECT_TRUE(spdy_session->unclaimed_pushed_streams_.empty()); + EXPECT_EQ(0u, num_unclaimed_pushed_streams(spdy_session)); HttpResponseInfo response = *trans0->GetResponseInfo(); EXPECT_TRUE(response.headers); @@ -5113,7 +5472,7 @@ TEST_F(SpdyNetworkTransactionTest, ServerPushValidCrossOriginWithOpenSession) { spdy_session_pool->FindAvailableSession( key0, /* enable_ip_based_pooling = */ true, log_); - EXPECT_TRUE(spdy_session0->unclaimed_pushed_streams_.empty()); + EXPECT_EQ(0u, num_unclaimed_pushed_streams(spdy_session0)); HostPortPair host_port_pair1("docs.example.org", 443); SpdySessionKey key1(host_port_pair1, ProxyServer::Direct(), @@ -5122,9 +5481,9 @@ TEST_F(SpdyNetworkTransactionTest, ServerPushValidCrossOriginWithOpenSession) { spdy_session_pool->FindAvailableSession( key1, /* enable_ip_based_pooling = */ true, log_); - EXPECT_EQ(1u, spdy_session1->unclaimed_pushed_streams_.size()); - EXPECT_EQ(1u, - spdy_session1->unclaimed_pushed_streams_.count(GURL(url_to_push))); + EXPECT_EQ(1u, num_unclaimed_pushed_streams(spdy_session1)); + EXPECT_TRUE( + has_unclaimed_pushed_stream_for_url(spdy_session1, GURL(url_to_push))); // Request |url_to_push|, which should be served from the pushed resource. HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session()); @@ -5136,8 +5495,8 @@ TEST_F(SpdyNetworkTransactionTest, ServerPushValidCrossOriginWithOpenSession) { rv = callback2.GetResult(rv); EXPECT_THAT(rv, IsOk()); - EXPECT_TRUE(spdy_session0->unclaimed_pushed_streams_.empty()); - EXPECT_TRUE(spdy_session1->unclaimed_pushed_streams_.empty()); + EXPECT_EQ(0u, num_unclaimed_pushed_streams(spdy_session0)); + EXPECT_EQ(0u, num_unclaimed_pushed_streams(spdy_session1)); HttpResponseInfo response0 = *trans0->GetResponseInfo(); EXPECT_TRUE(response0.headers); @@ -6160,7 +6519,7 @@ TEST_F(SpdyNetworkTransactionTest, GoAwayOnOddPushStreamId) { SpdyHeaderBlock push_headers; spdy_util_.AddUrlToHeaderBlock("http://www.example.org/a.dat", &push_headers); SpdySerializedFrame push( - spdy_util_.ConstructInitialSpdyPushFrame(std::move(push_headers), 3, 1)); + spdy_util_.ConstructSpdyPushPromise(1, 3, std::move(push_headers))); MockRead reads[] = {CreateMockRead(push, 1)}; SpdySerializedFrame req( @@ -6186,8 +6545,8 @@ TEST_F(SpdyNetworkTransactionTest, SpdyHeaderBlock push_b_headers; spdy_util_.AddUrlToHeaderBlock(GetDefaultUrlWithPath("/b.dat"), &push_b_headers); - SpdySerializedFrame push_b(spdy_util_.ConstructInitialSpdyPushFrame( - std::move(push_b_headers), 2, 1)); + SpdySerializedFrame push_b( + spdy_util_.ConstructSpdyPushPromise(1, 2, std::move(push_b_headers))); MockRead reads[] = { CreateMockRead(push_a, 1), CreateMockRead(push_b, 3), }; @@ -6559,4 +6918,101 @@ TEST_F(SpdyNetworkTransactionTest, RequestHeadersCallback) { EXPECT_TRUE(raw_headers.request_line().empty()); } +// A request that has adopted a push promise and later got reset by the server +// should be retried on a new stream. +// Regression test for https://crbug.com/798508. +TEST_F(SpdyNetworkTransactionTest, PushCanceledByServerAfterClaimed) { + const char pushed_url[] = "https://www.example.org/a.dat"; + // Construct a request to the default URL on stream 1. + SpdySerializedFrame req( + spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true)); + SpdySerializedFrame req2(spdy_util_.ConstructSpdyGet(pushed_url, 3, LOWEST)); + // Construct a priority frame for stream 2. + SpdySerializedFrame priority( + spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true)); + MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(priority, 3), + CreateMockWrite(req2, 6)}; + + // Construct a Push Promise frame, with no response. + SpdySerializedFrame push_promise(spdy_util_.ConstructSpdyPushPromise( + 1, 2, spdy_util_.ConstructGetHeaderBlock(pushed_url))); + // Construct a RST frame, canceling stream 2. + SpdySerializedFrame rst_server( + spdy_util_.ConstructSpdyRstStream(2, ERROR_CODE_CANCEL)); + // Construct response headers and bodies. + SpdySerializedFrame resp1(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); + SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true)); + SpdySerializedFrame resp2(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3)); + SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, true)); + MockRead reads[] = { + CreateMockRead(push_promise, 1), MockRead(ASYNC, ERR_IO_PENDING, 2), + CreateMockRead(rst_server, 4), MockRead(ASYNC, ERR_IO_PENDING, 5), + CreateMockRead(resp1, 7), CreateMockRead(body1, 8), + CreateMockRead(resp2, 9), CreateMockRead(body2, 10), + MockRead(ASYNC, 0, 11)}; + + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); + + NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr); + + helper.RunPreTestSetup(); + helper.AddData(&data); + + HttpNetworkTransaction* trans = helper.trans(); + + // First request to start the connection. + TestCompletionCallback callback1; + int rv = trans->Start(&request_, callback1.callback(), log_); + EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); + + data.RunUntilPaused(); + + // Get a SpdySession. + SpdySessionKey key(HostPortPair::FromURL(request_.url), ProxyServer::Direct(), + PRIVACY_MODE_DISABLED); + HttpNetworkSession* session = helper.session(); + base::WeakPtr<SpdySession> spdy_session = + session->spdy_session_pool()->FindAvailableSession( + key, /* enable_ip_based_pooling = */ true, log_); + + // Verify that there is one unclaimed push stream. + EXPECT_EQ(1u, num_unclaimed_pushed_streams(spdy_session)); + + // Claim the pushed stream. + HttpNetworkTransaction transaction2(DEFAULT_PRIORITY, session); + TestCompletionCallback callback2; + HttpRequestInfo request2; + request2.method = "GET"; + request2.url = GURL(pushed_url); + transaction2.Start(&request2, callback2.callback(), log_); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(3u, spdy_stream_hi_water_mark(spdy_session)); + + EXPECT_EQ(0u, num_unclaimed_pushed_streams(spdy_session)); + + // Continue reading and get the RST. + data.Resume(); + base::RunLoop().RunUntilIdle(); + + // Make sure we got the RST and retried the request. + EXPECT_EQ(2u, num_active_streams(spdy_session)); + EXPECT_EQ(0u, num_unclaimed_pushed_streams(spdy_session)); + EXPECT_EQ(5u, spdy_stream_hi_water_mark(spdy_session)); + + data.Resume(); + + // Test that transactions succeeded. + rv = callback1.WaitForResult(); + ASSERT_THAT(rv, IsOk()); + + rv = callback2.WaitForResult(); + ASSERT_THAT(rv, IsOk()); + + // Read EOF. + base::RunLoop().RunUntilIdle(); + + // Verify that all data was read and written. + helper.VerifyDataConsumed(); +} + } // namespace net diff --git a/chromium/net/spdy/chromium/spdy_proxy_client_socket.cc b/chromium/net/spdy/chromium/spdy_proxy_client_socket.cc index fb1168aa059..e23640ca3f3 100644 --- a/chromium/net/spdy/chromium/spdy_proxy_client_socket.cc +++ b/chromium/net/spdy/chromium/spdy_proxy_client_socket.cc @@ -26,6 +26,7 @@ #include "net/log/net_log_event_type.h" #include "net/log/net_log_source_type.h" #include "net/spdy/chromium/spdy_http_utils.h" +#include "net/traffic_annotation/network_traffic_annotation.h" #include "url/gurl.h" namespace net { @@ -189,6 +190,11 @@ int64_t SpdyProxyClientSocket::GetTotalReceivedBytes() const { return 0; } +void SpdyProxyClientSocket::ApplySocketTag(const SocketTag& tag) { + // Underlying SpdySession can be tagged, but |spdy_stream_| cannot. + CHECK(false); +} + int SpdyProxyClientSocket::Read(IOBuffer* buf, int buf_len, const CompletionCallback& callback) { DCHECK(read_callback_.is_null()); @@ -219,8 +225,11 @@ size_t SpdyProxyClientSocket::PopulateUserReadBuffer(char* data, size_t len) { return read_buffer_queue_.Dequeue(data, len); } -int SpdyProxyClientSocket::Write(IOBuffer* buf, int buf_len, - const CompletionCallback& callback) { +int SpdyProxyClientSocket::Write( + IOBuffer* buf, + int buf_len, + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& traffic_annotation) { DCHECK(write_callback_.is_null()); if (next_state_ != STATE_OPEN) return ERR_SOCKET_NOT_CONNECTED; diff --git a/chromium/net/spdy/chromium/spdy_proxy_client_socket.h b/chromium/net/spdy/chromium/spdy_proxy_client_socket.h index 60c095a9962..d95589dc7a2 100644 --- a/chromium/net/spdy/chromium/spdy_proxy_client_socket.h +++ b/chromium/net/spdy/chromium/spdy_proxy_client_socket.h @@ -31,6 +31,7 @@ #include "net/spdy/chromium/spdy_stream.h" #include "net/spdy/core/spdy_protocol.h" #include "net/spdy/platform/api/spdy_string.h" +#include "net/traffic_annotation/network_traffic_annotation.h" namespace net { @@ -78,6 +79,7 @@ class NET_EXPORT_PRIVATE SpdyProxyClientSocket : public ProxyClientSocket, void ClearConnectionAttempts() override {} void AddConnectionAttempts(const ConnectionAttempts& attempts) override {} int64_t GetTotalReceivedBytes() const override; + void ApplySocketTag(const SocketTag& tag) override; // Socket implementation. int Read(IOBuffer* buf, @@ -85,7 +87,8 @@ class NET_EXPORT_PRIVATE SpdyProxyClientSocket : public ProxyClientSocket, const CompletionCallback& callback) override; int Write(IOBuffer* buf, int buf_len, - const CompletionCallback& callback) override; + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& traffic_annotation) override; int SetReceiveBufferSize(int32_t size) override; int SetSendBufferSize(int32_t size) override; int GetPeerAddress(IPEndPoint* address) const override; diff --git a/chromium/net/spdy/chromium/spdy_proxy_client_socket_unittest.cc b/chromium/net/spdy/chromium/spdy_proxy_client_socket_unittest.cc index df25f48c75b..e8eccf49e0e 100644 --- a/chromium/net/spdy/chromium/spdy_proxy_client_socket_unittest.cc +++ b/chromium/net/spdy/chromium/spdy_proxy_client_socket_unittest.cc @@ -33,6 +33,7 @@ #include "net/test/cert_test_util.h" #include "net/test/gtest_util.h" #include "net/test/test_data_directory.h" +#include "net/traffic_annotation/network_traffic_annotation_test_helper.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/platform_test.h" @@ -286,8 +287,8 @@ void SpdyProxyClientSocketTest::AssertWriteReturns(const char* data, int len, int rv) { scoped_refptr<IOBufferWithSize> buf(CreateBuffer(data, len)); - EXPECT_EQ(rv, - sock_->Write(buf.get(), buf->size(), write_callback_.callback())); + EXPECT_EQ(rv, sock_->Write(buf.get(), buf->size(), write_callback_.callback(), + TRAFFIC_ANNOTATION_FOR_TESTS)); } void SpdyProxyClientSocketTest::AssertWriteLength(int len) { @@ -590,7 +591,8 @@ TEST_F(SpdyProxyClientSocketTest, WriteSplitsLargeDataIntoMultipleFrames) { big_data.length())); EXPECT_EQ(ERR_IO_PENDING, - sock_->Write(buf.get(), buf->size(), write_callback_.callback())); + sock_->Write(buf.get(), buf->size(), write_callback_.callback(), + TRAFFIC_ANNOTATION_FOR_TESTS)); EXPECT_EQ(buf->size(), write_callback_.WaitForResult()); } @@ -1055,7 +1057,8 @@ TEST_F(SpdyProxyClientSocketTest, WriteOnClosedStream) { ResumeAndRun(); scoped_refptr<IOBufferWithSize> buf(CreateBuffer(kMsg1, kLen1)); EXPECT_EQ(ERR_SOCKET_NOT_CONNECTED, - sock_->Write(buf.get(), buf->size(), CompletionCallback())); + sock_->Write(buf.get(), buf->size(), CompletionCallback(), + TRAFFIC_ANNOTATION_FOR_TESTS)); } // Calling Write() on a disconnected socket is an error. @@ -1081,7 +1084,8 @@ TEST_F(SpdyProxyClientSocketTest, WriteOnDisconnectedSocket) { scoped_refptr<IOBufferWithSize> buf(CreateBuffer(kMsg1, kLen1)); EXPECT_EQ(ERR_SOCKET_NOT_CONNECTED, - sock_->Write(buf.get(), buf->size(), CompletionCallback())); + sock_->Write(buf.get(), buf->size(), CompletionCallback(), + TRAFFIC_ANNOTATION_FOR_TESTS)); // Let the RST_STREAM write while |rst| is in-scope. base::RunLoop().RunUntilIdle(); @@ -1109,7 +1113,8 @@ TEST_F(SpdyProxyClientSocketTest, WritePendingOnClose) { scoped_refptr<IOBufferWithSize> buf(CreateBuffer(kMsg1, kLen1)); EXPECT_EQ(ERR_IO_PENDING, - sock_->Write(buf.get(), buf->size(), write_callback_.callback())); + sock_->Write(buf.get(), buf->size(), write_callback_.callback(), + TRAFFIC_ANNOTATION_FOR_TESTS)); // Make sure the write actually starts. base::RunLoop().RunUntilIdle(); @@ -1141,7 +1146,8 @@ TEST_F(SpdyProxyClientSocketTest, DisconnectWithWritePending) { scoped_refptr<IOBufferWithSize> buf(CreateBuffer(kMsg1, kLen1)); EXPECT_EQ(ERR_IO_PENDING, - sock_->Write(buf.get(), buf->size(), write_callback_.callback())); + sock_->Write(buf.get(), buf->size(), write_callback_.callback(), + TRAFFIC_ANNOTATION_FOR_TESTS)); sock_->Disconnect(); @@ -1213,10 +1219,9 @@ TEST_F(SpdyProxyClientSocketTest, RstWithReadAndWritePending) { sock_->Read(read_buf.get(), kLen1, read_callback_.callback())); scoped_refptr<IOBufferWithSize> write_buf(CreateBuffer(kMsg1, kLen1)); - EXPECT_EQ( - ERR_IO_PENDING, - sock_->Write( - write_buf.get(), write_buf->size(), write_callback_.callback())); + EXPECT_EQ(ERR_IO_PENDING, sock_->Write(write_buf.get(), write_buf->size(), + write_callback_.callback(), + TRAFFIC_ANNOTATION_FOR_TESTS)); ResumeAndRun(); @@ -1299,7 +1304,7 @@ class DeleteSockCallback : public TestCompletionCallbackBase { callback_(base::Bind(&DeleteSockCallback::OnComplete, base::Unretained(this))) {} - ~DeleteSockCallback() override {} + ~DeleteSockCallback() override = default; const CompletionCallback& callback() const { return callback_; } @@ -1345,10 +1350,9 @@ TEST_F(SpdyProxyClientSocketTest, RstWithReadAndWritePendingDelete) { sock_->Read(read_buf.get(), kLen1, read_callback.callback())); scoped_refptr<IOBufferWithSize> write_buf(CreateBuffer(kMsg1, kLen1)); - EXPECT_EQ( - ERR_IO_PENDING, - sock_->Write( - write_buf.get(), write_buf->size(), write_callback_.callback())); + EXPECT_EQ(ERR_IO_PENDING, sock_->Write(write_buf.get(), write_buf->size(), + write_callback_.callback(), + TRAFFIC_ANNOTATION_FOR_TESTS)); ResumeAndRun(); diff --git a/chromium/net/spdy/chromium/spdy_session.cc b/chromium/net/spdy/chromium/spdy_session.cc index 420ec31090b..682dde85439 100644 --- a/chromium/net/spdy/chromium/spdy_session.cc +++ b/chromium/net/spdy/chromium/spdy_session.cc @@ -13,8 +13,8 @@ #include "base/feature_list.h" #include "base/location.h" #include "base/logging.h" +#include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" -#include "base/metrics/sparse_histogram.h" #include "base/single_thread_task_runner.h" #include "base/stl_util.h" #include "base/strings/string_number_conversions.h" @@ -57,6 +57,7 @@ #include "net/ssl/channel_id_service.h" #include "net/ssl/ssl_cipher_suite_names.h" #include "net/ssl/ssl_connection_status_flags.h" +#include "url/url_constants.h" namespace net { @@ -746,7 +747,6 @@ SpdySession::SpdySession( transport_security_state_(transport_security_state), stream_hi_water_mark_(kFirstStreamId), last_accepted_push_stream_id_(0), - unclaimed_pushed_streams_(this), push_delegate_(push_delegate), num_pushed_streams_(0u), num_active_pushed_streams_(0u), @@ -818,20 +818,35 @@ SpdySession::~SpdySession() { net_log_.EndEvent(NetLogEventType::HTTP2_SESSION); } -int SpdySession::GetPushStream(const GURL& url, - RequestPriority priority, - SpdyStream** stream, - const NetLogWithSource& stream_net_log) { +int SpdySession::GetPushedStream(const GURL& url, + SpdyStreamId pushed_stream_id, + RequestPriority priority, + SpdyStream** stream, + const NetLogWithSource& stream_net_log) { CHECK(!in_io_loop_); + // |pushed_stream_id| must be valid. + DCHECK_NE(pushed_stream_id, kNoPushedStreamFound); + // |pushed_stream_id| must already have been claimed. + DCHECK_NE(pushed_stream_id, + pool_->push_promise_index()->FindStream(url, this)); if (availability_state_ == STATE_DRAINING) { *stream = nullptr; return ERR_CONNECTION_CLOSED; } - *stream = GetActivePushStream(url); - if (!*stream) - return OK; + ActiveStreamMap::iterator active_it = active_streams_.find(pushed_stream_id); + if (active_it == active_streams_.end()) { + // A previously claimed pushed stream might not be available, for example, + // if the server has reset it in the meanwhile. + return ERR_SPDY_PUSHED_STREAM_NOT_AVAILABLE; + } + + net_log_.AddEvent( + NetLogEventType::HTTP2_STREAM_ADOPTED_PUSH_STREAM, + base::Bind(&NetLogSpdyAdoptedPushStreamCallback, pushed_stream_id, &url)); + + *stream = active_it->second; DCHECK_LT(streams_pushed_and_claimed_count_, streams_pushed_count_); streams_pushed_and_claimed_count_++; @@ -857,12 +872,11 @@ int SpdySession::GetPushStream(const GURL& url, } void SpdySession::CancelPush(const GURL& url) { - UnclaimedPushedStreamContainer::const_iterator unclaimed_it = - unclaimed_pushed_streams_.find(url); - if (unclaimed_it == unclaimed_pushed_streams_.end()) + const SpdyStreamId stream_id = + pool_->push_promise_index()->FindStream(url, this); + if (stream_id == kNoPushedStreamFound) return; - const SpdyStreamId stream_id = unclaimed_it->second; DCHECK(active_streams_.find(stream_id) != active_streams_.end()); ResetStream(stream_id, ERROR_CODE_CANCEL, "Cancelled push stream."); } @@ -912,7 +926,7 @@ void SpdySession::InitializeWithSocket( READ_STATE_DO_READ, OK)); } -bool SpdySession::VerifyDomainAuthentication(const SpdyString& domain) { +bool SpdySession::VerifyDomainAuthentication(const SpdyString& domain) const { if (availability_state_ == STATE_DRAINING) return false; @@ -1254,7 +1268,7 @@ std::unique_ptr<base::Value> SpdySession::GetInfoAsValue() const { dict->SetInteger("active_streams", active_streams_.size()); dict->SetInteger("unclaimed_pushed_streams", - unclaimed_pushed_streams_.size()); + pool_->push_promise_index()->CountStreamsForSession(this)); dict->SetString( "negotiated_protocol", @@ -1289,15 +1303,6 @@ bool SpdySession::GetLoadTimingInfo(SpdyStreamId stream_id, load_timing_info); } -size_t SpdySession::num_unclaimed_pushed_streams() const { - return unclaimed_pushed_streams_.size(); -} - -size_t SpdySession::count_unclaimed_pushed_streams_for_url( - const GURL& url) const { - return unclaimed_pushed_streams_.count(url); -} - int SpdySession::GetPeerAddress(IPEndPoint* address) const { if (connection_->socket()) return connection_->socket()->GetPeerAddress(address); @@ -1352,6 +1357,48 @@ bool SpdySession::CloseOneIdleConnection() { return false; } +bool SpdySession::ValidatePushedStream(SpdyStreamId stream_id, + const GURL& url, + const HttpRequestInfo& request_info, + const SpdySessionKey& key) const { + // Proxy server and privacy mode must match. + if (key.proxy_server() != spdy_session_key_.proxy_server() || + key.privacy_mode() != spdy_session_key_.privacy_mode()) { + return false; + } + // Certificate must match for encrypted schemes only. + if (url.SchemeIsCryptographic() && + !VerifyDomainAuthentication(key.host_port_pair().host())) { + return false; + } + + ActiveStreamMap::const_iterator stream_it = active_streams_.find(stream_id); + if (stream_it == active_streams_.end()) { + // Only active streams should be in Http2PushPromiseIndex. + NOTREACHED(); + return false; + } + const SpdyHeaderBlock& request_headers = stream_it->second->request_headers(); + SpdyHeaderBlock::const_iterator method_it = + request_headers.find(kHttp2MethodHeader); + if (method_it == request_headers.end()) { + // TryCreatePushStream() would have reset the stream if it had no method. + NOTREACHED(); + return false; + } + + // Request method must match. + if (request_info.method != method_it->second) { + return false; + } + + return true; +} + +base::WeakPtr<SpdySession> SpdySession::GetWeakPtrToSession() { + return GetWeakPtr(); +} + size_t SpdySession::DumpMemoryStats(StreamSocket::SocketMemoryStats* stats, bool* is_session_active) const { // TODO(xunjieli): Include |pending_create_stream_queues_| when WeakPtr is @@ -1366,7 +1413,6 @@ size_t SpdySession::DumpMemoryStats(StreamSocket::SocketMemoryStats* stats, SpdyEstimateMemoryUsage(spdy_session_key_) + SpdyEstimateMemoryUsage(pooled_aliases_) + SpdyEstimateMemoryUsage(active_streams_) + - SpdyEstimateMemoryUsage(unclaimed_pushed_streams_) + SpdyEstimateMemoryUsage(created_streams_) + SpdyEstimateMemoryUsage(write_queue_) + SpdyEstimateMemoryUsage(in_flight_write_) + @@ -1376,55 +1422,6 @@ size_t SpdySession::DumpMemoryStats(StreamSocket::SocketMemoryStats* stats, SpdyEstimateMemoryUsage(priority_dependency_state_); } -SpdySession::UnclaimedPushedStreamContainer::UnclaimedPushedStreamContainer( - SpdySession* spdy_session) - : spdy_session_(spdy_session) {} -SpdySession::UnclaimedPushedStreamContainer::~UnclaimedPushedStreamContainer() { -} - -bool SpdySession::UnclaimedPushedStreamContainer::erase(const GURL& url) { - const_iterator it = find(url); - if (it == end()) - return false; - - erase(it); - return true; -} - -SpdySession::UnclaimedPushedStreamContainer::iterator -SpdySession::UnclaimedPushedStreamContainer::erase(const_iterator it) { - DCHECK(spdy_session_->pool_); - DCHECK(it != end()); - // Only allow cross-origin push for secure resources. - if (it->first.SchemeIsCryptographic()) { - spdy_session_->pool_->push_promise_index()->UnregisterUnclaimedPushedStream( - it->first, spdy_session_); - } - return streams_.erase(it); -} - -bool SpdySession::UnclaimedPushedStreamContainer::insert( - const GURL& url, - SpdyStreamId stream_id) { - DCHECK(spdy_session_->pool_); - auto result = streams_.insert(std::make_pair(url, stream_id)); - if (!result.second) { - // Only one pushed stream is allowed for each URL. - return false; - } - // Only allow cross-origin push for https resources. - if (url.SchemeIsCryptographic()) { - spdy_session_->pool_->push_promise_index()->RegisterUnclaimedPushedStream( - url, spdy_session_->GetWeakPtr()); - } - return true; -} - -size_t SpdySession::UnclaimedPushedStreamContainer::EstimateMemoryUsage() - const { - return SpdyEstimateMemoryUsage(streams_); -} - // {,Try}CreateStream() can be called with |in_io_loop_| set if a stream is // being created in response to another being closed due to received data. @@ -1627,6 +1624,12 @@ void SpdySession::TryCreatePushStream(SpdyStreamId stream_id, } DCHECK(gurl.is_valid()); + if (!gurl.SchemeIs(url::kHttpScheme) && !gurl.SchemeIs(url::kHttpsScheme)) { + EnqueueResetStreamFrame(stream_id, request_priority, + ERROR_CODE_REFUSED_STREAM, + "Only http and https resources can be pushed."); + return; + } // Cross-origin push validation. GURL associated_url(associated_it->second->GetUrlFromHeaders()); @@ -1634,15 +1637,15 @@ void SpdySession::TryCreatePushStream(SpdyStreamId stream_id, if (proxy_delegate_ && proxy_delegate_->IsTrustedSpdyProxy( ProxyServer(ProxyServer::SCHEME_HTTPS, host_port_pair()))) { - // Disallow pushing of HTTPS content by trusted proxy. - if (gurl.SchemeIs("https")) { + if (!gurl.SchemeIs(url::kHttpScheme)) { EnqueueResetStreamFrame( stream_id, request_priority, ERROR_CODE_REFUSED_STREAM, - "Cross origin HTTPS content from trusted proxy."); + "Only http scheme allowed for cross origin push by trusted proxy."); return; } } else { - if (!gurl.SchemeIs("https") || !associated_url.SchemeIs("https")) { + if (!gurl.SchemeIs(url::kHttpsScheme) || + !associated_url.SchemeIs(url::kHttpsScheme)) { EnqueueResetStreamFrame( stream_id, request_priority, ERROR_CODE_REFUSED_STREAM, "Both pushed URL and associated URL must have https scheme."); @@ -1663,8 +1666,7 @@ void SpdySession::TryCreatePushStream(SpdyStreamId stream_id, // "Promised requests MUST be cacheable and MUST be safe [...]" (RFC7540 // Section 8.2). Only cacheable safe request methods are GET and HEAD. SpdyHeaderBlock::const_iterator it = headers.find(kHttp2MethodHeader); - if (it == headers.end() || - (it->second.compare("GET") != 0 && it->second.compare("HEAD") != 0)) { + if (it == headers.end() || (it->second != "GET" && it->second != "HEAD")) { EnqueueResetStreamFrame(stream_id, request_priority, ERROR_CODE_REFUSED_STREAM, "Inadequate request method."); @@ -1672,7 +1674,8 @@ void SpdySession::TryCreatePushStream(SpdyStreamId stream_id, } // Insertion fails if there already is a pushed stream with the same path. - if (!unclaimed_pushed_streams_.insert(gurl, stream_id)) { + if (!pool_->push_promise_index()->RegisterUnclaimedPushedStream( + gurl, stream_id, this)) { EnqueueResetStreamFrame(stream_id, request_priority, ERROR_CODE_REFUSED_STREAM, "Duplicate pushed stream with url: " + gurl.spec()); @@ -1742,7 +1745,8 @@ void SpdySession::CloseActiveStreamIterator(ActiveStreamMap::iterator it, // push is hardly used. Write tests for this and fix this. (See // http://crbug.com/261712 .) if (owned_stream->type() == SPDY_PUSH_STREAM) { - if (unclaimed_pushed_streams_.erase(owned_stream->url())) { + if (pool_->push_promise_index()->UnregisterUnclaimedPushedStream( + owned_stream->url(), owned_stream->stream_id(), this)) { bytes_pushed_and_unclaimed_count_ += owned_stream->recv_bytes(); } bytes_pushed_count_ += owned_stream->recv_bytes(); @@ -2417,28 +2421,6 @@ void SpdySession::DeleteStream(std::unique_ptr<SpdyStream> stream, int status) { } } -SpdyStream* SpdySession::GetActivePushStream(const GURL& url) { - UnclaimedPushedStreamContainer::const_iterator unclaimed_it = - unclaimed_pushed_streams_.find(url); - if (unclaimed_it == unclaimed_pushed_streams_.end()) - return nullptr; - - const SpdyStreamId stream_id = unclaimed_it->second; - unclaimed_pushed_streams_.erase(unclaimed_it); - - ActiveStreamMap::iterator active_it = active_streams_.find(stream_id); - if (active_it == active_streams_.end()) { - NOTREACHED(); - return nullptr; - } - - SpdyStream* stream = active_it->second; - net_log_.AddEvent( - NetLogEventType::HTTP2_STREAM_ADOPTED_PUSH_STREAM, - base::Bind(&NetLogSpdyAdoptedPushStreamCallback, stream_id, &url)); - return stream; -} - void SpdySession::RecordPingRTTHistogram(base::TimeDelta duration) { UMA_HISTOGRAM_CUSTOM_TIMES("Net.SpdyPing.RTT", duration, base::TimeDelta::FromMilliseconds(1), @@ -2493,7 +2475,7 @@ void SpdySession::DcheckDraining() const { DcheckGoingAway(); DCHECK_EQ(availability_state_, STATE_DRAINING); DCHECK(active_streams_.empty()); - DCHECK(unclaimed_pushed_streams_.empty()); + DCHECK_EQ(0u, pool_->push_promise_index()->CountStreamsForSession(this)); } void SpdySession::DoDrainSession(Error err, const SpdyString& description) { @@ -2532,7 +2514,7 @@ void SpdySession::DoDrainSession(Error err, const SpdyString& description) { NetLogEventType::HTTP2_SESSION_CLOSE, base::Bind(&NetLogSpdySessionCloseCallback, err, &description)); - UMA_HISTOGRAM_SPARSE_SLOWLY("Net.SpdySession.ClosedOnError", -err); + base::UmaHistogramSparse("Net.SpdySession.ClosedOnError", -err); if (err == OK) { // We ought to be going away already, as this is a graceful close. @@ -2586,21 +2568,17 @@ void SpdySession::CancelPushedStreamIfUnclaimed(SpdyStreamId stream_id) { if (active_it == active_streams_.end()) return; - // Grab URL for faster lookup in unclaimed_pushed_streams_. - const GURL& url = active_it->second->url(); - UnclaimedPushedStreamContainer::const_iterator unclaimed_it = - unclaimed_pushed_streams_.find(url); // Make sure to cancel the correct stream. It is possible that the pushed // stream |stream_id| is already claimed, and another stream has been pushed // for the same URL. - if (unclaimed_it == unclaimed_pushed_streams_.end() || - unclaimed_it->second != stream_id) { + const GURL& url = active_it->second->url(); + if (pool_->push_promise_index()->FindStream(url, this) != stream_id) { return; } LogAbandonedActiveStream(active_it, ERR_TIMED_OUT); // CloseActiveStreamIterator() will remove the stream from - // |unclaimed_pushed_streams_|. + // |pool_->push_promise_index()|. ResetStreamIterator(active_it, ERROR_CODE_REFUSED_STREAM, "Stream not claimed."); } @@ -2676,9 +2654,13 @@ void SpdySession::OnRstStream(SpdyStreamId stream_id, return; } + DCHECK(it->second); CHECK_EQ(it->second->stream_id(), stream_id); - if (error_code == ERROR_CODE_NO_ERROR) { + if (it->second->ShouldRetryRSTPushStream()) { + CloseActiveStreamIterator(it, + ERR_SPDY_CLAIMED_PUSHED_STREAM_RESET_BY_SERVER); + } else if (error_code == ERROR_CODE_NO_ERROR) { CloseActiveStreamIterator(it, ERR_SPDY_RST_STREAM_NO_ERROR_RECEIVED); } else if (error_code == ERROR_CODE_REFUSED_STREAM) { CloseActiveStreamIterator(it, ERR_SPDY_SERVER_REFUSED_STREAM); @@ -2713,7 +2695,8 @@ void SpdySession::OnGoAway(SpdyStreamId last_accepted_stream_id, net_log_.AddEvent( NetLogEventType::HTTP2_SESSION_RECV_GOAWAY, base::Bind(&NetLogSpdyRecvGoAwayCallback, last_accepted_stream_id, - active_streams_.size(), unclaimed_pushed_streams_.size(), + active_streams_.size(), + pool_->push_promise_index()->CountStreamsForSession(this), error_code, debug_data)); MakeUnavailable(); if (error_code == ERROR_CODE_HTTP_1_1_REQUIRED) { @@ -2976,7 +2959,7 @@ void SpdySession::OnAltSvc( if (origin.empty()) return; const GURL gurl(origin); - if (!gurl.SchemeIs("https")) + if (!gurl.SchemeIs(url::kHttpsScheme)) return; SSLInfo ssl_info; if (!GetSSLInfo(&ssl_info)) @@ -2993,7 +2976,7 @@ void SpdySession::OnAltSvc( if (it == active_streams_.end()) return; const GURL& gurl(it->second->url()); - if (!gurl.SchemeIs("https")) + if (!gurl.SchemeIs(url::kHttpsScheme)) return; scheme_host_port = url::SchemeHostPort(gurl); } diff --git a/chromium/net/spdy/chromium/spdy_session.h b/chromium/net/spdy/chromium/spdy_session.h index d90c2b9dd8c..dae7d2ae9fa 100644 --- a/chromium/net/spdy/chromium/spdy_session.h +++ b/chromium/net/spdy/chromium/spdy_session.h @@ -13,7 +13,6 @@ #include <set> #include <vector> -#include "base/compiler_specific.h" #include "base/containers/circular_deque.h" #include "base/gtest_prod_util.h" #include "base/macros.h" @@ -234,7 +233,8 @@ class NET_EXPORT_PRIVATE SpdyStreamRequest { class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface, public SpdyFramerDebugVisitorInterface, public MultiplexedSession, - public HigherLayeredPool { + public HigherLayeredPool, + public Http2PushPromiseIndex::Delegate { public: // TODO(akalin): Use base::TickClock when it becomes available. typedef base::TimeTicks (*TimeFunc)(void); @@ -284,12 +284,22 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface, // reset). Returns an error (not ERR_IO_PENDING) otherwise, and // resets |spdy_stream|. // + // If |pushed_stream_id != kNoPushedStreamFound|, then the pushed stream with + // pushed_stream_id is used. An error is returned if that stream is not + // available. + // + // If |pushed_stream_id == kNoPushedStreamFound|, then any matching pushed + // stream that has not been claimed by another request can be used. This can + // happen, for example, with http scheme pushed streams, or if the pushed + // stream was received from the server in the meanwhile. + // // If a stream was found and the stream is still open, the priority // of that stream is updated to match |priority|. - int GetPushStream(const GURL& url, - RequestPriority priority, - SpdyStream** spdy_stream, - const NetLogWithSource& stream_net_log); + int GetPushedStream(const GURL& url, + SpdyStreamId pushed_stream_id, + RequestPriority priority, + SpdyStream** spdy_stream, + const NetLogWithSource& stream_net_log); // Called when the pushed stream should be cancelled. If the pushed stream is // not claimed and active, sends RST to the server to cancel the stream. @@ -316,7 +326,7 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface, // TODO(wtc): rename this function and the Net.SpdyIPPoolDomainMatch // histogram because this function does more than verifying domain // authentication now. - bool VerifyDomainAuthentication(const SpdyString& domain); + bool VerifyDomainAuthentication(const SpdyString& domain) const; // Pushes the given producer into the write queue for // |stream|. |stream| is guaranteed to be activated before the @@ -446,29 +456,6 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface, return !active_streams_.empty() || !created_streams_.empty(); } - // Access to the number of active and pending streams. These are primarily - // available for testing and diagnostics. - size_t num_active_streams() const { return active_streams_.size(); } - size_t num_unclaimed_pushed_streams() const; - size_t num_created_streams() const { return created_streams_.size(); } - size_t count_unclaimed_pushed_streams_for_url(const GURL& url) const; - - size_t num_pushed_streams() const { return num_pushed_streams_; } - size_t num_active_pushed_streams() const { - return num_active_pushed_streams_; - } - - size_t pending_create_stream_queue_size(RequestPriority priority) const { - DCHECK_GE(priority, MINIMUM_PRIORITY); - DCHECK_LE(priority, MAXIMUM_PRIORITY); - return pending_create_stream_queues_[priority].size(); - } - - // Returns the current |stream_initial_send_window_size_|. - int32_t stream_initial_send_window_size() const { - return stream_initial_send_window_size_; - } - // Returns true if no stream in the session can send data due to // session flow control. bool IsSendStalled() const { return session_send_window_size_ == 0; } @@ -493,12 +480,19 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface, // standards for TLS. bool HasAcceptableTransportSecurity() const; - // Must be used only by |pool_|. + // Must be used only by |pool_| (including |pool_.push_promise_index_|). base::WeakPtr<SpdySession> GetWeakPtr(); // HigherLayeredPool implementation: bool CloseOneIdleConnection() override; + // Http2PushPromiseIndex::Delegate implementation: + bool ValidatePushedStream(SpdyStreamId stream_id, + const GURL& url, + const HttpRequestInfo& request_info, + const SpdySessionKey& key) const override; + base::WeakPtr<SpdySession> GetWeakPtrToSession() override; + // Dumps memory allocation stats to |stats|. Sets |*is_session_active| to // indicate whether session is active. // |stats| can be assumed as being default initialized upon entry. @@ -516,44 +510,10 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface, friend class SpdyHttpStreamTest; friend class SpdyNetworkTransactionTest; friend class SpdyProxyClientSocketTest; + friend class SpdySessionPoolTest; friend class SpdySessionTest; friend class SpdyStreamRequest; - // Allow tests to access our innards for testing purposes. - FRIEND_TEST_ALL_PREFIXES(SpdySessionTest, ClientPing); - FRIEND_TEST_ALL_PREFIXES(SpdySessionTest, FailedPing); - FRIEND_TEST_ALL_PREFIXES(SpdySessionTest, WaitingForWrongPing); - FRIEND_TEST_ALL_PREFIXES(SpdySessionTest, CancelPushBeforeClaimed); - FRIEND_TEST_ALL_PREFIXES(SpdySessionTest, CancelPushAfterSessionGoesAway); - FRIEND_TEST_ALL_PREFIXES(SpdySessionTest, CancelPushAfterExpired); - FRIEND_TEST_ALL_PREFIXES(SpdySessionTest, ClaimPushedStreamBeforeExpires); - FRIEND_TEST_ALL_PREFIXES(SpdySessionTest, ProtocolNegotiation); - FRIEND_TEST_ALL_PREFIXES(SpdySessionTest, AdjustRecvWindowSize); - FRIEND_TEST_ALL_PREFIXES(SpdySessionTest, AdjustSendWindowSize); - FRIEND_TEST_ALL_PREFIXES(SpdySessionTest, SessionFlowControlInactiveStream); - FRIEND_TEST_ALL_PREFIXES(SpdySessionTest, SessionFlowControlPadding); - FRIEND_TEST_ALL_PREFIXES(SpdySessionTest, - SessionFlowControlTooMuchDataTwoDataFrames); - FRIEND_TEST_ALL_PREFIXES(SpdySessionTest, - StreamFlowControlTooMuchDataTwoDataFrames); - FRIEND_TEST_ALL_PREFIXES(SpdySessionTest, SessionFlowControlNoReceiveLeaks); - FRIEND_TEST_ALL_PREFIXES(SpdySessionTest, SessionFlowControlNoSendLeaks); - FRIEND_TEST_ALL_PREFIXES(SpdySessionTest, SessionFlowControlEndToEnd); - FRIEND_TEST_ALL_PREFIXES(SpdySessionTest, StreamIdSpaceExhausted); - FRIEND_TEST_ALL_PREFIXES(SpdySessionTest, MaxConcurrentStreamsZero); - FRIEND_TEST_ALL_PREFIXES(SpdySessionTest, UnstallRacesWithStreamCreation); - FRIEND_TEST_ALL_PREFIXES(SpdySessionTest, GoAwayOnSessionFlowControlError); - FRIEND_TEST_ALL_PREFIXES(SpdySessionTest, - RejectPushedStreamExceedingConcurrencyLimit); - FRIEND_TEST_ALL_PREFIXES(SpdySessionTest, IgnoreReservedRemoteStreamsCount); - FRIEND_TEST_ALL_PREFIXES(SpdySessionTest, - CancelReservedStreamOnHeadersReceived); - FRIEND_TEST_ALL_PREFIXES(SpdySessionTest, RejectInvalidUnknownFrames); - FRIEND_TEST_ALL_PREFIXES(SpdySessionPoolTest, IPAddressChanged); - FRIEND_TEST_ALL_PREFIXES(SpdyNetworkTransactionTest, - ServerPushValidCrossOrigin); - FRIEND_TEST_ALL_PREFIXES(SpdyNetworkTransactionTest, - ServerPushValidCrossOriginWithOpenSession); FRIEND_TEST_ALL_PREFIXES(RecordPushedStreamHistogramTest, VaryResponseHeader); using PendingStreamRequestQueue = @@ -587,52 +547,6 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface, WRITE_STATE_DO_WRITE_COMPLETE, }; - // Container class for unclaimed pushed streams on a SpdySession. Guarantees - // that |spdy_session_.pool_| gets notified every time a stream is pushed or - // an unclaimed pushed stream is claimed. - class UnclaimedPushedStreamContainer { - public: - using PushedStreamMap = std::map<GURL, SpdyStreamId>; - using iterator = PushedStreamMap::iterator; - using const_iterator = PushedStreamMap::const_iterator; - - UnclaimedPushedStreamContainer() = delete; - explicit UnclaimedPushedStreamContainer(SpdySession* spdy_session); - ~UnclaimedPushedStreamContainer(); - - bool empty() const { return streams_.empty(); } - size_t size() const { return streams_.size(); } - const_iterator begin() const { return streams_.begin(); } - const_iterator end() const { return streams_.end(); } - const_iterator find(const GURL& url) const { return streams_.find(url); } - size_t count(const GURL& url) const { return streams_.count(url); } - const_iterator lower_bound(const GURL& url) const { - return streams_.lower_bound(url); - } - - // Return true if there was an element with |url|, which was then erased. - bool erase(const GURL& url); - - // Return the iterator following |it|. - iterator erase(const_iterator it); - - // Return true if there was not already an entry with |url|, - // in which case the insertion was successful. - bool insert(const GURL& url, SpdyStreamId stream_id) WARN_UNUSED_RESULT; - - size_t EstimateMemoryUsage() const; - - private: - SpdySession* spdy_session_; - - // (Bijective) map from the URL to the ID of the streams that have - // already started to be pushed by the server, but do not have - // consumers yet. Contains a subset of |active_streams_|. - PushedStreamMap streams_; - - DISALLOW_COPY_AND_ASSIGN(UnclaimedPushedStreamContainer); - }; - // Called by SpdyStreamRequest to start a request to create a // stream. If OK is returned, then |stream| will be filled in with a // valid stream. If ERR_IO_PENDING is returned, then @@ -793,11 +707,6 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface, // that |stream| may hold the last reference to the session. void DeleteStream(std::unique_ptr<SpdyStream> stream, int status); - // Check if we have a pending pushed-stream for this url - // Returns the stream if found (and returns it from the pending - // list). Returns NULL otherwise. - SpdyStream* GetActivePushStream(const GURL& url); - void RecordPingRTTHistogram(base::TimeDelta duration); void RecordHistograms(); void RecordProtocolErrorHistogram(SpdyProtocolErrorDetails details); @@ -950,30 +859,6 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface, // empty. SpdyStreamId PopStreamToPossiblyResume(); - // -------------------------- - // Helper methods for testing - // -------------------------- - - void set_connection_at_risk_of_loss_time(base::TimeDelta duration) { - connection_at_risk_of_loss_time_ = duration; - } - - void set_hung_interval(base::TimeDelta duration) { - hung_interval_ = duration; - } - - void set_max_concurrent_pushed_streams(size_t value) { - max_concurrent_pushed_streams_ = value; - } - - int64_t pings_in_flight() const { return pings_in_flight_; } - - SpdyPingId next_ping_id() const { return next_ping_id_; } - - base::TimeTicks last_read_time() const { return last_read_time_; } - - bool check_ping_status_pending() const { return check_ping_status_pending_; } - // Whether Do{Read,Write}Loop() is in the call stack. Useful for // making sure we don't destroy ourselves prematurely in that case. bool in_io_loop_; @@ -1020,8 +905,6 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface, // them? ActiveStreamMap active_streams_; - UnclaimedPushedStreamContainer unclaimed_pushed_streams_; - // Not owned. |push_delegate_| outlives the session and handles server pushes // received by session. ServerPushDelegate* push_delegate_; diff --git a/chromium/net/spdy/chromium/spdy_session_key.cc b/chromium/net/spdy/chromium/spdy_session_key.cc index 42e260c25e0..be206e5a9b3 100644 --- a/chromium/net/spdy/chromium/spdy_session_key.cc +++ b/chromium/net/spdy/chromium/spdy_session_key.cc @@ -12,8 +12,7 @@ namespace net { -SpdySessionKey::SpdySessionKey() : privacy_mode_(PRIVACY_MODE_DISABLED) { -} +SpdySessionKey::SpdySessionKey() = default; SpdySessionKey::SpdySessionKey(const HostPortPair& host_port_pair, const ProxyServer& proxy_server, @@ -25,18 +24,9 @@ SpdySessionKey::SpdySessionKey(const HostPortPair& host_port_pair, << ", privacy=" << privacy_mode; } -SpdySessionKey::SpdySessionKey(const HostPortProxyPair& host_port_proxy_pair, - PrivacyMode privacy_mode) - : host_port_proxy_pair_(host_port_proxy_pair), - privacy_mode_(privacy_mode) { - DVLOG(1) << "SpdySessionKey(hppp=" << host_port_proxy_pair.first.ToString() - << "," << host_port_proxy_pair.second.ToURI() - << ", privacy=" << privacy_mode; -} - SpdySessionKey::SpdySessionKey(const SpdySessionKey& other) = default; -SpdySessionKey::~SpdySessionKey() {} +SpdySessionKey::~SpdySessionKey() = default; bool SpdySessionKey::operator<(const SpdySessionKey& other) const { return std::tie(privacy_mode_, host_port_proxy_pair_.first, @@ -45,7 +35,7 @@ bool SpdySessionKey::operator<(const SpdySessionKey& other) const { other.host_port_proxy_pair_.second); } -bool SpdySessionKey::Equals(const SpdySessionKey& other) const { +bool SpdySessionKey::operator==(const SpdySessionKey& other) const { return privacy_mode_ == other.privacy_mode_ && host_port_proxy_pair_.first.Equals(other.host_port_proxy_pair_.first) && host_port_proxy_pair_.second == other.host_port_proxy_pair_.second; diff --git a/chromium/net/spdy/chromium/spdy_session_key.h b/chromium/net/spdy/chromium/spdy_session_key.h index 7aa59a0c8bf..ef5ac192fac 100644 --- a/chromium/net/spdy/chromium/spdy_session_key.h +++ b/chromium/net/spdy/chromium/spdy_session_key.h @@ -19,10 +19,6 @@ class NET_EXPORT_PRIVATE SpdySessionKey { const ProxyServer& proxy_server, PrivacyMode privacy_mode); - // Temporary hack for implicit copy constructor - SpdySessionKey(const HostPortProxyPair& host_port_proxy_pair, - PrivacyMode privacy_mode); - SpdySessionKey(const SpdySessionKey& other); ~SpdySessionKey(); @@ -30,8 +26,8 @@ class NET_EXPORT_PRIVATE SpdySessionKey { // Comparator function so this can be placed in a std::map. bool operator<(const SpdySessionKey& other) const; - // Equality test of contents. (Probably another violation of style guide). - bool Equals(const SpdySessionKey& other) const; + // Equality test of contents. + bool operator==(const SpdySessionKey& other) const; const HostPortProxyPair& host_port_proxy_pair() const { return host_port_proxy_pair_; @@ -55,7 +51,7 @@ class NET_EXPORT_PRIVATE SpdySessionKey { private: HostPortProxyPair host_port_proxy_pair_; // If enabled, then session cannot be tracked by the server. - PrivacyMode privacy_mode_; + PrivacyMode privacy_mode_ = PRIVACY_MODE_DISABLED; }; } // namespace net diff --git a/chromium/net/spdy/chromium/spdy_session_pool.cc b/chromium/net/spdy/chromium/spdy_session_pool.cc index e0e7d35435a..312e581ac3f 100644 --- a/chromium/net/spdy/chromium/spdy_session_pool.cc +++ b/chromium/net/spdy/chromium/spdy_session_pool.cc @@ -4,6 +4,7 @@ #include "net/spdy/chromium/spdy_session_pool.h" +#include <algorithm> #include <utility> #include "base/logging.h" @@ -13,6 +14,7 @@ #include "base/trace_event/process_memory_dump.h" #include "base/trace_event/trace_event.h" #include "base/values.h" +#include "build/build_config.h" #include "net/base/address_list.h" #include "net/base/trace_constants.h" #include "net/http/http_network_session.h" @@ -77,6 +79,8 @@ SpdySessionPool::SpdySessionPool( SpdySessionPool::~SpdySessionPool() { DCHECK(spdy_session_request_map_.empty()); + // TODO(bnc): CloseAllSessions() is also called in HttpNetworkSession + // destructor, one of the two calls should be removed. CloseAllSessions(); while (!sessions_.empty()) { @@ -138,7 +142,7 @@ base::WeakPtr<SpdySession> SpdySessionPool::FindAvailableSession( const NetLogWithSource& net_log) { AvailableSessionMap::iterator it = LookupAvailableSessionByKey(key); if (it != available_sessions_.end()) { - if (key.Equals(it->second->spdy_session_key())) { + if (key == it->second->spdy_session_key()) { UMA_HISTOGRAM_ENUMERATION("Net.SpdySessionGet", FOUND_EXISTING, SPDY_SESSION_GET_MAX); net_log.AddEvent( @@ -270,7 +274,9 @@ void SpdySessionPool::CloseCurrentIdleSessions() { } void SpdySessionPool::CloseAllSessions() { - while (!available_sessions_.empty()) { + auto is_draining = [](const SpdySession* s) { return s->IsDraining(); }; + // Repeat until every SpdySession owned by |this| is draining. + while (!std::all_of(sessions_.begin(), sessions_.end(), is_draining)) { CloseCurrentSessionsHelper(ERR_ABORTED, "Closing all sessions.", false /* idle_only */); } @@ -286,7 +292,7 @@ std::unique_ptr<base::Value> SpdySessionPool::SpdySessionPoolInfoToValue() // host_port_proxy_pair (not an alias). const SpdySessionKey& key = it->first; const SpdySessionKey& session_key = it->second->spdy_session_key(); - if (key.Equals(session_key)) + if (key == session_key) list->Append(it->second->GetInfoAsValue()); } return std::move(list); @@ -358,7 +364,8 @@ void SpdySessionPool::OnNewSpdySessionReady( direct || request->url().SchemeIs(url::kHttpsScheme); request->OnStreamReadyOnPooledConnection( used_ssl_config, used_proxy_info, - std::make_unique<SpdyHttpStream>(spdy_session, use_relative_url, + std::make_unique<SpdyHttpStream>(spdy_session, kNoPushedStreamFound, + use_relative_url, source_dependency)); } } @@ -439,7 +446,8 @@ void SpdySessionPool::DumpMemoryStats( num_active_sessions++; } total_size += SpdyEstimateMemoryUsage(ObtainHpackHuffmanTable()) + - SpdyEstimateMemoryUsage(ObtainHpackStaticTable()); + SpdyEstimateMemoryUsage(ObtainHpackStaticTable()) + + SpdyEstimateMemoryUsage(push_promise_index_); base::trace_event::MemoryAllocatorDump* dump = pmd->CreateAllocatorDump(SpdyStringPrintf( "%s/spdy_session_pool", parent_dump_absolute_name.c_str())); @@ -498,7 +506,7 @@ void SpdySessionPool::RemoveAliases(const SpdySessionKey& key) { // Walk the aliases map, find references to this pair. // TODO(mbelshe): Figure out if this is too expensive. for (AliasMap::iterator it = aliases_.begin(); it != aliases_.end(); ) { - if (it->second.Equals(key)) { + if (it->second == key) { AliasMap::iterator old_it = it; ++it; aliases_.erase(old_it); @@ -521,16 +529,20 @@ void SpdySessionPool::CloseCurrentSessionsHelper(Error error, const SpdyString& description, bool idle_only) { WeakSessionList current_sessions = GetCurrentSessions(); - for (WeakSessionList::const_iterator it = current_sessions.begin(); - it != current_sessions.end(); ++it) { - if (!*it) + for (base::WeakPtr<SpdySession>& session : current_sessions) { + if (!session) continue; - if (idle_only && (*it)->is_active()) + if (idle_only && session->is_active()) continue; - (*it)->CloseSessionOnError(error, description); - DCHECK(!IsSessionAvailable(*it)); + if (session->IsDraining()) + continue; + + session->CloseSessionOnError(error, description); + + DCHECK(!IsSessionAvailable(session)); + DCHECK(!session || session->IsDraining()); } } diff --git a/chromium/net/spdy/chromium/spdy_session_pool.h b/chromium/net/spdy/chromium/spdy_session_pool.h index 223b5ae5af3..09f3a826912 100644 --- a/chromium/net/spdy/chromium/spdy_session_pool.h +++ b/chromium/net/spdy/chromium/spdy_session_pool.h @@ -111,6 +111,10 @@ class NET_EXPORT SpdySessionPool void RemoveUnavailableSession( const base::WeakPtr<SpdySession>& unavailable_session); + // Note that the next three methods close sessions, potentially notifing + // delegates of error or synchronously invoking callbacks, which might trigger + // retries, thus opening new sessions. + // Close only the currently existing SpdySessions with |error|. // Let any new ones created while this method is running continue to // live. @@ -121,8 +125,9 @@ class NET_EXPORT SpdySessionPool // live. void CloseCurrentIdleSessions(); - // Close all SpdySessions, including any new ones created in the process of - // closing the current ones. + // Repeatedly close all SpdySessions until all of them (including new ones + // created in the process of closing the current ones, and new ones created in + // the process of closing those new ones, etc.) are unavailable. void CloseAllSessions(); // Creates a Value summary of the state of the spdy session pool. diff --git a/chromium/net/spdy/chromium/spdy_session_pool_unittest.cc b/chromium/net/spdy/chromium/spdy_session_pool_unittest.cc index 0d9cc49fa57..74169d9afff 100644 --- a/chromium/net/spdy/chromium/spdy_session_pool_unittest.cc +++ b/chromium/net/spdy/chromium/spdy_session_pool_unittest.cc @@ -13,6 +13,7 @@ #include "base/trace_event/memory_allocator_dump.h" #include "base/trace_event/process_memory_dump.h" #include "base/trace_event/trace_event_argument.h" +#include "build/build_config.h" #include "net/dns/host_cache.h" #include "net/http/http_network_session.h" #include "net/log/net_log_with_source.h" @@ -66,6 +67,10 @@ class SpdySessionPoolTest : public ::testing::Test { void RunIPPoolingTest(SpdyPoolCloseSessionsType close_sessions_type); + size_t num_active_streams(base::WeakPtr<SpdySession> session) { + return session->active_streams_.size(); + } + SpdySessionDependencies session_deps_; std::unique_ptr<HttpNetworkSession> http_session_; SpdySessionPool* spdy_session_pool_; @@ -80,7 +85,7 @@ class SessionOpeningDelegate : public SpdyStream::Delegate { : spdy_session_pool_(spdy_session_pool), key_(key) {} - ~SessionOpeningDelegate() override {} + ~SessionOpeningDelegate() override = default; void OnHeadersSent() override {} @@ -778,7 +783,7 @@ TEST_F(SpdySessionPoolTest, IPAddressChanged) { EXPECT_TRUE(sessionC->IsDraining()); EXPECT_EQ(1u, - sessionA->num_active_streams()); // Active stream is still active. + num_active_streams(sessionA)); // Active stream is still active. EXPECT_FALSE(delegateA.StreamIsClosed()); EXPECT_TRUE(delegateB.StreamIsClosed()); // Created stream was closed. @@ -802,6 +807,114 @@ TEST_F(SpdySessionPoolTest, IPAddressChanged) { #endif // defined(OS_ANDROID) || defined(OS_WIN) || defined(OS_IOS) } +// Regression test for https://crbug.com/789791. +TEST_F(SpdySessionPoolTest, HandleIPAddressChangeThenShutdown) { + MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING)}; + SpdyTestUtil spdy_util; + SpdySerializedFrame req(spdy_util.ConstructSpdyGet(kDefaultUrl, 1, MEDIUM)); + MockWrite writes[] = {CreateMockWrite(req, 1)}; + StaticSocketDataProvider data(reads, arraysize(reads), writes, + arraysize(writes)); + + MockConnect connect_data(SYNCHRONOUS, OK); + data.set_connect_data(connect_data); + + session_deps_.socket_factory->AddSocketDataProvider(&data); + AddSSLSocketData(); + + CreateNetworkSession(); + + const GURL url(kDefaultUrl); + SpdySessionKey key(HostPortPair::FromURL(url), ProxyServer::Direct(), + PRIVACY_MODE_DISABLED); + base::WeakPtr<SpdySession> session = + CreateSpdySession(http_session_.get(), key, NetLogWithSource()); + + base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously( + SPDY_BIDIRECTIONAL_STREAM, session, url, MEDIUM, NetLogWithSource()); + test::StreamDelegateDoNothing delegate(spdy_stream); + spdy_stream->SetDelegate(&delegate); + + SpdyHeaderBlock headers(spdy_util.ConstructGetHeaderBlock(url.spec())); + spdy_stream->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND); + + base::RunLoop().RunUntilIdle(); + EXPECT_TRUE(delegate.send_headers_completed()); + + spdy_session_pool_->OnIPAddressChanged(); + +#if defined(OS_ANDROID) || defined(OS_WIN) || defined(OS_IOS) + EXPECT_EQ(1u, num_active_streams(session)); + EXPECT_TRUE(session->IsGoingAway()); + EXPECT_FALSE(session->IsDraining()); +#else + EXPECT_EQ(0u, num_active_streams(session)); + EXPECT_FALSE(session->IsGoingAway()); + EXPECT_TRUE(session->IsDraining()); +#endif // defined(OS_ANDROID) || defined(OS_WIN) || defined(OS_IOS) + + http_session_.reset(); + + data.AllReadDataConsumed(); + data.AllWriteDataConsumed(); +} + +// Regression test for https://crbug.com/789791. +TEST_F(SpdySessionPoolTest, HandleGracefulGoawayThenShutdown) { + SpdyTestUtil spdy_util; + SpdySerializedFrame goaway(spdy_util.ConstructSpdyGoAway( + 0x7fffffff, ERROR_CODE_NO_ERROR, "Graceful shutdown.")); + MockRead reads[] = { + MockRead(ASYNC, ERR_IO_PENDING, 1), CreateMockRead(goaway, 2), + MockRead(ASYNC, ERR_IO_PENDING, 3), MockRead(ASYNC, OK, 4)}; + SpdySerializedFrame req(spdy_util.ConstructSpdyGet(kDefaultUrl, 1, MEDIUM)); + MockWrite writes[] = {CreateMockWrite(req, 0)}; + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); + + MockConnect connect_data(SYNCHRONOUS, OK); + data.set_connect_data(connect_data); + + session_deps_.socket_factory->AddSocketDataProvider(&data); + AddSSLSocketData(); + + CreateNetworkSession(); + + const GURL url(kDefaultUrl); + SpdySessionKey key(HostPortPair::FromURL(url), ProxyServer::Direct(), + PRIVACY_MODE_DISABLED); + base::WeakPtr<SpdySession> session = + CreateSpdySession(http_session_.get(), key, NetLogWithSource()); + + base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously( + SPDY_BIDIRECTIONAL_STREAM, session, url, MEDIUM, NetLogWithSource()); + test::StreamDelegateDoNothing delegate(spdy_stream); + spdy_stream->SetDelegate(&delegate); + + SpdyHeaderBlock headers(spdy_util.ConstructGetHeaderBlock(url.spec())); + spdy_stream->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND); + + // Send headers. + base::RunLoop().RunUntilIdle(); + EXPECT_TRUE(delegate.send_headers_completed()); + + EXPECT_EQ(1u, num_active_streams(session)); + EXPECT_FALSE(session->IsGoingAway()); + EXPECT_FALSE(session->IsDraining()); + + // Read GOAWAY. + data.Resume(); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(1u, num_active_streams(session)); + EXPECT_TRUE(session->IsGoingAway()); + EXPECT_FALSE(session->IsDraining()); + + http_session_.reset(); + + data.AllReadDataConsumed(); + data.AllWriteDataConsumed(); +} + class SpdySessionMemoryDumpTest : public SpdySessionPoolTest, public testing::WithParamInterface< diff --git a/chromium/net/spdy/chromium/spdy_session_unittest.cc b/chromium/net/spdy/chromium/spdy_session_unittest.cc index c4fb3dc94dd..60e54bc8ff2 100644 --- a/chromium/net/spdy/chromium/spdy_session_unittest.cc +++ b/chromium/net/spdy/chromium/spdy_session_unittest.cc @@ -22,6 +22,7 @@ #include "net/base/test_data_stream.h" #include "net/base/test_proxy_delegate.h" #include "net/cert/ct_policy_status.h" +#include "net/http/http_request_info.h" #include "net/log/net_log_event_type.h" #include "net/log/net_log_source.h" #include "net/log/test_net_log.h" @@ -29,6 +30,7 @@ #include "net/log/test_net_log_util.h" #include "net/proxy/proxy_server.h" #include "net/socket/client_socket_pool_manager.h" +#include "net/socket/socket_tag.h" #include "net/socket/socket_test_util.h" #include "net/spdy/chromium/spdy_http_utils.h" #include "net/spdy/chromium/spdy_session_pool.h" @@ -53,6 +55,7 @@ namespace { const char kHttpURLFromAnotherOrigin[] = "http://www.example2.org/a.dat"; const char kHttpsURLFromAnotherOrigin[] = "https://www.example2.org/b.dat"; +const char kPushedUrl[] = "https://www.example.org/a.dat"; const char kBodyData[] = "Body data"; const size_t kBodyDataSize = arraysize(kBodyData); @@ -175,14 +178,14 @@ class SpdySessionTest : public PlatformTest { void StallSessionSend() { // Reduce the send window size to 0 to stall. - while (session_->session_send_window_size_ > 0) { - session_->DecreaseSendWindowSize(std::min( - kMaxSpdyFrameChunkSize, session_->session_send_window_size_)); + while (session_send_window_size() > 0) { + DecreaseSendWindowSize( + std::min(kMaxSpdyFrameChunkSize, session_send_window_size())); } } void UnstallSessionSend(int32_t delta_window_size) { - session_->IncreaseSendWindowSize(delta_window_size); + IncreaseSendWindowSize(delta_window_size); } void StallStreamSend(SpdyStream* stream) { @@ -201,6 +204,135 @@ class SpdySessionTest : public PlatformTest { const base::Callback<void(SpdyStream*)>& stall_function, const base::Callback<void(SpdyStream*, int32_t)>& unstall_function); + // SpdySession private methods. + + void MaybeSendPrefacePing() { session_->MaybeSendPrefacePing(); } + + void WritePingFrame(SpdyPingId unique_id, bool is_ack) { + session_->WritePingFrame(unique_id, is_ack); + } + + void CheckPingStatus(base::TimeTicks last_check_time) { + session_->CheckPingStatus(last_check_time); + } + + bool OnUnknownFrame(SpdyStreamId stream_id, uint8_t frame_type) { + return session_->OnUnknownFrame(stream_id, frame_type); + } + + void IncreaseSendWindowSize(int delta_window_size) { + session_->IncreaseSendWindowSize(delta_window_size); + } + + void DecreaseSendWindowSize(int32_t delta_window_size) { + session_->DecreaseSendWindowSize(delta_window_size); + } + + void IncreaseRecvWindowSize(int delta_window_size) { + session_->IncreaseRecvWindowSize(delta_window_size); + } + + void DecreaseRecvWindowSize(int32_t delta_window_size) { + session_->DecreaseRecvWindowSize(delta_window_size); + } + + // Accessors for SpdySession private members. + + void set_in_io_loop(bool in_io_loop) { session_->in_io_loop_ = in_io_loop; } + + void set_stream_hi_water_mark(SpdyStreamId stream_hi_water_mark) { + session_->stream_hi_water_mark_ = stream_hi_water_mark; + } + + void set_last_accepted_push_stream_id( + SpdyStreamId last_accepted_push_stream_id) { + session_->last_accepted_push_stream_id_ = last_accepted_push_stream_id; + } + + size_t num_pushed_streams() { return session_->num_pushed_streams_; } + + size_t num_active_pushed_streams() { + return session_->num_active_pushed_streams_; + } + + size_t max_concurrent_streams() { return session_->max_concurrent_streams_; } + + void set_max_concurrent_streams(size_t max_concurrent_streams) { + session_->max_concurrent_streams_ = max_concurrent_streams; + } + + void set_max_concurrent_pushed_streams(size_t max_concurrent_pushed_streams) { + session_->max_concurrent_pushed_streams_ = max_concurrent_pushed_streams; + } + + int64_t pings_in_flight() { return session_->pings_in_flight_; } + + SpdyPingId next_ping_id() { return session_->next_ping_id_; } + + base::TimeTicks last_read_time() { return session_->last_read_time_; } + + void set_last_read_time(base::TimeTicks last_read_time) { + session_->last_read_time_ = last_read_time; + } + + bool check_ping_status_pending() { + return session_->check_ping_status_pending_; + } + + void set_check_ping_status_pending(bool check_ping_status_pending) { + session_->check_ping_status_pending_ = check_ping_status_pending; + } + + int32_t session_send_window_size() { + return session_->session_send_window_size_; + } + + int32_t session_recv_window_size() { + return session_->session_recv_window_size_; + } + + void set_session_recv_window_size(int32_t session_recv_window_size) { + session_->session_recv_window_size_ = session_recv_window_size; + } + + int32_t session_unacked_recv_window_bytes() { + return session_->session_unacked_recv_window_bytes_; + } + + int32_t stream_initial_send_window_size() { + return session_->stream_initial_send_window_size_; + } + + void set_connection_at_risk_of_loss_time(base::TimeDelta duration) { + session_->connection_at_risk_of_loss_time_ = duration; + } + + void set_hung_interval(base::TimeDelta duration) { + session_->hung_interval_ = duration; + } + + // Quantities derived from SpdySession private members. + + size_t pending_create_stream_queue_size(RequestPriority priority) { + DCHECK_GE(priority, MINIMUM_PRIORITY); + DCHECK_LE(priority, MAXIMUM_PRIORITY); + return session_->pending_create_stream_queues_[priority].size(); + } + + size_t num_active_streams() { return session_->active_streams_.size(); } + + size_t num_created_streams() { return session_->created_streams_.size(); } + + size_t num_unclaimed_pushed_streams() { + return spdy_session_pool_->push_promise_index()->CountStreamsForSession( + session_.get()); + } + + bool has_unclaimed_pushed_stream_for_url(const GURL& url) { + return spdy_session_pool_->push_promise_index()->FindStream( + url, session_.get()) != kNoPushedStreamFound; + } + // Original socket limits. Some tests set these. Safest to always restore // them once each test has been run. int old_max_group_sockets_; @@ -238,9 +370,9 @@ namespace { // given SpdyStreamRequest. class StreamRequestDestroyingCallback : public TestCompletionCallbackBase { public: - StreamRequestDestroyingCallback() {} + StreamRequestDestroyingCallback() = default; - ~StreamRequestDestroyingCallback() override {} + ~StreamRequestDestroyingCallback() override = default; void SetRequestToDestroy(std::unique_ptr<SpdyStreamRequest> request) { request_ = std::move(request); @@ -892,24 +1024,23 @@ TEST_F(SpdySessionTest, ClientPing) { base::TimeTicks before_ping_time = base::TimeTicks::Now(); - session_->set_connection_at_risk_of_loss_time( - base::TimeDelta::FromSeconds(-1)); - session_->set_hung_interval(base::TimeDelta::FromMilliseconds(50)); + set_connection_at_risk_of_loss_time(base::TimeDelta::FromSeconds(-1)); + set_hung_interval(base::TimeDelta::FromMilliseconds(50)); - session_->MaybeSendPrefacePing(); + MaybeSendPrefacePing(); - EXPECT_EQ(1, session_->pings_in_flight()); - EXPECT_EQ(2u, session_->next_ping_id()); - EXPECT_TRUE(session_->check_ping_status_pending()); + EXPECT_EQ(1, pings_in_flight()); + EXPECT_EQ(2u, next_ping_id()); + EXPECT_TRUE(check_ping_status_pending()); base::RunLoop().RunUntilIdle(); - session_->CheckPingStatus(before_ping_time); + CheckPingStatus(before_ping_time); - EXPECT_EQ(0, session_->pings_in_flight()); - EXPECT_EQ(2u, session_->next_ping_id()); - EXPECT_FALSE(session_->check_ping_status_pending()); - EXPECT_GE(session_->last_read_time(), before_ping_time); + EXPECT_EQ(0, pings_in_flight()); + EXPECT_EQ(2u, next_ping_id()); + EXPECT_FALSE(check_ping_status_pending()); + EXPECT_GE(last_read_time(), before_ping_time); data.Resume(); base::RunLoop().RunUntilIdle(); @@ -1050,9 +1181,9 @@ TEST_F(SpdySessionTest, StreamIdSpaceExhausted) { CreateSpdySession(); // Fix stream_hi_water_mark_ to allow for two stream activations. - session_->stream_hi_water_mark_ = kLastStreamId - 2; + set_stream_hi_water_mark(kLastStreamId - 2); // Fix max_concurrent_streams to allow for three stream creations. - session_->max_concurrent_streams_ = 3; + set_max_concurrent_streams(3); // Create three streams synchronously, and begin a fourth (which is stalled). base::WeakPtr<SpdyStream> stream1 = @@ -1081,9 +1212,9 @@ TEST_F(SpdySessionTest, StreamIdSpaceExhausted) { MEDIUM, NetLogWithSource(), callback4.callback())); // Streams 1-3 were created. 4th is stalled. No streams are active yet. - EXPECT_EQ(0u, session_->num_active_streams()); - EXPECT_EQ(3u, session_->num_created_streams()); - EXPECT_EQ(1u, session_->pending_create_stream_queue_size(MEDIUM)); + EXPECT_EQ(0u, num_active_streams()); + EXPECT_EQ(3u, num_created_streams()); + EXPECT_EQ(1u, pending_create_stream_queue_size(MEDIUM)); // Activate stream 1. One ID remains available. stream1->SendRequestHeaders(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl), @@ -1091,9 +1222,9 @@ TEST_F(SpdySessionTest, StreamIdSpaceExhausted) { base::RunLoop().RunUntilIdle(); EXPECT_EQ(kLastStreamId - 2u, stream1->stream_id()); - EXPECT_EQ(1u, session_->num_active_streams()); - EXPECT_EQ(2u, session_->num_created_streams()); - EXPECT_EQ(1u, session_->pending_create_stream_queue_size(MEDIUM)); + EXPECT_EQ(1u, num_active_streams()); + EXPECT_EQ(2u, num_created_streams()); + EXPECT_EQ(1u, pending_create_stream_queue_size(MEDIUM)); // Activate stream 2. ID space is exhausted. stream2->SendRequestHeaders(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl), @@ -1102,14 +1233,14 @@ TEST_F(SpdySessionTest, StreamIdSpaceExhausted) { // Active streams remain active. EXPECT_EQ(kLastStreamId, stream2->stream_id()); - EXPECT_EQ(2u, session_->num_active_streams()); + EXPECT_EQ(2u, num_active_streams()); // Session is going away. Created and stalled streams were aborted. - EXPECT_EQ(SpdySession::STATE_GOING_AWAY, session_->availability_state_); + EXPECT_TRUE(session_->IsGoingAway()); EXPECT_THAT(delegate3.WaitForClose(), IsError(ERR_ABORTED)); EXPECT_THAT(callback4.WaitForResult(), IsError(ERR_ABORTED)); - EXPECT_EQ(0u, session_->num_created_streams()); - EXPECT_EQ(0u, session_->pending_create_stream_queue_size(MEDIUM)); + EXPECT_EQ(0u, num_created_streams()); + EXPECT_EQ(0u, pending_create_stream_queue_size(MEDIUM)); // Read responses on remaining active streams. data.Resume(); @@ -1175,7 +1306,7 @@ TEST_F(SpdySessionTest, MaxConcurrentStreamsZero) { // Receive SETTINGS frame that sets max_concurrent_streams to zero. base::RunLoop().RunUntilIdle(); - EXPECT_EQ(0u, session_->max_concurrent_streams_); + EXPECT_EQ(0u, max_concurrent_streams()); // Start request. SpdyStreamRequest request; @@ -1186,17 +1317,17 @@ TEST_F(SpdySessionTest, MaxConcurrentStreamsZero) { EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); // Stream is stalled. - EXPECT_EQ(1u, session_->pending_create_stream_queue_size(MEDIUM)); - EXPECT_EQ(0u, session_->num_created_streams()); + EXPECT_EQ(1u, pending_create_stream_queue_size(MEDIUM)); + EXPECT_EQ(0u, num_created_streams()); // Receive SETTINGS frame that sets max_concurrent_streams to one. data.Resume(); base::RunLoop().RunUntilIdle(); - EXPECT_EQ(1u, session_->max_concurrent_streams_); + EXPECT_EQ(1u, max_concurrent_streams()); // Stream is created. - EXPECT_EQ(0u, session_->pending_create_stream_queue_size(MEDIUM)); - EXPECT_EQ(1u, session_->num_created_streams()); + EXPECT_EQ(0u, pending_create_stream_queue_size(MEDIUM)); + EXPECT_EQ(1u, num_created_streams()); EXPECT_THAT(callback.WaitForResult(), IsOk()); @@ -1238,7 +1369,7 @@ TEST_F(SpdySessionTest, UnstallRacesWithStreamCreation) { CreateSpdySession(); // Fix max_concurrent_streams to allow for one open stream. - session_->max_concurrent_streams_ = 1; + set_max_concurrent_streams(1); // Create two streams: one synchronously, and one which stalls. base::WeakPtr<SpdyStream> stream1 = @@ -1252,36 +1383,36 @@ TEST_F(SpdySessionTest, UnstallRacesWithStreamCreation) { request2.StartRequest(SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, MEDIUM, NetLogWithSource(), callback2.callback())); - EXPECT_EQ(1u, session_->num_created_streams()); - EXPECT_EQ(1u, session_->pending_create_stream_queue_size(MEDIUM)); + EXPECT_EQ(1u, num_created_streams()); + EXPECT_EQ(1u, pending_create_stream_queue_size(MEDIUM)); // Cancel the first stream. A callback to unstall the second stream was // posted. Don't run it yet. stream1->Cancel(); - EXPECT_EQ(0u, session_->num_created_streams()); - EXPECT_EQ(0u, session_->pending_create_stream_queue_size(MEDIUM)); + EXPECT_EQ(0u, num_created_streams()); + EXPECT_EQ(0u, pending_create_stream_queue_size(MEDIUM)); // Create a third stream prior to the second stream's callback. base::WeakPtr<SpdyStream> stream3 = CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, MEDIUM, NetLogWithSource()); - EXPECT_EQ(1u, session_->num_created_streams()); - EXPECT_EQ(0u, session_->pending_create_stream_queue_size(MEDIUM)); + EXPECT_EQ(1u, num_created_streams()); + EXPECT_EQ(0u, pending_create_stream_queue_size(MEDIUM)); // Now run the message loop. The unstalled stream will re-stall itself. base::RunLoop().RunUntilIdle(); - EXPECT_EQ(1u, session_->num_created_streams()); - EXPECT_EQ(1u, session_->pending_create_stream_queue_size(MEDIUM)); + EXPECT_EQ(1u, num_created_streams()); + EXPECT_EQ(1u, pending_create_stream_queue_size(MEDIUM)); // Cancel the third stream and run the message loop. Verify that the second // stream creation now completes. stream3->Cancel(); base::RunLoop().RunUntilIdle(); - EXPECT_EQ(1u, session_->num_created_streams()); - EXPECT_EQ(0u, session_->pending_create_stream_queue_size(MEDIUM)); + EXPECT_EQ(1u, num_created_streams()); + EXPECT_EQ(0u, pending_create_stream_queue_size(MEDIUM)); EXPECT_THAT(callback2.WaitForResult(), IsOk()); } @@ -1294,8 +1425,8 @@ TEST_F(SpdySessionTest, CancelPushAfterSessionGoesAway) { spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true)); MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(priority, 2)}; - SpdySerializedFrame push(spdy_util_.ConstructSpdyPush( - nullptr, 0, 2, 1, "https://www.example.org/a.dat")); + SpdySerializedFrame push( + spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl)); SpdySerializedFrame push_body(spdy_util_.ConstructSpdyDataFrame(2, false)); MockRead reads[] = {CreateMockRead(push, 1), CreateMockRead(push_body, 3), MockRead(ASYNC, ERR_IO_PENDING, 4), @@ -1321,14 +1452,14 @@ TEST_F(SpdySessionTest, CancelPushAfterSessionGoesAway) { base::RunLoop().RunUntilIdle(); // Verify that there is one unclaimed push stream. - EXPECT_EQ(1u, session_->num_unclaimed_pushed_streams()); - EXPECT_EQ(1u, session_->count_unclaimed_pushed_streams_for_url( - GURL("https://www.example.org/a.dat"))); + const GURL pushed_url(kPushedUrl); + EXPECT_EQ(1u, num_unclaimed_pushed_streams()); + EXPECT_TRUE(has_unclaimed_pushed_stream_for_url(pushed_url)); // Unclaimed push body consumes bytes from the session window. EXPECT_EQ(kDefaultInitialWindowSize - kUploadDataSize, - session_->session_recv_window_size_); - EXPECT_EQ(0, session_->session_unacked_recv_window_bytes_); + session_recv_window_size()); + EXPECT_EQ(0, session_unacked_recv_window_bytes()); // Read and process EOF. data.Resume(); @@ -1336,8 +1467,7 @@ TEST_F(SpdySessionTest, CancelPushAfterSessionGoesAway) { // Cancel the push after session goes away. The test must not crash. EXPECT_FALSE(session_); - EXPECT_TRUE( - test_push_delegate_->CancelPush(GURL("https://www.example.org/a.dat"))); + EXPECT_TRUE(test_push_delegate_->CancelPush(pushed_url)); histogram_tester.ExpectBucketCount("Net.SpdyStreamsPushedPerSession", 1, 1); histogram_tester.ExpectBucketCount("Net.SpdySession.PushedBytes", 6, 1); @@ -1362,8 +1492,8 @@ TEST_F(SpdySessionTest, CancelPushAfterExpired) { CreateMockWrite(rst, 5), }; - SpdySerializedFrame push(spdy_util_.ConstructSpdyPush( - nullptr, 0, 2, 1, "https://www.example.org/a.dat")); + SpdySerializedFrame push( + spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl)); SpdySerializedFrame push_body(spdy_util_.ConstructSpdyDataFrame(2, false)); MockRead reads[] = {CreateMockRead(push, 1), CreateMockRead(push_body, 2), MockRead(ASYNC, ERR_IO_PENDING, 4), @@ -1390,7 +1520,7 @@ TEST_F(SpdySessionTest, CancelPushAfterExpired) { transport_params, nullptr, nullptr, key_.host_port_pair(), SSLConfig(), key_.privacy_mode(), 0, false); int rv = connection->Init( - key_.host_port_pair().ToString(), ssl_params, MEDIUM, + key_.host_port_pair().ToString(), ssl_params, MEDIUM, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), http_session_->GetSSLSocketPool(HttpNetworkSession::NORMAL_SOCKET_POOL), log_.bound()); @@ -1421,14 +1551,14 @@ TEST_F(SpdySessionTest, CancelPushAfterExpired) { task_runner->RunUntilIdle(); // Verify that there is one unclaimed push stream. - const GURL pushed_url("https://www.example.org/a.dat"); - EXPECT_EQ(1u, session_->num_unclaimed_pushed_streams()); - EXPECT_EQ(1u, session_->count_unclaimed_pushed_streams_for_url(pushed_url)); + const GURL pushed_url(kPushedUrl); + EXPECT_EQ(1u, num_unclaimed_pushed_streams()); + EXPECT_TRUE(has_unclaimed_pushed_stream_for_url(pushed_url)); // Unclaimed push body consumes bytes from the session window. EXPECT_EQ(kDefaultInitialWindowSize - kUploadDataSize, - session_->session_recv_window_size_); - EXPECT_EQ(0, session_->session_unacked_recv_window_bytes_); + session_recv_window_size()); + EXPECT_EQ(0, session_unacked_recv_window_bytes()); // Fast forward to CancelPushedStreamIfUnclaimed() that was posted with a // delay. @@ -1436,16 +1566,16 @@ TEST_F(SpdySessionTest, CancelPushAfterExpired) { task_runner->RunUntilIdle(); // Verify that pushed stream is cancelled. - EXPECT_EQ(0u, session_->num_unclaimed_pushed_streams()); + EXPECT_EQ(0u, num_unclaimed_pushed_streams()); // Verify that the session window reclaimed the evicted stream body. - EXPECT_EQ(kDefaultInitialWindowSize, session_->session_recv_window_size_); - EXPECT_EQ(kUploadDataSize, session_->session_unacked_recv_window_bytes_); + EXPECT_EQ(kDefaultInitialWindowSize, session_recv_window_size()); + EXPECT_EQ(kUploadDataSize, session_unacked_recv_window_bytes()); // Try to cancel the expired push after its expiration: must not crash. EXPECT_TRUE(session_); EXPECT_TRUE(test_push_delegate_->CancelPush(pushed_url)); - EXPECT_EQ(0u, session_->num_unclaimed_pushed_streams()); + EXPECT_EQ(0u, num_unclaimed_pushed_streams()); // Read and process EOF. data.Resume(); @@ -1470,8 +1600,8 @@ TEST_F(SpdySessionTest, ClaimPushedStreamBeforeExpires) { spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true)); MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(priority, 3)}; - SpdySerializedFrame push(spdy_util_.ConstructSpdyPush( - nullptr, 0, 2, 1, "https://www.example.org/a.dat")); + SpdySerializedFrame push( + spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl)); SpdySerializedFrame push_body(spdy_util_.ConstructSpdyDataFrame(2, false)); MockRead reads[] = {CreateMockRead(push, 1), CreateMockRead(push_body, 2), MockRead(ASYNC, ERR_IO_PENDING, 4), @@ -1498,7 +1628,7 @@ TEST_F(SpdySessionTest, ClaimPushedStreamBeforeExpires) { transport_params, nullptr, nullptr, key_.host_port_pair(), SSLConfig(), key_.privacy_mode(), 0, false); int rv = connection->Init( - key_.host_port_pair().ToString(), ssl_params, MEDIUM, + key_.host_port_pair().ToString(), ssl_params, MEDIUM, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), http_session_->GetSSLSocketPool(HttpNetworkSession::NORMAL_SOCKET_POOL), log_.bound()); @@ -1529,27 +1659,39 @@ TEST_F(SpdySessionTest, ClaimPushedStreamBeforeExpires) { task_runner->RunUntilIdle(); // Verify that there is one unclaimed push stream. - const GURL pushed_url("https://www.example.org/a.dat"); - EXPECT_EQ(1u, session_->num_unclaimed_pushed_streams()); - EXPECT_EQ(1u, session_->count_unclaimed_pushed_streams_for_url(pushed_url)); + const GURL pushed_url(kPushedUrl); + EXPECT_EQ(1u, num_unclaimed_pushed_streams()); + EXPECT_TRUE(has_unclaimed_pushed_stream_for_url(pushed_url)); // Unclaimed push body consumes bytes from the session window. EXPECT_EQ(kDefaultInitialWindowSize - kUploadDataSize, - session_->session_recv_window_size_); - EXPECT_EQ(0, session_->session_unacked_recv_window_bytes_); + session_recv_window_size()); + EXPECT_EQ(0, session_unacked_recv_window_bytes()); + + // Claim pushed stream from Http2PushPromiseIndex. + HttpRequestInfo push_request; + push_request.url = pushed_url; + push_request.method = "GET"; + base::WeakPtr<SpdySession> session_with_pushed_stream; + SpdyStreamId pushed_stream_id; + spdy_session_pool_->push_promise_index()->ClaimPushedStream( + key_, pushed_url, push_request, &session_with_pushed_stream, + &pushed_stream_id); + EXPECT_EQ(session_.get(), session_with_pushed_stream.get()); + EXPECT_EQ(2u, pushed_stream_id); + + // Verify that pushed stream is claimed. + EXPECT_EQ(0u, num_unclaimed_pushed_streams()); SpdyStream* spdy_stream2; - rv = session_->GetPushStream(pushed_url, MEDIUM, &spdy_stream2, - NetLogWithSource()); + rv = session_->GetPushedStream(pushed_url, pushed_stream_id, MEDIUM, + &spdy_stream2, NetLogWithSource()); ASSERT_THAT(rv, IsOk()); ASSERT_TRUE(spdy_stream2); test::StreamDelegateDoNothing delegate2(spdy_stream2->GetWeakPtr()); spdy_stream2->SetDelegate(&delegate2); - // Verify that pushed stream is claimed. - EXPECT_EQ(0u, session_->num_unclaimed_pushed_streams()); - // Fast forward to CancelPushedStreamIfUnclaimed() that was posted with a // delay. CancelPushedStreamIfUnclaimed() must be a no-op. task_runner->FastForwardUntilNoTasksRemain(); @@ -1579,8 +1721,8 @@ TEST_F(SpdySessionTest, CancelPushBeforeClaimed) { MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(priority, 3), CreateMockWrite(rst, 5)}; - SpdySerializedFrame push(spdy_util_.ConstructSpdyPush( - nullptr, 0, 2, 1, "https://www.example.org/a.dat")); + SpdySerializedFrame push( + spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl)); SpdySerializedFrame push_body(spdy_util_.ConstructSpdyDataFrame(2, false)); MockRead reads[] = {CreateMockRead(push, 1), CreateMockRead(push_body, 2), MockRead(ASYNC, ERR_IO_PENDING, 4), @@ -1606,23 +1748,23 @@ TEST_F(SpdySessionTest, CancelPushBeforeClaimed) { base::RunLoop().RunUntilIdle(); // Verify that there is one unclaimed push stream. - const GURL pushed_url("https://www.example.org/a.dat"); - EXPECT_EQ(1u, session_->num_unclaimed_pushed_streams()); - EXPECT_EQ(1u, session_->count_unclaimed_pushed_streams_for_url(pushed_url)); + const GURL pushed_url(kPushedUrl); + EXPECT_EQ(1u, num_unclaimed_pushed_streams()); + EXPECT_TRUE(has_unclaimed_pushed_stream_for_url(pushed_url)); // Unclaimed push body consumes bytes from the session window. EXPECT_EQ(kDefaultInitialWindowSize - kUploadDataSize, - session_->session_recv_window_size_); - EXPECT_EQ(0, session_->session_unacked_recv_window_bytes_); + session_recv_window_size()); + EXPECT_EQ(0, session_unacked_recv_window_bytes()); // Cancel the push before it is claimed. EXPECT_TRUE(test_push_delegate_->CancelPush(pushed_url)); - EXPECT_EQ(0u, session_->num_unclaimed_pushed_streams()); - EXPECT_EQ(0u, session_->count_unclaimed_pushed_streams_for_url(pushed_url)); + EXPECT_EQ(0u, num_unclaimed_pushed_streams()); + EXPECT_FALSE(has_unclaimed_pushed_stream_for_url(pushed_url)); // Verify that the session window reclaimed the evicted stream body. - EXPECT_EQ(kDefaultInitialWindowSize, session_->session_recv_window_size_); - EXPECT_EQ(kUploadDataSize, session_->session_unacked_recv_window_bytes_); + EXPECT_EQ(kDefaultInitialWindowSize, session_recv_window_size()); + EXPECT_EQ(kUploadDataSize, session_unacked_recv_window_bytes()); EXPECT_TRUE(session_); @@ -1664,30 +1806,28 @@ TEST_F(SpdySessionTest, FailedPing) { test::StreamDelegateSendImmediate delegate(spdy_stream1, nullptr); spdy_stream1->SetDelegate(&delegate); - session_->set_connection_at_risk_of_loss_time( - base::TimeDelta::FromSeconds(0)); - session_->set_hung_interval(base::TimeDelta::FromSeconds(0)); + set_connection_at_risk_of_loss_time(base::TimeDelta::FromSeconds(0)); + set_hung_interval(base::TimeDelta::FromSeconds(0)); // Send a PING frame. - session_->WritePingFrame(1, false); - EXPECT_LT(0, session_->pings_in_flight()); - EXPECT_EQ(2u, session_->next_ping_id()); - EXPECT_TRUE(session_->check_ping_status_pending()); + WritePingFrame(1, false); + EXPECT_LT(0, pings_in_flight()); + EXPECT_EQ(2u, next_ping_id()); + EXPECT_TRUE(check_ping_status_pending()); // Assert session is not closed. EXPECT_TRUE(session_->IsAvailable()); - EXPECT_LT(0u, - session_->num_active_streams() + session_->num_created_streams()); + EXPECT_LT(0u, num_active_streams() + num_created_streams()); EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_)); // We set last time we have received any data in 1 sec less than now. // CheckPingStatus will trigger timeout because hung interval is zero. base::TimeTicks now = base::TimeTicks::Now(); - session_->last_read_time_ = now - base::TimeDelta::FromSeconds(1); - session_->CheckPingStatus(now); + set_last_read_time(now - base::TimeDelta::FromSeconds(1)); + CheckPingStatus(now); // Set check_ping_status_pending_ so that DCHECK in pending CheckPingStatus() // on message loop does not fail. - session_->check_ping_status_pending_ = true; + set_check_ping_status_pending(true); // Execute pending CheckPingStatus() and drain session. base::RunLoop().RunUntilIdle(); @@ -1719,11 +1859,10 @@ TEST_F(SpdySessionTest, WaitingForWrongPing) { CreateSpdySession(); // Negative value means a preface ping will always be sent. - session_->set_connection_at_risk_of_loss_time( - base::TimeDelta::FromSeconds(-1)); + set_connection_at_risk_of_loss_time(base::TimeDelta::FromSeconds(-1)); const base::TimeDelta hung_interval = base::TimeDelta::FromMilliseconds(100); - session_->set_hung_interval(hung_interval); + set_hung_interval(hung_interval); base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, session_, test_url_, @@ -1732,31 +1871,31 @@ TEST_F(SpdySessionTest, WaitingForWrongPing) { test::StreamDelegateSendImmediate delegate(spdy_stream1, nullptr); spdy_stream1->SetDelegate(&delegate); - EXPECT_EQ(0, session_->pings_in_flight()); - EXPECT_EQ(1u, session_->next_ping_id()); - EXPECT_FALSE(session_->check_ping_status_pending()); + EXPECT_EQ(0, pings_in_flight()); + EXPECT_EQ(1u, next_ping_id()); + EXPECT_FALSE(check_ping_status_pending()); // Send preface ping and post CheckPingStatus() task with delay. - session_->MaybeSendPrefacePing(); + MaybeSendPrefacePing(); - EXPECT_EQ(1, session_->pings_in_flight()); - EXPECT_EQ(2u, session_->next_ping_id()); - EXPECT_TRUE(session_->check_ping_status_pending()); + EXPECT_EQ(1, pings_in_flight()); + EXPECT_EQ(2u, next_ping_id()); + EXPECT_TRUE(check_ping_status_pending()); // Read PING ACK. base::RunLoop().RunUntilIdle(); - EXPECT_EQ(0, session_->pings_in_flight()); - EXPECT_TRUE(session_->check_ping_status_pending()); + EXPECT_EQ(0, pings_in_flight()); + EXPECT_TRUE(check_ping_status_pending()); // Fast forward mock time and send another preface ping. // This will not post another CheckPingStatus(). g_time_delta = base::TimeDelta::FromMilliseconds(150); - session_->MaybeSendPrefacePing(); + MaybeSendPrefacePing(); - EXPECT_EQ(0, session_->pings_in_flight()); - EXPECT_EQ(2u, session_->next_ping_id()); - EXPECT_TRUE(session_->check_ping_status_pending()); + EXPECT_EQ(0, pings_in_flight()); + EXPECT_EQ(2u, next_ping_id()); + EXPECT_TRUE(check_ping_status_pending()); // Read EOF. data.Resume(); @@ -1768,7 +1907,7 @@ TEST_F(SpdySessionTest, WaitingForWrongPing) { // that could be used to call RunLoop::Quit(). // TODO(bnc): Fix once a RunLoop-compatible mock time framework is supported. // See https://crbug.com/708584#c75. - EXPECT_TRUE(session_->check_ping_status_pending()); + EXPECT_TRUE(check_ping_status_pending()); // Finish going away. base::RunLoop().RunUntilIdle(); @@ -2481,7 +2620,7 @@ class SessionClosingDelegate : public test::StreamDelegateDoNothing { : StreamDelegateDoNothing(stream), session_to_close_(session_to_close) {} - ~SessionClosingDelegate() override {} + ~SessionClosingDelegate() override = default; void OnClose(int status) override { session_to_close_->CloseSessionOnError(ERR_SPDY_PROTOCOL_ERROR, "Error"); @@ -2667,9 +2806,9 @@ TEST_F(SpdySessionTest, CloseTwoStalledCreateStream) { request3.StartRequest(SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, LOWEST, NetLogWithSource(), callback3.callback())); - EXPECT_EQ(0u, session_->num_active_streams()); - EXPECT_EQ(1u, session_->num_created_streams()); - EXPECT_EQ(2u, session_->pending_create_stream_queue_size(LOWEST)); + EXPECT_EQ(0u, num_active_streams()); + EXPECT_EQ(1u, num_created_streams()); + EXPECT_EQ(2u, pending_create_stream_queue_size(LOWEST)); SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); spdy_stream1->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND); @@ -2680,16 +2819,16 @@ TEST_F(SpdySessionTest, CloseTwoStalledCreateStream) { EXPECT_FALSE(spdy_stream1); EXPECT_EQ(1u, delegate1.stream_id()); - EXPECT_EQ(0u, session_->num_active_streams()); - EXPECT_EQ(1u, session_->pending_create_stream_queue_size(LOWEST)); + EXPECT_EQ(0u, num_active_streams()); + EXPECT_EQ(1u, pending_create_stream_queue_size(LOWEST)); // Pump loop for SpdySession::ProcessPendingStreamRequests() to // create the 2nd stream. base::RunLoop().RunUntilIdle(); - EXPECT_EQ(0u, session_->num_active_streams()); - EXPECT_EQ(1u, session_->num_created_streams()); - EXPECT_EQ(1u, session_->pending_create_stream_queue_size(LOWEST)); + EXPECT_EQ(0u, num_active_streams()); + EXPECT_EQ(1u, num_created_streams()); + EXPECT_EQ(1u, pending_create_stream_queue_size(LOWEST)); base::WeakPtr<SpdyStream> stream2 = request2.ReleaseStream(); test::StreamDelegateDoNothing delegate2(stream2); @@ -2703,16 +2842,16 @@ TEST_F(SpdySessionTest, CloseTwoStalledCreateStream) { EXPECT_FALSE(stream2); EXPECT_EQ(3u, delegate2.stream_id()); - EXPECT_EQ(0u, session_->num_active_streams()); - EXPECT_EQ(0u, session_->pending_create_stream_queue_size(LOWEST)); + EXPECT_EQ(0u, num_active_streams()); + EXPECT_EQ(0u, pending_create_stream_queue_size(LOWEST)); // Pump loop for SpdySession::ProcessPendingStreamRequests() to // create the 3rd stream. base::RunLoop().RunUntilIdle(); - EXPECT_EQ(0u, session_->num_active_streams()); - EXPECT_EQ(1u, session_->num_created_streams()); - EXPECT_EQ(0u, session_->pending_create_stream_queue_size(LOWEST)); + EXPECT_EQ(0u, num_active_streams()); + EXPECT_EQ(1u, num_created_streams()); + EXPECT_EQ(0u, pending_create_stream_queue_size(LOWEST)); base::WeakPtr<SpdyStream> stream3 = request3.ReleaseStream(); test::StreamDelegateDoNothing delegate3(stream3); @@ -2726,9 +2865,9 @@ TEST_F(SpdySessionTest, CloseTwoStalledCreateStream) { EXPECT_FALSE(stream3); EXPECT_EQ(5u, delegate3.stream_id()); - EXPECT_EQ(0u, session_->num_active_streams()); - EXPECT_EQ(0u, session_->num_created_streams()); - EXPECT_EQ(0u, session_->pending_create_stream_queue_size(LOWEST)); + EXPECT_EQ(0u, num_active_streams()); + EXPECT_EQ(0u, num_created_streams()); + EXPECT_EQ(0u, pending_create_stream_queue_size(LOWEST)); data.Resume(); base::RunLoop().RunUntilIdle(); @@ -2777,9 +2916,9 @@ TEST_F(SpdySessionTest, CancelTwoStalledCreateStream) { request3.StartRequest(SPDY_BIDIRECTIONAL_STREAM, session_, test_url_, LOWEST, NetLogWithSource(), callback3.callback())); - EXPECT_EQ(0u, session_->num_active_streams()); - EXPECT_EQ(kInitialMaxConcurrentStreams, session_->num_created_streams()); - EXPECT_EQ(2u, session_->pending_create_stream_queue_size(LOWEST)); + EXPECT_EQ(0u, num_active_streams()); + EXPECT_EQ(kInitialMaxConcurrentStreams, num_created_streams()); + EXPECT_EQ(2u, pending_create_stream_queue_size(LOWEST)); // Cancel the first stream; this will allow the second stream to be created. EXPECT_TRUE(spdy_stream1); @@ -2787,9 +2926,9 @@ TEST_F(SpdySessionTest, CancelTwoStalledCreateStream) { EXPECT_FALSE(spdy_stream1); EXPECT_THAT(callback2.WaitForResult(), IsOk()); - EXPECT_EQ(0u, session_->num_active_streams()); - EXPECT_EQ(kInitialMaxConcurrentStreams, session_->num_created_streams()); - EXPECT_EQ(1u, session_->pending_create_stream_queue_size(LOWEST)); + EXPECT_EQ(0u, num_active_streams()); + EXPECT_EQ(kInitialMaxConcurrentStreams, num_created_streams()); + EXPECT_EQ(1u, pending_create_stream_queue_size(LOWEST)); // Cancel the second stream; this will allow the third stream to be created. base::WeakPtr<SpdyStream> spdy_stream2 = request2.ReleaseStream(); @@ -2797,17 +2936,17 @@ TEST_F(SpdySessionTest, CancelTwoStalledCreateStream) { EXPECT_FALSE(spdy_stream2); EXPECT_THAT(callback3.WaitForResult(), IsOk()); - EXPECT_EQ(0u, session_->num_active_streams()); - EXPECT_EQ(kInitialMaxConcurrentStreams, session_->num_created_streams()); - EXPECT_EQ(0u, session_->pending_create_stream_queue_size(LOWEST)); + EXPECT_EQ(0u, num_active_streams()); + EXPECT_EQ(kInitialMaxConcurrentStreams, num_created_streams()); + EXPECT_EQ(0u, pending_create_stream_queue_size(LOWEST)); // Cancel the third stream. base::WeakPtr<SpdyStream> spdy_stream3 = request3.ReleaseStream(); spdy_stream3->Cancel(); EXPECT_FALSE(spdy_stream3); - EXPECT_EQ(0u, session_->num_active_streams()); - EXPECT_EQ(kInitialMaxConcurrentStreams - 1, session_->num_created_streams()); - EXPECT_EQ(0u, session_->pending_create_stream_queue_size(LOWEST)); + EXPECT_EQ(0u, num_active_streams()); + EXPECT_EQ(kInitialMaxConcurrentStreams - 1, num_created_streams()); + EXPECT_EQ(0u, pending_create_stream_queue_size(LOWEST)); } // Test that SpdySession::DoReadLoop reads data from the socket @@ -3280,9 +3419,9 @@ TEST_F(SpdySessionTest, ProtocolNegotiation) { CreateNetworkSession(); session_ = CreateFakeSpdySession(spdy_session_pool_, key_); - EXPECT_EQ(kDefaultInitialWindowSize, session_->session_send_window_size_); - EXPECT_EQ(kDefaultInitialWindowSize, session_->session_recv_window_size_); - EXPECT_EQ(0, session_->session_unacked_recv_window_bytes_); + EXPECT_EQ(kDefaultInitialWindowSize, session_send_window_size()); + EXPECT_EQ(kDefaultInitialWindowSize, session_recv_window_size()); + EXPECT_EQ(0, session_unacked_recv_window_bytes()); } // Tests the case of a non-SPDY request closing an idle SPDY session when no @@ -3320,10 +3459,11 @@ TEST_F(SpdySessionTest, CloseOneIdleConnection) { host_port2, false, OnHostResolutionCallback(), TransportSocketParams::COMBINE_CONNECT_AND_WRITE_DEFAULT)); auto connection2 = std::make_unique<ClientSocketHandle>(); - EXPECT_EQ(ERR_IO_PENDING, - connection2->Init(host_port2.ToString(), params2, DEFAULT_PRIORITY, - ClientSocketPool::RespectLimits::ENABLED, - callback2.callback(), pool, NetLogWithSource())); + EXPECT_EQ( + ERR_IO_PENDING, + connection2->Init(host_port2.ToString(), params2, DEFAULT_PRIORITY, + SocketTag(), ClientSocketPool::RespectLimits::ENABLED, + callback2.callback(), pool, NetLogWithSource())); EXPECT_TRUE(pool->IsStalled()); // The socket pool should close the connection asynchronously and establish a @@ -3399,10 +3539,11 @@ TEST_F(SpdySessionTest, CloseOneIdleConnectionWithAlias) { host_port3, false, OnHostResolutionCallback(), TransportSocketParams::COMBINE_CONNECT_AND_WRITE_DEFAULT)); auto connection3 = std::make_unique<ClientSocketHandle>(); - EXPECT_EQ(ERR_IO_PENDING, - connection3->Init(host_port3.ToString(), params3, DEFAULT_PRIORITY, - ClientSocketPool::RespectLimits::ENABLED, - callback3.callback(), pool, NetLogWithSource())); + EXPECT_EQ( + ERR_IO_PENDING, + connection3->Init(host_port3.ToString(), params3, DEFAULT_PRIORITY, + SocketTag(), ClientSocketPool::RespectLimits::ENABLED, + callback3.callback(), pool, NetLogWithSource())); EXPECT_TRUE(pool->IsStalled()); // The socket pool should close the connection asynchronously and establish a @@ -3478,10 +3619,11 @@ TEST_F(SpdySessionTest, CloseSessionOnIdleWhenPoolStalled) { host_port2, false, OnHostResolutionCallback(), TransportSocketParams::COMBINE_CONNECT_AND_WRITE_DEFAULT)); auto connection2 = std::make_unique<ClientSocketHandle>(); - EXPECT_EQ(ERR_IO_PENDING, - connection2->Init(host_port2.ToString(), params2, DEFAULT_PRIORITY, - ClientSocketPool::RespectLimits::ENABLED, - callback2.callback(), pool, NetLogWithSource())); + EXPECT_EQ( + ERR_IO_PENDING, + connection2->Init(host_port2.ToString(), params2, DEFAULT_PRIORITY, + SocketTag(), ClientSocketPool::RespectLimits::ENABLED, + callback2.callback(), pool, NetLogWithSource())); EXPECT_TRUE(pool->IsStalled()); // Running the message loop should cause the socket pool to ask the SPDY @@ -3545,7 +3687,7 @@ class StreamCreatingDelegate : public test::StreamDelegateDoNothing { : StreamDelegateDoNothing(stream), session_(session) {} - ~StreamCreatingDelegate() override {} + ~StreamCreatingDelegate() override = default; void OnClose(int status) override { GURL url(kDefaultUrl); @@ -3609,8 +3751,8 @@ TEST_F(SpdySessionTest, CreateStreamOnStreamReset) { EXPECT_FALSE(spdy_stream); EXPECT_TRUE(delegate.StreamIsClosed()); - EXPECT_EQ(0u, session_->num_active_streams()); - EXPECT_EQ(1u, session_->num_created_streams()); + EXPECT_EQ(0u, num_active_streams()); + EXPECT_EQ(1u, num_created_streams()); data.Resume(); base::RunLoop().RunUntilIdle(); @@ -3656,7 +3798,7 @@ TEST_F(SpdySessionTest, UpdateStreamsSendWindowSize) { // Process the SETTINGS frame. base::RunLoop().RunUntilIdle(); - EXPECT_EQ(session_->stream_initial_send_window_size(), window_size); + EXPECT_EQ(stream_initial_send_window_size(), window_size); EXPECT_EQ(spdy_stream1->send_window_size(), window_size); // Release the first one, this will allow the second to be created. @@ -3703,29 +3845,29 @@ TEST_F(SpdySessionTest, AdjustRecvWindowSize) { CreateNetworkSession(); CreateSpdySession(); - EXPECT_EQ(initial_window_size, session_->session_recv_window_size_); - EXPECT_EQ(0, session_->session_unacked_recv_window_bytes_); + EXPECT_EQ(initial_window_size, session_recv_window_size()); + EXPECT_EQ(0, session_unacked_recv_window_bytes()); - session_->IncreaseRecvWindowSize(delta_window_size); + IncreaseRecvWindowSize(delta_window_size); EXPECT_EQ(initial_window_size + delta_window_size, - session_->session_recv_window_size_); - EXPECT_EQ(delta_window_size, session_->session_unacked_recv_window_bytes_); + session_recv_window_size()); + EXPECT_EQ(delta_window_size, session_unacked_recv_window_bytes()); // Should trigger sending a WINDOW_UPDATE frame. - session_->IncreaseRecvWindowSize(initial_window_size); + IncreaseRecvWindowSize(initial_window_size); EXPECT_EQ(initial_window_size + delta_window_size + initial_window_size, - session_->session_recv_window_size_); - EXPECT_EQ(0, session_->session_unacked_recv_window_bytes_); + session_recv_window_size()); + EXPECT_EQ(0, session_unacked_recv_window_bytes()); base::RunLoop().RunUntilIdle(); // DecreaseRecvWindowSize() expects |in_io_loop_| to be true. - session_->in_io_loop_ = true; - session_->DecreaseRecvWindowSize(initial_window_size + delta_window_size + - initial_window_size); - session_->in_io_loop_ = false; - EXPECT_EQ(0, session_->session_recv_window_size_); - EXPECT_EQ(0, session_->session_unacked_recv_window_bytes_); + set_in_io_loop(true); + DecreaseRecvWindowSize(initial_window_size + delta_window_size + + initial_window_size); + set_in_io_loop(false); + EXPECT_EQ(0, session_recv_window_size()); + EXPECT_EQ(0, session_unacked_recv_window_bytes()); EXPECT_TRUE(session_); data.Resume(); @@ -3751,14 +3893,14 @@ TEST_F(SpdySessionTest, AdjustSendWindowSize) { const int32_t initial_window_size = kDefaultInitialWindowSize; const int32_t delta_window_size = 100; - EXPECT_EQ(initial_window_size, session_->session_send_window_size_); + EXPECT_EQ(initial_window_size, session_send_window_size()); - session_->IncreaseSendWindowSize(delta_window_size); + IncreaseSendWindowSize(delta_window_size); EXPECT_EQ(initial_window_size + delta_window_size, - session_->session_send_window_size_); + session_send_window_size()); - session_->DecreaseSendWindowSize(delta_window_size); - EXPECT_EQ(initial_window_size, session_->session_send_window_size_); + DecreaseSendWindowSize(delta_window_size); + EXPECT_EQ(initial_window_size, session_send_window_size()); } // Incoming data for an inactive stream should not cause the session @@ -3780,13 +3922,13 @@ TEST_F(SpdySessionTest, SessionFlowControlInactiveStream) { CreateNetworkSession(); CreateSpdySession(); - EXPECT_EQ(kDefaultInitialWindowSize, session_->session_recv_window_size_); - EXPECT_EQ(0, session_->session_unacked_recv_window_bytes_); + EXPECT_EQ(kDefaultInitialWindowSize, session_recv_window_size()); + EXPECT_EQ(0, session_unacked_recv_window_bytes()); base::RunLoop().RunUntilIdle(); - EXPECT_EQ(kDefaultInitialWindowSize, session_->session_recv_window_size_); - EXPECT_EQ(kUploadDataSize, session_->session_unacked_recv_window_bytes_); + EXPECT_EQ(kDefaultInitialWindowSize, session_recv_window_size()); + EXPECT_EQ(kUploadDataSize, session_unacked_recv_window_bytes()); EXPECT_TRUE(session_); data.Resume(); @@ -3814,14 +3956,14 @@ TEST_F(SpdySessionTest, SessionFlowControlPadding) { CreateNetworkSession(); CreateSpdySession(); - EXPECT_EQ(kDefaultInitialWindowSize, session_->session_recv_window_size_); - EXPECT_EQ(0, session_->session_unacked_recv_window_bytes_); + EXPECT_EQ(kDefaultInitialWindowSize, session_recv_window_size()); + EXPECT_EQ(0, session_unacked_recv_window_bytes()); base::RunLoop().RunUntilIdle(); - EXPECT_EQ(kDefaultInitialWindowSize, session_->session_recv_window_size_); + EXPECT_EQ(kDefaultInitialWindowSize, session_recv_window_size()); EXPECT_EQ(kUploadDataSize + padding_length, - session_->session_unacked_recv_window_bytes_); + session_unacked_recv_window_bytes()); data.Resume(); base::RunLoop().RunUntilIdle(); @@ -3935,20 +4077,19 @@ TEST_F(SpdySessionTest, SessionFlowControlTooMuchDataTwoDataFrames) { CreateSpdySession(); // Setting session level receiving window size to smaller than initial is not // possible via SpdySessionPoolPeer. - session_->session_recv_window_size_ = session_max_recv_window_size; + set_session_recv_window_size(session_max_recv_window_size); // First data frame is immediately consumed and does not trigger // WINDOW_UPDATE. base::RunLoop().RunUntilIdle(); - EXPECT_EQ(first_data_frame_size, - session_->session_unacked_recv_window_bytes_); - EXPECT_EQ(session_max_recv_window_size, session_->session_recv_window_size_); - EXPECT_EQ(SpdySession::STATE_AVAILABLE, session_->availability_state_); + EXPECT_EQ(first_data_frame_size, session_unacked_recv_window_bytes()); + EXPECT_EQ(session_max_recv_window_size, session_recv_window_size()); + EXPECT_TRUE(session_->IsAvailable()); // Second data frame overflows receiving window, causes session to close. data.Resume(); base::RunLoop().RunUntilIdle(); - EXPECT_EQ(SpdySession::STATE_DRAINING, session_->availability_state_); + EXPECT_TRUE(session_->IsDraining()); } // Regression test for a bug that was caused by including unsent WINDOW_UPDATE @@ -4046,7 +4187,7 @@ class DropReceivedDataDelegate : public test::StreamDelegateSendImmediate { SpdyStringPiece data) : StreamDelegateSendImmediate(stream, data) {} - ~DropReceivedDataDelegate() override {} + ~DropReceivedDataDelegate() override = default; // Drop any received data. void OnDataReceived(std::unique_ptr<SpdyBuffer> buffer) override {} @@ -4102,21 +4243,21 @@ TEST_F(SpdySessionTest, SessionFlowControlNoReceiveLeaks) { stream->SendRequestHeaders(std::move(headers), MORE_DATA_TO_SEND)); const int32_t initial_window_size = kDefaultInitialWindowSize; - EXPECT_EQ(initial_window_size, session_->session_recv_window_size_); - EXPECT_EQ(0, session_->session_unacked_recv_window_bytes_); + EXPECT_EQ(initial_window_size, session_recv_window_size()); + EXPECT_EQ(0, session_unacked_recv_window_bytes()); base::RunLoop().RunUntilIdle(); - EXPECT_EQ(initial_window_size, session_->session_recv_window_size_); - EXPECT_EQ(kMsgDataSize, session_->session_unacked_recv_window_bytes_); + EXPECT_EQ(initial_window_size, session_recv_window_size()); + EXPECT_EQ(kMsgDataSize, session_unacked_recv_window_bytes()); stream->Close(); EXPECT_FALSE(stream); EXPECT_THAT(delegate.WaitForClose(), IsOk()); - EXPECT_EQ(initial_window_size, session_->session_recv_window_size_); - EXPECT_EQ(kMsgDataSize, session_->session_unacked_recv_window_bytes_); + EXPECT_EQ(initial_window_size, session_recv_window_size()); + EXPECT_EQ(kMsgDataSize, session_unacked_recv_window_bytes()); data.Resume(); base::RunLoop().RunUntilIdle(); @@ -4167,25 +4308,24 @@ TEST_F(SpdySessionTest, SessionFlowControlNoSendLeaks) { stream->SendRequestHeaders(std::move(headers), MORE_DATA_TO_SEND)); const int32_t initial_window_size = kDefaultInitialWindowSize; - EXPECT_EQ(initial_window_size, session_->session_send_window_size_); + EXPECT_EQ(initial_window_size, session_send_window_size()); // Write request. base::RunLoop().RunUntilIdle(); - EXPECT_EQ(initial_window_size, session_->session_send_window_size_); + EXPECT_EQ(initial_window_size, session_send_window_size()); // Read response, but do not run the message loop, so that the body is not // written to the socket. data.Resume(); - EXPECT_EQ(initial_window_size - kMsgDataSize, - session_->session_send_window_size_); + EXPECT_EQ(initial_window_size - kMsgDataSize, session_send_window_size()); // Closing the stream should increase the session's send window. stream->Close(); EXPECT_FALSE(stream); - EXPECT_EQ(initial_window_size, session_->session_send_window_size_); + EXPECT_EQ(initial_window_size, session_send_window_size()); EXPECT_THAT(delegate.WaitForClose(), IsOk()); @@ -4250,53 +4390,49 @@ TEST_F(SpdySessionTest, SessionFlowControlEndToEnd) { stream->SendRequestHeaders(std::move(headers), MORE_DATA_TO_SEND)); const int32_t initial_window_size = kDefaultInitialWindowSize; - EXPECT_EQ(initial_window_size, session_->session_send_window_size_); - EXPECT_EQ(initial_window_size, session_->session_recv_window_size_); - EXPECT_EQ(0, session_->session_unacked_recv_window_bytes_); + EXPECT_EQ(initial_window_size, session_send_window_size()); + EXPECT_EQ(initial_window_size, session_recv_window_size()); + EXPECT_EQ(0, session_unacked_recv_window_bytes()); // Send request and message. base::RunLoop().RunUntilIdle(); - EXPECT_EQ(initial_window_size - kMsgDataSize, - session_->session_send_window_size_); - EXPECT_EQ(initial_window_size, session_->session_recv_window_size_); - EXPECT_EQ(0, session_->session_unacked_recv_window_bytes_); + EXPECT_EQ(initial_window_size - kMsgDataSize, session_send_window_size()); + EXPECT_EQ(initial_window_size, session_recv_window_size()); + EXPECT_EQ(0, session_unacked_recv_window_bytes()); // Read echo. data.Resume(); base::RunLoop().RunUntilIdle(); - EXPECT_EQ(initial_window_size - kMsgDataSize, - session_->session_send_window_size_); - EXPECT_EQ(initial_window_size - kMsgDataSize, - session_->session_recv_window_size_); - EXPECT_EQ(0, session_->session_unacked_recv_window_bytes_); + EXPECT_EQ(initial_window_size - kMsgDataSize, session_send_window_size()); + EXPECT_EQ(initial_window_size - kMsgDataSize, session_recv_window_size()); + EXPECT_EQ(0, session_unacked_recv_window_bytes()); // Read window update. data.Resume(); base::RunLoop().RunUntilIdle(); - EXPECT_EQ(initial_window_size, session_->session_send_window_size_); - EXPECT_EQ(initial_window_size - kMsgDataSize, - session_->session_recv_window_size_); - EXPECT_EQ(0, session_->session_unacked_recv_window_bytes_); + EXPECT_EQ(initial_window_size, session_send_window_size()); + EXPECT_EQ(initial_window_size - kMsgDataSize, session_recv_window_size()); + EXPECT_EQ(0, session_unacked_recv_window_bytes()); EXPECT_EQ(msg_data, delegate.TakeReceivedData()); // Draining the delegate's read queue should increase the session's // receive window. - EXPECT_EQ(initial_window_size, session_->session_send_window_size_); - EXPECT_EQ(initial_window_size, session_->session_recv_window_size_); - EXPECT_EQ(kMsgDataSize, session_->session_unacked_recv_window_bytes_); + EXPECT_EQ(initial_window_size, session_send_window_size()); + EXPECT_EQ(initial_window_size, session_recv_window_size()); + EXPECT_EQ(kMsgDataSize, session_unacked_recv_window_bytes()); stream->Close(); EXPECT_FALSE(stream); EXPECT_THAT(delegate.WaitForClose(), IsOk()); - EXPECT_EQ(initial_window_size, session_->session_send_window_size_); - EXPECT_EQ(initial_window_size, session_->session_recv_window_size_); - EXPECT_EQ(kMsgDataSize, session_->session_unacked_recv_window_bytes_); + EXPECT_EQ(initial_window_size, session_send_window_size()); + EXPECT_EQ(initial_window_size, session_recv_window_size()); + EXPECT_EQ(kMsgDataSize, session_unacked_recv_window_bytes()); data.Resume(); base::RunLoop().RunUntilIdle(); @@ -4656,7 +4792,7 @@ class StreamClosingDelegate : public test::StreamDelegateWithBody { SpdyStringPiece data) : StreamDelegateWithBody(stream, data) {} - ~StreamClosingDelegate() override {} + ~StreamClosingDelegate() override = default; void set_stream_to_close(const base::WeakPtr<SpdyStream>& stream_to_close) { stream_to_close_ = stream_to_close; @@ -4947,7 +5083,7 @@ TEST_F(SpdySessionTest, GoAwayOnSessionFlowControlError) { base::RunLoop().RunUntilIdle(); // Put session on the edge of overflowing it's recv window. - session_->session_recv_window_size_ = 1; + set_session_recv_window_size(1); // Read response headers & body. Body overflows the session window, and a // goaway is written. @@ -4965,8 +5101,8 @@ TEST_F(SpdySessionTest, PushedStreamShouldNotCountToClientConcurrencyLimit) { new_settings[SETTINGS_MAX_CONCURRENT_STREAMS] = 2; SpdySerializedFrame settings_frame( spdy_util_.ConstructSpdySettings(new_settings)); - SpdySerializedFrame pushed(spdy_util_.ConstructSpdyPush( - nullptr, 0, 2, 1, "https://www.example.org/a.dat")); + SpdySerializedFrame pushed( + spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl)); MockRead reads[] = { CreateMockRead(settings_frame, 0), MockRead(ASYNC, ERR_IO_PENDING, 3), @@ -5004,10 +5140,10 @@ TEST_F(SpdySessionTest, PushedStreamShouldNotCountToClientConcurrencyLimit) { test::StreamDelegateDoNothing delegate1(spdy_stream1); spdy_stream1->SetDelegate(&delegate1); - EXPECT_EQ(0u, session_->num_active_streams()); - EXPECT_EQ(1u, session_->num_created_streams()); - EXPECT_EQ(0u, session_->num_pushed_streams()); - EXPECT_EQ(0u, session_->num_active_pushed_streams()); + EXPECT_EQ(0u, num_active_streams()); + EXPECT_EQ(1u, num_created_streams()); + EXPECT_EQ(0u, num_pushed_streams()); + EXPECT_EQ(0u, num_active_pushed_streams()); SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); spdy_stream1->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND); @@ -5016,18 +5152,18 @@ TEST_F(SpdySessionTest, PushedStreamShouldNotCountToClientConcurrencyLimit) { EXPECT_EQ(0u, delegate1.stream_id()); base::RunLoop().RunUntilIdle(); EXPECT_EQ(1u, delegate1.stream_id()); - EXPECT_EQ(1u, session_->num_active_streams()); - EXPECT_EQ(0u, session_->num_created_streams()); - EXPECT_EQ(0u, session_->num_pushed_streams()); - EXPECT_EQ(0u, session_->num_active_pushed_streams()); + EXPECT_EQ(1u, num_active_streams()); + EXPECT_EQ(0u, num_created_streams()); + EXPECT_EQ(0u, num_pushed_streams()); + EXPECT_EQ(0u, num_active_pushed_streams()); // Run until pushed stream is created. data.Resume(); base::RunLoop().RunUntilIdle(); - EXPECT_EQ(2u, session_->num_active_streams()); - EXPECT_EQ(0u, session_->num_created_streams()); - EXPECT_EQ(1u, session_->num_pushed_streams()); - EXPECT_EQ(1u, session_->num_active_pushed_streams()); + EXPECT_EQ(2u, num_active_streams()); + EXPECT_EQ(0u, num_created_streams()); + EXPECT_EQ(1u, num_pushed_streams()); + EXPECT_EQ(1u, num_active_pushed_streams()); // Second stream should not be stalled, although we have 2 active streams, but // one of them is push stream and should not be taken into account when we @@ -5036,10 +5172,10 @@ TEST_F(SpdySessionTest, PushedStreamShouldNotCountToClientConcurrencyLimit) { CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, LOWEST, NetLogWithSource()); EXPECT_TRUE(spdy_stream2); - EXPECT_EQ(2u, session_->num_active_streams()); - EXPECT_EQ(1u, session_->num_created_streams()); - EXPECT_EQ(1u, session_->num_pushed_streams()); - EXPECT_EQ(1u, session_->num_active_pushed_streams()); + EXPECT_EQ(2u, num_active_streams()); + EXPECT_EQ(1u, num_created_streams()); + EXPECT_EQ(1u, num_pushed_streams()); + EXPECT_EQ(1u, num_active_pushed_streams()); // Read EOF. data.Resume(); @@ -5048,8 +5184,8 @@ TEST_F(SpdySessionTest, PushedStreamShouldNotCountToClientConcurrencyLimit) { } TEST_F(SpdySessionTest, RejectPushedStreamExceedingConcurrencyLimit) { - SpdySerializedFrame push_a(spdy_util_.ConstructSpdyPush( - nullptr, 0, 2, 1, "https://www.example.org/a.dat")); + SpdySerializedFrame push_a( + spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl)); SpdySerializedFrame push_b(spdy_util_.ConstructSpdyPush( nullptr, 0, 4, 1, "https://www.example.org/b.dat")); MockRead reads[] = { @@ -5078,7 +5214,7 @@ TEST_F(SpdySessionTest, RejectPushedStreamExceedingConcurrencyLimit) { CreateNetworkSession(); CreateSpdySession(); - session_->set_max_concurrent_pushed_streams(1); + set_max_concurrent_pushed_streams(1); base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, @@ -5088,10 +5224,10 @@ TEST_F(SpdySessionTest, RejectPushedStreamExceedingConcurrencyLimit) { test::StreamDelegateDoNothing delegate1(spdy_stream1); spdy_stream1->SetDelegate(&delegate1); - EXPECT_EQ(0u, session_->num_active_streams()); - EXPECT_EQ(1u, session_->num_created_streams()); - EXPECT_EQ(0u, session_->num_pushed_streams()); - EXPECT_EQ(0u, session_->num_active_pushed_streams()); + EXPECT_EQ(0u, num_active_streams()); + EXPECT_EQ(1u, num_created_streams()); + EXPECT_EQ(0u, num_pushed_streams()); + EXPECT_EQ(0u, num_active_pushed_streams()); SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); spdy_stream1->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND); @@ -5100,26 +5236,26 @@ TEST_F(SpdySessionTest, RejectPushedStreamExceedingConcurrencyLimit) { EXPECT_EQ(0u, delegate1.stream_id()); base::RunLoop().RunUntilIdle(); EXPECT_EQ(1u, delegate1.stream_id()); - EXPECT_EQ(1u, session_->num_active_streams()); - EXPECT_EQ(0u, session_->num_created_streams()); - EXPECT_EQ(0u, session_->num_pushed_streams()); - EXPECT_EQ(0u, session_->num_active_pushed_streams()); + EXPECT_EQ(1u, num_active_streams()); + EXPECT_EQ(0u, num_created_streams()); + EXPECT_EQ(0u, num_pushed_streams()); + EXPECT_EQ(0u, num_active_pushed_streams()); // Run until pushed stream is created. data.Resume(); base::RunLoop().RunUntilIdle(); - EXPECT_EQ(2u, session_->num_active_streams()); - EXPECT_EQ(0u, session_->num_created_streams()); - EXPECT_EQ(1u, session_->num_pushed_streams()); - EXPECT_EQ(1u, session_->num_active_pushed_streams()); + EXPECT_EQ(2u, num_active_streams()); + EXPECT_EQ(0u, num_created_streams()); + EXPECT_EQ(1u, num_pushed_streams()); + EXPECT_EQ(1u, num_active_pushed_streams()); // Reset incoming pushed stream. data.Resume(); base::RunLoop().RunUntilIdle(); - EXPECT_EQ(2u, session_->num_active_streams()); - EXPECT_EQ(0u, session_->num_created_streams()); - EXPECT_EQ(1u, session_->num_pushed_streams()); - EXPECT_EQ(1u, session_->num_active_pushed_streams()); + EXPECT_EQ(2u, num_active_streams()); + EXPECT_EQ(0u, num_created_streams()); + EXPECT_EQ(1u, num_pushed_streams()); + EXPECT_EQ(1u, num_active_pushed_streams()); // Read EOF. data.Resume(); @@ -5184,10 +5320,10 @@ TEST_F(SpdySessionTest, TrustedSpdyProxy) { test::StreamDelegateDoNothing delegate(spdy_stream); spdy_stream->SetDelegate(&delegate); - EXPECT_EQ(0u, session_->num_active_streams()); - EXPECT_EQ(1u, session_->num_created_streams()); - EXPECT_EQ(0u, session_->num_pushed_streams()); - EXPECT_EQ(0u, session_->num_active_pushed_streams()); + EXPECT_EQ(0u, num_active_streams()); + EXPECT_EQ(1u, num_created_streams()); + EXPECT_EQ(0u, num_pushed_streams()); + EXPECT_EQ(0u, num_active_pushed_streams()); SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); spdy_stream->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND); @@ -5196,26 +5332,26 @@ TEST_F(SpdySessionTest, TrustedSpdyProxy) { EXPECT_EQ(0u, delegate.stream_id()); base::RunLoop().RunUntilIdle(); EXPECT_EQ(1u, delegate.stream_id()); - EXPECT_EQ(1u, session_->num_active_streams()); - EXPECT_EQ(0u, session_->num_created_streams()); - EXPECT_EQ(0u, session_->num_pushed_streams()); - EXPECT_EQ(0u, session_->num_active_pushed_streams()); + EXPECT_EQ(1u, num_active_streams()); + EXPECT_EQ(0u, num_created_streams()); + EXPECT_EQ(0u, num_pushed_streams()); + EXPECT_EQ(0u, num_active_pushed_streams()); // Run until pushed stream is created. data.Resume(); base::RunLoop().RunUntilIdle(); - EXPECT_EQ(2u, session_->num_active_streams()); - EXPECT_EQ(0u, session_->num_created_streams()); - EXPECT_EQ(1u, session_->num_pushed_streams()); - EXPECT_EQ(1u, session_->num_active_pushed_streams()); + EXPECT_EQ(2u, num_active_streams()); + EXPECT_EQ(0u, num_created_streams()); + EXPECT_EQ(1u, num_pushed_streams()); + EXPECT_EQ(1u, num_active_pushed_streams()); // Reset incoming pushed stream. data.Resume(); base::RunLoop().RunUntilIdle(); - EXPECT_EQ(2u, session_->num_active_streams()); - EXPECT_EQ(0u, session_->num_created_streams()); - EXPECT_EQ(1u, session_->num_pushed_streams()); - EXPECT_EQ(1u, session_->num_active_pushed_streams()); + EXPECT_EQ(2u, num_active_streams()); + EXPECT_EQ(0u, num_created_streams()); + EXPECT_EQ(1u, num_pushed_streams()); + EXPECT_EQ(1u, num_active_pushed_streams()); // Read EOF. data.Resume(); @@ -5263,10 +5399,10 @@ TEST_F(SpdySessionTest, TrustedSpdyProxyNotSet) { test::StreamDelegateDoNothing delegate(spdy_stream); spdy_stream->SetDelegate(&delegate); - EXPECT_EQ(0u, session_->num_active_streams()); - EXPECT_EQ(1u, session_->num_created_streams()); - EXPECT_EQ(0u, session_->num_pushed_streams()); - EXPECT_EQ(0u, session_->num_active_pushed_streams()); + EXPECT_EQ(0u, num_active_streams()); + EXPECT_EQ(1u, num_created_streams()); + EXPECT_EQ(0u, num_pushed_streams()); + EXPECT_EQ(0u, num_active_pushed_streams()); SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); spdy_stream->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND); @@ -5275,10 +5411,10 @@ TEST_F(SpdySessionTest, TrustedSpdyProxyNotSet) { EXPECT_EQ(0u, delegate.stream_id()); base::RunLoop().RunUntilIdle(); EXPECT_EQ(1u, delegate.stream_id()); - EXPECT_EQ(1u, session_->num_active_streams()); - EXPECT_EQ(0u, session_->num_created_streams()); - EXPECT_EQ(0u, session_->num_pushed_streams()); - EXPECT_EQ(0u, session_->num_active_pushed_streams()); + EXPECT_EQ(1u, num_active_streams()); + EXPECT_EQ(0u, num_created_streams()); + EXPECT_EQ(0u, num_pushed_streams()); + EXPECT_EQ(0u, num_active_pushed_streams()); // Read EOF. data.Resume(); @@ -5287,14 +5423,14 @@ TEST_F(SpdySessionTest, TrustedSpdyProxyNotSet) { } TEST_F(SpdySessionTest, IgnoreReservedRemoteStreamsCount) { - SpdySerializedFrame push_a(spdy_util_.ConstructSpdyPush( - nullptr, 0, 2, 1, "https://www.example.org/a.dat")); + SpdySerializedFrame push_a( + spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl)); SpdyHeaderBlock push_headers; push_headers[":method"] = "GET"; spdy_util_.AddUrlToHeaderBlock("https://www.example.org/b.dat", &push_headers); SpdySerializedFrame push_b( - spdy_util_.ConstructInitialSpdyPushFrame(std::move(push_headers), 4, 1)); + spdy_util_.ConstructSpdyPushPromise(1, 4, std::move(push_headers))); SpdySerializedFrame headers_b( spdy_util_.ConstructSpdyPushHeaders(4, nullptr, 0)); MockRead reads[] = { @@ -5324,7 +5460,7 @@ TEST_F(SpdySessionTest, IgnoreReservedRemoteStreamsCount) { CreateNetworkSession(); CreateSpdySession(); - session_->set_max_concurrent_pushed_streams(1); + set_max_concurrent_pushed_streams(1); base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, @@ -5334,10 +5470,10 @@ TEST_F(SpdySessionTest, IgnoreReservedRemoteStreamsCount) { test::StreamDelegateDoNothing delegate1(spdy_stream1); spdy_stream1->SetDelegate(&delegate1); - EXPECT_EQ(0u, session_->num_active_streams()); - EXPECT_EQ(1u, session_->num_created_streams()); - EXPECT_EQ(0u, session_->num_pushed_streams()); - EXPECT_EQ(0u, session_->num_active_pushed_streams()); + EXPECT_EQ(0u, num_active_streams()); + EXPECT_EQ(1u, num_created_streams()); + EXPECT_EQ(0u, num_pushed_streams()); + EXPECT_EQ(0u, num_active_pushed_streams()); SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); spdy_stream1->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND); @@ -5346,35 +5482,35 @@ TEST_F(SpdySessionTest, IgnoreReservedRemoteStreamsCount) { EXPECT_EQ(0u, delegate1.stream_id()); base::RunLoop().RunUntilIdle(); EXPECT_EQ(1u, delegate1.stream_id()); - EXPECT_EQ(1u, session_->num_active_streams()); - EXPECT_EQ(0u, session_->num_created_streams()); - EXPECT_EQ(0u, session_->num_pushed_streams()); - EXPECT_EQ(0u, session_->num_active_pushed_streams()); + EXPECT_EQ(1u, num_active_streams()); + EXPECT_EQ(0u, num_created_streams()); + EXPECT_EQ(0u, num_pushed_streams()); + EXPECT_EQ(0u, num_active_pushed_streams()); // Run until pushed stream is created. data.Resume(); base::RunLoop().RunUntilIdle(); - EXPECT_EQ(2u, session_->num_active_streams()); - EXPECT_EQ(0u, session_->num_created_streams()); - EXPECT_EQ(1u, session_->num_pushed_streams()); - EXPECT_EQ(1u, session_->num_active_pushed_streams()); + EXPECT_EQ(2u, num_active_streams()); + EXPECT_EQ(0u, num_created_streams()); + EXPECT_EQ(1u, num_pushed_streams()); + EXPECT_EQ(1u, num_active_pushed_streams()); // Accept promised stream. It should not count towards pushed stream limit. data.Resume(); base::RunLoop().RunUntilIdle(); - EXPECT_EQ(3u, session_->num_active_streams()); - EXPECT_EQ(0u, session_->num_created_streams()); - EXPECT_EQ(2u, session_->num_pushed_streams()); - EXPECT_EQ(1u, session_->num_active_pushed_streams()); + EXPECT_EQ(3u, num_active_streams()); + EXPECT_EQ(0u, num_created_streams()); + EXPECT_EQ(2u, num_pushed_streams()); + EXPECT_EQ(1u, num_active_pushed_streams()); // Reset last pushed stream upon headers reception as it is going to be 2nd, // while we accept only one. data.Resume(); base::RunLoop().RunUntilIdle(); - EXPECT_EQ(2u, session_->num_active_streams()); - EXPECT_EQ(0u, session_->num_created_streams()); - EXPECT_EQ(1u, session_->num_pushed_streams()); - EXPECT_EQ(1u, session_->num_active_pushed_streams()); + EXPECT_EQ(2u, num_active_streams()); + EXPECT_EQ(0u, num_created_streams()); + EXPECT_EQ(1u, num_pushed_streams()); + EXPECT_EQ(1u, num_active_pushed_streams()); // Read EOF. data.Resume(); @@ -5383,12 +5519,11 @@ TEST_F(SpdySessionTest, IgnoreReservedRemoteStreamsCount) { } TEST_F(SpdySessionTest, CancelReservedStreamOnHeadersReceived) { - const char kPushedUrl[] = "https://www.example.org/a.dat"; SpdyHeaderBlock push_headers; push_headers[":method"] = "GET"; spdy_util_.AddUrlToHeaderBlock(kPushedUrl, &push_headers); SpdySerializedFrame push_promise( - spdy_util_.ConstructInitialSpdyPushFrame(std::move(push_headers), 2, 1)); + spdy_util_.ConstructSpdyPushPromise(1, 2, std::move(push_headers))); SpdySerializedFrame headers_frame( spdy_util_.ConstructSpdyPushHeaders(2, nullptr, 0)); MockRead reads[] = { @@ -5424,10 +5559,10 @@ TEST_F(SpdySessionTest, CancelReservedStreamOnHeadersReceived) { test::StreamDelegateDoNothing delegate1(spdy_stream1); spdy_stream1->SetDelegate(&delegate1); - EXPECT_EQ(0u, session_->num_active_streams()); - EXPECT_EQ(1u, session_->num_created_streams()); - EXPECT_EQ(0u, session_->num_pushed_streams()); - EXPECT_EQ(0u, session_->num_active_pushed_streams()); + EXPECT_EQ(0u, num_active_streams()); + EXPECT_EQ(1u, num_created_streams()); + EXPECT_EQ(0u, num_pushed_streams()); + EXPECT_EQ(0u, num_active_pushed_streams()); SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); spdy_stream1->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND); @@ -5436,22 +5571,38 @@ TEST_F(SpdySessionTest, CancelReservedStreamOnHeadersReceived) { EXPECT_EQ(0u, delegate1.stream_id()); base::RunLoop().RunUntilIdle(); EXPECT_EQ(1u, delegate1.stream_id()); - EXPECT_EQ(1u, session_->num_active_streams()); - EXPECT_EQ(0u, session_->num_created_streams()); - EXPECT_EQ(0u, session_->num_pushed_streams()); - EXPECT_EQ(0u, session_->num_active_pushed_streams()); + EXPECT_EQ(1u, num_active_streams()); + EXPECT_EQ(0u, num_created_streams()); + EXPECT_EQ(0u, num_pushed_streams()); + EXPECT_EQ(0u, num_active_pushed_streams()); + EXPECT_EQ(0u, num_unclaimed_pushed_streams()); // Run until pushed stream is created. data.Resume(); base::RunLoop().RunUntilIdle(); - EXPECT_EQ(2u, session_->num_active_streams()); - EXPECT_EQ(0u, session_->num_created_streams()); - EXPECT_EQ(1u, session_->num_pushed_streams()); - EXPECT_EQ(0u, session_->num_active_pushed_streams()); + EXPECT_EQ(2u, num_active_streams()); + EXPECT_EQ(0u, num_created_streams()); + EXPECT_EQ(1u, num_pushed_streams()); + EXPECT_EQ(0u, num_active_pushed_streams()); + EXPECT_EQ(1u, num_unclaimed_pushed_streams()); + + // Claim pushed stream from Http2PushPromiseIndex. + const GURL pushed_url(kPushedUrl); + HttpRequestInfo push_request; + push_request.url = pushed_url; + push_request.method = "GET"; + base::WeakPtr<SpdySession> session_with_pushed_stream; + SpdyStreamId pushed_stream_id; + spdy_session_pool_->push_promise_index()->ClaimPushedStream( + key_, pushed_url, push_request, &session_with_pushed_stream, + &pushed_stream_id); + EXPECT_EQ(session_.get(), session_with_pushed_stream.get()); + EXPECT_EQ(2u, pushed_stream_id); + EXPECT_EQ(0u, num_unclaimed_pushed_streams()); SpdyStream* pushed_stream; - int rv = session_->GetPushStream(GURL(kPushedUrl), IDLE, &pushed_stream, - NetLogWithSource()); + int rv = session_->GetPushedStream(pushed_url, pushed_stream_id, IDLE, + &pushed_stream, NetLogWithSource()); ASSERT_THAT(rv, IsOk()); ASSERT_TRUE(pushed_stream); test::StreamDelegateCloseOnHeaders delegate2(pushed_stream->GetWeakPtr()); @@ -5461,10 +5612,11 @@ TEST_F(SpdySessionTest, CancelReservedStreamOnHeadersReceived) { // that all our counters are in consistent state. data.Resume(); base::RunLoop().RunUntilIdle(); - EXPECT_EQ(1u, session_->num_active_streams()); - EXPECT_EQ(0u, session_->num_created_streams()); - EXPECT_EQ(0u, session_->num_pushed_streams()); - EXPECT_EQ(0u, session_->num_active_pushed_streams()); + EXPECT_EQ(1u, num_active_streams()); + EXPECT_EQ(0u, num_created_streams()); + EXPECT_EQ(0u, num_pushed_streams()); + EXPECT_EQ(0u, num_active_pushed_streams()); + EXPECT_EQ(0u, num_unclaimed_pushed_streams()); // Read EOF. data.Resume(); @@ -5473,6 +5625,128 @@ TEST_F(SpdySessionTest, CancelReservedStreamOnHeadersReceived) { EXPECT_TRUE(data.AllReadDataConsumed()); } +TEST_F(SpdySessionTest, GetPushedStream) { + SpdyHeaderBlock push_headers; + push_headers[":method"] = "GET"; + spdy_util_.AddUrlToHeaderBlock(kPushedUrl, &push_headers); + SpdySerializedFrame push_promise( + spdy_util_.ConstructSpdyPushPromise(1, 2, std::move(push_headers))); + SpdySerializedFrame headers_frame( + spdy_util_.ConstructSpdyPushHeaders(2, nullptr, 0)); + MockRead reads[] = { + MockRead(ASYNC, ERR_IO_PENDING, 1), CreateMockRead(push_promise, 2), + MockRead(ASYNC, ERR_IO_PENDING, 4), CreateMockRead(headers_frame, 5), + MockRead(ASYNC, ERR_IO_PENDING, 7), MockRead(ASYNC, 0, 8)}; + + SpdySerializedFrame req( + spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true)); + SpdySerializedFrame priority( + spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true)); + SpdySerializedFrame rst( + spdy_util_.ConstructSpdyRstStream(2, ERROR_CODE_CANCEL)); + MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(priority, 3), + CreateMockWrite(rst, 6)}; + + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); + session_deps_.socket_factory->AddSocketDataProvider(&data); + + AddSSLSocketData(); + + CreateNetworkSession(); + CreateSpdySession(); + + base::WeakPtr<SpdyStream> spdy_stream1 = + CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, + test_url_, LOWEST, NetLogWithSource()); + ASSERT_TRUE(spdy_stream1); + EXPECT_EQ(0u, spdy_stream1->stream_id()); + test::StreamDelegateDoNothing delegate1(spdy_stream1); + spdy_stream1->SetDelegate(&delegate1); + + EXPECT_EQ(0u, num_active_streams()); + EXPECT_EQ(1u, num_created_streams()); + EXPECT_EQ(0u, num_pushed_streams()); + EXPECT_EQ(0u, num_active_pushed_streams()); + + SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); + spdy_stream1->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND); + + // Activate first request. + EXPECT_EQ(0u, delegate1.stream_id()); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(1u, delegate1.stream_id()); + EXPECT_EQ(1u, num_active_streams()); + EXPECT_EQ(0u, num_created_streams()); + EXPECT_EQ(0u, num_pushed_streams()); + EXPECT_EQ(0u, num_active_pushed_streams()); + + // No streams are pushed yet, therefore GetPushedStream() should return an + // error. + const GURL pushed_url(kPushedUrl); + SpdyStream* pushed_stream; + int rv = session_->GetPushedStream(pushed_url, 2 /* pushed_stream_id */, IDLE, + &pushed_stream, NetLogWithSource()); + EXPECT_THAT(rv, IsError(ERR_SPDY_PUSHED_STREAM_NOT_AVAILABLE)); + + // Read PUSH_PROMISE. + data.Resume(); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(2u, num_active_streams()); + EXPECT_EQ(0u, num_created_streams()); + EXPECT_EQ(1u, num_pushed_streams()); + EXPECT_EQ(0u, num_active_pushed_streams()); + EXPECT_EQ(1u, num_unclaimed_pushed_streams()); + + // Claim pushed stream from Http2PushPromiseIndex so that GetPushedStream() + // can be called. + HttpRequestInfo push_request; + push_request.url = pushed_url; + push_request.method = "GET"; + base::WeakPtr<SpdySession> session_with_pushed_stream; + SpdyStreamId pushed_stream_id; + spdy_session_pool_->push_promise_index()->ClaimPushedStream( + key_, pushed_url, push_request, &session_with_pushed_stream, + &pushed_stream_id); + EXPECT_EQ(session_.get(), session_with_pushed_stream.get()); + EXPECT_EQ(2u, pushed_stream_id); + + // Verify that pushed stream is claimed. + EXPECT_EQ(0u, num_unclaimed_pushed_streams()); + + // GetPushedStream() should return an error if there does not exist a pushed + // stream with ID |pushed_stream_id|. + rv = session_->GetPushedStream(pushed_url, 4 /* pushed_stream_id */, IDLE, + &pushed_stream, NetLogWithSource()); + EXPECT_THAT(rv, IsError(ERR_SPDY_PUSHED_STREAM_NOT_AVAILABLE)); + + // GetPushedStream() should return OK and return the pushed stream in + // |pushed_stream| outparam if |pushed_stream_id| matches. + rv = session_->GetPushedStream(pushed_url, 2 /* pushed_stream_id */, IDLE, + &pushed_stream, NetLogWithSource()); + EXPECT_THAT(rv, IsOk()); + ASSERT_TRUE(pushed_stream); + test::StreamDelegateCloseOnHeaders delegate2(pushed_stream->GetWeakPtr()); + pushed_stream->SetDelegate(&delegate2); + + // Upon reading pushed headers, delegate closes the stream. + data.Resume(); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(1u, num_active_streams()); + EXPECT_EQ(0u, num_created_streams()); + EXPECT_EQ(0u, num_pushed_streams()); + EXPECT_EQ(0u, num_active_pushed_streams()); + + // Read EOF. + data.Resume(); + base::RunLoop().RunUntilIdle(); + + EXPECT_TRUE(delegate1.StreamIsClosed()); + EXPECT_TRUE(delegate2.StreamIsClosed()); + + EXPECT_TRUE(data.AllWriteDataConsumed()); + EXPECT_TRUE(data.AllReadDataConsumed()); +} + TEST_F(SpdySessionTest, RejectInvalidUnknownFrames) { session_deps_.host_resolver->set_synchronous_mode(true); @@ -5488,17 +5762,17 @@ TEST_F(SpdySessionTest, RejectInvalidUnknownFrames) { CreateNetworkSession(); CreateSpdySession(); - session_->stream_hi_water_mark_ = 5; + set_stream_hi_water_mark(5); // Low client (odd) ids are fine. - EXPECT_TRUE(session_->OnUnknownFrame(3, 0)); + EXPECT_TRUE(OnUnknownFrame(3, 0)); // Client id exceeding watermark. - EXPECT_FALSE(session_->OnUnknownFrame(9, 0)); + EXPECT_FALSE(OnUnknownFrame(9, 0)); - session_->last_accepted_push_stream_id_ = 6; + set_last_accepted_push_stream_id(6); // Low server (even) ids are fine. - EXPECT_TRUE(session_->OnUnknownFrame(2, 0)); + EXPECT_TRUE(OnUnknownFrame(2, 0)); // Server id exceeding last accepted id. - EXPECT_FALSE(session_->OnUnknownFrame(8, 0)); + EXPECT_FALSE(OnUnknownFrame(8, 0)); } enum ReadIfReadySupport { diff --git a/chromium/net/spdy/chromium/spdy_stream.cc b/chromium/net/spdy/chromium/spdy_stream.cc index 685bc8385e3..41e08ed9154 100644 --- a/chromium/net/spdy/chromium/spdy_stream.cc +++ b/chromium/net/spdy/chromium/spdy_stream.cc @@ -65,7 +65,7 @@ class SpdyStream::HeadersBufferProducer : public SpdyBufferProducer { DCHECK(stream_.get()); } - ~HeadersBufferProducer() override {} + ~HeadersBufferProducer() override = default; std::unique_ptr<SpdyBuffer> ProduceBuffer() override { if (!stream_.get()) { @@ -455,6 +455,12 @@ void SpdyStream::OnHeadersReceived(const SpdyHeaderBlock& response_headers, } } +bool SpdyStream::ShouldRetryRSTPushStream() { + // Retry if the stream is a pushed stream, has been claimed, but did not yet + // receive response headers + return (response_headers_.empty() && type_ == SPDY_PUSH_STREAM && delegate_); +} + void SpdyStream::OnPushPromiseHeadersReceived(SpdyHeaderBlock headers) { CHECK(!request_headers_valid_); CHECK_EQ(io_state_, STATE_IDLE); diff --git a/chromium/net/spdy/chromium/spdy_stream.h b/chromium/net/spdy/chromium/spdy_stream.h index 7ba0ff6d667..06e6b1e8396 100644 --- a/chromium/net/spdy/chromium/spdy_stream.h +++ b/chromium/net/spdy/chromium/spdy_stream.h @@ -370,9 +370,12 @@ class NET_EXPORT_PRIVATE SpdyStream { int64_t raw_received_bytes() const { return raw_received_bytes_; } int64_t raw_sent_bytes() const { return raw_sent_bytes_; } int recv_bytes() const { return recv_bytes_; } + bool ShouldRetryRSTPushStream(); bool GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const; + const SpdyHeaderBlock& request_headers() { return request_headers_; } + // Get the URL from the appropriate stream headers, or the empty // GURL() if it is unknown. const GURL& GetUrlFromHeaders() const { return url_from_header_block_; } diff --git a/chromium/net/spdy/chromium/spdy_stream_test_util.cc b/chromium/net/spdy/chromium/spdy_stream_test_util.cc index 00b9ab9cd0c..b891cd2ac22 100644 --- a/chromium/net/spdy/chromium/spdy_stream_test_util.cc +++ b/chromium/net/spdy/chromium/spdy_stream_test_util.cc @@ -21,7 +21,7 @@ ClosingDelegate::ClosingDelegate( DCHECK(stream_); } -ClosingDelegate::~ClosingDelegate() {} +ClosingDelegate::~ClosingDelegate() = default; void ClosingDelegate::OnHeadersSent() {} @@ -51,8 +51,7 @@ StreamDelegateBase::StreamDelegateBase( send_headers_completed_(false) { } -StreamDelegateBase::~StreamDelegateBase() { -} +StreamDelegateBase::~StreamDelegateBase() = default; void StreamDelegateBase::OnHeadersSent() { stream_id_ = stream_->stream_id(); @@ -114,16 +113,14 @@ StreamDelegateDoNothing::StreamDelegateDoNothing( const base::WeakPtr<SpdyStream>& stream) : StreamDelegateBase(stream) {} -StreamDelegateDoNothing::~StreamDelegateDoNothing() { -} +StreamDelegateDoNothing::~StreamDelegateDoNothing() = default; StreamDelegateSendImmediate::StreamDelegateSendImmediate( const base::WeakPtr<SpdyStream>& stream, SpdyStringPiece data) : StreamDelegateBase(stream), data_(data) {} -StreamDelegateSendImmediate::~StreamDelegateSendImmediate() { -} +StreamDelegateSendImmediate::~StreamDelegateSendImmediate() = default; void StreamDelegateSendImmediate::OnHeadersReceived( const SpdyHeaderBlock& response_headers) { @@ -139,8 +136,7 @@ StreamDelegateWithBody::StreamDelegateWithBody( SpdyStringPiece data) : StreamDelegateBase(stream), buf_(new StringIOBuffer(data.as_string())) {} -StreamDelegateWithBody::~StreamDelegateWithBody() { -} +StreamDelegateWithBody::~StreamDelegateWithBody() = default; void StreamDelegateWithBody::OnHeadersSent() { StreamDelegateBase::OnHeadersSent(); @@ -152,8 +148,7 @@ StreamDelegateCloseOnHeaders::StreamDelegateCloseOnHeaders( : StreamDelegateBase(stream) { } -StreamDelegateCloseOnHeaders::~StreamDelegateCloseOnHeaders() { -} +StreamDelegateCloseOnHeaders::~StreamDelegateCloseOnHeaders() = default; void StreamDelegateCloseOnHeaders::OnHeadersReceived( const SpdyHeaderBlock& response_headers) { diff --git a/chromium/net/spdy/chromium/spdy_stream_unittest.cc b/chromium/net/spdy/chromium/spdy_stream_unittest.cc index 911a1836e83..12e40c0266c 100644 --- a/chromium/net/spdy/chromium/spdy_stream_unittest.cc +++ b/chromium/net/spdy/chromium/spdy_stream_unittest.cc @@ -17,14 +17,17 @@ #include "base/run_loop.h" #include "net/base/completion_callback.h" #include "net/base/request_priority.h" +#include "net/http/http_request_info.h" #include "net/log/net_log_event_type.h" #include "net/log/test_net_log.h" #include "net/log/test_net_log_entry.h" #include "net/log/test_net_log_util.h" #include "net/socket/socket_test_util.h" #include "net/spdy/chromium/buffered_spdy_framer.h" +#include "net/spdy/chromium/http2_push_promise_index.h" #include "net/spdy/chromium/spdy_http_utils.h" #include "net/spdy/chromium/spdy_session.h" +#include "net/spdy/chromium/spdy_session_pool.h" #include "net/spdy/chromium/spdy_stream_test_util.h" #include "net/spdy/chromium/spdy_test_util_common.h" #include "net/spdy/core/spdy_protocol.h" @@ -69,7 +72,7 @@ class SpdyStreamTest : public ::testing::Test { offset_(0), ssl_(SYNCHRONOUS, OK) {} - ~SpdyStreamTest() override {} + ~SpdyStreamTest() override = default; base::WeakPtr<SpdySession> CreateDefaultSpdySession() { SpdySessionKey key(HostPortPair::FromURL(url_), ProxyServer::Direct(), @@ -136,6 +139,15 @@ class SpdyStreamTest : public ::testing::Test { session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_); } + static size_t num_pushed_streams(base::WeakPtr<SpdySession> session) { + return session->num_pushed_streams_; + } + + static SpdySessionPool* spdy_session_pool( + base::WeakPtr<SpdySession> session) { + return session->pool_; + } + const GURL url_; SpdyTestUtil spdy_util_; SpdySessionDependencies session_deps_; @@ -208,7 +220,7 @@ class StreamDelegateWithTrailers : public test::StreamDelegateWithBody { SpdyStringPiece data) : StreamDelegateWithBody(stream, data) {} - ~StreamDelegateWithTrailers() override {} + ~StreamDelegateWithTrailers() override = default; void OnTrailers(const SpdyHeaderBlock& trailers) override { trailers_ = trailers.Clone(); @@ -343,9 +355,23 @@ TEST_F(SpdyStreamTest, PushedStream) { data.RunUntilPaused(); + const SpdySessionKey key(HostPortPair::FromURL(url_), ProxyServer::Direct(), + PRIVACY_MODE_DISABLED); + const GURL pushed_url(kPushUrl); + HttpRequestInfo push_request; + push_request.url = pushed_url; + push_request.method = "GET"; + base::WeakPtr<SpdySession> session_with_pushed_stream; + SpdyStreamId pushed_stream_id; + spdy_session_pool(session)->push_promise_index()->ClaimPushedStream( + key, pushed_url, push_request, &session_with_pushed_stream, + &pushed_stream_id); + EXPECT_EQ(session.get(), session_with_pushed_stream.get()); + EXPECT_EQ(2u, pushed_stream_id); + SpdyStream* push_stream; - EXPECT_THAT(session->GetPushStream(GURL(kPushUrl), IDLE, &push_stream, - NetLogWithSource()), + EXPECT_THAT(session->GetPushedStream(pushed_url, pushed_stream_id, IDLE, + &push_stream, NetLogWithSource()), IsOk()); ASSERT_TRUE(push_stream); EXPECT_EQ(kPushUrl, push_stream->GetUrlFromHeaders().spec()); @@ -656,11 +682,7 @@ TEST_F(SpdyStreamTest, UpperCaseHeadersOnPush) { data.RunUntilPaused(); - SpdyStream* push_stream; - EXPECT_THAT(session->GetPushStream(GURL(kPushUrl), IDLE, &push_stream, - NetLogWithSource()), - IsOk()); - EXPECT_FALSE(push_stream); + EXPECT_EQ(0u, num_pushed_streams(session)); data.Resume(); @@ -732,8 +754,8 @@ TEST_F(SpdyStreamTest, HeadersMustHaveStatusOnPushedStream) { SpdySerializedFrame reply(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); AddRead(reply); - SpdySerializedFrame push_promise(spdy_util_.ConstructInitialSpdyPushFrame( - spdy_util_.ConstructGetHeaderBlock(kPushUrl), 2, 1)); + SpdySerializedFrame push_promise(spdy_util_.ConstructSpdyPushPromise( + 1, 2, spdy_util_.ConstructGetHeaderBlock(kPushUrl))); AddRead(push_promise); SpdySerializedFrame priority( @@ -848,8 +870,8 @@ TEST_F(SpdyStreamTest, HeadersMustPreceedDataOnPushedStream) { SpdySerializedFrame reply(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); AddRead(reply); - SpdySerializedFrame push_promise(spdy_util_.ConstructInitialSpdyPushFrame( - spdy_util_.ConstructGetHeaderBlock(kPushUrl), 2, 1)); + SpdySerializedFrame push_promise(spdy_util_.ConstructSpdyPushPromise( + 1, 2, spdy_util_.ConstructGetHeaderBlock(kPushUrl))); AddRead(push_promise); SpdySerializedFrame priority( diff --git a/chromium/net/spdy/chromium/spdy_test_util_common.cc b/chromium/net/spdy/chromium/spdy_test_util_common.cc index 3a0dc7a706e..daa832c40bb 100644 --- a/chromium/net/spdy/chromium/spdy_test_util_common.cc +++ b/chromium/net/spdy/chromium/spdy_test_util_common.cc @@ -22,6 +22,7 @@ #include "net/log/net_log_with_source.h" #include "net/socket/client_socket_handle.h" #include "net/socket/next_proto.h" +#include "net/socket/socket_tag.h" #include "net/socket/ssl_client_socket.h" #include "net/socket/transport_client_socket_pool.h" #include "net/spdy/chromium/buffered_spdy_framer.h" @@ -31,6 +32,7 @@ #include "net/spdy/core/spdy_alt_svc_wire_format.h" #include "net/spdy/core/spdy_framer.h" #include "net/test/gtest_util.h" +#include "net/traffic_annotation/network_traffic_annotation_test_helper.h" #include "net/url_request/url_request_job_factory_impl.h" #include "testing/gmock/include/gmock/gmock.h" @@ -156,7 +158,7 @@ namespace { class PriorityGetter : public BufferedSpdyFramerVisitorInterface { public: PriorityGetter() : priority_(0) {} - ~PriorityGetter() override {} + ~PriorityGetter() override = default; SpdyPriority priority() const { return priority_; @@ -238,9 +240,9 @@ base::WeakPtr<SpdyStream> CreateStreamSynchronously( (rv == OK) ? stream_request.ReleaseStream() : base::WeakPtr<SpdyStream>(); } -StreamReleaserCallback::StreamReleaserCallback() {} +StreamReleaserCallback::StreamReleaserCallback() = default; -StreamReleaserCallback::~StreamReleaserCallback() {} +StreamReleaserCallback::~StreamReleaserCallback() = default; CompletionCallback StreamReleaserCallback::MakeCallback( SpdyStreamRequest* request) { @@ -324,7 +326,8 @@ SpdySessionDependencies::SpdySessionDependencies( time_func(&base::TimeTicks::Now), enable_http2_alternative_service(false), net_log(nullptr), - http_09_on_non_default_ports_enabled(false) { + http_09_on_non_default_ports_enabled(false), + disable_idle_sockets_close_on_memory_pressure(false) { // Note: The CancelledTransaction test does cleanup by running all // tasks in the message loop (RunAllPending). Unfortunately, that // doesn't clean up tasks on the host resolver thread; and @@ -335,7 +338,7 @@ SpdySessionDependencies::SpdySessionDependencies( http2_settings[SETTINGS_INITIAL_WINDOW_SIZE] = kDefaultInitialWindowSize; } -SpdySessionDependencies::~SpdySessionDependencies() {} +SpdySessionDependencies::~SpdySessionDependencies() = default; // static std::unique_ptr<HttpNetworkSession> SpdySessionDependencies::SpdyCreateSession( @@ -378,6 +381,8 @@ HttpNetworkSession::Params SpdySessionDependencies::CreateSessionParams( session_deps->enable_http2_alternative_service; params.http_09_on_non_default_ports_enabled = session_deps->http_09_on_non_default_ports_enabled; + params.disable_idle_sockets_close_on_memory_pressure = + session_deps->disable_idle_sockets_close_on_memory_pressure; return params; } @@ -405,7 +410,7 @@ HttpNetworkSession::Context SpdySessionDependencies::CreateSessionContext( class AllowAnyCertCTPolicyEnforcer : public CTPolicyEnforcer { public: - AllowAnyCertCTPolicyEnforcer() {} + AllowAnyCertCTPolicyEnforcer() = default; ~AllowAnyCertCTPolicyEnforcer() override = default; ct::CTPolicyCompliance CheckCompliance( @@ -488,7 +493,7 @@ base::WeakPtr<SpdySession> CreateSpdySessionHelper( transport_params, nullptr, nullptr, key.host_port_pair(), ssl_config, key.privacy_mode(), 0, /* expect_spdy = */ false); int rv = connection->Init( - key.host_port_pair().ToString(), ssl_params, MEDIUM, + key.host_port_pair().ToString(), ssl_params, MEDIUM, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, callback.callback(), http_session->GetSSLSocketPool(HttpNetworkSession::NORMAL_SOCKET_POOL), net_log); @@ -529,7 +534,7 @@ class FakeSpdySessionClientSocket : public MockClientSocket { explicit FakeSpdySessionClientSocket(int read_result) : MockClientSocket(NetLogWithSource()), read_result_(read_result) {} - ~FakeSpdySessionClientSocket() override {} + ~FakeSpdySessionClientSocket() override = default; int Read(IOBuffer* buf, int buf_len, @@ -539,7 +544,8 @@ class FakeSpdySessionClientSocket : public MockClientSocket { int Write(IOBuffer* buf, int buf_len, - const CompletionCallback& callback) override { + const CompletionCallback& callback, + const NetworkTrafficAnnotationTag& traffic_annotation) override { return ERR_IO_PENDING; } @@ -627,7 +633,7 @@ SpdyTestUtil::SpdyTestUtil() response_spdy_framer_(SpdyFramer::ENABLE_COMPRESSION), default_url_(GURL(kDefaultUrl)) {} -SpdyTestUtil::~SpdyTestUtil() {} +SpdyTestUtil::~SpdyTestUtil() = default; void SpdyTestUtil::AddUrlToHeaderBlock(SpdyStringPiece url, SpdyHeaderBlock* headers) const { @@ -805,10 +811,8 @@ SpdySerializedFrame SpdyTestUtil::ConstructSpdyPush( SpdyHeaderBlock push_promise_header_block; push_promise_header_block[kHttp2MethodHeader] = "GET"; AddUrlToHeaderBlock(url, &push_promise_header_block); - SpdyPushPromiseIR push_promise(associated_stream_id, stream_id, - std::move(push_promise_header_block)); - SpdySerializedFrame push_promise_frame( - response_spdy_framer_.SerializeFrame(push_promise)); + SpdySerializedFrame push_promise_frame(ConstructSpdyPushPromise( + associated_stream_id, stream_id, std::move(push_promise_header_block))); SpdyHeaderBlock headers_header_block; headers_header_block[kHttp2StatusHeader] = "200"; @@ -832,10 +836,8 @@ SpdySerializedFrame SpdyTestUtil::ConstructSpdyPush( SpdyHeaderBlock push_promise_header_block; push_promise_header_block[kHttp2MethodHeader] = "GET"; AddUrlToHeaderBlock(url, &push_promise_header_block); - SpdyPushPromiseIR push_promise(associated_stream_id, stream_id, - std::move(push_promise_header_block)); - SpdySerializedFrame push_promise_frame( - response_spdy_framer_.SerializeFrame(push_promise)); + SpdySerializedFrame push_promise_frame(ConstructSpdyPushPromise( + associated_stream_id, stream_id, std::move(push_promise_header_block))); SpdyHeaderBlock headers_header_block; headers_header_block["hello"] = "bye"; @@ -849,10 +851,10 @@ SpdySerializedFrame SpdyTestUtil::ConstructSpdyPush( return CombineFrames({&push_promise_frame, &headers_frame}); } -SpdySerializedFrame SpdyTestUtil::ConstructInitialSpdyPushFrame( - SpdyHeaderBlock headers, - int stream_id, - int associated_stream_id) { +SpdySerializedFrame SpdyTestUtil::ConstructSpdyPushPromise( + SpdyStreamId associated_stream_id, + SpdyStreamId stream_id, + SpdyHeaderBlock headers) { SpdyPushPromiseIR push_promise(associated_stream_id, stream_id, std::move(headers)); return SpdySerializedFrame( diff --git a/chromium/net/spdy/chromium/spdy_test_util_common.h b/chromium/net/spdy/chromium/spdy_test_util_common.h index 316a8b920d4..5aa3cd6a43b 100644 --- a/chromium/net/spdy/chromium/spdy_test_util_common.h +++ b/chromium/net/spdy/chromium/spdy_test_util_common.h @@ -220,6 +220,7 @@ struct SpdySessionDependencies { bool enable_http2_alternative_service; NetLog* net_log; bool http_09_on_non_default_ports_enabled; + bool disable_idle_sockets_close_on_memory_pressure; }; class SpdyURLRequestContext : public URLRequestContext { @@ -372,10 +373,10 @@ class SpdyTestUtil { RequestPriority priority, const HostPortPair& host_port_pair); - // Constructs a SPDY PUSH_PROMISE frame. + // Constructs a PUSH_PROMISE frame and a HEADERS frame on the pushed stream. // |extra_headers| are the extra header-value pairs, which typically // will vary the most between calls. - // Returns a SpdySerializedFrame. + // Returns a SpdySerializedFrame object with the two frames concatenated. SpdySerializedFrame ConstructSpdyPush(const char* const extra_headers[], int extra_header_count, int stream_id, @@ -389,9 +390,11 @@ class SpdyTestUtil { const char* status, const char* location); - SpdySerializedFrame ConstructInitialSpdyPushFrame(SpdyHeaderBlock headers, - int stream_id, - int associated_stream_id); + // Constructs a PUSH_PROMISE frame. + SpdySerializedFrame ConstructSpdyPushPromise( + SpdyStreamId associated_stream_id, + SpdyStreamId stream_id, + SpdyHeaderBlock headers); SpdySerializedFrame ConstructSpdyPushHeaders( int stream_id, diff --git a/chromium/net/spdy/chromium/spdy_write_queue.cc b/chromium/net/spdy/chromium/spdy_write_queue.cc index 246c4d921a1..2d874e44ae1 100644 --- a/chromium/net/spdy/chromium/spdy_write_queue.cc +++ b/chromium/net/spdy/chromium/spdy_write_queue.cc @@ -17,7 +17,7 @@ namespace net { -SpdyWriteQueue::PendingWrite::PendingWrite() {} +SpdyWriteQueue::PendingWrite::PendingWrite() = default; SpdyWriteQueue::PendingWrite::PendingWrite( SpdyFrameType frame_type, @@ -28,7 +28,7 @@ SpdyWriteQueue::PendingWrite::PendingWrite( stream(stream), has_stream(stream.get() != nullptr) {} -SpdyWriteQueue::PendingWrite::~PendingWrite() {} +SpdyWriteQueue::PendingWrite::~PendingWrite() = default; SpdyWriteQueue::PendingWrite::PendingWrite(PendingWrite&& other) = default; SpdyWriteQueue::PendingWrite& SpdyWriteQueue::PendingWrite::operator=( diff --git a/chromium/net/spdy/core/fuzzing/hpack_fuzz_util.cc b/chromium/net/spdy/core/fuzzing/hpack_fuzz_util.cc index 3d7ec4edbcb..356040139f4 100644 --- a/chromium/net/spdy/core/fuzzing/hpack_fuzz_util.cc +++ b/chromium/net/spdy/core/fuzzing/hpack_fuzz_util.cc @@ -35,14 +35,14 @@ const size_t kValueLengthMax = 75; using base::RandBytesAsString; using std::map; -HpackFuzzUtil::GeneratorContext::GeneratorContext() {} -HpackFuzzUtil::GeneratorContext::~GeneratorContext() {} +HpackFuzzUtil::GeneratorContext::GeneratorContext() = default; +HpackFuzzUtil::GeneratorContext::~GeneratorContext() = default; HpackFuzzUtil::Input::Input() : offset(0) {} -HpackFuzzUtil::Input::~Input() {} +HpackFuzzUtil::Input::~Input() = default; -HpackFuzzUtil::FuzzerContext::FuzzerContext() {} -HpackFuzzUtil::FuzzerContext::~FuzzerContext() {} +HpackFuzzUtil::FuzzerContext::FuzzerContext() = default; +HpackFuzzUtil::FuzzerContext::~FuzzerContext() = default; // static void HpackFuzzUtil::InitializeGeneratorContext(GeneratorContext* context) { diff --git a/chromium/net/spdy/core/hpack/hpack_decoder_adapter.cc b/chromium/net/spdy/core/hpack/hpack_decoder_adapter.cc index c3197005f30..4a11a32b514 100644 --- a/chromium/net/spdy/core/hpack/hpack_decoder_adapter.cc +++ b/chromium/net/spdy/core/hpack/hpack_decoder_adapter.cc @@ -21,7 +21,7 @@ HpackDecoderAdapter::HpackDecoderAdapter() max_decode_buffer_size_bytes_(kMaxDecodeBufferSizeBytes), header_block_started_(false) {} -HpackDecoderAdapter::~HpackDecoderAdapter() {} +HpackDecoderAdapter::~HpackDecoderAdapter() = default; void HpackDecoderAdapter::ApplyHeaderTableSizeSetting(size_t size_setting) { DVLOG(2) << "HpackDecoderAdapter::ApplyHeaderTableSizeSetting"; @@ -111,7 +111,7 @@ size_t HpackDecoderAdapter::EstimateMemoryUsage() const { } HpackDecoderAdapter::ListenerAdapter::ListenerAdapter() : handler_(nullptr) {} -HpackDecoderAdapter::ListenerAdapter::~ListenerAdapter() {} +HpackDecoderAdapter::ListenerAdapter::~ListenerAdapter() = default; void HpackDecoderAdapter::ListenerAdapter::set_handler( SpdyHeadersHandlerInterface* handler) { diff --git a/chromium/net/spdy/core/hpack/hpack_decoder_adapter_test.cc b/chromium/net/spdy/core/hpack/hpack_decoder_adapter_test.cc index 4e36442197b..eebd473e77e 100644 --- a/chromium/net/spdy/core/hpack/hpack_decoder_adapter_test.cc +++ b/chromium/net/spdy/core/hpack/hpack_decoder_adapter_test.cc @@ -144,11 +144,11 @@ class HpackDecoderAdapterTest if (randomly_split_input_buffer_) { do { // Decode some fragment of the remaining bytes. - size_t bytes = str.length(); + size_t bytes = str.size(); if (!str.empty()) { - bytes = random_.Uniform(str.length()) + 1; + bytes = random_.Uniform(str.size()) + 1; } - EXPECT_LE(bytes, str.length()); + EXPECT_LE(bytes, str.size()); if (!HandleControlFrameHeadersData(str.substr(0, bytes))) { decode_has_failed_ = true; return false; diff --git a/chromium/net/spdy/core/hpack/hpack_encoder.cc b/chromium/net/spdy/core/hpack/hpack_encoder.cc index 1ae47c67791..824b0a3e3eb 100644 --- a/chromium/net/spdy/core/hpack/hpack_encoder.cc +++ b/chromium/net/spdy/core/hpack/hpack_encoder.cc @@ -83,7 +83,7 @@ HpackEncoder::HpackEncoder(const HpackHuffmanTable& table) enable_compression_(true), should_emit_table_size_(false) {} -HpackEncoder::~HpackEncoder() {} +HpackEncoder::~HpackEncoder() = default; void HpackEncoder::EncodeHeaderSet(const Representations& representations, SpdyString* output) { diff --git a/chromium/net/spdy/core/hpack/hpack_encoder_test.cc b/chromium/net/spdy/core/hpack/hpack_encoder_test.cc index fb10c8ff7c2..477bc37c817 100644 --- a/chromium/net/spdy/core/hpack/hpack_encoder_test.cc +++ b/chromium/net/spdy/core/hpack/hpack_encoder_test.cc @@ -445,7 +445,7 @@ TEST_P(HpackEncoderTest, PseudoHeadersFirst) { } TEST_P(HpackEncoderTest, CookieToCrumbs) { - test::HpackEncoderPeer peer(NULL); + test::HpackEncoderPeer peer(nullptr); std::vector<SpdyStringPiece> out; // Leading and trailing whitespace is consumed. A space after ';' is consumed. @@ -479,7 +479,7 @@ TEST_P(HpackEncoderTest, CookieToCrumbs) { } TEST_P(HpackEncoderTest, DecomposeRepresentation) { - test::HpackEncoderPeer peer(NULL); + test::HpackEncoderPeer peer(nullptr); std::vector<SpdyStringPiece> out; peer.DecomposeRepresentation("", &out); diff --git a/chromium/net/spdy/core/hpack/hpack_entry.cc b/chromium/net/spdy/core/hpack/hpack_entry.cc index 86d120bb5b2..a948877cd6d 100644 --- a/chromium/net/spdy/core/hpack/hpack_entry.cc +++ b/chromium/net/spdy/core/hpack/hpack_entry.cc @@ -63,7 +63,7 @@ HpackEntry& HpackEntry::operator=(const HpackEntry& other) { return *this; } -HpackEntry::~HpackEntry() {} +HpackEntry::~HpackEntry() = default; // static size_t HpackEntry::Size(SpdyStringPiece name, SpdyStringPiece value) { diff --git a/chromium/net/spdy/core/hpack/hpack_header_table.cc b/chromium/net/spdy/core/hpack/hpack_header_table.cc index dc29b5cccff..ba7b787f6de 100644 --- a/chromium/net/spdy/core/hpack/hpack_header_table.cc +++ b/chromium/net/spdy/core/hpack/hpack_header_table.cc @@ -39,11 +39,11 @@ HpackHeaderTable::HpackHeaderTable() max_size_(kDefaultHeaderTableSizeSetting), total_insertions_(static_entries_.size()) {} -HpackHeaderTable::~HpackHeaderTable() {} +HpackHeaderTable::~HpackHeaderTable() = default; const HpackEntry* HpackHeaderTable::GetByIndex(size_t index) { if (index == 0) { - return NULL; + return nullptr; } index -= 1; if (index < static_entries_.size()) { @@ -57,7 +57,7 @@ const HpackEntry* HpackHeaderTable::GetByIndex(size_t index) { } return result; } - return NULL; + return nullptr; } const HpackEntry* HpackHeaderTable::GetByName(SpdyStringPiece name) { @@ -77,7 +77,7 @@ const HpackEntry* HpackHeaderTable::GetByName(SpdyStringPiece name) { return result; } } - return NULL; + return nullptr; } const HpackEntry* HpackHeaderTable::GetByNameAndValue(SpdyStringPiece name, @@ -99,7 +99,7 @@ const HpackEntry* HpackHeaderTable::GetByNameAndValue(SpdyStringPiece name, return result; } } - return NULL; + return nullptr; } size_t HpackHeaderTable::IndexOf(const HpackEntry* entry) const { @@ -192,7 +192,7 @@ const HpackEntry* HpackHeaderTable::TryAddEntry(SpdyStringPiece name, // Entire table has been emptied, but there's still insufficient room. DCHECK(dynamic_entries_.empty()); DCHECK_EQ(0u, size_); - return NULL; + return nullptr; } dynamic_entries_.push_front(HpackEntry(name, value, false, // is_static diff --git a/chromium/net/spdy/core/hpack/hpack_header_table_test.cc b/chromium/net/spdy/core/hpack/hpack_header_table_test.cc index 141d58b43cb..4be29b4d6b2 100644 --- a/chromium/net/spdy/core/hpack/hpack_header_table_test.cc +++ b/chromium/net/spdy/core/hpack/hpack_header_table_test.cc @@ -109,7 +109,7 @@ class HpackHeaderTableTest : public ::testing::Test { EXPECT_EQ(0, distance(begin, end)); const HpackEntry* entry = table_.TryAddEntry(it->name(), it->value()); - EXPECT_NE(entry, static_cast<HpackEntry*>(NULL)); + EXPECT_NE(entry, static_cast<HpackEntry*>(nullptr)); } for (size_t i = 0; i != entries.size(); ++i) { @@ -225,7 +225,7 @@ TEST_F(HpackHeaderTableTest, EntryIndexing) { EXPECT_EQ(entry7, table_.GetByName("key-2")); EXPECT_EQ(entry2->name(), table_.GetByName(first_static_entry->name())->name()); - EXPECT_EQ(NULL, table_.GetByName("not-present")); + EXPECT_EQ(nullptr, table_.GetByName("not-present")); // Querying by name & value returns the lowest-index matching entry among // static entries, and the highest-index one among dynamic entries. @@ -238,8 +238,8 @@ TEST_F(HpackHeaderTableTest, EntryIndexing) { first_static_entry->value())); EXPECT_EQ(entry2, table_.GetByNameAndValue(first_static_entry->name(), "Value Four")); - EXPECT_EQ(NULL, table_.GetByNameAndValue("key-1", "Not Present")); - EXPECT_EQ(NULL, table_.GetByNameAndValue("not-present", "Value One")); + EXPECT_EQ(nullptr, table_.GetByNameAndValue("key-1", "Not Present")); + EXPECT_EQ(nullptr, table_.GetByNameAndValue("not-present", "Value One")); // Evict |entry1|. Queries for its name & value now return the static entry. // |entry2| remains queryable. @@ -252,7 +252,7 @@ TEST_F(HpackHeaderTableTest, EntryIndexing) { // Evict |entry2|. Queries by its name & value are not found. peer_.Evict(1); - EXPECT_EQ(NULL, + EXPECT_EQ(nullptr, table_.GetByNameAndValue(first_static_entry->name(), "Value Four")); } @@ -394,7 +394,7 @@ TEST_F(HpackHeaderTableTest, TryAddTooLargeEntry) { const HpackEntry* new_entry = table_.TryAddEntry(long_entry.name(), long_entry.value()); - EXPECT_EQ(new_entry, static_cast<HpackEntry*>(NULL)); + EXPECT_EQ(new_entry, static_cast<HpackEntry*>(nullptr)); EXPECT_EQ(0u, peer_.dynamic_entries().size()); } diff --git a/chromium/net/spdy/core/hpack/hpack_huffman_table.cc b/chromium/net/spdy/core/hpack/hpack_huffman_table.cc index dbfa8e5051c..842acf2d100 100644 --- a/chromium/net/spdy/core/hpack/hpack_huffman_table.cc +++ b/chromium/net/spdy/core/hpack/hpack_huffman_table.cc @@ -32,7 +32,7 @@ bool SymbolIdCompare(const HpackHuffmanSymbol& a, const HpackHuffmanSymbol& b) { HpackHuffmanTable::HpackHuffmanTable() : pad_bits_(0), failed_symbol_id_(0) {} -HpackHuffmanTable::~HpackHuffmanTable() {} +HpackHuffmanTable::~HpackHuffmanTable() = default; bool HpackHuffmanTable::Initialize(const HpackHuffmanSymbol* input_symbols, size_t symbol_count) { diff --git a/chromium/net/spdy/core/hpack/hpack_output_stream.cc b/chromium/net/spdy/core/hpack/hpack_output_stream.cc index 6f01f64f104..49b2d60fa13 100644 --- a/chromium/net/spdy/core/hpack/hpack_output_stream.cc +++ b/chromium/net/spdy/core/hpack/hpack_output_stream.cc @@ -13,7 +13,7 @@ namespace net { HpackOutputStream::HpackOutputStream() : bit_offset_(0) {} -HpackOutputStream::~HpackOutputStream() {} +HpackOutputStream::~HpackOutputStream() = default; void HpackOutputStream::AppendBits(uint8_t bits, size_t bit_size) { DCHECK_GT(bit_size, 0u); diff --git a/chromium/net/spdy/core/hpack/hpack_static_table.cc b/chromium/net/spdy/core/hpack/hpack_static_table.cc index 2eb17206098..0b3c0dc38a4 100644 --- a/chromium/net/spdy/core/hpack/hpack_static_table.cc +++ b/chromium/net/spdy/core/hpack/hpack_static_table.cc @@ -12,9 +12,9 @@ namespace net { -HpackStaticTable::HpackStaticTable() {} +HpackStaticTable::HpackStaticTable() = default; -HpackStaticTable::~HpackStaticTable() {} +HpackStaticTable::~HpackStaticTable() = default; void HpackStaticTable::Initialize(const HpackStaticEntry* static_entry_table, size_t static_entry_count) { diff --git a/chromium/net/spdy/core/http2_frame_decoder_adapter.cc b/chromium/net/spdy/core/http2_frame_decoder_adapter.cc index ad714052466..0655db68fe4 100644 --- a/chromium/net/spdy/core/http2_frame_decoder_adapter.cc +++ b/chromium/net/spdy/core/http2_frame_decoder_adapter.cc @@ -160,12 +160,15 @@ const char* Http2DecoderAdapter::SpdyFramerErrorToString( return "UNKNOWN_ERROR"; } -Http2DecoderAdapter::Http2DecoderAdapter() { +Http2DecoderAdapter::Http2DecoderAdapter() : Http2DecoderAdapter(false) {} + +Http2DecoderAdapter::Http2DecoderAdapter(bool h2_on_stream_pad_length) + : h2_on_stream_pad_length_(h2_on_stream_pad_length) { DVLOG(1) << "Http2DecoderAdapter ctor"; ResetInternal(); } -Http2DecoderAdapter::~Http2DecoderAdapter() {} +Http2DecoderAdapter::~Http2DecoderAdapter() = default; void Http2DecoderAdapter::set_visitor(SpdyFramerVisitorInterface* visitor) { visitor_ = visitor; @@ -436,10 +439,13 @@ void Http2DecoderAdapter::OnContinuationEnd() { void Http2DecoderAdapter::OnPadLength(size_t trailing_length) { DVLOG(1) << "OnPadLength: " << trailing_length; opt_pad_length_ = trailing_length; + DCHECK_LT(trailing_length, 256u); if (frame_header_.type == Http2FrameType::DATA) { - visitor()->OnStreamPadding(stream_id(), 1); - } else if (frame_header_.type == Http2FrameType::HEADERS) { - CHECK_LT(trailing_length, 256u); + if (h2_on_stream_pad_length_) { + visitor()->OnStreamPadLength(stream_id(), trailing_length); + } else { + visitor()->OnStreamPadding(stream_id(), 1); + } } } diff --git a/chromium/net/spdy/core/http2_frame_decoder_adapter.h b/chromium/net/spdy/core/http2_frame_decoder_adapter.h index c3e08b3be4a..94be5d4c353 100644 --- a/chromium/net/spdy/core/http2_frame_decoder_adapter.h +++ b/chromium/net/spdy/core/http2_frame_decoder_adapter.h @@ -77,6 +77,7 @@ class SPDY_EXPORT_PRIVATE Http2DecoderAdapter static const char* SpdyFramerErrorToString(SpdyFramerError spdy_framer_error); Http2DecoderAdapter(); + explicit Http2DecoderAdapter(bool h2_on_stream_pad_length); ~Http2DecoderAdapter() override; // Set callbacks to be called from the framer. A visitor must be set, or @@ -314,6 +315,9 @@ class SPDY_EXPORT_PRIVATE Http2DecoderAdapter bool handling_extension_payload_ = false; bool process_single_input_frame_ = false; + + // Flag value latched at construction. + const bool h2_on_stream_pad_length_ : 1; }; // Http2DecoderAdapter will use the given visitor implementing this @@ -364,7 +368,13 @@ class SPDY_EXPORT_PRIVATE SpdyFramerVisitorInterface { // |stream_id| The stream that was receiving data. virtual void OnStreamEnd(SpdyStreamId stream_id) = 0; - // Called when padding is received (padding length field or padding octets). + // Called when padding length field is received on a DATA frame. + // |stream_id| The stream receiving data. + // |value| The value of the padding length field. + virtual void OnStreamPadLength(SpdyStreamId stream_id, size_t value) {} + + // Called when padding is received (the trailing octets, not pad_len field) on + // a DATA frame. // |stream_id| The stream receiving data. // |len| The number of padding octets. virtual void OnStreamPadding(SpdyStreamId stream_id, size_t len) = 0; diff --git a/chromium/net/spdy/core/mock_spdy_framer_visitor.cc b/chromium/net/spdy/core/mock_spdy_framer_visitor.cc index 437dc57ba17..f9f3f407ebe 100644 --- a/chromium/net/spdy/core/mock_spdy_framer_visitor.cc +++ b/chromium/net/spdy/core/mock_spdy_framer_visitor.cc @@ -12,7 +12,7 @@ MockSpdyFramerVisitor::MockSpdyFramerVisitor() { DelegateHeaderHandling(); } -MockSpdyFramerVisitor::~MockSpdyFramerVisitor() {} +MockSpdyFramerVisitor::~MockSpdyFramerVisitor() = default; } // namespace test diff --git a/chromium/net/spdy/core/mock_spdy_framer_visitor.h b/chromium/net/spdy/core/mock_spdy_framer_visitor.h index 8bff920ec92..696d508b9ff 100644 --- a/chromium/net/spdy/core/mock_spdy_framer_visitor.h +++ b/chromium/net/spdy/core/mock_spdy_framer_visitor.h @@ -32,6 +32,7 @@ class MockSpdyFramerVisitor : public SpdyFramerVisitorInterface { MOCK_METHOD3(OnStreamFrameData, void(SpdyStreamId stream_id, const char* data, size_t len)); MOCK_METHOD1(OnStreamEnd, void(SpdyStreamId stream_id)); + MOCK_METHOD2(OnStreamPadLength, void(SpdyStreamId stream_id, size_t value)); MOCK_METHOD2(OnStreamPadding, void(SpdyStreamId stream_id, size_t len)); MOCK_METHOD1(OnHeaderFrameStart, SpdyHeadersHandlerInterface*(SpdyStreamId stream_id)); diff --git a/chromium/net/spdy/core/spdy_alt_svc_wire_format.cc b/chromium/net/spdy/core/spdy_alt_svc_wire_format.cc index a0a378300a5..df8b7d88c89 100644 --- a/chromium/net/spdy/core/spdy_alt_svc_wire_format.cc +++ b/chromium/net/spdy/core/spdy_alt_svc_wire_format.cc @@ -35,7 +35,7 @@ bool ParsePositiveIntegerImpl(SpdyStringPiece::const_iterator c, } // namespace -SpdyAltSvcWireFormat::AlternativeService::AlternativeService() {} +SpdyAltSvcWireFormat::AlternativeService::AlternativeService() = default; SpdyAltSvcWireFormat::AlternativeService::AlternativeService( const SpdyString& protocol_id, @@ -49,7 +49,7 @@ SpdyAltSvcWireFormat::AlternativeService::AlternativeService( max_age(max_age), version(version) {} -SpdyAltSvcWireFormat::AlternativeService::~AlternativeService() {} +SpdyAltSvcWireFormat::AlternativeService::~AlternativeService() = default; SpdyAltSvcWireFormat::AlternativeService::AlternativeService( const AlternativeService& other) = default; diff --git a/chromium/net/spdy/core/spdy_deframer_visitor.cc b/chromium/net/spdy/core/spdy_deframer_visitor.cc index 20489d73b2e..e7d1a46daaf 100644 --- a/chromium/net/spdy/core/spdy_deframer_visitor.cc +++ b/chromium/net/spdy/core/spdy_deframer_visitor.cc @@ -126,7 +126,7 @@ class SpdyTestDeframerImpl : public SpdyTestDeframer, : listener_(std::move(listener)) { CHECK(listener_); } - ~SpdyTestDeframerImpl() override {} + ~SpdyTestDeframerImpl() override = default; bool AtFrameEnd() override; @@ -172,6 +172,7 @@ class SpdyTestDeframerImpl : public SpdyTestDeframer, const char* data, size_t len) override; void OnStreamEnd(SpdyStreamId stream_id) override; + void OnStreamPadLength(SpdyStreamId stream_id, size_t value) override; void OnStreamPadding(SpdyStreamId stream_id, size_t len) override; bool OnUnknownFrame(SpdyStreamId stream_id, uint8_t frame_type) override; void OnWindowUpdate(SpdyStreamId stream_id, int delta_window_size) override; @@ -676,8 +677,23 @@ void SpdyTestDeframerImpl::OnStreamFrameData(SpdyStreamId stream_id, data_->append(data, len); } -// Called when padding is skipped over, including the padding length field at -// the start of the frame payload, and the actual padding at the end. len will +// Called when receiving the padding length field at the start of the DATA frame +// payload. value will be in the range 0 to 255. +void SpdyTestDeframerImpl::OnStreamPadLength(SpdyStreamId stream_id, + size_t value) { + DVLOG(1) << "OnStreamPadding stream_id: " << stream_id + << " value: " << value; + CHECK(frame_type_ == DATA || frame_type_ == HEADERS || + frame_type_ == PUSH_PROMISE) + << " frame_type_=" << Http2FrameTypeToString(frame_type_); + CHECK_EQ(stream_id_, stream_id); + CHECK_GE(255u, value); + // Count the padding length byte against total padding. + padding_len_ += 1; + CHECK_EQ(1u, padding_len_); +} + +// Called when padding is skipped over at the end of the DATA frame. len will // be in the range 1 to 255. void SpdyTestDeframerImpl::OnStreamPadding(SpdyStreamId stream_id, size_t len) { DVLOG(1) << "OnStreamPadding stream_id: " << stream_id << " len: " << len; @@ -765,7 +781,7 @@ class LoggingSpdyDeframerDelegate : public SpdyDeframerVisitorInterface { wrapped_ = SpdyMakeUnique<SpdyDeframerVisitorInterface>(); } } - ~LoggingSpdyDeframerDelegate() override {} + ~LoggingSpdyDeframerDelegate() override = default; void OnAltSvc(std::unique_ptr<SpdyAltSvcIR> frame) override { DVLOG(1) << "LoggingSpdyDeframerDelegate::OnAltSvc"; @@ -857,7 +873,7 @@ SpdyDeframerVisitorInterface::LogBeforeVisiting( std::move(wrapped_listener)); } -CollectedFrame::CollectedFrame() {} +CollectedFrame::CollectedFrame() = default; CollectedFrame::CollectedFrame(CollectedFrame&& other) : frame_ir(std::move(other.frame_ir)), @@ -865,7 +881,7 @@ CollectedFrame::CollectedFrame(CollectedFrame&& other) settings(std::move(other.settings)), error_reported(other.error_reported) {} -CollectedFrame::~CollectedFrame() {} +CollectedFrame::~CollectedFrame() = default; CollectedFrame& CollectedFrame::operator=(CollectedFrame&& other) { frame_ir = std::move(other.frame_ir); diff --git a/chromium/net/spdy/core/spdy_frame_builder.cc b/chromium/net/spdy/core/spdy_frame_builder.cc index 23eff899b8a..90a28a997f1 100644 --- a/chromium/net/spdy/core/spdy_frame_builder.cc +++ b/chromium/net/spdy/core/spdy_frame_builder.cc @@ -26,7 +26,7 @@ SpdyFrameBuilder::SpdyFrameBuilder(size_t size, ZeroCopyOutputBuffer* output) length_(0), offset_(0) {} -SpdyFrameBuilder::~SpdyFrameBuilder() {} +SpdyFrameBuilder::~SpdyFrameBuilder() = default; char* SpdyFrameBuilder::GetWritableBuffer(size_t length) { if (!CanWrite(length)) { @@ -120,7 +120,7 @@ bool SpdyFrameBuilder::BeginNewFrameInternal(uint8_t raw_frame_type, return success; } -bool SpdyFrameBuilder::WriteStringPiece32(const SpdyStringPiece& value) { +bool SpdyFrameBuilder::WriteStringPiece32(const SpdyStringPiece value) { if (!WriteUInt32(value.size())) { return false; } diff --git a/chromium/net/spdy/core/spdy_frame_builder.h b/chromium/net/spdy/core/spdy_frame_builder.h index b75e73b0db7..f7474570e9e 100644 --- a/chromium/net/spdy/core/spdy_frame_builder.h +++ b/chromium/net/spdy/core/spdy_frame_builder.h @@ -99,7 +99,7 @@ class SPDY_EXPORT_PRIVATE SpdyFrameBuilder { return (WriteBytes(&upper, sizeof(upper)) && WriteBytes(&lower, sizeof(lower))); } - bool WriteStringPiece32(const SpdyStringPiece& value); + bool WriteStringPiece32(const SpdyStringPiece value); bool WriteBytes(const void* data, uint32_t data_len); private: diff --git a/chromium/net/spdy/core/spdy_framer.cc b/chromium/net/spdy/core/spdy_framer.cc index 4e90c0558e6..eaefdde4918 100644 --- a/chromium/net/spdy/core/spdy_framer.cc +++ b/chromium/net/spdy/core/spdy_framer.cc @@ -4,8 +4,6 @@ #include "net/spdy/core/spdy_framer.h" -#include <string.h> - #include <algorithm> #include <cctype> #include <ios> @@ -191,8 +189,8 @@ bool WritePayloadWithContinuation(SpdyFrameBuilder* builder, size_t bytes_remaining = 0; bytes_remaining = hpack_encoding.size() - std::min(hpack_encoding.size(), - SpdyFramer::kMaxControlFrameSendSize - - builder->length() - padding_payload_len); + kHttp2MaxControlFrameSendSize - builder->length() - + padding_payload_len); bool ret = builder->WriteBytes(&hpack_encoding[0], hpack_encoding.size() - bytes_remaining); if (padding_payload_len > 0) { @@ -203,8 +201,8 @@ bool WritePayloadWithContinuation(SpdyFrameBuilder* builder, // Tack on CONTINUATION frames for the overflow. while (bytes_remaining > 0 && ret) { size_t bytes_to_write = - std::min(bytes_remaining, SpdyFramer::kMaxControlFrameSendSize - - kContinuationFrameMinimumSize); + std::min(bytes_remaining, + kHttp2MaxControlFrameSendSize - kContinuationFrameMinimumSize); // Write CONTINUATION frame prefix. if (bytes_remaining == bytes_to_write) { flags |= end_flag; @@ -278,19 +276,13 @@ void SerializeAltSvcBuilderHelper(const SpdyAltSvcIR& altsvc_ir, } // namespace -// Even though the length field is 24 bits, we keep this 16 kB -// limit on control frame size for legacy reasons and to -// mitigate DOS attacks. -const size_t SpdyFramer::kMaxControlFrameSendSize = - kHttp2DefaultFramePayloadLimit - 1; - SpdyFramer::SpdyFramer(CompressionOption option) : debug_visitor_(nullptr), compression_option_(option) { - static_assert(kMaxControlFrameSendSize <= kHttp2DefaultFrameSizeLimit, + static_assert(kHttp2MaxControlFrameSendSize <= kHttp2DefaultFrameSizeLimit, "Our send limit should be at most our receive limit."); } -SpdyFramer::~SpdyFramer() {} +SpdyFramer::~SpdyFramer() = default; void SpdyFramer::set_debug_visitor( SpdyFramerDebugVisitorInterface* debug_visitor) { @@ -300,7 +292,7 @@ void SpdyFramer::set_debug_visitor( SpdyFramer::SpdyFrameIterator::SpdyFrameIterator(SpdyFramer* framer) : framer_(framer), is_first_frame_(true), has_next_frame_(true) {} -SpdyFramer::SpdyFrameIterator::~SpdyFrameIterator() {} +SpdyFramer::SpdyFrameIterator::~SpdyFrameIterator() = default; size_t SpdyFramer::SpdyFrameIterator::NextFrame(ZeroCopyOutputBuffer* output) { const SpdyFrameIR& frame_ir = GetIR(); @@ -313,7 +305,8 @@ size_t SpdyFramer::SpdyFrameIterator::NextFrame(ZeroCopyOutputBuffer* output) { const size_t size_without_block = is_first_frame_ ? GetFrameSizeSansBlock() : kContinuationFrameMinimumSize; auto encoding = SpdyMakeUnique<SpdyString>(); - encoder_->Next(kMaxControlFrameSendSize - size_without_block, encoding.get()); + encoder_->Next(kHttp2MaxControlFrameSendSize - size_without_block, + encoding.get()); has_next_frame_ = encoder_->HasNext(); if (framer_->debug_visitor_ != nullptr) { @@ -352,7 +345,7 @@ SpdyFramer::SpdyHeaderFrameIterator::SpdyHeaderFrameIterator( SetEncoder(headers_ir_.get()); } -SpdyFramer::SpdyHeaderFrameIterator::~SpdyHeaderFrameIterator() {} +SpdyFramer::SpdyHeaderFrameIterator::~SpdyHeaderFrameIterator() = default; const SpdyFrameIR& SpdyFramer::SpdyHeaderFrameIterator::GetIR() const { return *(headers_ir_.get()); @@ -376,7 +369,8 @@ SpdyFramer::SpdyPushPromiseFrameIterator::SpdyPushPromiseFrameIterator( SetEncoder(push_promise_ir_.get()); } -SpdyFramer::SpdyPushPromiseFrameIterator::~SpdyPushPromiseFrameIterator() {} +SpdyFramer::SpdyPushPromiseFrameIterator::~SpdyPushPromiseFrameIterator() = + default; const SpdyFrameIR& SpdyFramer::SpdyPushPromiseFrameIterator::GetIR() const { return *(push_promise_ir_.get()); @@ -398,7 +392,7 @@ SpdyFramer::SpdyControlFrameIterator::SpdyControlFrameIterator( std::unique_ptr<const SpdyFrameIR> frame_ir) : framer_(framer), frame_ir_(std::move(frame_ir)) {} -SpdyFramer::SpdyControlFrameIterator::~SpdyControlFrameIterator() {} +SpdyFramer::SpdyControlFrameIterator::~SpdyControlFrameIterator() = default; size_t SpdyFramer::SpdyControlFrameIterator::NextFrame( ZeroCopyOutputBuffer* output) { @@ -591,7 +585,7 @@ void SpdyFramer::SerializeHeadersBuilderHelper(const SpdyHeadersIR& headers, GetHpackEncoder()->EncodeHeaderSet(headers.header_block(), hpack_encoding); *size = *size + hpack_encoding->size(); - if (*size > kMaxControlFrameSendSize) { + if (*size > kHttp2MaxControlFrameSendSize) { *size = *size + GetNumberRequiredContinuationFrames(*size) * kContinuationFrameMinimumSize; *flags = *flags & ~HEADERS_FLAG_END_HEADERS; @@ -610,7 +604,7 @@ void SpdyFramer::SerializeHeadersBuilderHelper(const SpdyHeadersIR& headers, // WritePayloadWithContinuation() will serialize CONTINUATION frames as // necessary. *length_field = - std::min(*length_field, kMaxControlFrameSendSize - kFrameHeaderSize); + std::min(*length_field, kHttp2MaxControlFrameSendSize - kFrameHeaderSize); } SpdySerializedFrame SpdyFramer::SerializeHeaders(const SpdyHeadersIR& headers) { @@ -685,7 +679,7 @@ void SpdyFramer::SerializePushPromiseBuilderHelper( GetHpackEncoder()->EncodeHeaderSet(push_promise.header_block(), hpack_encoding); *size = *size + hpack_encoding->size(); - if (*size > kMaxControlFrameSendSize) { + if (*size > kHttp2MaxControlFrameSendSize) { *size = *size + GetNumberRequiredContinuationFrames(*size) * kContinuationFrameMinimumSize; *flags = *flags & ~PUSH_PROMISE_FLAG_END_PUSH_PROMISE; @@ -701,7 +695,8 @@ SpdySerializedFrame SpdyFramer::SerializePushPromise( &size); SpdyFrameBuilder builder(size); - size_t length = std::min(size, kMaxControlFrameSendSize) - kFrameHeaderSize; + size_t length = + std::min(size, kHttp2MaxControlFrameSendSize) - kFrameHeaderSize; builder.BeginNewFrame(SpdyFrameType::PUSH_PROMISE, flags, push_promise.stream_id(), length); int padding_payload_len = 0; @@ -790,7 +785,7 @@ class FrameSerializationVisitor : public SpdyFrameVisitor { public: explicit FrameSerializationVisitor(SpdyFramer* framer) : framer_(framer), frame_() {} - ~FrameSerializationVisitor() override {} + ~FrameSerializationVisitor() override = default; SpdySerializedFrame ReleaseSerializedFrame() { return std::move(frame_); } @@ -1119,7 +1114,8 @@ bool SpdyFramer::SerializePushPromise(const SpdyPushPromiseIR& push_promise, bool ok = true; SpdyFrameBuilder builder(size, output); - size_t length = std::min(size, kMaxControlFrameSendSize) - kFrameHeaderSize; + size_t length = + std::min(size, kHttp2MaxControlFrameSendSize) - kFrameHeaderSize; ok = builder.BeginNewFrame(SpdyFrameType::PUSH_PROMISE, flags, push_promise.stream_id(), length); @@ -1214,7 +1210,7 @@ class FrameSerializationVisitorWithOutput : public SpdyFrameVisitor { explicit FrameSerializationVisitorWithOutput(SpdyFramer* framer, ZeroCopyOutputBuffer* output) : framer_(framer), output_(output), result_(false) {} - ~FrameSerializationVisitorWithOutput() override {} + ~FrameSerializationVisitorWithOutput() override = default; size_t Result() { return result_; } @@ -1271,15 +1267,6 @@ size_t SpdyFramer::SerializeFrame(const SpdyFrameIR& frame, return visitor.Result() ? free_bytes_before - output->BytesFree() : 0; } -size_t SpdyFramer::GetNumberRequiredContinuationFrames(size_t size) { - DCHECK_GT(size, SpdyFramer::kMaxControlFrameSendSize); - size_t overflow = size - SpdyFramer::kMaxControlFrameSendSize; - int payload_size = - SpdyFramer::kMaxControlFrameSendSize - kContinuationFrameMinimumSize; - // This is ceiling(overflow/payload_size) using integer arithmetics. - return (overflow - 1) / payload_size + 1; -} - HpackEncoder* SpdyFramer::GetHpackEncoder() { if (hpack_encoder_.get() == nullptr) { hpack_encoder_ = SpdyMakeUnique<HpackEncoder>(ObtainHpackHuffmanTable()); diff --git a/chromium/net/spdy/core/spdy_framer.h b/chromium/net/spdy/core/spdy_framer.h index 38143205c18..3b999abaef7 100644 --- a/chromium/net/spdy/core/spdy_framer.h +++ b/chromium/net/spdy/core/spdy_framer.h @@ -72,12 +72,6 @@ class SPDY_EXPORT_PRIVATE SpdyFramer { // Gets the serialized flags for the given |frame|. static uint8_t GetSerializedFlags(const SpdyFrameIR& frame); - // The maximum size of the control frames that we send, including the size of - // the header. This limit is arbitrary. We can enforce it here or at the - // application layer. We chose the framing layer, but this can be changed (or - // removed) if necessary later down the line. - static const size_t kMaxControlFrameSendSize; - // Serialize a data frame. static SpdySerializedFrame SerializeData(const SpdyDataIR& data_ir); // Serializes the data frame header and optionally padding length fields, @@ -369,8 +363,6 @@ class SPDY_EXPORT_PRIVATE SpdyFramer { }; private: - static size_t GetNumberRequiredContinuationFrames(size_t size); - void SerializeHeadersBuilderHelper(const SpdyHeadersIR& headers, uint8_t* flags, size_t* size, diff --git a/chromium/net/spdy/core/spdy_framer_test.cc b/chromium/net/spdy/core/spdy_framer_test.cc index 2b4030f074b..c5fad9ee027 100644 --- a/chromium/net/spdy/core/spdy_framer_test.cc +++ b/chromium/net/spdy/core/spdy_framer_test.cc @@ -5,7 +5,6 @@ #include "net/spdy/core/spdy_framer.h" #include <stdlib.h> -#include <string.h> #include <algorithm> #include <limits> @@ -17,6 +16,7 @@ #include "base/macros.h" #include "base/strings/string_number_conversions.h" #include "net/quic/platform/api/quic_flags.h" +#include "net/spdy/chromium/spdy_flags.h" #include "net/spdy/core/array_output_buffer.h" #include "net/spdy/core/hpack/hpack_constants.h" #include "net/spdy/core/mock_spdy_framer_visitor.h" @@ -26,6 +26,7 @@ #include "net/spdy/core/spdy_protocol.h" #include "net/spdy/core/spdy_test_utils.h" #include "net/spdy/platform/api/spdy_ptr_util.h" +#include "net/spdy/platform/api/spdy_string.h" #include "net/spdy/platform/api/spdy_string_utils.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -39,7 +40,7 @@ namespace test { namespace { -const int64_t kSize = 64 * 1024; +const int64_t kSize = 1024 * 1024; char output_buffer[kSize] = ""; // frame_list_char is used to hold frames to be compared with output_buffer. @@ -217,11 +218,6 @@ MATCHER_P(IsFrameUnionOf, frame_list, "") { class SpdyFramerPeer { public: - static size_t GetNumberRequiredContinuationFrames(SpdyFramer* framer, - size_t size) { - return framer->GetNumberRequiredContinuationFrames(size); - } - // TODO(dahollings): Remove these methods when deprecating non-incremental // header serialization path. static std::unique_ptr<SpdyHeadersIR> CloneSpdyHeadersIR( @@ -375,6 +371,7 @@ class TestSpdyVisitor : public SpdyFramerVisitorInterface, explicit TestSpdyVisitor(SpdyFramer::CompressionOption option) : framer_(option), + deframer_(FLAGS_chromium_http2_flag_h2_on_stream_pad_length), error_count_(0), headers_frame_count_(0), push_promise_frame_count_(0), @@ -438,6 +435,13 @@ class TestSpdyVisitor : public SpdyFramerVisitorInterface, ++end_of_stream_count_; } + void OnStreamPadLength(SpdyStreamId stream_id, size_t value) override { + VLOG(1) << "OnStreamPadding(" << stream_id << ", " << value << ")\n"; + EXPECT_EQ(header_stream_id_, stream_id); + // Count the padding length field byte against total data bytes. + data_bytes_ += 1; + } + void OnStreamPadding(SpdyStreamId stream_id, size_t len) override { VLOG(1) << "OnStreamPadding(" << stream_id << ", " << len << ")\n"; EXPECT_EQ(header_stream_id_, stream_id); @@ -732,7 +736,8 @@ class SpdyFramerTest : public ::testing::TestWithParam<Output> { public: SpdyFramerTest() : output_(output_buffer, kSize), - framer_(SpdyFramer::ENABLE_COMPRESSION) {} + framer_(SpdyFramer::ENABLE_COMPRESSION), + deframer_(FLAGS_chromium_http2_flag_h2_on_stream_pad_length) {} protected: void SetUp() override { @@ -954,7 +959,11 @@ TEST_P(SpdyFramerTest, CorrectlySizedDataPaddingNoError) { { testing::InSequence seq; EXPECT_CALL(visitor, OnDataFrameHeader(1, 5, false)); - EXPECT_CALL(visitor, OnStreamPadding(1, 1)); + if (FLAGS_chromium_http2_flag_h2_on_stream_pad_length) { + EXPECT_CALL(visitor, OnStreamPadLength(1, 4)); + } else { + EXPECT_CALL(visitor, OnStreamPadding(1, 1)); + } EXPECT_CALL(visitor, OnError(_)).Times(0); // Note that OnStreamFrameData(1, _, 1)) is never called // since there is no data, only padding @@ -2404,14 +2413,10 @@ TEST_P(SpdyFramerTest, CreatePushPromiseUncompressed) { // Regression test for https://crbug.com/464748. TEST_P(SpdyFramerTest, GetNumberRequiredContinuationFrames) { - EXPECT_EQ(1u, SpdyFramerPeer::GetNumberRequiredContinuationFrames( - &framer_, 16383 + 16374)); - EXPECT_EQ(2u, SpdyFramerPeer::GetNumberRequiredContinuationFrames( - &framer_, 16383 + 16374 + 1)); - EXPECT_EQ(2u, SpdyFramerPeer::GetNumberRequiredContinuationFrames( - &framer_, 16383 + 2 * 16374)); - EXPECT_EQ(3u, SpdyFramerPeer::GetNumberRequiredContinuationFrames( - &framer_, 16383 + 2 * 16374 + 1)); + EXPECT_EQ(1u, GetNumberRequiredContinuationFrames(16383 + 16374)); + EXPECT_EQ(2u, GetNumberRequiredContinuationFrames(16383 + 16374 + 1)); + EXPECT_EQ(2u, GetNumberRequiredContinuationFrames(16383 + 2 * 16374)); + EXPECT_EQ(3u, GetNumberRequiredContinuationFrames(16383 + 2 * 16374 + 1)); } TEST_P(SpdyFramerTest, CreateContinuationUncompressed) { @@ -2560,7 +2565,7 @@ TEST_P(SpdyFramerTest, CreatePushPromiseThenContinuationUncompressed) { SpdyPushPromiseIR push_promise(/* stream_id = */ 42, /* promised_stream_id = */ 57); push_promise.set_padding_len(1); - SpdyString big_value(SpdyFramer::kMaxControlFrameSendSize, 'x'); + SpdyString big_value(kHttp2MaxControlFrameSendSize, 'x'); push_promise.SetHeader("xxx", big_value); SpdySerializedFrame frame(SpdyFramerPeer::SerializePushPromise( &framer, push_promise, use_output_ ? &output_ : nullptr)); @@ -2582,7 +2587,7 @@ TEST_P(SpdyFramerTest, CreatePushPromiseThenContinuationUncompressed) { // Length of everything listed above except big_value. int len_non_data_payload = 31; - EXPECT_EQ(SpdyFramer::kMaxControlFrameSendSize + len_non_data_payload, + EXPECT_EQ(kHttp2MaxControlFrameSendSize + len_non_data_payload, frame.size()); // Partially compare the PUSH_PROMISE frame against the template. @@ -2593,7 +2598,7 @@ TEST_P(SpdyFramerTest, CreatePushPromiseThenContinuationUncompressed) { kPartialPushPromiseFrameData, arraysize(kPartialPushPromiseFrameData)); // Compare the CONTINUATION frame against the template. - frame_data += SpdyFramer::kMaxControlFrameSendSize; + frame_data += kHttp2MaxControlFrameSendSize; CompareCharArraysWithHexError( kDescription, frame_data, arraysize(kContinuationFrameData), kContinuationFrameData, arraysize(kContinuationFrameData)); @@ -2749,12 +2754,12 @@ TEST_P(SpdyFramerTest, TooLargeHeadersFrameUsesContinuation) { // Exact payload length will change with HPACK, but this should be long // enough to cause an overflow. - const size_t kBigValueSize = SpdyFramer::kMaxControlFrameSendSize; + const size_t kBigValueSize = kHttp2MaxControlFrameSendSize; SpdyString big_value(kBigValueSize, 'x'); headers.SetHeader("aa", big_value); SpdySerializedFrame control_frame(SpdyFramerPeer::SerializeHeaders( &framer, headers, use_output_ ? &output_ : nullptr)); - EXPECT_GT(control_frame.size(), SpdyFramer::kMaxControlFrameSendSize); + EXPECT_GT(control_frame.size(), kHttp2MaxControlFrameSendSize); TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); visitor.SimulateInFramer( @@ -2774,7 +2779,7 @@ TEST_P(SpdyFramerTest, MultipleContinuationFramesWithIterator) { // Exact payload length will change with HPACK, but this should be long // enough to cause an overflow. - const size_t kBigValueSize = SpdyFramer::kMaxControlFrameSendSize; + const size_t kBigValueSize = kHttp2MaxControlFrameSendSize; SpdyString big_valuex(kBigValueSize, 'x'); headers->SetHeader("aa", big_valuex); SpdyString big_valuez(kBigValueSize, 'z'); @@ -2785,7 +2790,7 @@ TEST_P(SpdyFramerTest, MultipleContinuationFramesWithIterator) { EXPECT_TRUE(frame_it.HasNextFrame()); EXPECT_GT(frame_it.NextFrame(&output_), 0u); SpdySerializedFrame headers_frame(output_.Begin(), output_.Size(), false); - EXPECT_EQ(headers_frame.size(), SpdyFramer::kMaxControlFrameSendSize); + EXPECT_EQ(headers_frame.size(), kHttp2MaxControlFrameSendSize); TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); visitor.SimulateInFramer( @@ -2801,7 +2806,7 @@ TEST_P(SpdyFramerTest, MultipleContinuationFramesWithIterator) { EXPECT_TRUE(frame_it.HasNextFrame()); EXPECT_GT(frame_it.NextFrame(&output_), 0u); SpdySerializedFrame first_cont_frame(output_.Begin(), output_.Size(), false); - EXPECT_EQ(first_cont_frame.size(), SpdyFramer::kMaxControlFrameSendSize); + EXPECT_EQ(first_cont_frame.size(), kHttp2MaxControlFrameSendSize); visitor.SimulateInFramer( reinterpret_cast<unsigned char*>(first_cont_frame.data()), @@ -2816,7 +2821,7 @@ TEST_P(SpdyFramerTest, MultipleContinuationFramesWithIterator) { EXPECT_TRUE(frame_it.HasNextFrame()); EXPECT_GT(frame_it.NextFrame(&output_), 0u); SpdySerializedFrame second_cont_frame(output_.Begin(), output_.Size(), false); - EXPECT_LT(second_cont_frame.size(), SpdyFramer::kMaxControlFrameSendSize); + EXPECT_LT(second_cont_frame.size(), kHttp2MaxControlFrameSendSize); visitor.SimulateInFramer( reinterpret_cast<unsigned char*>(second_cont_frame.data()), @@ -2839,7 +2844,7 @@ TEST_P(SpdyFramerTest, PushPromiseFramesWithIterator) { // Exact payload length will change with HPACK, but this should be long // enough to cause an overflow. - const size_t kBigValueSize = SpdyFramer::kMaxControlFrameSendSize; + const size_t kBigValueSize = kHttp2MaxControlFrameSendSize; SpdyString big_valuex(kBigValueSize, 'x'); push_promise->SetHeader("aa", big_valuex); SpdyString big_valuez(kBigValueSize, 'z'); @@ -2852,7 +2857,7 @@ TEST_P(SpdyFramerTest, PushPromiseFramesWithIterator) { EXPECT_GT(frame_it.NextFrame(&output_), 0u); SpdySerializedFrame push_promise_frame(output_.Begin(), output_.Size(), false); - EXPECT_EQ(push_promise_frame.size(), SpdyFramer::kMaxControlFrameSendSize); + EXPECT_EQ(push_promise_frame.size(), kHttp2MaxControlFrameSendSize); TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); visitor.SimulateInFramer( @@ -2869,7 +2874,7 @@ TEST_P(SpdyFramerTest, PushPromiseFramesWithIterator) { EXPECT_GT(frame_it.NextFrame(&output_), 0u); SpdySerializedFrame first_cont_frame(output_.Begin(), output_.Size(), false); - EXPECT_EQ(first_cont_frame.size(), SpdyFramer::kMaxControlFrameSendSize); + EXPECT_EQ(first_cont_frame.size(), kHttp2MaxControlFrameSendSize); visitor.SimulateInFramer( reinterpret_cast<unsigned char*>(first_cont_frame.data()), first_cont_frame.size()); @@ -2883,7 +2888,7 @@ TEST_P(SpdyFramerTest, PushPromiseFramesWithIterator) { output_.Reset(); EXPECT_GT(frame_it.NextFrame(&output_), 0u); SpdySerializedFrame second_cont_frame(output_.Begin(), output_.Size(), false); - EXPECT_LT(second_cont_frame.size(), SpdyFramer::kMaxControlFrameSendSize); + EXPECT_LT(second_cont_frame.size(), kHttp2MaxControlFrameSendSize); visitor.SimulateInFramer( reinterpret_cast<unsigned char*>(second_cont_frame.data()), @@ -2968,12 +2973,12 @@ TEST_P(SpdyFramerTest, TooLargePushPromiseFrameUsesContinuation) { // Exact payload length will change with HPACK, but this should be long // enough to cause an overflow. - const size_t kBigValueSize = SpdyFramer::kMaxControlFrameSendSize; + const size_t kBigValueSize = kHttp2MaxControlFrameSendSize; SpdyString big_value(kBigValueSize, 'x'); push_promise.SetHeader("aa", big_value); SpdySerializedFrame control_frame(SpdyFramerPeer::SerializePushPromise( &framer, push_promise, use_output_ ? &output_ : nullptr)); - EXPECT_GT(control_frame.size(), SpdyFramer::kMaxControlFrameSendSize); + EXPECT_GT(control_frame.size(), kHttp2MaxControlFrameSendSize); TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); visitor.SimulateInFramer( @@ -3265,7 +3270,11 @@ TEST_P(SpdyFramerTest, ProcessDataFrameWithPadding) { bytes_consumed += kDataFrameMinimumSize; // Send the padding length field. - EXPECT_CALL(visitor, OnStreamPadding(1, 1)); + if (FLAGS_chromium_http2_flag_h2_on_stream_pad_length) { + EXPECT_CALL(visitor, OnStreamPadLength(1, kPaddingLen - 1)); + } else { + EXPECT_CALL(visitor, OnStreamPadding(1, 1)); + } CHECK_EQ(1u, deframer_.ProcessInput(frame.data() + bytes_consumed, 1)); CHECK_EQ(deframer_.state(), Http2DecoderAdapter::SPDY_FORWARD_STREAM_FRAME); CHECK_EQ(deframer_.spdy_framer_error(), Http2DecoderAdapter::SPDY_NO_ERROR); @@ -4873,6 +4882,90 @@ TEST_P(SpdyFramerTest, ProcessAtMostOneFrame) { } } +namespace { +void CheckFrameAndIRSize(SpdyFrameIR* ir, + SpdyFramer* framer, + ArrayOutputBuffer* output_buffer) { + output_buffer->Reset(); + SpdyFrameType type = ir->frame_type(); + size_t ir_size = ir->size(); + framer->SerializeFrame(*ir, output_buffer); + if (type == SpdyFrameType::HEADERS || type == SpdyFrameType::PUSH_PROMISE) { + // For HEADERS and PUSH_PROMISE, the size is an estimate. + EXPECT_GE(ir_size, output_buffer->Size() * 9 / 10); + EXPECT_LT(ir_size, output_buffer->Size() * 11 / 10); + } else { + EXPECT_EQ(ir_size, output_buffer->Size()); + } +} +} // namespace + +TEST_P(SpdyFramerTest, SpdyFrameIRSize) { + SpdyFramer framer(SpdyFramer::DISABLE_COMPRESSION); + + const char bytes[] = "this is a very short data frame"; + SpdyDataIR data_ir(1, SpdyStringPiece(bytes, arraysize(bytes))); + CheckFrameAndIRSize(&data_ir, &framer, &output_); + + SpdyRstStreamIR rst_ir(/* stream_id = */ 1, ERROR_CODE_PROTOCOL_ERROR); + CheckFrameAndIRSize(&rst_ir, &framer, &output_); + + SpdySettingsIR settings_ir; + settings_ir.AddSetting(SETTINGS_HEADER_TABLE_SIZE, 5); + settings_ir.AddSetting(SETTINGS_ENABLE_PUSH, 6); + settings_ir.AddSetting(SETTINGS_MAX_CONCURRENT_STREAMS, 7); + CheckFrameAndIRSize(&settings_ir, &framer, &output_); + + SpdyPingIR ping_ir(42); + CheckFrameAndIRSize(&ping_ir, &framer, &output_); + + SpdyGoAwayIR goaway_ir(97, ERROR_CODE_NO_ERROR, "Goaway description"); + CheckFrameAndIRSize(&goaway_ir, &framer, &output_); + + SpdyHeadersIR headers_ir(1); + headers_ir.SetHeader("alpha", "beta"); + headers_ir.SetHeader("gamma", "charlie"); + headers_ir.SetHeader("cookie", "key1=value1; key2=value2"); + CheckFrameAndIRSize(&headers_ir, &framer, &output_); + + SpdyHeadersIR headers_ir_with_continuation(1); + headers_ir_with_continuation.SetHeader("alpha", SpdyString(100000, 'x')); + headers_ir_with_continuation.SetHeader("beta", SpdyString(100000, 'x')); + headers_ir_with_continuation.SetHeader("cookie", "key1=value1; key2=value2"); + CheckFrameAndIRSize(&headers_ir_with_continuation, &framer, &output_); + + SpdyWindowUpdateIR window_update_ir(4, 1024); + CheckFrameAndIRSize(&window_update_ir, &framer, &output_); + + SpdyPushPromiseIR push_promise_ir(3, 8); + push_promise_ir.SetHeader("alpha", SpdyString(100000, 'x')); + push_promise_ir.SetHeader("beta", SpdyString(100000, 'x')); + push_promise_ir.SetHeader("cookie", "key1=value1; key2=value2"); + CheckFrameAndIRSize(&push_promise_ir, &framer, &output_); + + SpdyAltSvcWireFormat::AlternativeService altsvc1( + "pid1", "host", 443, 5, SpdyAltSvcWireFormat::VersionVector()); + SpdyAltSvcWireFormat::AlternativeService altsvc2( + "p\"=i:d", "h_\\o\"st", 123, 42, SpdyAltSvcWireFormat::VersionVector{24}); + SpdyAltSvcWireFormat::AlternativeServiceVector altsvc_vector; + altsvc_vector.push_back(altsvc1); + altsvc_vector.push_back(altsvc2); + SpdyAltSvcIR altsvc_ir(0); + altsvc_ir.set_origin("o_r|g!n"); + altsvc_ir.add_altsvc(altsvc1); + altsvc_ir.add_altsvc(altsvc2); + CheckFrameAndIRSize(&altsvc_ir, &framer, &output_); + + SpdyPriorityIR priority_ir(3, 1, 256, false); + CheckFrameAndIRSize(&priority_ir, &framer, &output_); + + const char kDescription[] = "Unknown frame"; + const uint8_t kType = 0xaf; + const uint8_t kFlags = 0x11; + SpdyUnknownIR unknown_ir(2, kType, kFlags, kDescription); + CheckFrameAndIRSize(&unknown_ir, &framer, &output_); +} + } // namespace test } // namespace net diff --git a/chromium/net/spdy/core/spdy_header_block.cc b/chromium/net/spdy/core/spdy_header_block.cc index 9fda908dfb7..fb2c4cb0c9b 100644 --- a/chromium/net/spdy/core/spdy_header_block.cc +++ b/chromium/net/spdy/core/spdy_header_block.cc @@ -106,22 +106,30 @@ class SpdyHeaderBlock::Storage { SpdyHeaderBlock::HeaderValue::HeaderValue(Storage* storage, SpdyStringPiece key, SpdyStringPiece initial_value) - : storage_(storage), fragments_({initial_value}), pair_({key, {}}) {} + : storage_(storage), + fragments_({initial_value}), + pair_({key, {}}), + size_(initial_value.size()), + separator_size_(SeparatorForKey(key).size()) {} SpdyHeaderBlock::HeaderValue::HeaderValue(HeaderValue&& other) : storage_(other.storage_), fragments_(std::move(other.fragments_)), - pair_(std::move(other.pair_)) {} + pair_(std::move(other.pair_)), + size_(other.size_), + separator_size_(other.separator_size_) {} SpdyHeaderBlock::HeaderValue& SpdyHeaderBlock::HeaderValue::operator=( HeaderValue&& other) { storage_ = other.storage_; fragments_ = std::move(other.fragments_); pair_ = std::move(other.pair_); + size_ = other.size_; + separator_size_ = other.separator_size_; return *this; } -SpdyHeaderBlock::HeaderValue::~HeaderValue() {} +SpdyHeaderBlock::HeaderValue::~HeaderValue() = default; SpdyStringPiece SpdyHeaderBlock::HeaderValue::ConsolidatedValue() const { if (fragments_.empty()) { @@ -135,6 +143,7 @@ SpdyStringPiece SpdyHeaderBlock::HeaderValue::ConsolidatedValue() const { } void SpdyHeaderBlock::HeaderValue::Append(SpdyStringPiece fragment) { + size_ += (fragment.size() + separator_size_); fragments_.push_back(fragment); } @@ -146,19 +155,21 @@ SpdyHeaderBlock::HeaderValue::as_pair() const { SpdyHeaderBlock::iterator::iterator(MapType::const_iterator it) : it_(it) {} -SpdyHeaderBlock::iterator::iterator(const iterator& other) : it_(other.it_) {} +SpdyHeaderBlock::iterator::iterator(const iterator& other) = default; -SpdyHeaderBlock::iterator::~iterator() {} +SpdyHeaderBlock::iterator::~iterator() = default; SpdyHeaderBlock::ValueProxy::ValueProxy( SpdyHeaderBlock::MapType* block, SpdyHeaderBlock::Storage* storage, SpdyHeaderBlock::MapType::iterator lookup_result, - const SpdyStringPiece key) + const SpdyStringPiece key, + size_t* spdy_header_block_value_size) : block_(block), storage_(storage), lookup_result_(lookup_result), key_(key), + spdy_header_block_value_size_(spdy_header_block_value_size), valid_(true) {} SpdyHeaderBlock::ValueProxy::ValueProxy(ValueProxy&& other) @@ -166,6 +177,7 @@ SpdyHeaderBlock::ValueProxy::ValueProxy(ValueProxy&& other) storage_(other.storage_), lookup_result_(other.lookup_result_), key_(other.key_), + spdy_header_block_value_size_(other.spdy_header_block_value_size_), valid_(true) { other.valid_ = false; } @@ -178,6 +190,7 @@ SpdyHeaderBlock::ValueProxy& SpdyHeaderBlock::ValueProxy::operator=( key_ = other.key_; valid_ = true; other.valid_ = false; + spdy_header_block_value_size_ = other.spdy_header_block_value_size_; return *this; } @@ -193,6 +206,7 @@ SpdyHeaderBlock::ValueProxy::~ValueProxy() { SpdyHeaderBlock::ValueProxy& SpdyHeaderBlock::ValueProxy::operator=( const SpdyStringPiece value) { + *spdy_header_block_value_size_ += value.size(); if (lookup_result_ == block_->end()) { DVLOG(1) << "Inserting: (" << key_ << ", " << value << ")"; lookup_result_ = @@ -202,6 +216,7 @@ SpdyHeaderBlock::ValueProxy& SpdyHeaderBlock::ValueProxy::operator=( .first; } else { DVLOG(1) << "Updating key: " << key_ << " with value: " << value; + *spdy_header_block_value_size_ -= lookup_result_->second.SizeEstimate(); lookup_result_->second = HeaderValue(storage_, key_, storage_->Write(value)); } @@ -220,11 +235,13 @@ SpdyHeaderBlock::SpdyHeaderBlock() : block_(kInitialMapBuckets) {} SpdyHeaderBlock::SpdyHeaderBlock(SpdyHeaderBlock&& other) = default; -SpdyHeaderBlock::~SpdyHeaderBlock() {} +SpdyHeaderBlock::~SpdyHeaderBlock() = default; SpdyHeaderBlock& SpdyHeaderBlock::operator=(SpdyHeaderBlock&& other) { block_.swap(other.block_); storage_.swap(other.storage_); + key_size_ = other.key_size_; + value_size_ = other.value_size_; return *this; } @@ -257,13 +274,26 @@ SpdyString SpdyHeaderBlock::DebugString() const { return output; } +void SpdyHeaderBlock::erase(SpdyStringPiece key) { + auto iter = block_.find(key); + if (iter != block_.end()) { + key_size_ -= key.size(); + value_size_ -= iter->second.SizeEstimate(); + block_.erase(iter); + } +} + void SpdyHeaderBlock::clear() { + key_size_ = 0; + value_size_ = 0; block_.clear(); storage_.reset(); } void SpdyHeaderBlock::insert(const SpdyHeaderBlock::value_type& value) { // TODO(birenroy): Write new value in place of old value, if it fits. + value_size_ += value.second.size(); + auto iter = block_.find(value.first); if (iter == block_.end()) { DVLOG(1) << "Inserting: (" << value.first << ", " << value.second << ")"; @@ -271,6 +301,7 @@ void SpdyHeaderBlock::insert(const SpdyHeaderBlock::value_type& value) { } else { DVLOG(1) << "Updating key: " << iter->first << " with value: " << value.second; + value_size_ -= iter->second.SizeEstimate(); auto* storage = GetStorage(); iter->second = HeaderValue(storage, iter->first, storage->Write(value.second)); @@ -285,25 +316,29 @@ SpdyHeaderBlock::ValueProxy SpdyHeaderBlock::operator[]( if (iter == block_.end()) { // We write the key first, to assure that the ValueProxy has a // reference to a valid SpdyStringPiece in its operator=. - out_key = GetStorage()->Write(key); + out_key = WriteKey(key); DVLOG(2) << "Key written as: " << std::hex << static_cast<const void*>(key.data()) << ", " << std::dec << key.size(); } else { out_key = iter->first; } - return ValueProxy(&block_, GetStorage(), iter, out_key); + return ValueProxy(&block_, GetStorage(), iter, out_key, &value_size_); } void SpdyHeaderBlock::AppendValueOrAddHeader(const SpdyStringPiece key, const SpdyStringPiece value) { + value_size_ += value.size(); + auto iter = block_.find(key); if (iter == block_.end()) { DVLOG(1) << "Inserting: (" << key << ", " << value << ")"; + AppendHeader(key, value); return; } DVLOG(1) << "Updating key: " << iter->first << "; appending value: " << value; + value_size_ += SeparatorForKey(key).size(); iter->second.Append(GetStorage()->Write(value)); } @@ -315,8 +350,8 @@ size_t SpdyHeaderBlock::EstimateMemoryUsage() const { void SpdyHeaderBlock::AppendHeader(const SpdyStringPiece key, const SpdyStringPiece value) { + auto backed_key = WriteKey(key); auto* storage = GetStorage(); - auto backed_key = storage->Write(key); block_.emplace(std::make_pair( backed_key, HeaderValue(storage, backed_key, storage->Write(value)))); } @@ -344,6 +379,11 @@ std::unique_ptr<base::Value> SpdyHeaderBlockNetLogCallback( return std::move(dict); } +SpdyStringPiece SpdyHeaderBlock::WriteKey(const SpdyStringPiece key) { + key_size_ += key.size(); + return GetStorage()->Write(key); +} + size_t SpdyHeaderBlock::bytes_allocated() const { if (storage_ == nullptr) { return 0; diff --git a/chromium/net/spdy/core/spdy_header_block.h b/chromium/net/spdy/core/spdy_header_block.h index c82383e20f6..248ec73f0be 100644 --- a/chromium/net/spdy/core/spdy_header_block.h +++ b/chromium/net/spdy/core/spdy_header_block.h @@ -72,6 +72,10 @@ class SPDY_EXPORT_PRIVATE SpdyHeaderBlock { SpdyStringPiece value() const { return as_pair().second; } const std::pair<SpdyStringPiece, SpdyStringPiece>& as_pair() const; + // Size estimate including separators. Used when keys are erased from + // SpdyHeaderBlock. + size_t SizeEstimate() const { return size_; } + private: // May allocate a large contiguous region of memory to hold the concatenated // fragments and separators. @@ -81,6 +85,8 @@ class SPDY_EXPORT_PRIVATE SpdyHeaderBlock { mutable std::vector<SpdyStringPiece> fragments_; // The first element is the key; the second is the consolidated value. mutable std::pair<SpdyStringPiece, SpdyStringPiece> pair_; + size_t size_ = 0; + size_t separator_size_ = 0; }; typedef linked_hash_map<SpdyStringPiece, HeaderValue, base::StringPieceHash> @@ -163,7 +169,7 @@ class SPDY_EXPORT_PRIVATE SpdyHeaderBlock { const_iterator find(SpdyStringPiece key) const { return const_iterator(block_.find(key)); } - void erase(SpdyStringPiece key) { block_.erase(key); } + void erase(SpdyStringPiece key); // Clears both our MapType member and the memory used to hold headers. void clear(); @@ -211,29 +217,37 @@ class SPDY_EXPORT_PRIVATE SpdyHeaderBlock { ValueProxy(SpdyHeaderBlock::MapType* block, SpdyHeaderBlock::Storage* storage, SpdyHeaderBlock::MapType::iterator lookup_result, - const SpdyStringPiece key); + const SpdyStringPiece key, + size_t* spdy_header_block_value_size); SpdyHeaderBlock::MapType* block_; SpdyHeaderBlock::Storage* storage_; SpdyHeaderBlock::MapType::iterator lookup_result_; SpdyStringPiece key_; + size_t* spdy_header_block_value_size_; bool valid_; }; // Returns the estimate of dynamically allocated memory in bytes. size_t EstimateMemoryUsage() const; + size_t TotalBytesUsed() const { return key_size_ + value_size_; } + private: friend class test::SpdyHeaderBlockPeer; void AppendHeader(const SpdyStringPiece key, const SpdyStringPiece value); Storage* GetStorage(); + SpdyStringPiece WriteKey(const SpdyStringPiece key); size_t bytes_allocated() const; // SpdyStringPieces held by |block_| point to memory owned by |*storage_|. // |storage_| might be nullptr as long as |block_| is empty. MapType block_; std::unique_ptr<Storage> storage_; + + size_t key_size_ = 0; + size_t value_size_ = 0; }; // Writes |fragments| to |dst|, joined by |separator|. |dst| must be large diff --git a/chromium/net/spdy/core/spdy_header_block_test.cc b/chromium/net/spdy/core/spdy_header_block_test.cc index 98881620f6c..da0eb7d6d6a 100644 --- a/chromium/net/spdy/core/spdy_header_block_test.cc +++ b/chromium/net/spdy/core/spdy_header_block_test.cc @@ -206,5 +206,49 @@ TEST(JoinTest, JoinMultiple) { EXPECT_EQ("one, two, three", SpdyStringPiece(buf, written)); } +namespace { +size_t SpdyHeaderBlockSize(const SpdyHeaderBlock& block) { + size_t size = 0; + for (const auto& pair : block) { + size += pair.first.size() + pair.second.size(); + } + return size; +} +} // namespace + +// Tests SpdyHeaderBlock SizeEstimate(). +TEST(SpdyHeaderBlockTest, TotalBytesUsed) { + SpdyHeaderBlock block; + const size_t value_size = 300; + block["foo"] = SpdyString(value_size, 'x'); + EXPECT_EQ(block.TotalBytesUsed(), SpdyHeaderBlockSize(block)); + block.insert(std::make_pair("key", SpdyString(value_size, 'x'))); + EXPECT_EQ(block.TotalBytesUsed(), SpdyHeaderBlockSize(block)); + block.AppendValueOrAddHeader("abc", SpdyString(value_size, 'x')); + EXPECT_EQ(block.TotalBytesUsed(), SpdyHeaderBlockSize(block)); + + // Replace value for existing key. + block["foo"] = SpdyString(value_size, 'x'); + EXPECT_EQ(block.TotalBytesUsed(), SpdyHeaderBlockSize(block)); + block.insert(std::make_pair("key", SpdyString(value_size, 'x'))); + EXPECT_EQ(block.TotalBytesUsed(), SpdyHeaderBlockSize(block)); + // Add value for existing key. + block.AppendValueOrAddHeader("abc", SpdyString(value_size, 'x')); + EXPECT_EQ(block.TotalBytesUsed(), SpdyHeaderBlockSize(block)); + + // Copies/clones SpdyHeaderBlock. + size_t block_size = block.TotalBytesUsed(); + SpdyHeaderBlock block_copy = std::move(block); + EXPECT_EQ(block_size, block_copy.TotalBytesUsed()); + + // Erases key. + block_copy.erase("foo"); + EXPECT_EQ(block_copy.TotalBytesUsed(), SpdyHeaderBlockSize(block_copy)); + block_copy.erase("key"); + EXPECT_EQ(block_copy.TotalBytesUsed(), SpdyHeaderBlockSize(block_copy)); + block_copy.erase("abc"); + EXPECT_EQ(block_copy.TotalBytesUsed(), SpdyHeaderBlockSize(block_copy)); +} + } // namespace test } // namespace net diff --git a/chromium/net/spdy/core/spdy_no_op_visitor.cc b/chromium/net/spdy/core/spdy_no_op_visitor.cc index b82e547adfc..a196069c20e 100644 --- a/chromium/net/spdy/core/spdy_no_op_visitor.cc +++ b/chromium/net/spdy/core/spdy_no_op_visitor.cc @@ -13,7 +13,7 @@ SpdyNoOpVisitor::SpdyNoOpVisitor() { static_assert(std::is_abstract<SpdyNoOpVisitor>::value == false, "Need to update SpdyNoOpVisitor."); } -SpdyNoOpVisitor::~SpdyNoOpVisitor() {} +SpdyNoOpVisitor::~SpdyNoOpVisitor() = default; SpdyHeadersHandlerInterface* SpdyNoOpVisitor::OnHeaderFrameStart( SpdyStreamId stream_id) { diff --git a/chromium/net/spdy/core/spdy_pinnable_buffer_piece.cc b/chromium/net/spdy/core/spdy_pinnable_buffer_piece.cc index a277060dbe6..588a17be30b 100644 --- a/chromium/net/spdy/core/spdy_pinnable_buffer_piece.cc +++ b/chromium/net/spdy/core/spdy_pinnable_buffer_piece.cc @@ -11,7 +11,7 @@ namespace net { SpdyPinnableBufferPiece::SpdyPinnableBufferPiece() : buffer_(nullptr), length_(0) {} -SpdyPinnableBufferPiece::~SpdyPinnableBufferPiece() {} +SpdyPinnableBufferPiece::~SpdyPinnableBufferPiece() = default; void SpdyPinnableBufferPiece::Pin() { if (!storage_ && buffer_ != nullptr && length_ != 0) { diff --git a/chromium/net/spdy/core/spdy_protocol.cc b/chromium/net/spdy/core/spdy_protocol.cc index e13761b5462..3b57e367869 100644 --- a/chromium/net/spdy/core/spdy_protocol.cc +++ b/chromium/net/spdy/core/spdy_protocol.cc @@ -206,6 +206,15 @@ const char* ErrorCodeToString(SpdyErrorCode error_code) { return "UNKNOWN_ERROR_CODE"; } +size_t GetNumberRequiredContinuationFrames(size_t size) { + DCHECK_GT(size, kHttp2MaxControlFrameSendSize); + size_t overflow = size - kHttp2MaxControlFrameSendSize; + int payload_size = + kHttp2MaxControlFrameSendSize - kContinuationFrameMinimumSize; + // This is ceiling(overflow/payload_size) using integer arithmetics. + return (overflow - 1) / payload_size + 1; +} + const char* const kHttp2Npn = "h2"; const char* const kHttp2AuthorityHeader = ":authority"; @@ -232,7 +241,7 @@ SpdyFrameWithHeaderBlockIR::SpdyFrameWithHeaderBlockIR( SpdyHeaderBlock header_block) : SpdyFrameWithFinIR(stream_id), header_block_(std::move(header_block)) {} -SpdyFrameWithHeaderBlockIR::~SpdyFrameWithHeaderBlockIR() {} +SpdyFrameWithHeaderBlockIR::~SpdyFrameWithHeaderBlockIR() = default; SpdyDataIR::SpdyDataIR(SpdyStreamId stream_id, SpdyStringPiece data) : SpdyFrameWithFinIR(stream_id), @@ -261,7 +270,7 @@ SpdyDataIR::SpdyDataIR(SpdyStreamId stream_id) padded_(false), padding_payload_len_(0) {} -SpdyDataIR::~SpdyDataIR() {} +SpdyDataIR::~SpdyDataIR() = default; void SpdyDataIR::Visit(SpdyFrameVisitor* visitor) const { return visitor->VisitData(*this); @@ -272,7 +281,12 @@ SpdyFrameType SpdyDataIR::frame_type() const { } int SpdyDataIR::flow_control_window_consumed() const { - return padded() ? 1 + padding_payload_len() + data_len() : data_len(); + return padded_ ? 1 + padding_payload_len_ + data_len_ : data_len_; +} + +size_t SpdyDataIR::size() const { + return kFrameHeaderSize + + (padded() ? 1 + padding_payload_len() + data_len() : data_len()); } SpdyRstStreamIR::SpdyRstStreamIR(SpdyStreamId stream_id, @@ -281,7 +295,7 @@ SpdyRstStreamIR::SpdyRstStreamIR(SpdyStreamId stream_id, set_error_code(error_code); } -SpdyRstStreamIR::~SpdyRstStreamIR() {} +SpdyRstStreamIR::~SpdyRstStreamIR() = default; void SpdyRstStreamIR::Visit(SpdyFrameVisitor* visitor) const { return visitor->VisitRstStream(*this); @@ -291,9 +305,13 @@ SpdyFrameType SpdyRstStreamIR::frame_type() const { return SpdyFrameType::RST_STREAM; } +size_t SpdyRstStreamIR::size() const { + return kRstStreamFrameSize; +} + SpdySettingsIR::SpdySettingsIR() : is_ack_(false) {} -SpdySettingsIR::~SpdySettingsIR() {} +SpdySettingsIR::~SpdySettingsIR() = default; void SpdySettingsIR::Visit(SpdyFrameVisitor* visitor) const { return visitor->VisitSettings(*this); @@ -303,6 +321,10 @@ SpdyFrameType SpdySettingsIR::frame_type() const { return SpdyFrameType::SETTINGS; } +size_t SpdySettingsIR::size() const { + return kFrameHeaderSize + values_.size() * kSettingsOneSettingSize; +} + void SpdyPingIR::Visit(SpdyFrameVisitor* visitor) const { return visitor->VisitPing(*this); } @@ -311,6 +333,10 @@ SpdyFrameType SpdyPingIR::frame_type() const { return SpdyFrameType::PING; } +size_t SpdyPingIR::size() const { + return kPingFrameSize; +} + SpdyGoAwayIR::SpdyGoAwayIR(SpdyStreamId last_good_stream_id, SpdyErrorCode error_code, SpdyStringPiece description) @@ -335,7 +361,7 @@ SpdyGoAwayIR::SpdyGoAwayIR(SpdyStreamId last_good_stream_id, set_error_code(error_code); } -SpdyGoAwayIR::~SpdyGoAwayIR() {} +SpdyGoAwayIR::~SpdyGoAwayIR() = default; void SpdyGoAwayIR::Visit(SpdyFrameVisitor* visitor) const { return visitor->VisitGoAway(*this); @@ -345,12 +371,16 @@ SpdyFrameType SpdyGoAwayIR::frame_type() const { return SpdyFrameType::GOAWAY; } +size_t SpdyGoAwayIR::size() const { + return kGoawayFrameMinimumSize + description_.size(); +} + SpdyContinuationIR::SpdyContinuationIR(SpdyStreamId stream_id) : SpdyFrameIR(stream_id), end_headers_(false) { encoding_ = SpdyMakeUnique<SpdyString>(); } -SpdyContinuationIR::~SpdyContinuationIR() {} +SpdyContinuationIR::~SpdyContinuationIR() = default; void SpdyContinuationIR::Visit(SpdyFrameVisitor* visitor) const { return visitor->VisitContinuation(*this); @@ -360,6 +390,13 @@ SpdyFrameType SpdyContinuationIR::frame_type() const { return SpdyFrameType::CONTINUATION; } +size_t SpdyContinuationIR::size() const { + // We don't need to get the size of CONTINUATION frame directly. It is + // calculated in HEADERS or PUSH_PROMISE frame. + SPDY_BUG << "Shouldn't not call size() for CONTINUATION frame."; + return 0; +} + void SpdyHeadersIR::Visit(SpdyFrameVisitor* visitor) const { return visitor->VisitHeaders(*this); } @@ -368,6 +405,29 @@ SpdyFrameType SpdyHeadersIR::frame_type() const { return SpdyFrameType::HEADERS; } +size_t SpdyHeadersIR::size() const { + size_t size = kHeadersFrameMinimumSize; + + if (padded_) { + // Padding field length. + size += 1; + size += padding_payload_len_; + } + + if (has_priority_) { + size += 5; + } + + // Assume no hpack encoding is applied. + size += header_block().TotalBytesUsed() + + header_block().size() * kPerHeaderHpackOverhead; + if (size > kHttp2MaxControlFrameSendSize) { + size += GetNumberRequiredContinuationFrames(size) * + kContinuationFrameMinimumSize; + } + return size; +} + void SpdyWindowUpdateIR::Visit(SpdyFrameVisitor* visitor) const { return visitor->VisitWindowUpdate(*this); } @@ -376,6 +436,10 @@ SpdyFrameType SpdyWindowUpdateIR::frame_type() const { return SpdyFrameType::WINDOW_UPDATE; } +size_t SpdyWindowUpdateIR::size() const { + return kWindowUpdateFrameSize; +} + void SpdyPushPromiseIR::Visit(SpdyFrameVisitor* visitor) const { return visitor->VisitPushPromise(*this); } @@ -384,9 +448,26 @@ SpdyFrameType SpdyPushPromiseIR::frame_type() const { return SpdyFrameType::PUSH_PROMISE; } +size_t SpdyPushPromiseIR::size() const { + size_t size = kPushPromiseFrameMinimumSize; + + if (padded_) { + // Padding length field. + size += 1; + size += padding_payload_len_; + } + + size += header_block().TotalBytesUsed(); + if (size > kHttp2MaxControlFrameSendSize) { + size += GetNumberRequiredContinuationFrames(size) * + kContinuationFrameMinimumSize; + } + return size; +} + SpdyAltSvcIR::SpdyAltSvcIR(SpdyStreamId stream_id) : SpdyFrameIR(stream_id) {} -SpdyAltSvcIR::~SpdyAltSvcIR() {} +SpdyAltSvcIR::~SpdyAltSvcIR() = default; void SpdyAltSvcIR::Visit(SpdyFrameVisitor* visitor) const { return visitor->VisitAltSvc(*this); @@ -396,6 +477,16 @@ SpdyFrameType SpdyAltSvcIR::frame_type() const { return SpdyFrameType::ALTSVC; } +size_t SpdyAltSvcIR::size() const { + size_t size = kGetAltSvcFrameMinimumSize; + size += origin_.length(); + // TODO(yasong): estimates the size without serializing the vector. + SpdyString str = + SpdyAltSvcWireFormat::SerializeHeaderFieldValue(altsvc_vector_); + size += str.size(); + return size; +} + void SpdyPriorityIR::Visit(SpdyFrameVisitor* visitor) const { return visitor->VisitPriority(*this); } @@ -404,6 +495,10 @@ SpdyFrameType SpdyPriorityIR::frame_type() const { return SpdyFrameType::PRIORITY; } +size_t SpdyPriorityIR::size() const { + return kPriorityFrameSize; +} + void SpdyUnknownIR::Visit(SpdyFrameVisitor* visitor) const { return visitor->VisitUnknown(*this); } @@ -412,6 +507,10 @@ SpdyFrameType SpdyUnknownIR::frame_type() const { return static_cast<SpdyFrameType>(type()); } +size_t SpdyUnknownIR::size() const { + return kFrameHeaderSize + payload_.size(); +} + int SpdyUnknownIR::flow_control_window_consumed() const { if (frame_type() == SpdyFrameType::DATA) { return payload_.size(); diff --git a/chromium/net/spdy/core/spdy_protocol.h b/chromium/net/spdy/core/spdy_protocol.h index 8b806a9a030..be15a0affc8 100644 --- a/chromium/net/spdy/core/spdy_protocol.h +++ b/chromium/net/spdy/core/spdy_protocol.h @@ -51,6 +51,12 @@ const uint32_t kSpdyMaxFrameSizeLimit = (1 << 24) - 1; // the maximum control frame size we accept. const uint32_t kHttp2DefaultFramePayloadLimit = 1 << 14; +// The maximum size of the control frames that we send, including the size of +// the header. This limit is arbitrary. We can enforce it here or at the +// application layer. We chose the framing layer, but this can be changed (or +// removed) if necessary later down the line. +const size_t kHttp2MaxControlFrameSendSize = kHttp2DefaultFramePayloadLimit - 1; + // Number of octets in the frame header. const size_t kFrameHeaderSize = 9; @@ -276,6 +282,8 @@ const size_t kPriorityFrameSize = kFrameHeaderSize + 5; // RST_STREAM frame has error_code (4 octets) field. const size_t kRstStreamFrameSize = kFrameHeaderSize + 4; const size_t kSettingsFrameMinimumSize = kFrameHeaderSize; +const size_t kSettingsOneSettingSize = + sizeof(uint32_t) + sizeof(SpdySettingsIds); // PUSH_PROMISE frame has promised_stream_id (4 octet) field. const size_t kPushPromiseFrameMinimumSize = kFrameHeaderSize + 4; // PING frame has opaque_bytes (8 octet) field. @@ -300,6 +308,10 @@ const int32_t kInitialStreamWindowSize = 64 * 1024 - 1; const int32_t kInitialSessionWindowSize = 64 * 1024 - 1; // The NPN string for HTTP2, "h2". extern const char* const kHttp2Npn; +// An estimate size of the HPACK overhead for each header field. 1 bytes for +// indexed literal, 1 bytes for key literal and length encoding, and 2 bytes for +// value literal and length encoding. +const size_t kPerHeaderHpackOverhead = 4; // Names of pseudo-headers defined for HTTP/2 requests. SPDY_EXPORT_PRIVATE extern const char* const kHttp2AuthorityHeader; @@ -310,6 +322,8 @@ SPDY_EXPORT_PRIVATE extern const char* const kHttp2SchemeHeader; // Name of pseudo-header defined for HTTP/2 responses. SPDY_EXPORT_PRIVATE extern const char* const kHttp2StatusHeader; +SPDY_EXPORT_PRIVATE size_t GetNumberRequiredContinuationFrames(size_t size); + // Variant type (i.e. tagged union) that is either a SPDY 3.x priority value, // or else an HTTP/2 stream dependency tuple {parent stream ID, weight, // exclusive bit}. Templated to allow for use by QUIC code; SPDY and HTTP/2 @@ -417,6 +431,9 @@ class SPDY_EXPORT_PRIVATE SpdyFrameIR { virtual SpdyFrameType frame_type() const = 0; SpdyStreamId stream_id() const { return stream_id_; } virtual bool fin() const; + // Returns an estimate of the size of the serialized frame, without applying + // compression. May not be exact. + virtual size_t size() const = 0; // Returns the number of bytes of flow control window that would be consumed // by this frame if written to the wire. @@ -535,6 +552,8 @@ class SPDY_EXPORT_PRIVATE SpdyDataIR : public SpdyFrameWithFinIR { int flow_control_window_consumed() const override; + size_t size() const override; + private: // Used to store data that this SpdyDataIR should own. std::unique_ptr<SpdyString> data_store_; @@ -561,6 +580,8 @@ class SPDY_EXPORT_PRIVATE SpdyRstStreamIR : public SpdyFrameIR { SpdyFrameType frame_type() const override; + size_t size() const override; + private: SpdyErrorCode error_code_; @@ -583,6 +604,8 @@ class SPDY_EXPORT_PRIVATE SpdySettingsIR : public SpdyFrameIR { SpdyFrameType frame_type() const override; + size_t size() const override; + private: SettingsMap values_; bool is_ack_; @@ -602,6 +625,8 @@ class SPDY_EXPORT_PRIVATE SpdyPingIR : public SpdyFrameIR { SpdyFrameType frame_type() const override; + size_t size() const override; + private: SpdyPingId id_; bool is_ack_; @@ -648,6 +673,8 @@ class SPDY_EXPORT_PRIVATE SpdyGoAwayIR : public SpdyFrameIR { SpdyFrameType frame_type() const override; + size_t size() const override; + private: SpdyStreamId last_good_stream_id_; SpdyErrorCode error_code_; @@ -668,6 +695,8 @@ class SPDY_EXPORT_PRIVATE SpdyHeadersIR : public SpdyFrameWithHeaderBlockIR { SpdyFrameType frame_type() const override; + size_t size() const override; + bool has_priority() const { return has_priority_; } void set_has_priority(bool has_priority) { has_priority_ = has_priority; } int weight() const { return weight_; } @@ -714,6 +743,8 @@ class SPDY_EXPORT_PRIVATE SpdyWindowUpdateIR : public SpdyFrameIR { SpdyFrameType frame_type() const override; + size_t size() const override; + private: int32_t delta_; @@ -738,6 +769,8 @@ class SPDY_EXPORT_PRIVATE SpdyPushPromiseIR SpdyFrameType frame_type() const override; + size_t size() const override; + bool padded() const { return padded_; } int padding_payload_len() const { return padding_payload_len_; } void set_padding_len(int padding_len) { @@ -772,6 +805,7 @@ class SPDY_EXPORT_PRIVATE SpdyContinuationIR : public SpdyFrameIR { void take_encoding(std::unique_ptr<SpdyString> encoding) { encoding_ = std::move(encoding); } + size_t size() const override; private: std::unique_ptr<SpdyString> encoding_; @@ -798,6 +832,8 @@ class SPDY_EXPORT_PRIVATE SpdyAltSvcIR : public SpdyFrameIR { SpdyFrameType frame_type() const override; + size_t size() const override; + private: SpdyString origin_; SpdyAltSvcWireFormat::AlternativeServiceVector altsvc_vector_; @@ -822,6 +858,8 @@ class SPDY_EXPORT_PRIVATE SpdyPriorityIR : public SpdyFrameIR { SpdyFrameType frame_type() const override; + size_t size() const override; + private: SpdyStreamId parent_stream_id_; int weight_; @@ -852,6 +890,8 @@ class SPDY_EXPORT_PRIVATE SpdyUnknownIR : public SpdyFrameIR { int flow_control_window_consumed() const override; + size_t size() const override; + protected: // Allows subclasses to overwrite the default length. void set_length(int length) { length_ = length; } diff --git a/chromium/net/spdy/core/spdy_test_utils.cc b/chromium/net/spdy/core/spdy_test_utils.cc index 1717236f4b9..e8e29f7b7b8 100644 --- a/chromium/net/spdy/core/spdy_test_utils.cc +++ b/chromium/net/spdy/core/spdy_test_utils.cc @@ -149,9 +149,9 @@ void TestHeadersHandler::OnHeaderBlockEnd( compressed_header_bytes_parsed_ = compressed_header_bytes_parsed; } -TestServerPushDelegate::TestServerPushDelegate() {} +TestServerPushDelegate::TestServerPushDelegate() = default; -TestServerPushDelegate::~TestServerPushDelegate() {} +TestServerPushDelegate::~TestServerPushDelegate() = default; void TestServerPushDelegate::OnPush( std::unique_ptr<ServerPushHelper> push_helper, diff --git a/chromium/net/ssl/client_cert_identity.cc b/chromium/net/ssl/client_cert_identity.cc index 3b89f41f757..928aafde8ab 100644 --- a/chromium/net/ssl/client_cert_identity.cc +++ b/chromium/net/ssl/client_cert_identity.cc @@ -5,6 +5,7 @@ #include "net/ssl/client_cert_identity.h" #include "base/bind.h" +#include "net/cert/x509_util.h" #include "net/ssl/ssl_private_key.h" namespace net { @@ -38,7 +39,7 @@ void ClientCertIdentity::SelfOwningAcquirePrivateKey( } void ClientCertIdentity::SetIntermediates( - X509Certificate::OSCertHandles intermediates) { + std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates) { // Allow UTF-8 inside PrintableStrings in client certificates. See // crbug.com/770323. // TODO(mattm): Perhaps X509Certificate should have a method to clone the @@ -47,9 +48,10 @@ void ClientCertIdentity::SetIntermediates( // X509Certificate was initially created.) X509Certificate::UnsafeCreateOptions options; options.printable_string_is_utf8 = true; - cert_ = X509Certificate::CreateFromHandleUnsafeOptions( - cert_->os_cert_handle(), intermediates, options); - // |cert_->os_cert_handle()| was already successfully parsed, so this should + cert_ = X509Certificate::CreateFromBufferUnsafeOptions( + x509_util::DupCryptoBuffer(cert_->cert_buffer()), + std::move(intermediates), options); + // |cert_->cert_buffer()| was already successfully parsed, so this should // never fail. DCHECK(cert_); } @@ -82,10 +84,8 @@ bool ClientCertIdentitySorter::operator()( return a->valid_start() > b->valid_start(); // Otherwise, prefer client certificates with shorter chains. - const X509Certificate::OSCertHandles& a_intermediates = - a->GetIntermediateCertificates(); - const X509Certificate::OSCertHandles& b_intermediates = - b->GetIntermediateCertificates(); + const auto& a_intermediates = a->intermediate_buffers(); + const auto& b_intermediates = b->intermediate_buffers(); return a_intermediates.size() < b_intermediates.size(); } diff --git a/chromium/net/ssl/client_cert_identity.h b/chromium/net/ssl/client_cert_identity.h index 1f8e4cb79be..6848217b2d2 100644 --- a/chromium/net/ssl/client_cert_identity.h +++ b/chromium/net/ssl/client_cert_identity.h @@ -56,7 +56,8 @@ class NET_EXPORT ClientCertIdentity { // this will change the value of |certificate()|, and any references that // were retained to the previous value will not reflect the updated // intermediates list. - void SetIntermediates(X509Certificate::OSCertHandles intermediates); + void SetIntermediates( + std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates); private: scoped_refptr<net::X509Certificate> cert_; diff --git a/chromium/net/ssl/client_cert_store_mac.cc b/chromium/net/ssl/client_cert_store_mac.cc index cbbc35b4b61..b2fb32d680b 100644 --- a/chromium/net/ssl/client_cert_store_mac.cc +++ b/chromium/net/ssl/client_cert_store_mac.cc @@ -13,6 +13,8 @@ #include <algorithm> #include <memory> #include <string> +#include <utility> +#include <vector> #include "base/bind.h" #include "base/bind_helpers.h" @@ -132,7 +134,13 @@ bool IsIssuedByInKeychain(const std::vector<std::string>& valid_issuers, if (!new_cert || !new_cert->IsIssuedByEncoded(valid_issuers)) return false; - identity->SetIntermediates(new_cert->GetIntermediateCertificates()); + std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediate_buffers; + intermediate_buffers.reserve(new_cert->intermediate_buffers().size()); + for (const auto& intermediate : new_cert->intermediate_buffers()) { + intermediate_buffers.push_back( + x509_util::DupCryptoBuffer(intermediate.get())); + } + identity->SetIntermediates(std::move(intermediate_buffers)); return true; } @@ -193,7 +201,7 @@ bool SupportsSSLClientAuth(SecCertificateRef cert) { // storing the matching certificates in |selected_identities|. // If |query_keychain| is true, Keychain Services will be queried to construct // full certificate chains. If it is false, only the the certificates and their -// intermediates (available via X509Certificate::GetIntermediateCertificates()) +// intermediates (available via X509Certificate::intermediate_buffers()) // will be considered. void GetClientCertsImpl(std::unique_ptr<ClientCertIdentity> preferred_identity, ClientCertIdentityList regular_identities, @@ -219,9 +227,9 @@ void GetClientCertsImpl(std::unique_ptr<ClientCertIdentity> preferred_identity, selected_identities->begin(), selected_identities->end(), [&cert]( const std::unique_ptr<ClientCertIdentity>& other_cert_identity) { - return X509Certificate::IsSameOSCert( - cert->certificate()->os_cert_handle(), - other_cert_identity->certificate()->os_cert_handle()); + return x509_util::CryptoBufferEqual( + cert->certificate()->cert_buffer(), + other_cert_identity->certificate()->cert_buffer()); }); if (cert_iter != selected_identities->end()) continue; @@ -236,19 +244,56 @@ void GetClientCertsImpl(std::unique_ptr<ClientCertIdentity> preferred_identity, } // Preferred cert should appear first in the ui, so exclude it from the - // sorting. Compare the os_cert_handle since the X509Certificate object may + // sorting. Compare the cert_buffer since the X509Certificate object may // have changed if intermediates were added. ClientCertIdentityList::iterator sort_begin = selected_identities->begin(); ClientCertIdentityList::iterator sort_end = selected_identities->end(); if (preferred_cert_orig && sort_begin != sort_end && - X509Certificate::IsSameOSCert( - sort_begin->get()->certificate()->os_cert_handle(), - preferred_cert_orig->os_cert_handle())) { + x509_util::CryptoBufferEqual( + sort_begin->get()->certificate()->cert_buffer(), + preferred_cert_orig->cert_buffer())) { ++sort_begin; } sort(sort_begin, sort_end, ClientCertIdentitySorter()); } +// Given a |sec_identity|, identifies its corresponding certificate, and either +// adds it to |regular_identities| or assigns it to |preferred_identity|, if the +// |sec_identity| matches the |preferred_sec_identity|. +void AddIdentity(ScopedCFTypeRef<SecIdentityRef> sec_identity, + SecIdentityRef preferred_sec_identity, + ClientCertIdentityList* regular_identities, + std::unique_ptr<ClientCertIdentity>* preferred_identity) { + OSStatus err; + ScopedCFTypeRef<SecCertificateRef> cert_handle; + err = SecIdentityCopyCertificate(sec_identity.get(), + cert_handle.InitializeInto()); + if (err != noErr) + return; + + if (!SupportsSSLClientAuth(cert_handle.get())) + return; + + // Allow UTF-8 inside PrintableStrings in client certificates. See + // crbug.com/770323. + X509Certificate::UnsafeCreateOptions options; + options.printable_string_is_utf8 = true; + scoped_refptr<X509Certificate> cert( + x509_util::CreateX509CertificateFromSecCertificate(cert_handle.get(), {}, + options)); + if (!cert) + return; + + if (preferred_sec_identity && + CFEqual(preferred_sec_identity, sec_identity.get())) { + *preferred_identity = std::make_unique<ClientCertIdentityMac>( + std::move(cert), std::move(sec_identity)); + } else { + regular_identities->push_back(std::make_unique<ClientCertIdentityMac>( + std::move(cert), std::move(sec_identity))); + } +} + ClientCertIdentityList GetClientCertsOnBackgroundThread( const SSLCertRequestInfo& request) { std::string server_domain = request.host_and_port.host(); @@ -293,36 +338,8 @@ ClientCertIdentityList GetClientCertsOnBackgroundThread( } if (err) break; - - ScopedCFTypeRef<SecCertificateRef> cert_handle; - err = SecIdentityCopyCertificate(sec_identity.get(), - cert_handle.InitializeInto()); - if (err != noErr) - continue; - - if (!SupportsSSLClientAuth(cert_handle.get())) - continue; - - // Allow UTF-8 inside PrintableStrings in client certificates. See - // crbug.com/770323. - X509Certificate::UnsafeCreateOptions options; - options.printable_string_is_utf8 = true; - scoped_refptr<X509Certificate> cert( - x509_util::CreateX509CertificateFromSecCertificate( - cert_handle.get(), std::vector<SecCertificateRef>(), options)); - if (!cert) - continue; - - if (preferred_sec_identity && - CFEqual(preferred_sec_identity, sec_identity.get())) { - // Only one certificate should match. - DCHECK(!preferred_identity.get()); - preferred_identity = std::make_unique<ClientCertIdentityMac>( - std::move(cert), std::move(sec_identity)); - } else { - regular_identities.push_back(std::make_unique<ClientCertIdentityMac>( - std::move(cert), std::move(sec_identity))); - } + AddIdentity(std::move(sec_identity), preferred_sec_identity.get(), + ®ular_identities, &preferred_identity); } if (err != errSecItemNotFound) { @@ -330,6 +347,39 @@ ClientCertIdentityList GetClientCertsOnBackgroundThread( return ClientCertIdentityList(); } + // macOS provides two ways to search for identities. SecIdentitySearchCreate() + // is deprecated, as it relies on CSSM_KEYUSE_SIGN (part of the deprecated + // CDSM/CSSA implementation), but is necessary to return some certificates + // that would otherwise not be returned by SecItemCopyMatching(), which is the + // non-deprecated way. However, SecIdentitySearchCreate() will not return all + // items, particularly smart-card based identities, so it's necessary to call + // both functions. + static const void* kKeys[] = { + kSecClass, kSecMatchLimit, kSecReturnRef, kSecAttrCanSign, + }; + static const void* kValues[] = { + kSecClassIdentity, kSecMatchLimitAll, kCFBooleanTrue, kCFBooleanTrue, + }; + ScopedCFTypeRef<CFDictionaryRef> query(CFDictionaryCreate( + kCFAllocatorDefault, kKeys, kValues, arraysize(kValues), + &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); + ScopedCFTypeRef<CFArrayRef> result; + { + base::AutoLock lock(crypto::GetMacSecurityServicesLock()); + err = SecItemCopyMatching( + query, reinterpret_cast<CFTypeRef*>(result.InitializeInto())); + } + if (!err) { + for (CFIndex i = 0; i < CFArrayGetCount(result); i++) { + SecIdentityRef item = reinterpret_cast<SecIdentityRef>( + const_cast<void*>(CFArrayGetValueAtIndex(result, i))); + AddIdentity( + ScopedCFTypeRef<SecIdentityRef>(item, base::scoped_policy::RETAIN), + preferred_sec_identity.get(), ®ular_identities, + &preferred_identity); + } + } + ClientCertIdentityList selected_identities; GetClientCertsImpl(std::move(preferred_identity), std::move(regular_identities), request, true, diff --git a/chromium/net/ssl/client_cert_store_nss.cc b/chromium/net/ssl/client_cert_store_nss.cc index 512b38e81cb..7c773ee51d1 100644 --- a/chromium/net/ssl/client_cert_store_nss.cc +++ b/chromium/net/ssl/client_cert_store_nss.cc @@ -115,25 +115,22 @@ void ClientCertStoreNSS::FilterCertsOnWorkerThread( continue; } - X509Certificate::OSCertHandles intermediates_raw; - intermediates_raw.reserve(nss_intermediates.size()); std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates; intermediates.reserve(nss_intermediates.size()); for (const ScopedCERTCertificate& nss_intermediate : nss_intermediates) { bssl::UniquePtr<CRYPTO_BUFFER> intermediate_cert_handle( - X509Certificate::CreateOSCertHandleFromBytes( + X509Certificate::CreateCertBufferFromBytes( reinterpret_cast<const char*>(nss_intermediate->derCert.data), nss_intermediate->derCert.len)); if (!intermediate_cert_handle) break; - intermediates_raw.push_back(intermediate_cert_handle.get()); intermediates.push_back(std::move(intermediate_cert_handle)); } // Retain a copy of the intermediates. Some deployments expect the client to // supply intermediates out of the local store. See // https://crbug.com/548631. - (*examine_iter)->SetIntermediates(intermediates_raw); + (*examine_iter)->SetIntermediates(std::move(intermediates)); if (examine_iter == keep_iter) ++keep_iter; diff --git a/chromium/net/ssl/client_cert_store_nss_unittest.cc b/chromium/net/ssl/client_cert_store_nss_unittest.cc index 5b9b323a167..859a38c59e9 100644 --- a/chromium/net/ssl/client_cert_store_nss_unittest.cc +++ b/chromium/net/ssl/client_cert_store_nss_unittest.cc @@ -110,9 +110,9 @@ TEST(ClientCertStoreNSSTest, BuildsCertificateChain) { ASSERT_EQ(1u, selected_identities.size()); scoped_refptr<X509Certificate> selected_cert = selected_identities[0]->certificate(); - EXPECT_TRUE(X509Certificate::IsSameOSCert(client_1->os_cert_handle(), - selected_cert->os_cert_handle())); - ASSERT_EQ(0u, selected_cert->GetIntermediateCertificates().size()); + EXPECT_TRUE(x509_util::CryptoBufferEqual(client_1->cert_buffer(), + selected_cert->cert_buffer())); + ASSERT_EQ(0u, selected_cert->intermediate_buffers().size()); scoped_refptr<SSLPrivateKey> ssl_private_key; base::RunLoop key_loop; @@ -144,12 +144,12 @@ TEST(ClientCertStoreNSSTest, BuildsCertificateChain) { ASSERT_EQ(1u, selected_identities.size()); scoped_refptr<X509Certificate> selected_cert = selected_identities[0]->certificate(); - EXPECT_TRUE(X509Certificate::IsSameOSCert(client_1->os_cert_handle(), - selected_cert->os_cert_handle())); - ASSERT_EQ(1u, selected_cert->GetIntermediateCertificates().size()); - EXPECT_TRUE(X509Certificate::IsSameOSCert( - client_1_ca->os_cert_handle(), - selected_cert->GetIntermediateCertificates()[0])); + EXPECT_TRUE(x509_util::CryptoBufferEqual(client_1->cert_buffer(), + selected_cert->cert_buffer())); + ASSERT_EQ(1u, selected_cert->intermediate_buffers().size()); + EXPECT_TRUE(x509_util::CryptoBufferEqual( + client_1_ca->cert_buffer(), + selected_cert->intermediate_buffers()[0].get())); scoped_refptr<SSLPrivateKey> ssl_private_key; base::RunLoop key_loop; @@ -221,7 +221,7 @@ TEST(ClientCertStoreNSSTest, SubjectPrintableStringContainingUTF8) { scoped_refptr<X509Certificate> selected_cert = selected_identities[0]->certificate(); EXPECT_TRUE(x509_util::IsSameCertificate(cert.get(), selected_cert.get())); - EXPECT_EQ(0u, selected_cert->GetIntermediateCertificates().size()); + EXPECT_EQ(0u, selected_cert->intermediate_buffers().size()); scoped_refptr<SSLPrivateKey> ssl_private_key; base::RunLoop key_loop; diff --git a/chromium/net/ssl/client_cert_store_unittest-inl.h b/chromium/net/ssl/client_cert_store_unittest-inl.h index 4da72c4afbd..7cc02d3d4be 100644 --- a/chromium/net/ssl/client_cert_store_unittest-inl.h +++ b/chromium/net/ssl/client_cert_store_unittest-inl.h @@ -152,7 +152,7 @@ TYPED_TEST_P(ClientCertStoreTest, PrintableStringContainingUTF8) { X509Certificate::UnsafeCreateOptions options; options.printable_string_is_utf8 = true; scoped_refptr<X509Certificate> cert = - X509Certificate::CreateFromHandleUnsafeOptions(cert_handle.get(), {}, + X509Certificate::CreateFromBufferUnsafeOptions(std::move(cert_handle), {}, options); ASSERT_TRUE(cert); diff --git a/chromium/net/ssl/client_cert_store_win.cc b/chromium/net/ssl/client_cert_store_win.cc index 6622ea417f4..d9c271f3ab1 100644 --- a/chromium/net/ssl/client_cert_store_win.cc +++ b/chromium/net/ssl/client_cert_store_win.cc @@ -25,6 +25,7 @@ #include "net/ssl/ssl_platform_key_util.h" #include "net/ssl/ssl_platform_key_win.h" #include "net/ssl/ssl_private_key.h" +#include "third_party/boringssl/src/include/openssl/pool.h" namespace net { @@ -273,16 +274,16 @@ bool ClientCertStoreWin::SelectClientCertsForTesting( return false; // Add available certificates to the test store. - for (size_t i = 0; i < input_certs.size(); ++i) { + for (const auto& input_cert : input_certs) { // Add the certificate to the test store. PCCERT_CONTEXT cert = NULL; - std::string der_cert; - X509Certificate::GetDEREncoded(input_certs[i]->os_cert_handle(), &der_cert); if (!CertAddEncodedCertificateToStore( test_store, X509_ASN_ENCODING, - reinterpret_cast<const BYTE*>(der_cert.data()), - base::checked_cast<DWORD>(der_cert.size()), CERT_STORE_ADD_NEW, - &cert)) { + reinterpret_cast<const BYTE*>( + CRYPTO_BUFFER_data(input_cert->cert_buffer())), + base::checked_cast<DWORD>( + CRYPTO_BUFFER_len(input_cert->cert_buffer())), + CERT_STORE_ADD_NEW, &cert)) { return false; } // Hold the reference to the certificate (since we requested a copy). diff --git a/chromium/net/ssl/openssl_ssl_util.cc b/chromium/net/ssl/openssl_ssl_util.cc index ae0fb4f75e9..b2067f1fe1f 100644 --- a/chromium/net/ssl/openssl_ssl_util.cc +++ b/chromium/net/ssl/openssl_ssl_util.cc @@ -231,11 +231,10 @@ bool SetSSLChainAndKey(SSL* ssl, EVP_PKEY* pkey, const SSL_PRIVATE_KEY_METHOD* custom_key) { std::vector<CRYPTO_BUFFER*> chain_raw; - chain_raw.push_back(cert->os_cert_handle()); - for (X509Certificate::OSCertHandle handle : - cert->GetIntermediateCertificates()) { - chain_raw.push_back(handle); - } + chain_raw.reserve(1 + cert->intermediate_buffers().size()); + chain_raw.push_back(cert->cert_buffer()); + for (const auto& handle : cert->intermediate_buffers()) + chain_raw.push_back(handle.get()); if (!SSL_set_chain_and_key(ssl, chain_raw.data(), chain_raw.size(), pkey, custom_key)) { diff --git a/chromium/net/ssl/ssl_client_session_cache.cc b/chromium/net/ssl/ssl_client_session_cache.cc index eebca7640b3..f7fcdfa6e8a 100644 --- a/chromium/net/ssl/ssl_client_session_cache.cc +++ b/chromium/net/ssl/ssl_client_session_cache.cc @@ -17,7 +17,7 @@ namespace net { SSLClientSessionCache::SSLClientSessionCache(const Config& config) - : clock_(new base::DefaultClock), + : clock_(base::DefaultClock::GetInstance()), config_(config), cache_(config.max_entries), lookups_since_flush_(0) { @@ -87,9 +87,8 @@ void SSLClientSessionCache::Flush() { cache_.Clear(); } -void SSLClientSessionCache::SetClockForTesting( - std::unique_ptr<base::Clock> clock) { - clock_ = std::move(clock); +void SSLClientSessionCache::SetClockForTesting(base::Clock* clock) { + clock_ = clock; } bool SSLClientSessionCache::IsExpired(SSL_SESSION* session, time_t now) { diff --git a/chromium/net/ssl/ssl_client_session_cache.h b/chromium/net/ssl/ssl_client_session_cache.h index 865206ffe5e..ad64c8062db 100644 --- a/chromium/net/ssl/ssl_client_session_cache.h +++ b/chromium/net/ssl/ssl_client_session_cache.h @@ -64,7 +64,7 @@ class NET_EXPORT SSLClientSessionCache : public base::MemoryCoordinatorClient { // Removes all entries from the cache. void Flush(); - void SetClockForTesting(std::unique_ptr<base::Clock> clock); + void SetClockForTesting(base::Clock* clock); // Dumps memory allocation stats. |pmd| is the ProcessMemoryDump of the // browser process. @@ -101,7 +101,7 @@ class NET_EXPORT SSLClientSessionCache : public base::MemoryCoordinatorClient { void OnMemoryPressure( base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level); - std::unique_ptr<base::Clock> clock_; + base::Clock* clock_; Config config_; base::HashingMRUCache<std::string, Entry> cache_; size_t lookups_since_flush_; diff --git a/chromium/net/ssl/ssl_client_session_cache_unittest.cc b/chromium/net/ssl/ssl_client_session_cache_unittest.cc index 6b6299186a2..461fb189561 100644 --- a/chromium/net/ssl/ssl_client_session_cache_unittest.cc +++ b/chromium/net/ssl/ssl_client_session_cache_unittest.cc @@ -313,8 +313,8 @@ TEST_F(SSLClientSessionCacheTest, Expiration) { SSLClientSessionCache::Config config; config.expiration_check_count = kExpirationCheckCount; SSLClientSessionCache cache(config); - base::SimpleTestClock* clock = MakeTestClock().release(); - cache.SetClockForTesting(base::WrapUnique(clock)); + std::unique_ptr<base::SimpleTestClock> clock = MakeTestClock(); + cache.SetClockForTesting(clock.get()); // Add |kNumEntries - 1| entries. for (size_t i = 0; i < kNumEntries - 1; i++) { @@ -362,8 +362,8 @@ TEST_F(SSLClientSessionCacheTest, LookupExpirationCheck) { SSLClientSessionCache::Config config; config.expiration_check_count = kExpirationCheckCount; SSLClientSessionCache cache(config); - base::SimpleTestClock* clock = MakeTestClock().release(); - cache.SetClockForTesting(base::WrapUnique(clock)); + std::unique_ptr<base::SimpleTestClock> clock = MakeTestClock(); + cache.SetClockForTesting(clock.get()); // Insert an entry into the session cache. bssl::UniquePtr<SSL_SESSION> session = @@ -410,8 +410,8 @@ TEST_F(SSLClientSessionCacheTest, TestFlushOnMemoryNotifications) { SSLClientSessionCache::Config config; config.expiration_check_count = kExpirationCheckCount; SSLClientSessionCache cache(config); - base::SimpleTestClock* clock = MakeTestClock().release(); - cache.SetClockForTesting(base::WrapUnique(clock)); + std::unique_ptr<base::SimpleTestClock> clock = MakeTestClock(); + cache.SetClockForTesting(clock.get()); // Insert an entry into the session cache. bssl::UniquePtr<SSL_SESSION> session1 = diff --git a/chromium/net/ssl/ssl_config.cc b/chromium/net/ssl/ssl_config.cc index a460ebe038f..72d63d83a28 100644 --- a/chromium/net/ssl/ssl_config.cc +++ b/chromium/net/ssl/ssl_config.cc @@ -12,7 +12,7 @@ const uint16_t kDefaultSSLVersionMin = SSL_PROTOCOL_VERSION_TLS1; const uint16_t kDefaultSSLVersionMax = SSL_PROTOCOL_VERSION_TLS1_2; -const TLS13Variant kDefaultTLS13Variant = kTLS13VariantDraft; +const TLS13Variant kDefaultTLS13Variant = kTLS13VariantDraft22; SSLConfig::CertAndStatus::CertAndStatus() = default; SSLConfig::CertAndStatus::CertAndStatus(scoped_refptr<X509Certificate> cert_arg, @@ -26,6 +26,7 @@ SSLConfig::SSLConfig() rev_checking_required_local_anchors(false), sha1_local_anchors_enabled(true), common_name_fallback_local_anchors_enabled(true), + symantec_enforcement_disabled(false), version_min(kDefaultSSLVersionMin), version_max(kDefaultSSLVersionMax), tls13_variant(kDefaultTLS13Variant), @@ -69,6 +70,9 @@ int SSLConfig::GetCertVerifyFlags() const { flags |= CertVerifier::VERIFY_ENABLE_SHA1_LOCAL_ANCHORS; if (common_name_fallback_local_anchors_enabled) flags |= CertVerifier::VERIFY_ENABLE_COMMON_NAME_FALLBACK_LOCAL_ANCHORS; + if (symantec_enforcement_disabled) + flags |= CertVerifier::VERIFY_DISABLE_SYMANTEC_ENFORCEMENT; + return flags; } diff --git a/chromium/net/ssl/ssl_config.h b/chromium/net/ssl/ssl_config.h index cf6c693f425..d1d677179d1 100644 --- a/chromium/net/ssl/ssl_config.h +++ b/chromium/net/ssl/ssl_config.h @@ -36,10 +36,9 @@ enum TokenBindingParam { }; enum TLS13Variant { - kTLS13VariantDraft, - kTLS13VariantExperiment, kTLS13VariantExperiment2, - kTLS13VariantExperiment3, + kTLS13VariantDraft22, + kTLS13VariantDraft23, }; // Default minimum protocol version. @@ -94,6 +93,11 @@ struct NET_EXPORT SSLConfig { // (non-public) trust anchor will be allowed to match. bool common_name_fallback_local_anchors_enabled; + // symantec_enforcement_disabled is true if the policies outlined in + // https://security.googleblog.com/2017/09/chromes-plan-to-distrust-symantec.html + // should not be enforced. + bool symantec_enforcement_disabled; + // The minimum and maximum protocol versions that are enabled. // (Use the SSL_PROTOCOL_VERSION_xxx enumerators defined above.) // SSL 2.0 and SSL 3.0 are not supported. If version_max < version_min, it diff --git a/chromium/net/ssl/ssl_config_unittest.cc b/chromium/net/ssl/ssl_config_unittest.cc index 437edd5bd02..e3fca97dec2 100644 --- a/chromium/net/ssl/ssl_config_unittest.cc +++ b/chromium/net/ssl/ssl_config_unittest.cc @@ -15,32 +15,25 @@ void CheckCertVerifyFlags(SSLConfig* ssl_config, bool rev_checking_enabled, bool verify_ev_cert, bool cert_io_enabled, - bool rev_checking_required_local_anchors) { + bool rev_checking_required_local_anchors, + bool symantec_enforcement_disabled) { ssl_config->rev_checking_enabled = rev_checking_enabled; ssl_config->verify_ev_cert = verify_ev_cert; ssl_config->cert_io_enabled = cert_io_enabled; ssl_config->rev_checking_required_local_anchors = rev_checking_required_local_anchors; + ssl_config->symantec_enforcement_disabled = symantec_enforcement_disabled; + int flags = ssl_config->GetCertVerifyFlags(); - if (rev_checking_enabled) - EXPECT_TRUE(flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED); - else - EXPECT_FALSE(flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED); - if (verify_ev_cert) - EXPECT_TRUE(flags & CertVerifier::VERIFY_EV_CERT); - else - EXPECT_FALSE(flags & CertVerifier::VERIFY_EV_CERT); - if (cert_io_enabled) - EXPECT_TRUE(flags & CertVerifier::VERIFY_CERT_IO_ENABLED); - else - EXPECT_FALSE(flags & CertVerifier::VERIFY_CERT_IO_ENABLED); - if (rev_checking_required_local_anchors) { - EXPECT_TRUE(flags & - CertVerifier::VERIFY_REV_CHECKING_REQUIRED_LOCAL_ANCHORS); - } else { - EXPECT_FALSE(flags & - CertVerifier::VERIFY_REV_CHECKING_REQUIRED_LOCAL_ANCHORS); - } + EXPECT_EQ(rev_checking_enabled, + !!(flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED)); + EXPECT_EQ(verify_ev_cert, !!(flags & CertVerifier::VERIFY_EV_CERT)); + EXPECT_EQ(cert_io_enabled, !!(flags & CertVerifier::VERIFY_CERT_IO_ENABLED)); + EXPECT_EQ( + rev_checking_required_local_anchors, + !!(flags & CertVerifier::VERIFY_REV_CHECKING_REQUIRED_LOCAL_ANCHORS)); + EXPECT_EQ(symantec_enforcement_disabled, + !!(flags & CertVerifier::VERIFY_DISABLE_SYMANTEC_ENFORCEMENT)); } } // namespace @@ -51,37 +44,50 @@ TEST(SSLConfigTest, GetCertVerifyFlags) { /*rev_checking_enabled=*/true, /*verify_ev_cert=*/true, /*cert_io_enabled=*/true, - /*rev_checking_required_local_anchors=*/true); + /*rev_checking_required_local_anchors=*/true, + /*symantec_enforcement_disabled=*/true); CheckCertVerifyFlags(&ssl_config, /*rev_checking_enabled=*/false, /*verify_ev_cert=*/false, /*cert_io_enabled=*/false, - /*rev_checking_required_local_anchors=*/false); + /*rev_checking_required_local_anchors=*/false, + /*symantec_enforcement_disabled=*/false); CheckCertVerifyFlags(&ssl_config, /*rev_checking_enabled=*/true, /*verify_ev_cert=*/false, /*cert_io_enabled=*/false, - /*rev_checking_required_local_anchors=*/false); + /*rev_checking_required_local_anchors=*/false, + /*symantec_enforcement_disabled=*/false); CheckCertVerifyFlags(&ssl_config, /*rev_checking_enabled=*/false, /*verify_ev_cert=*/true, /*cert_io_enabled=*/false, - /*rev_checking_required_local_anchors=*/false); + /*rev_checking_required_local_anchors=*/false, + /*symantec_enforcement_disabled=*/false); CheckCertVerifyFlags(&ssl_config, /*rev_checking_enabled=*/false, /*verify_ev_cert=*/false, /*cert_io_enabled=*/true, - /*rev_checking_required_local_anchors=*/false); + /*rev_checking_required_local_anchors=*/false, + /*symantec_enforcement_disabled=*/false); CheckCertVerifyFlags(&ssl_config, /*rev_checking_enabled=*/false, /*verify_ev_cert=*/false, /*cert_io_enabled=*/false, - /*rev_checking_required_local_anchors=*/true); + /*rev_checking_required_local_anchors=*/true, + /*symantec_enforcement_disabled=*/false); + + CheckCertVerifyFlags(&ssl_config, + /*rev_checking_enabled=*/false, + /*verify_ev_cert=*/false, + /*cert_io_enabled=*/true, + /*rev_checking_required_local_anchors=*/false, + /*symantec_enforcement_disabled=*/true); } } // namespace net diff --git a/chromium/net/ssl/ssl_info.cc b/chromium/net/ssl/ssl_info.cc index 28fcc140d66..f80610f22ee 100644 --- a/chromium/net/ssl/ssl_info.cc +++ b/chromium/net/ssl/ssl_info.cc @@ -48,6 +48,7 @@ void SSLInfo::Reset() { ct::CTPolicyCompliance::CT_POLICY_COMPLIANCE_DETAILS_NOT_AVAILABLE; ct_policy_compliance_required = false; ocsp_result = OCSPVerifyResult(); + is_fatal_cert_error = false; } void SSLInfo::SetCertError(int error) { diff --git a/chromium/net/ssl/ssl_info.h b/chromium/net/ssl/ssl_info.h index fd39bbc9f62..2d903cf26df 100644 --- a/chromium/net/ssl/ssl_info.h +++ b/chromium/net/ssl/ssl_info.h @@ -139,6 +139,10 @@ class NET_EXPORT SSLInfo { // OCSP stapling details. OCSPVerifyResult ocsp_result; + + // True if there was a certificate error which should be treated as fatal, + // and false otherwise. + bool is_fatal_cert_error; }; } // namespace net diff --git a/chromium/net/ssl/ssl_platform_key_util.cc b/chromium/net/ssl/ssl_platform_key_util.cc index 46ba59f064f..70df11b4fd7 100644 --- a/chromium/net/ssl/ssl_platform_key_util.cc +++ b/chromium/net/ssl/ssl_platform_key_util.cc @@ -12,6 +12,7 @@ #include "crypto/openssl_util.h" #include "net/cert/asn1_util.h" #include "net/cert/x509_certificate.h" +#include "net/cert/x509_util.h" #include "third_party/boringssl/src/include/openssl/bytestring.h" #include "third_party/boringssl/src/include/openssl/ec_key.h" #include "third_party/boringssl/src/include/openssl/evp.h" @@ -54,11 +55,10 @@ bool GetClientCertInfo(const X509Certificate* certificate, size_t* out_max_length) { crypto::OpenSSLErrStackTracer tracker(FROM_HERE); - std::string der_encoded; base::StringPiece spki; - if (!X509Certificate::GetDEREncoded(certificate->os_cert_handle(), - &der_encoded) || - !asn1::ExtractSPKIFromDERCert(der_encoded, &spki)) { + if (!asn1::ExtractSPKIFromDERCert( + x509_util::CryptoBufferAsStringPiece(certificate->cert_buffer()), + &spki)) { LOG(ERROR) << "Could not extract SPKI from certificate."; return false; } diff --git a/chromium/net/test/cert_test_util.cc b/chromium/net/test/cert_test_util.cc index 0295d7b8963..454071f2fc7 100644 --- a/chromium/net/test/cert_test_util.cc +++ b/chromium/net/test/cert_test_util.cc @@ -9,6 +9,7 @@ #include "base/threading/thread_restrictions.h" #include "net/cert/ev_root_ca_metadata.h" #include "net/cert/x509_certificate.h" +#include "net/cert/x509_util.h" #include "net/test/test_data_directory.h" namespace net { @@ -52,12 +53,14 @@ scoped_refptr<X509Certificate> CreateCertificateChainFromFile( if (certs.empty()) return NULL; - X509Certificate::OSCertHandles intermediates; + std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates; for (size_t i = 1; i < certs.size(); ++i) - intermediates.push_back(certs[i]->os_cert_handle()); + intermediates.push_back( + x509_util::DupCryptoBuffer(certs[i]->cert_buffer())); - scoped_refptr<X509Certificate> result(X509Certificate::CreateFromHandle( - certs[0]->os_cert_handle(), intermediates)); + scoped_refptr<X509Certificate> result(X509Certificate::CreateFromBuffer( + x509_util::DupCryptoBuffer(certs[0]->cert_buffer()), + std::move(intermediates))); return result; } diff --git a/chromium/net/test/embedded_test_server/default_handlers.cc b/chromium/net/test/embedded_test_server/default_handlers.cc index a1e984fa631..05aa1037c5d 100644 --- a/chromium/net/test/embedded_test_server/default_handlers.cc +++ b/chromium/net/test/embedded_test_server/default_handlers.cc @@ -30,6 +30,7 @@ #include "base/time/time.h" #include "base/unguessable_token.h" #include "net/base/escape.h" +#include "net/base/host_port_pair.h" #include "net/base/url_util.h" #include "net/filter/filter_source_stream_test_util.h" #include "net/test/embedded_test_server/http_request.h" @@ -497,15 +498,16 @@ std::unique_ptr<HttpResponse> HandleAuthDigest(const HttpRequest& request) { return std::move(http_response); } -// /server-redirect?URL -// Returns a server-redirect (301) to URL. -std::unique_ptr<HttpResponse> HandleServerRedirect(const HttpRequest& request) { +// /server-redirect?URL (Also /server-redirect-xxx?URL) +// Returns a server redirect to URL. +std::unique_ptr<HttpResponse> HandleServerRedirect(HttpStatusCode redirect_code, + const HttpRequest& request) { GURL request_url = request.GetURL(); std::string dest = net::UnescapeURLComponent(request_url.query(), kUnescapeAll); std::unique_ptr<BasicHttpResponse> http_response(new BasicHttpResponse); - http_response->set_code(HTTP_MOVED_PERMANENTLY); + http_response->set_code(redirect_code); http_response->AddCustomHeader("Location", dest); http_response->set_content_type("text/html"); http_response->set_content(base::StringPrintf( @@ -668,10 +670,26 @@ std::unique_ptr<HttpResponse> HandleGzipBody(const HttpRequest& request) { return std::move(http_response); } +// /self.pac +// Returns a response that is a PAC script making requests use the +// EmbeddedTestServer itself as a proxy. +std::unique_ptr<HttpResponse> HandleSelfPac(const HttpRequest& request) { + std::unique_ptr<BasicHttpResponse> http_response = + std::make_unique<BasicHttpResponse>(); + http_response->set_content(base::StringPrintf( + "function FindProxyForURL(url, host) {\n" + "return 'PROXY %s';\n" + "}", + net::HostPortPair::FromURL(request.base_url).ToString().c_str())); + return std::move(http_response); +} + } // anonymous namespace #define PREFIXED_HANDLER(prefix, handler) \ base::Bind(&HandlePrefixedRequest, prefix, base::Bind(handler)) +#define SERVER_REDIRECT_HANDLER(prefix, handler, status_code) \ + base::Bind(&HandlePrefixedRequest, prefix, base::Bind(handler, status_code)) void RegisterDefaultHandlers(EmbeddedTestServer* server) { server->RegisterDefaultHandler(base::Bind(&HandleDefaultConnect)); @@ -703,8 +721,20 @@ void RegisterDefaultHandlers(EmbeddedTestServer* server) { PREFIXED_HANDLER("/auth-basic", &HandleAuthBasic)); server->RegisterDefaultHandler( PREFIXED_HANDLER("/auth-digest", &HandleAuthDigest)); - server->RegisterDefaultHandler( - PREFIXED_HANDLER("/server-redirect", &HandleServerRedirect)); + + server->RegisterDefaultHandler(SERVER_REDIRECT_HANDLER( + "/server-redirect", &HandleServerRedirect, HTTP_MOVED_PERMANENTLY)); + server->RegisterDefaultHandler(SERVER_REDIRECT_HANDLER( + "/server-redirect-301", &HandleServerRedirect, HTTP_MOVED_PERMANENTLY)); + server->RegisterDefaultHandler(SERVER_REDIRECT_HANDLER( + "/server-redirect-302", &HandleServerRedirect, HTTP_FOUND)); + server->RegisterDefaultHandler(SERVER_REDIRECT_HANDLER( + "/server-redirect-303", &HandleServerRedirect, HTTP_SEE_OTHER)); + server->RegisterDefaultHandler(SERVER_REDIRECT_HANDLER( + "/server-redirect-307", &HandleServerRedirect, HTTP_TEMPORARY_REDIRECT)); + server->RegisterDefaultHandler(SERVER_REDIRECT_HANDLER( + "/server-redirect-308", &HandleServerRedirect, HTTP_PERMANENT_REDIRECT)); + server->RegisterDefaultHandler(base::Bind(&HandleCrossSiteRedirect, server)); server->RegisterDefaultHandler( PREFIXED_HANDLER("/client-redirect", &HandleClientRedirect)); @@ -717,6 +747,7 @@ void RegisterDefaultHandlers(EmbeddedTestServer* server) { PREFIXED_HANDLER("/hung-after-headers", &HandleHungAfterHeadersResponse)); server->RegisterDefaultHandler( PREFIXED_HANDLER("/gzip-body", &HandleGzipBody)); + server->RegisterDefaultHandler(PREFIXED_HANDLER("/self.pac", &HandleSelfPac)); // TODO(svaldez): HandleDownload // TODO(svaldez): HandleDownloadFinish 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 de416f22aed..5caf5c59857 100644 --- a/chromium/net/test/embedded_test_server/embedded_test_server.cc +++ b/chromium/net/test/embedded_test_server/embedded_test_server.cc @@ -281,6 +281,10 @@ std::string EmbeddedTestServer::GetCertificateName() const { return "localhost_cert.pem"; case CERT_EXPIRED: return "expired_cert.pem"; + case CERT_COMMON_NAME_ONLY: + return "common_name_only.pem"; + case CERT_SHA1_LEAF: + return "sha1_leaf.pem"; } return "ok_cert.pem"; 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 5d26cf4ec37..a2d33517e9d 100644 --- a/chromium/net/test/embedded_test_server/embedded_test_server.h +++ b/chromium/net/test/embedded_test_server/embedded_test_server.h @@ -103,6 +103,13 @@ class EmbeddedTestServer { // Causes the testserver to use a hostname that is a domain // instead of an IP. CERT_COMMON_NAME_IS_DOMAIN, + + // A certificate that only contains a commonName, rather than also + // including a subjectAltName extension. + CERT_COMMON_NAME_ONLY, + + // A certificate that is a leaf certificate signed with SHA-1. + CERT_SHA1_LEAF, }; typedef base::Callback<std::unique_ptr<HttpResponse>( diff --git a/chromium/net/test/net_test_suite.cc b/chromium/net/test/net_test_suite.cc index 8b1a668540b..792eeab126f 100644 --- a/chromium/net/test/net_test_suite.cc +++ b/chromium/net/test/net_test_suite.cc @@ -15,6 +15,9 @@ #endif namespace { +base::test::ScopedTaskEnvironment::MainThreadType kDefaultMainThreadType = + base::test::ScopedTaskEnvironment::MainThreadType::IO; + NetTestSuite* g_current_net_test_suite = nullptr; } // namespace @@ -46,11 +49,13 @@ void NetTestSuite::Shutdown() { TestSuite::Shutdown(); } +// static base::test::ScopedTaskEnvironment* NetTestSuite::GetScopedTaskEnvironment() { DCHECK(g_current_net_test_suite); return g_current_net_test_suite->scoped_task_environment_.get(); } +// static void NetTestSuite::SetScopedTaskEnvironment( base::test::ScopedTaskEnvironment::MainThreadType type) { g_current_net_test_suite->scoped_task_environment_ = nullptr; @@ -58,6 +63,11 @@ void NetTestSuite::SetScopedTaskEnvironment( std::make_unique<base::test::ScopedTaskEnvironment>(type); } +// static +void NetTestSuite::ResetScopedTaskEnvironment() { + SetScopedTaskEnvironment(kDefaultMainThreadType); +} + void NetTestSuite::InitializeTestThread() { network_change_notifier_.reset(net::NetworkChangeNotifier::CreateMock()); @@ -74,5 +84,5 @@ void NetTestSuite::InitializeTestThreadNoNetworkChangeNotifier() { scoped_task_environment_ = std::make_unique<base::test::ScopedTaskEnvironment>( - base::test::ScopedTaskEnvironment::MainThreadType::IO); + kDefaultMainThreadType); } diff --git a/chromium/net/test/net_test_suite.h b/chromium/net/test/net_test_suite.h index 9cb4e355a81..a35a30c90e3 100644 --- a/chromium/net/test/net_test_suite.h +++ b/chromium/net/test/net_test_suite.h @@ -42,6 +42,10 @@ class NetTestSuite : public base::TestSuite { static void SetScopedTaskEnvironment( base::test::ScopedTaskEnvironment::MainThreadType type); + // Sets the global ScopedTaskEnvironment to a new environment of the default + // type used by NetTestSuite. + static void ResetScopedTaskEnvironment(); + protected: // Called from within Initialize(), but separate so that derived classes // can initialize the NetTestSuite instance only and not diff --git a/chromium/net/test/python_utils.cc b/chromium/net/test/python_utils.cc index 57429626b17..e439813a8c5 100644 --- a/chromium/net/test/python_utils.cc +++ b/chromium/net/test/python_utils.cc @@ -23,11 +23,16 @@ #endif const char kPythonPathEnv[] = "PYTHONPATH"; -const char kPythonVirtualEnv[] = "VIRTUAL_ENV"; +const char kVPythonClearPathEnv[] = "VPYTHON_CLEAR_PYTHONPATH"; void ClearPythonPath() { std::unique_ptr<base::Environment> env(base::Environment::Create()); env->UnSetVar(kPythonPathEnv); + + // vpython has instructions on BuildBot (not swarming or LUCI) to clear + // PYTHONPATH on invocation. Since we are clearing and manipulating it + // ourselves, we don't want vpython to throw out our hard work. + env->UnSetVar(kVPythonClearPathEnv); } void AppendToPythonPath(const base::FilePath& dir) { @@ -83,53 +88,19 @@ bool GetPyProtoPath(base::FilePath* dir) { return false; } -#if defined(OS_WIN) -struct PythonExePath { - PythonExePath() { - // This is test-only code, so CHECK with a subprocess invocation is ok. - base::CommandLine command(base::FilePath(FILE_PATH_LITERAL("cmd"))); - command.AppendArg("/c"); - command.AppendArg("python"); - command.AppendArg("-c"); - command.AppendArg("import sys; print sys.executable"); - std::string output; - CHECK(GetAppOutput(command, &output)); - // This does only work if cmd.exe doesn't use a non-US codepage. - path_ = base::ASCIIToUTF16(output); - TrimWhitespace(path_, base::TRIM_ALL, &path_); - } - base::string16 path_; -}; -static base::LazyInstance<PythonExePath>::Leaky g_python_path; -#endif - -bool IsInPythonVirtualEnv() { - return base::Environment::Create()->HasVar(kPythonVirtualEnv); -} - bool GetPythonCommand(base::CommandLine* python_cmd) { DCHECK(python_cmd); +// Use vpython to pick up src.git's vpython VirtualEnv spec. #if defined(OS_WIN) - // Most developers have depot_tools in their path, which only has a - // python.bat, not a python.exe. Go through cmd to find the path to - // the python executable. - // (Don't just return a a "cmd /c python" command line, because then tests - // that try to kill the python process will kill the cmd process instead, - // which can cause flakiness.) - python_cmd->SetProgram(base::FilePath(g_python_path.Get().path_)); + python_cmd->SetProgram(base::FilePath(FILE_PATH_LITERAL("vpython.bat"))); #else - python_cmd->SetProgram(base::FilePath(FILE_PATH_LITERAL("python"))); + python_cmd->SetProgram(base::FilePath(FILE_PATH_LITERAL("vpython"))); #endif // Launch python in unbuffered mode, so that python output doesn't mix with // gtest output in buildbot log files. See http://crbug.com/147368. python_cmd->AppendArg("-u"); - if (!IsInPythonVirtualEnv()) { - // Prevent using system-installed libraries. Use hermetic versioned copies. - python_cmd->AppendArg("-S"); - } - return true; } diff --git a/chromium/net/test/run_all_unittests.cc b/chromium/net/test/run_all_unittests.cc index 7ba6b98ad76..635c4099e9b 100644 --- a/chromium/net/test/run_all_unittests.cc +++ b/chromium/net/test/run_all_unittests.cc @@ -2,8 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <iostream> + #include "base/build_time.h" -#include "base/metrics/statistics_recorder.h" #include "base/test/launcher/unit_test_launcher.h" #include "build/build_config.h" #include "crypto/nss_util.h" @@ -50,9 +51,6 @@ bool VerifyBuildIsTimely() { } // namespace int main(int argc, char** argv) { - // Record histograms, so we can get histograms data in tests. - base::StatisticsRecorder::Initialize(); - if (!VerifyBuildIsTimely()) return 1; 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 3f9ba3e615f..75a4cf8dbf1 100644 --- a/chromium/net/test/spawned_test_server/base_test_server.cc +++ b/chromium/net/test/spawned_test_server/base_test_server.cc @@ -269,8 +269,7 @@ const HostPortPair& BaseTestServer::host_port_pair() const { } const base::DictionaryValue& BaseTestServer::server_data() const { - DCHECK(started_); - DCHECK(server_data_.get()); + DCHECK(server_data_); return *server_data_; } @@ -445,7 +444,7 @@ bool BaseTestServer::SetAndParseServerData(const std::string& server_data, VLOG(1) << "Server data: " << server_data; base::JSONReader json_reader; std::unique_ptr<base::Value> value(json_reader.ReadToValue(server_data)); - if (!value.get() || !value->IsType(base::Value::Type::DICTIONARY)) { + if (!value.get() || !value->is_dict()) { LOG(ERROR) << "Could not parse server data: " << json_reader.GetErrorMessage(); return false; @@ -581,6 +580,10 @@ bool BaseTestServer::GenerateArguments(base::DictionaryValue* arguments) const { arguments->SetInteger("cert-serial", ssl_options_.cert_serial); } + if (!ssl_options_.cert_common_name.empty()) { + arguments->SetString("cert-common-name", ssl_options_.cert_common_name); + } + // Check key exchange argument. std::unique_ptr<base::ListValue> key_exchange_values(new base::ListValue()); GetKeyExchangesList(ssl_options_.key_exchanges, key_exchange_values.get()); diff --git a/chromium/net/test/spawned_test_server/base_test_server.h b/chromium/net/test/spawned_test_server/base_test_server.h index a35d3816f59..c279b6cf21d 100644 --- a/chromium/net/test/spawned_test_server/base_test_server.h +++ b/chromium/net/test/spawned_test_server/base_test_server.h @@ -217,6 +217,10 @@ class BaseTestServer { // auto-generated leaf certificate when |server_certificate==CERT_AUTO|. uint64_t cert_serial = 0; + // If not empty, |cert_common_name| will be the common name of the + // auto-generated leaf certificate when |server_certificate==CERT_AUTO|. + std::string cert_common_name; + // True if a CertificateRequest should be sent to the client during // handshaking. bool request_client_certificate = false; @@ -381,6 +385,7 @@ class BaseTestServer { protected: virtual ~BaseTestServer(); Type type() const { return type_; } + const SSLOptions& ssl_options() const { return ssl_options_; } bool started() const { return started_; } 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 3f0ad15fdca..8528663b90a 100644 --- a/chromium/net/test/spawned_test_server/local_test_server.cc +++ b/chromium/net/test/spawned_test_server/local_test_server.cc @@ -167,15 +167,8 @@ bool LocalTestServer::SetPythonPath() const { } third_party_dir = third_party_dir.AppendASCII("third_party"); - // For simplejson. (simplejson, unlike all the other Python modules - // we include, doesn't have an extra 'simplejson' directory, so we - // need to include its parent directory, i.e. third_party_dir). - AppendToPythonPath(third_party_dir); - AppendToPythonPath(third_party_dir.AppendASCII("tlslite")); AppendToPythonPath( - third_party_dir.AppendASCII("pyftpdlib").AppendASCII("src")); - AppendToPythonPath( third_party_dir.AppendASCII("pywebsocket").AppendASCII("src")); // Locate the Python code generated by the protocol buffers compiler. @@ -203,7 +196,7 @@ bool LocalTestServer::AddCommandLineArguments( const std::string& key = it.key(); // Add arguments from a list. - if (value.IsType(base::Value::Type::LIST)) { + if (value.is_list()) { const base::ListValue* list = NULL; if (!value.GetAsList(&list) || !list || list->empty()) return false; diff --git a/chromium/net/test/spawned_test_server/remote_test_server.cc b/chromium/net/test/spawned_test_server/remote_test_server.cc index 6a26cde5f94..8cfe03b20d8 100644 --- a/chromium/net/test/spawned_test_server/remote_test_server.cc +++ b/chromium/net/test/spawned_test_server/remote_test_server.cc @@ -88,6 +88,20 @@ bool RemoteTestServer::StartInBackground() { // pass right server type to Python test server. arguments_dict.SetString("server-type", GetServerTypeString(type())); + // If the server is not on localhost and it's expected to start OCSP server + // then pass OCSP proxy port number, so the server can generate certificates + // for the OCSP server valid for the proxied port. + bool ocsp_server_enabled = + type() == TYPE_HTTPS && (ssl_options().server_certificate == + SSLOptions::CERT_AUTO_AIA_INTERMEDIATE || + !ssl_options().GetOCSPArgument().empty()); + if (config_.address() != IPAddress::IPv4Localhost() && ocsp_server_enabled) { + ocsp_proxy_ = + std::make_unique<RemoteTestServerProxy>(io_thread_.task_runner()); + arguments_dict.SetKey("ocsp-proxy-port-number", + base::Value(ocsp_proxy_->local_port())); + } + // Generate JSON-formatted argument string. std::string arguments_string; base::JSONWriter::Write(arguments_dict, &arguments_string); @@ -104,24 +118,36 @@ bool RemoteTestServer::StartInBackground() { bool RemoteTestServer::BlockUntilStarted() { DCHECK(start_request_); - std::string server_data; - bool request_result = start_request_->WaitForCompletion(&server_data); + std::string server_data_json; + bool request_result = start_request_->WaitForCompletion(&server_data_json); start_request_.reset(); if (!request_result) return false; - // Parse server_data. - if (server_data.empty() || - !SetAndParseServerData(server_data, &remote_port_)) { - LOG(ERROR) << "Could not parse server_data: " << server_data; + // Parse server_data_json. + if (server_data_json.empty() || + !SetAndParseServerData(server_data_json, &remote_port_)) { + LOG(ERROR) << "Could not parse server_data: " << server_data_json; return false; } // If the server is not on localhost then start a proxy on localhost to // forward connections to the server. if (config_.address() != IPAddress::IPv4Localhost()) { - test_server_proxy_ = std::make_unique<RemoteTestServerProxy>( - IPEndPoint(config_.address(), remote_port_), io_thread_.task_runner()); + test_server_proxy_ = + std::make_unique<RemoteTestServerProxy>(io_thread_.task_runner()); + test_server_proxy_->Start(IPEndPoint(config_.address(), remote_port_)); + + if (ocsp_proxy_) { + const base::Value* ocsp_port_value = server_data().FindKey("ocsp_port"); + if (ocsp_port_value && ocsp_port_value->is_int()) { + ocsp_proxy_->Start( + IPEndPoint(config_.address(), ocsp_port_value->GetInt())); + } else { + LOG(WARNING) << "testserver.py didn't return ocsp_port."; + } + } + SetPort(test_server_proxy_->local_port()); } else { SetPort(remote_port_); diff --git a/chromium/net/test/spawned_test_server/remote_test_server.h b/chromium/net/test/spawned_test_server/remote_test_server.h index af75d2f3d27..8a7e430d82d 100644 --- a/chromium/net/test/spawned_test_server/remote_test_server.h +++ b/chromium/net/test/spawned_test_server/remote_test_server.h @@ -93,6 +93,7 @@ class RemoteTestServer : public BaseTestServer { int remote_port_ = 0; std::unique_ptr<RemoteTestServerProxy> test_server_proxy_; + std::unique_ptr<RemoteTestServerProxy> ocsp_proxy_; DISALLOW_COPY_AND_ASSIGN(RemoteTestServer); }; diff --git a/chromium/net/test/spawned_test_server/remote_test_server_proxy.cc b/chromium/net/test/spawned_test_server/remote_test_server_proxy.cc index 70330cba600..86278709a79 100644 --- a/chromium/net/test/spawned_test_server/remote_test_server_proxy.cc +++ b/chromium/net/test/spawned_test_server/remote_test_server_proxy.cc @@ -197,10 +197,16 @@ void ConnectionProxy::Close() { // RemoteTestServerProxy implementation that runs on a background IO thread. class RemoteTestServerProxy::Core { public: - explicit Core(const IPEndPoint& remote_address); + Core(); ~Core(); - void Start(base::WaitableEvent* started_event); + // Creates local socket for accepting incoming connections and binds it to a + // port. local_port() comes valid after this call is complete. + void Initialize(base::WaitableEvent* initialized_event); + + // Starts accepting incoming connections and redirecting them to + // remote_address. Must be called only after Initialize(). + void Start(const IPEndPoint& remote_address); uint16_t local_port() const { return local_port_; } @@ -222,10 +228,12 @@ class RemoteTestServerProxy::Core { DISALLOW_COPY_AND_ASSIGN(Core); }; -RemoteTestServerProxy::Core::Core(const IPEndPoint& remote_address) - : remote_address_(remote_address) {} +RemoteTestServerProxy::Core::Core() {} + +void RemoteTestServerProxy::Core::Initialize( + base::WaitableEvent* initialized_event) { + CHECK(!socket_); -void RemoteTestServerProxy::Core::Start(base::WaitableEvent* started_event) { socket_ = std::make_unique<TCPServerSocket>(nullptr, net::NetLogSource()); int result = socket_->Listen(IPEndPoint(IPAddress::IPv4Localhost(), 0), 5); CHECK_EQ(result, OK); @@ -236,9 +244,14 @@ void RemoteTestServerProxy::Core::Start(base::WaitableEvent* started_event) { CHECK_EQ(result, OK); local_port_ = address.port(); - DoAcceptLoop(); + initialized_event->Signal(); +} + +void RemoteTestServerProxy::Core::Start(const IPEndPoint& remote_address) { + CHECK(socket_); - started_event->Signal(); + remote_address_ = remote_address; + DoAcceptLoop(); } RemoteTestServerProxy::Core::~Core() {} @@ -294,17 +307,16 @@ void RemoteTestServerProxy::Core::OnConnectionClosed( } RemoteTestServerProxy::RemoteTestServerProxy( - const IPEndPoint& remote_address, scoped_refptr<base::SingleThreadTaskRunner> io_task_runner) - : io_task_runner_(io_task_runner), - core_(std::make_unique<Core>(remote_address)) { - base::WaitableEvent started_event( + : io_task_runner_(io_task_runner), core_(std::make_unique<Core>()) { + base::WaitableEvent intialized_event( base::WaitableEvent::ResetPolicy::MANUAL, base::WaitableEvent::InitialState::NOT_SIGNALED); io_task_runner_->PostTask( FROM_HERE, - base::Bind(&Core::Start, base::Unretained(core_.get()), &started_event)); - started_event.Wait(); + base::BindOnce(&Core::Initialize, base::Unretained(core_.get()), + &intialized_event)); + intialized_event.Wait(); local_port_ = core_->local_port(); } @@ -314,4 +326,10 @@ RemoteTestServerProxy::~RemoteTestServerProxy() { io_task_runner_->DeleteSoon(FROM_HERE, core_.release()); } +void RemoteTestServerProxy::Start(const IPEndPoint& remote_address) { + io_task_runner_->PostTask( + FROM_HERE, base::BindOnce(&Core::Start, base::Unretained(core_.get()), + remote_address)); +} + } // namespace net diff --git a/chromium/net/test/spawned_test_server/remote_test_server_proxy.h b/chromium/net/test/spawned_test_server/remote_test_server_proxy.h index 538fcea075e..366e254e100 100644 --- a/chromium/net/test/spawned_test_server/remote_test_server_proxy.h +++ b/chromium/net/test/spawned_test_server/remote_test_server_proxy.h @@ -24,13 +24,16 @@ class IPEndPoint; // address. class RemoteTestServerProxy { public: - RemoteTestServerProxy( - const IPEndPoint& remote_address, + explicit RemoteTestServerProxy( scoped_refptr<base::SingleThreadTaskRunner> io_task_runner); ~RemoteTestServerProxy(); uint16_t local_port() const { return local_port_; } + // Starts the proxy for the specified |remote_address|. Must be called before + // any incoming connection on local_port() are initiated. + void Start(const IPEndPoint& remote_address); + private: class Core; diff --git a/chromium/net/test/spawned_test_server/remote_test_server_proxy_unittests.cc b/chromium/net/test/spawned_test_server/remote_test_server_proxy_unittests.cc index ddb623c13e0..7b3b6b5d110 100644 --- a/chromium/net/test/spawned_test_server/remote_test_server_proxy_unittests.cc +++ b/chromium/net/test/spawned_test_server/remote_test_server_proxy_unittests.cc @@ -35,10 +35,10 @@ class RemoteTestServerProxyTest : public testing::Test { result = listen_socket_->GetLocalAddress(&address); EXPECT_THAT(result, IsOk()); - proxy_ = std::make_unique<RemoteTestServerProxy>(address, - io_thread_.task_runner()); + proxy_ = std::make_unique<RemoteTestServerProxy>(io_thread_.task_runner()); proxy_address_ = IPEndPoint(IPAddress::IPv4Localhost(), proxy_->local_port()); + proxy_->Start(address); } void MakeConnection(std::unique_ptr<StreamSocket>* client_socket, diff --git a/chromium/net/third_party/nss/ssl/cmpcert.cc b/chromium/net/third_party/nss/ssl/cmpcert.cc index 64e482811f7..27ceeb8fd17 100644 --- a/chromium/net/third_party/nss/ssl/cmpcert.cc +++ b/chromium/net/third_party/nss/ssl/cmpcert.cc @@ -35,8 +35,8 @@ bool GetIssuerAndSubject(X509Certificate* cert, der::Input tbs_certificate_tlv; der::Input signature_algorithm_tlv; der::BitString signature_value; - if (!ParseCertificate(der::Input(CRYPTO_BUFFER_data(cert->os_cert_handle()), - CRYPTO_BUFFER_len(cert->os_cert_handle())), + if (!ParseCertificate(der::Input(CRYPTO_BUFFER_data(cert->cert_buffer()), + CRYPTO_BUFFER_len(cert->cert_buffer())), &tbs_certificate_tlv, &signature_algorithm_tlv, &signature_value, nullptr)) { return false; diff --git a/chromium/net/tools/cachetool/cachetool.cc b/chromium/net/tools/cachetool/cachetool.cc index 2c3207f854a..c93f7614479 100644 --- a/chromium/net/tools/cachetool/cachetool.cc +++ b/chromium/net/tools/cachetool/cachetool.cc @@ -194,7 +194,7 @@ class ProgramArgumentCommandMarshal final : public CommandMarshal { // Implements CommandMarshal. void ReturnBuffer(net::GrowableIOBuffer* buffer) override { DCHECK(!has_failed()); - std::cout.write(buffer->data(), buffer->offset()); + std::cout.write(buffer->StartOfBuffer(), buffer->offset()); } // Implements CommandMarshal. diff --git a/chromium/net/tools/cert_verify_tool/verify_using_cert_verify_proc.cc b/chromium/net/tools/cert_verify_tool/verify_using_cert_verify_proc.cc index 24e92313713..38f7c18fe4e 100644 --- a/chromium/net/tools/cert_verify_tool/verify_using_cert_verify_proc.cc +++ b/chromium/net/tools/cert_verify_tool/verify_using_cert_verify_proc.cc @@ -6,6 +6,7 @@ #include <iostream> +#include "base/strings/strcat.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" @@ -15,6 +16,7 @@ #include "net/cert/cert_verify_proc.h" #include "net/cert/cert_verify_result.h" #include "net/cert/x509_certificate.h" +#include "net/cert/x509_util.h" #include "net/tools/cert_verify_tool/cert_verify_tool_util.h" namespace { @@ -40,12 +42,11 @@ bool DumpX509CertificateChain(const base::FilePath& file_path, std::cerr << "ERROR: X509Certificate::GetPEMEncodedChain failed.\n"; return false; } - return WriteToFile(file_path, base::JoinString(pem_encoded, "")); + return WriteToFile(file_path, base::StrCat(pem_encoded)); } // Returns a hex-encoded sha256 of the DER-encoding of |cert_handle|. -std::string FingerPrintOSCertHandle( - net::X509Certificate::OSCertHandle cert_handle) { +std::string FingerPrintCryptoBuffer(const CRYPTO_BUFFER* cert_handle) { net::SHA256HashValue hash = net::X509Certificate::CalculateFingerprint256(cert_handle); return base::HexEncode(hash.data, arraysize(hash.data)); @@ -57,11 +58,10 @@ std::string SubjectFromX509Certificate(const net::X509Certificate* cert) { } // Returns a textual representation of the Subject of |cert_handle|. -std::string SubjectFromOSCertHandle( - net::X509Certificate::OSCertHandle cert_handle) { +std::string SubjectFromCryptoBuffer(CRYPTO_BUFFER* cert_handle) { scoped_refptr<net::X509Certificate> cert = - net::X509Certificate::CreateFromHandle( - cert_handle, net::X509Certificate::OSCertHandles()); + net::X509Certificate::CreateFromBuffer( + net::x509_util::DupCryptoBuffer(cert_handle), {}); if (!cert) return std::string(); return SubjectFromX509Certificate(cert.get()); @@ -97,12 +97,13 @@ void PrintCertVerifyResult(const net::CertVerifyResult& result) { if (result.verified_cert) { std::cout << "chain:\n " - << FingerPrintOSCertHandle(result.verified_cert->os_cert_handle()) + << FingerPrintCryptoBuffer(result.verified_cert->cert_buffer()) << " " << SubjectFromX509Certificate(result.verified_cert.get()) << "\n"; - for (auto* os_cert : result.verified_cert->GetIntermediateCertificates()) { - std::cout << " " << FingerPrintOSCertHandle(os_cert) << " " - << SubjectFromOSCertHandle(os_cert) << "\n"; + for (const auto& intermediate : + result.verified_cert->intermediate_buffers()) { + std::cout << " " << FingerPrintCryptoBuffer(intermediate.get()) << " " + << SubjectFromCryptoBuffer(intermediate.get()) << "\n"; } } } diff --git a/chromium/net/tools/ct_log_list/PRESUBMIT.py b/chromium/net/tools/ct_log_list/PRESUBMIT.py index ff9bf5c1830..ed1da40b331 100644 --- a/chromium/net/tools/ct_log_list/PRESUBMIT.py +++ b/chromium/net/tools/ct_log_list/PRESUBMIT.py @@ -8,10 +8,12 @@ def _RunMakeCTLogListTests(input_api, output_api): """Runs make_ct_known_logs_list unittests if related files were modified.""" - files = ('net/tools/ct_log_list/make_ct_known_logs_list.py', - 'net/tools/ct_log_list/make_ct_known_logs_list_unittest.py', - 'net/data/ssl/certificate_transparency/log_list.json') - if not any(f in input_api.LocalPaths() for f in files): + files = (input_api.os_path.normpath(x) for x in + ('net/tools/ct_log_list/make_ct_known_logs_list.py', + 'net/tools/ct_log_list/make_ct_known_logs_list_unittest.py', + 'net/data/ssl/certificate_transparency/log_list.json')) + if not any(f in (af.LocalPath() for af in input_api.change.AffectedFiles()) + for f in files): return [] test_path = input_api.os_path.join(input_api.PresubmitLocalPath(), 'make_ct_known_logs_list_unittest.py') @@ -31,4 +33,3 @@ def CheckChangeOnUpload(input_api, output_api): def CheckChangeOnCommit(input_api, output_api): return _RunMakeCTLogListTests(input_api, output_api) - diff --git a/chromium/net/tools/quic/chlo_extractor.cc b/chromium/net/tools/quic/chlo_extractor.cc index 38cb9893f31..4d71aa7f50c 100644 --- a/chromium/net/tools/quic/chlo_extractor.cc +++ b/chromium/net/tools/quic/chlo_extractor.cc @@ -26,7 +26,7 @@ class ChloFramerVisitor : public QuicFramerVisitorInterface, // QuicFramerVisitorInterface implementation void OnError(QuicFramer* framer) override {} - bool OnProtocolVersionMismatch(QuicTransportVersion version) override; + bool OnProtocolVersionMismatch(ParsedQuicVersion version) override; void OnPacket() override {} void OnPublicResetPacket(const QuicPublicResetPacket& packet) override {} void OnVersionNegotiationPacket( @@ -67,8 +67,7 @@ ChloFramerVisitor::ChloFramerVisitor(QuicFramer* framer, found_chlo_(false), connection_id_(0) {} -bool ChloFramerVisitor::OnProtocolVersionMismatch( - QuicTransportVersion version) { +bool ChloFramerVisitor::OnProtocolVersionMismatch(ParsedQuicVersion version) { if (!framer_->IsSupportedVersion(version)) { return false; } @@ -153,7 +152,7 @@ void ChloFramerVisitor::OnHandshakeMessage( // static bool ChloExtractor::Extract(const QuicEncryptedPacket& packet, - const QuicTransportVersionVector& versions, + const ParsedQuicVersionVector& versions, Delegate* delegate) { QuicFramer framer(versions, QuicTime::Zero(), Perspective::IS_SERVER); ChloFramerVisitor visitor(&framer, delegate); diff --git a/chromium/net/tools/quic/chlo_extractor.h b/chromium/net/tools/quic/chlo_extractor.h index 6ad12c5fed3..b56df49aa26 100644 --- a/chromium/net/tools/quic/chlo_extractor.h +++ b/chromium/net/tools/quic/chlo_extractor.h @@ -28,7 +28,7 @@ class ChloExtractor { // of |delegate|. Return true if a CHLO message was found, and false // otherwise. static bool Extract(const QuicEncryptedPacket& packet, - const QuicTransportVersionVector& versions, + const ParsedQuicVersionVector& versions, Delegate* delegate); ChloExtractor(const ChloExtractor&) = delete; diff --git a/chromium/net/tools/quic/chlo_extractor_test.cc b/chromium/net/tools/quic/chlo_extractor_test.cc index 4fdd591a3ee..169288712a9 100644 --- a/chromium/net/tools/quic/chlo_extractor_test.cc +++ b/chromium/net/tools/quic/chlo_extractor_test.cc @@ -46,7 +46,7 @@ class ChloExtractorTest : public QuicTest { header_.connection_id = 42; header_.connection_id_length = PACKET_8BYTE_CONNECTION_ID; header_.version_flag = true; - header_.version = AllSupportedTransportVersions().front(); + header_.version = AllSupportedVersions().front(); header_.reset_flag = false; header_.packet_number_length = PACKET_6BYTE_PACKET_NUMBER; header_.packet_number = 1; @@ -56,8 +56,8 @@ class ChloExtractorTest : public QuicTest { QuicFrame frame(stream_frame); QuicFrames frames; frames.push_back(frame); - QuicFramer framer(SupportedTransportVersions(header_.version), - QuicTime::Zero(), Perspective::IS_CLIENT); + QuicFramer framer(SupportedVersions(header_.version), QuicTime::Zero(), + Perspective::IS_CLIENT); std::unique_ptr<QuicPacket> packet( BuildUnsizedDataPacket(&framer, header_, frames)); EXPECT_TRUE(packet != nullptr); @@ -85,18 +85,18 @@ TEST_F(ChloExtractorTest, FindsValidChlo) { .AsStringPiece() .as_string()); // Construct a CHLO with each supported version - for (QuicTransportVersion version : AllSupportedTransportVersions()) { - QuicTransportVersionVector versions(SupportedTransportVersions(version)); + for (ParsedQuicVersion version : AllSupportedVersions()) { + ParsedQuicVersionVector versions(SupportedVersions(version)); header_.version = version; MakePacket( new QuicStreamFrame(kCryptoStreamId, false, 0, client_hello_str)); EXPECT_TRUE(ChloExtractor::Extract(*packet_, versions, &delegate_)) - << QuicVersionToString(version); - EXPECT_EQ(version, delegate_.transport_version()); + << ParsedQuicVersionToString(version); + EXPECT_EQ(version.transport_version, delegate_.transport_version()); EXPECT_EQ(header_.connection_id, delegate_.connection_id()); EXPECT_EQ(client_hello.DebugString(Perspective::IS_SERVER), delegate_.chlo()) - << QuicVersionToString(version); + << ParsedQuicVersionToString(version); } } @@ -109,8 +109,8 @@ TEST_F(ChloExtractorTest, DoesNotFindValidChloOnWrongStream) { .as_string()); MakePacket( new QuicStreamFrame(kCryptoStreamId + 1, false, 0, client_hello_str)); - EXPECT_FALSE(ChloExtractor::Extract(*packet_, AllSupportedTransportVersions(), - &delegate_)); + EXPECT_FALSE( + ChloExtractor::Extract(*packet_, AllSupportedVersions(), &delegate_)); } TEST_F(ChloExtractorTest, DoesNotFindValidChloOnWrongOffset) { @@ -121,14 +121,14 @@ TEST_F(ChloExtractorTest, DoesNotFindValidChloOnWrongOffset) { .AsStringPiece() .as_string()); MakePacket(new QuicStreamFrame(kCryptoStreamId, false, 1, client_hello_str)); - EXPECT_FALSE(ChloExtractor::Extract(*packet_, AllSupportedTransportVersions(), - &delegate_)); + EXPECT_FALSE( + ChloExtractor::Extract(*packet_, AllSupportedVersions(), &delegate_)); } TEST_F(ChloExtractorTest, DoesNotFindInvalidChlo) { MakePacket(new QuicStreamFrame(kCryptoStreamId, false, 0, "foo")); - EXPECT_FALSE(ChloExtractor::Extract(*packet_, AllSupportedTransportVersions(), - &delegate_)); + EXPECT_FALSE( + ChloExtractor::Extract(*packet_, AllSupportedVersions(), &delegate_)); } } // namespace diff --git a/chromium/net/tools/quic/end_to_end_test.cc b/chromium/net/tools/quic/end_to_end_test.cc index ceeca25dd90..053e63f6bbb 100644 --- a/chromium/net/tools/quic/end_to_end_test.cc +++ b/chromium/net/tools/quic/end_to_end_test.cc @@ -56,6 +56,7 @@ #include "net/tools/quic/quic_server.h" #include "net/tools/quic/quic_simple_server_stream.h" #include "net/tools/quic/quic_spdy_client_stream.h" +#include "net/tools/quic/test_tools/bad_packet_writer.h" #include "net/tools/quic/test_tools/packet_dropping_test_writer.h" #include "net/tools/quic/test_tools/packet_reordering_writer.h" #include "net/tools/quic/test_tools/quic_client_peer.h" @@ -80,9 +81,9 @@ const float kSessionToStreamRatio = 1.5; // Run all tests with the cross products of all versions. struct TestParams { - TestParams(const QuicTransportVersionVector& client_supported_versions, - const QuicTransportVersionVector& server_supported_versions, - QuicTransportVersion negotiated_version, + TestParams(const ParsedQuicVersionVector& client_supported_versions, + const ParsedQuicVersionVector& server_supported_versions, + ParsedQuicVersion negotiated_version, bool client_supports_stateless_rejects, bool server_uses_stateless_rejects_if_peer_supported, QuicTag congestion_control_tag, @@ -100,10 +101,11 @@ struct TestParams { friend std::ostream& operator<<(std::ostream& os, const TestParams& p) { os << "{ server_supported_versions: " - << QuicTransportVersionVectorToString(p.server_supported_versions); + << ParsedQuicVersionVectorToString(p.server_supported_versions); os << " client_supported_versions: " - << QuicTransportVersionVectorToString(p.client_supported_versions); - os << " negotiated_version: " << QuicVersionToString(p.negotiated_version); + << ParsedQuicVersionVectorToString(p.client_supported_versions); + os << " negotiated_version: " + << ParsedQuicVersionToString(p.negotiated_version); os << " client_supports_stateless_rejects: " << p.client_supports_stateless_rejects; os << " server_uses_stateless_rejects_if_peer_supported: " @@ -116,9 +118,9 @@ struct TestParams { return os; } - QuicTransportVersionVector client_supported_versions; - QuicTransportVersionVector server_supported_versions; - QuicTransportVersion negotiated_version; + ParsedQuicVersionVector client_supported_versions; + ParsedQuicVersionVector server_supported_versions; + ParsedQuicVersion negotiated_version; bool client_supports_stateless_rejects; bool server_uses_stateless_rejects_if_peer_supported; QuicTag congestion_control_tag; @@ -136,13 +138,12 @@ std::vector<TestParams> GetTestParams() { // these tests need to ensure that clients are never attempting // to do 0-RTT across incompatible versions. Chromium only supports // a single version at a time anyway. :) - QuicTransportVersionVector all_supported_versions = - AllSupportedTransportVersions(); + ParsedQuicVersionVector all_supported_versions = AllSupportedVersions(); // Even though this currently has one element, it may well get another // with future versions of QUIC, so don't remove it. - QuicTransportVersionVector version_buckets[1]; + ParsedQuicVersionVector version_buckets[1]; - for (const QuicTransportVersion version : all_supported_versions) { + for (const ParsedQuicVersion version : all_supported_versions) { // Versions: 35+ // QUIC_VERSION_35 allows endpoints to independently set stream limit. version_buckets[0].push_back(version); @@ -186,10 +187,10 @@ std::vector<TestParams> GetTestParams() { continue; } - for (const QuicTransportVersionVector& client_versions : + for (const ParsedQuicVersionVector& client_versions : version_buckets) { CHECK(!client_versions.empty()); - if (FilterSupportedTransportVersions(client_versions).empty()) { + if (FilterSupportedVersions(client_versions).empty()) { continue; } // Add an entry for server and client supporting all @@ -214,9 +215,9 @@ std::vector<TestParams> GetTestParams() { // occur. Skip the i = 0 case because it is essentially the // same as the default case. for (size_t i = 1; i < client_versions.size(); ++i) { - QuicTransportVersionVector server_supported_versions; + ParsedQuicVersionVector server_supported_versions; server_supported_versions.push_back(client_versions[i]); - if (FilterSupportedTransportVersions(server_supported_versions) + if (FilterSupportedVersions(server_supported_versions) .empty()) { continue; } @@ -271,6 +272,7 @@ class EndToEndTest : public QuicTestWithParam<TestParams> { client_writer_(nullptr), server_writer_(nullptr), server_started_(false), + negotiated_version_(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED), chlo_multiplier_(0), stream_factory_(nullptr), support_server_push_(false) { @@ -376,17 +378,8 @@ class EndToEndTest : public QuicTestWithParam<TestParams> { // TODO(nimia): Consider setting the congestion control algorithm for the // client as well according to the test parameter. copt.push_back(GetParam().congestion_control_tag); - if (GetParam().congestion_control_tag == kQBIC) { - copt.push_back(kCCVX); - } - if (GetParam().congestion_control_tag == kQBIC) { - copt.push_back(kCBQT); - } - if (GetParam().congestion_control_tag == kQBIC) { - copt.push_back(kCPAU); - } if (GetParam().congestion_control_tag == kTPCC && - FLAGS_quic_reloadable_flag_quic_enable_pcc) { + GetQuicReloadableFlag(quic_enable_pcc)) { copt.push_back(kTPCC); } @@ -433,8 +426,8 @@ class EndToEndTest : public QuicTestWithParam<TestParams> { } void StartServer() { - FLAGS_quic_reloadable_flag_quic_use_cheap_stateless_rejects = - GetParam().use_cheap_stateless_reject; + SetQuicReloadableFlag(quic_use_cheap_stateless_rejects, + GetParam().use_cheap_stateless_reject); auto* test_server = new QuicTestServer( crypto_test_utils::ProofSourceForTesting(), server_config_, @@ -450,8 +443,9 @@ class EndToEndTest : public QuicTestWithParam<TestParams> { QuicServerPeer::GetDispatcher(server_thread_->server()); QuicDispatcherPeer::UseWriter(dispatcher, server_writer_); - FLAGS_quic_reloadable_flag_enable_quic_stateless_reject_support = - GetParam().server_uses_stateless_rejects_if_peer_supported; + SetQuicReloadableFlag( + enable_quic_stateless_reject_support, + GetParam().server_uses_stateless_rejects_if_peer_supported); server_writer_->Initialize(QuicDispatcherPeer::GetHelper(dispatcher), QuicDispatcherPeer::GetAlarmFactory(dispatcher), @@ -513,7 +507,7 @@ class EndToEndTest : public QuicTestWithParam<TestParams> { client_->client()->client_session()->connection()->GetStats(); // TODO(ianswett): Determine why this becomes even more flaky with BBR // enabled. b/62141144 - if (!had_packet_loss && !FLAGS_quic_reloadable_flag_quic_default_to_bbr) { + if (!had_packet_loss && !GetQuicReloadableFlag(quic_default_to_bbr)) { EXPECT_EQ(0u, client_stats.packets_lost); } EXPECT_EQ(0u, client_stats.packets_discarded); @@ -587,10 +581,10 @@ class EndToEndTest : public QuicTestWithParam<TestParams> { bool server_started_; QuicConfig client_config_; QuicConfig server_config_; - QuicTransportVersionVector client_supported_versions_; - QuicTransportVersionVector server_supported_versions_; + ParsedQuicVersionVector client_supported_versions_; + ParsedQuicVersionVector server_supported_versions_; QuicTagVector client_extra_copts_; - QuicTransportVersion negotiated_version_; + ParsedQuicVersion negotiated_version_; size_t chlo_multiplier_; QuicTestServer::StreamFactory* stream_factory_; bool support_server_push_; @@ -1789,7 +1783,7 @@ TEST_P(EndToEndTest, FlowControlsSynced) { QuicSpdySessionPeer::GetHeadersStream(client_session)->flow_controller(); QuicFlowController* server_header_stream_flow_controller = QuicSpdySessionPeer::GetHeadersStream(server_session)->flow_controller(); - if (FLAGS_quic_reloadable_flag_quic_send_max_header_list_size) { + if (GetQuicReloadableFlag(quic_send_max_header_list_size)) { // Both client and server are sending this SETTINGS frame, and the send // window is consumed. But because of timing issue, the server may send or // not send the frame, and the client may send/ not send / receive / not @@ -1813,7 +1807,7 @@ TEST_P(EndToEndTest, FlowControlsSynced) { ->flow_controller()); } - if (FLAGS_quic_reloadable_flag_quic_send_max_header_list_size) { + if (GetQuicReloadableFlag(quic_send_max_header_list_size)) { // Client *may* have received the SETTINGs frame. // TODO(fayang): Rewrite this part because it is hacky. float ratio1 = static_cast<float>(QuicFlowControllerPeer::ReceiveWindowSize( @@ -2401,7 +2395,7 @@ class MockableQuicClientThatDropsBody : public MockableQuicClient { QuicSocketAddress server_address, const QuicServerId& server_id, const QuicConfig& config, - const QuicTransportVersionVector& supported_versions, + const ParsedQuicVersionVector& supported_versions, EpollServer* epoll_server) : MockableQuicClient(server_address, server_id, @@ -2420,11 +2414,10 @@ class MockableQuicClientThatDropsBody : public MockableQuicClient { class QuicTestClientThatDropsBody : public QuicTestClient { public: - QuicTestClientThatDropsBody( - QuicSocketAddress server_address, - const string& server_hostname, - const QuicConfig& config, - const QuicTransportVersionVector& supported_versions) + QuicTestClientThatDropsBody(QuicSocketAddress server_address, + const string& server_hostname, + const QuicConfig& config, + const ParsedQuicVersionVector& supported_versions) : QuicTestClient(server_address, server_hostname, config, @@ -2935,8 +2928,6 @@ class WindowUpdateObserver : public QuicConnectionDebugVisitor { }; TEST_P(EndToEndTest, WindowUpdateInAck) { - FLAGS_quic_reloadable_flag_quic_enable_version_38 = true; - FLAGS_quic_reloadable_flag_quic_enable_version_39 = true; ASSERT_TRUE(Initialize()); EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); WindowUpdateObserver observer; @@ -2966,13 +2957,30 @@ TEST_P(EndToEndTest, SendStatelessResetTokenInShlo) { ASSERT_TRUE(Initialize()); EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); QuicConfig* config = client_->client()->session()->config(); - if (FLAGS_quic_reloadable_flag_quic_send_reset_token_in_shlo) { - EXPECT_TRUE(config->HasReceivedStatelessResetToken()); - EXPECT_EQ(1010101u, config->ReceivedStatelessResetToken()); - } + EXPECT_TRUE(config->HasReceivedStatelessResetToken()); + EXPECT_EQ(1010101u, config->ReceivedStatelessResetToken()); client_->Disconnect(); } +// Regression test of b/70782529. +TEST_P(EndToEndTest, DoNotCrashOnPacketWriteError) { + ASSERT_TRUE(Initialize()); + BadPacketWriter* bad_writer = + new BadPacketWriter(/*packet_causing_write_error=*/5, + /*error_code=*/90); + std::unique_ptr<QuicTestClient> client(CreateQuicClient(bad_writer)); + + // 1 MB body. + string body(1024 * 1024, 'a'); + SpdyHeaderBlock headers; + headers[":method"] = "POST"; + headers[":path"] = "/foo"; + headers[":scheme"] = "https"; + headers[":authority"] = server_hostname_; + + client->SendCustomSynchronousRequest(headers, body); +} + class EndToEndBufferedPacketsTest : public EndToEndTest { public: void CreateClientWithWriter() override { diff --git a/chromium/net/tools/quic/quic_client.cc b/chromium/net/tools/quic/quic_client.cc index ee4e5847abf..49af6ae8a59 100644 --- a/chromium/net/tools/quic/quic_client.cc +++ b/chromium/net/tools/quic/quic_client.cc @@ -37,7 +37,7 @@ namespace net { QuicClient::QuicClient(QuicSocketAddress server_address, const QuicServerId& server_id, - const QuicTransportVersionVector& supported_versions, + const ParsedQuicVersionVector& supported_versions, EpollServer* epoll_server, std::unique_ptr<ProofVerifier> proof_verifier) : QuicClient( @@ -52,7 +52,7 @@ QuicClient::QuicClient(QuicSocketAddress server_address, QuicClient::QuicClient( QuicSocketAddress server_address, const QuicServerId& server_id, - const QuicTransportVersionVector& supported_versions, + const ParsedQuicVersionVector& supported_versions, EpollServer* epoll_server, std::unique_ptr<QuicClientEpollNetworkHelper> network_helper, std::unique_ptr<ProofVerifier> proof_verifier) @@ -67,7 +67,7 @@ QuicClient::QuicClient( QuicClient::QuicClient( QuicSocketAddress server_address, const QuicServerId& server_id, - const QuicTransportVersionVector& supported_versions, + const ParsedQuicVersionVector& supported_versions, const QuicConfig& config, EpollServer* epoll_server, std::unique_ptr<QuicClientEpollNetworkHelper> network_helper, diff --git a/chromium/net/tools/quic/quic_client.h b/chromium/net/tools/quic/quic_client.h index 278d3b712b7..031cdff92ea 100644 --- a/chromium/net/tools/quic/quic_client.h +++ b/chromium/net/tools/quic/quic_client.h @@ -39,19 +39,19 @@ class QuicClient : public QuicSpdyClientBase { // This will create its own QuicClientEpollNetworkHelper. QuicClient(QuicSocketAddress server_address, const QuicServerId& server_id, - const QuicTransportVersionVector& supported_versions, + const ParsedQuicVersionVector& supported_versions, EpollServer* epoll_server, std::unique_ptr<ProofVerifier> proof_verifier); // This will take ownership of a passed in network primitive. QuicClient(QuicSocketAddress server_address, const QuicServerId& server_id, - const QuicTransportVersionVector& supported_versions, + const ParsedQuicVersionVector& supported_versions, EpollServer* epoll_server, std::unique_ptr<QuicClientEpollNetworkHelper> network_helper, std::unique_ptr<ProofVerifier> proof_verifier); QuicClient(QuicSocketAddress server_address, const QuicServerId& server_id, - const QuicTransportVersionVector& supported_versions, + const ParsedQuicVersionVector& supported_versions, const QuicConfig& config, EpollServer* epoll_server, std::unique_ptr<QuicClientEpollNetworkHelper> network_helper, diff --git a/chromium/net/tools/quic/quic_client_base.cc b/chromium/net/tools/quic/quic_client_base.cc index 0ef9999d78b..310a5c01b9d 100644 --- a/chromium/net/tools/quic/quic_client_base.cc +++ b/chromium/net/tools/quic/quic_client_base.cc @@ -7,6 +7,7 @@ #include "net/quic/core/crypto/quic_random.h" #include "net/quic/core/quic_server_id.h" #include "net/quic/core/spdy_utils.h" +#include "net/quic/core/tls_client_handshaker.h" #include "net/quic/platform/api/quic_flags.h" #include "net/quic/platform/api/quic_logging.h" #include "net/quic/platform/api/quic_text_utils.h" @@ -20,7 +21,7 @@ QuicClientBase::NetworkHelper::~NetworkHelper() = default; QuicClientBase::QuicClientBase( const QuicServerId& server_id, - const QuicTransportVersionVector& supported_versions, + const ParsedQuicVersionVector& supported_versions, const QuicConfig& config, QuicConnectionHelperInterface* helper, QuicAlarmFactory* alarm_factory, @@ -30,7 +31,8 @@ QuicClientBase::QuicClientBase( initialized_(false), local_port_(0), config_(config), - crypto_config_(std::move(proof_verifier)), + crypto_config_(std::move(proof_verifier), + TlsClientHandshaker::CreateSslCtx()), helper_(helper), alarm_factory_(alarm_factory), supported_versions_(supported_versions), @@ -81,7 +83,7 @@ bool QuicClientBase::Connect() { while (EncryptionBeingEstablished()) { WaitForEvents(); } - if (FLAGS_quic_reloadable_flag_enable_quic_stateless_reject_support && + if (GetQuicReloadableFlag(enable_quic_stateless_reject_support) && connected()) { // Resend any previously queued data. ResendSavedData(); @@ -169,7 +171,7 @@ bool QuicClientBase::WaitForEvents() { DCHECK(session() != nullptr); if (!connected() && session()->error() == QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) { - DCHECK(FLAGS_quic_reloadable_flag_enable_quic_stateless_reject_support); + DCHECK(GetQuicReloadableFlag(enable_quic_stateless_reject_support)); QUIC_DLOG(INFO) << "Detected stateless reject while waiting for events. " << "Attempting to reconnect."; Connect(); diff --git a/chromium/net/tools/quic/quic_client_base.h b/chromium/net/tools/quic/quic_client_base.h index db021899351..cb26051945c 100644 --- a/chromium/net/tools/quic/quic_client_base.h +++ b/chromium/net/tools/quic/quic_client_base.h @@ -59,7 +59,7 @@ class QuicClientBase { }; QuicClientBase(const QuicServerId& server_id, - const QuicTransportVersionVector& supported_versions, + const ParsedQuicVersionVector& supported_versions, const QuicConfig& config, QuicConnectionHelperInterface* helper, QuicAlarmFactory* alarm_factory, @@ -142,12 +142,11 @@ class QuicClientBase { crypto_config_.tb_key_params = QuicTagVector{kTB10}; } - const QuicTransportVersionVector& supported_versions() const { + const ParsedQuicVersionVector& supported_versions() const { return supported_versions_; } - void SetSupportedTransportVersions( - const QuicTransportVersionVector& versions) { + void SetSupportedVersions(const ParsedQuicVersionVector& versions) { supported_versions_ = versions; } @@ -207,10 +206,6 @@ class QuicClientBase { } void reset_writer() { writer_.reset(); } - QuicByteCount initial_max_packet_length() { - return initial_max_packet_length_; - } - ProofVerifier* proof_verifier() const; void set_bind_to_address(QuicIpAddress address) { @@ -278,14 +273,6 @@ class QuicClientBase { QuicAlarmFactory* alarm_factory() { return alarm_factory_.get(); } - void set_num_sent_client_hellos(int num_sent_client_hellos) { - num_sent_client_hellos_ = num_sent_client_hellos; - } - - void set_num_stateless_rejects_received(int num_stateless_rejects_received) { - num_stateless_rejects_received_ = num_stateless_rejects_received; - } - // Subclasses may need to explicitly clear the session on destruction // if they create it with objects that will be destroyed before this is. // You probably want to call this if you override CreateQuicSpdyClientSession. @@ -329,7 +316,7 @@ class QuicClientBase { // element, with subsequent elements in descending order (versions can be // skipped as necessary). We will always pick supported_versions_[0] as the // initial version to use. - QuicTransportVersionVector supported_versions_; + ParsedQuicVersionVector supported_versions_; // The initial value of maximum packet size of the connection. If set to // zero, the default is used. diff --git a/chromium/net/tools/quic/quic_client_bin.cc b/chromium/net/tools/quic/quic_client_bin.cc index 583620c55b4..d5c43714a0b 100644 --- a/chromium/net/tools/quic/quic_client_bin.cc +++ b/chromium/net/tools/quic/quic_client_bin.cc @@ -255,12 +255,12 @@ int main(int argc, char* argv[]) { net::EpollServer epoll_server; net::QuicServerId server_id(url.host(), url.port(), net::PRIVACY_MODE_DISABLED); - net::QuicTransportVersionVector versions = - net::AllSupportedTransportVersions(); + net::ParsedQuicVersionVector versions = net::AllSupportedVersions(); if (FLAGS_quic_version != -1) { versions.clear(); - versions.push_back( - static_cast<net::QuicTransportVersion>(FLAGS_quic_version)); + versions.push_back(net::ParsedQuicVersion( + net::PROTOCOL_QUIC_CRYPTO, + static_cast<net::QuicTransportVersion>(FLAGS_quic_version))); } // For secure QUIC we need to verify the cert chain. std::unique_ptr<CertVerifier> cert_verifier(CertVerifier::CreateDefault()); @@ -289,7 +289,7 @@ int main(int argc, char* argv[]) { net::QuicErrorCode error = client.session()->error(); if (FLAGS_version_mismatch_ok && error == net::QUIC_INVALID_VERSION) { cout << "Server talks QUIC, but none of the versions supported by " - << "this client: " << QuicTransportVersionVectorToString(versions) + << "this client: " << ParsedQuicVersionVectorToString(versions) << endl; // Version mismatch is not deemed a failure. return 0; diff --git a/chromium/net/tools/quic/quic_client_test.cc b/chromium/net/tools/quic/quic_client_test.cc index 941996cb21b..e9b7e5d6d21 100644 --- a/chromium/net/tools/quic/quic_client_test.cc +++ b/chromium/net/tools/quic/quic_client_test.cc @@ -53,7 +53,7 @@ QuicClient* CreateAndInitializeQuicClient(EpollServer* eps, uint16_t port) { QuicSocketAddress server_address(QuicSocketAddress(TestLoopback(), port)); QuicServerId server_id("hostname", server_address.port(), PRIVACY_MODE_DISABLED); - QuicTransportVersionVector versions = AllSupportedTransportVersions(); + ParsedQuicVersionVector versions = AllSupportedVersions(); QuicClient* client = new QuicClient(server_address, server_id, versions, eps, crypto_test_utils::ProofVerifierForTesting()); diff --git a/chromium/net/tools/quic/quic_dispatcher.cc b/chromium/net/tools/quic/quic_dispatcher.cc index 3d1188dc15f..a5214d53826 100644 --- a/chromium/net/tools/quic/quic_dispatcher.cc +++ b/chromium/net/tools/quic/quic_dispatcher.cc @@ -56,7 +56,7 @@ class PacketCollector : public QuicPacketCreator::DelegateInterface, explicit PacketCollector(QuicBufferAllocator* allocator) : send_buffer_( allocator, - FLAGS_quic_reloadable_flag_quic_allow_multiple_acks_for_data2) {} + GetQuicReloadableFlag(quic_allow_multiple_acks_for_data2)) {} ~PacketCollector() override = default; // QuicPacketCreator::DelegateInterface methods: @@ -140,7 +140,7 @@ class StatelessConnectionTerminator { creator_.Flush(); DCHECK_EQ(1u, collector_.packets()->size()); time_wait_list_manager_->AddConnectionIdToTimeWait( - connection_id_, framer_->transport_version(), + connection_id_, framer_->version(), /*connection_rejected_statelessly=*/false, collector_.packets()); } @@ -166,7 +166,7 @@ class StatelessConnectionTerminator { creator_.Flush(); } time_wait_list_manager_->AddConnectionIdToTimeWait( - connection_id_, framer_->transport_version(), + connection_id_, framer_->version(), /*connection_rejected_statelessly=*/true, collector_.packets()); DCHECK(time_wait_list_manager_->IsConnectionIdInTimeWait(connection_id_)); } @@ -257,7 +257,7 @@ QuicDispatcher::QuicDispatcher( buffered_packets_(this, helper_->GetClock(), alarm_factory_.get()), current_packet_(nullptr), version_manager_(version_manager), - framer_(GetSupportedTransportVersions(), + framer_(GetSupportedVersions(), /*unused*/ QuicTime::Zero(), Perspective::IS_SERVER), last_error_(QUIC_NO_ERROR), @@ -355,12 +355,12 @@ bool QuicDispatcher::OnUnauthenticatedPublicHeader( // Unless the packet provides a version, assume that we can continue // processing using our preferred version. - QuicTransportVersion version = GetSupportedTransportVersions().front(); + ParsedQuicVersion version = GetSupportedVersions().front(); if (header.version_flag) { - QuicTransportVersion packet_version = header.version; - if (framer_.supported_versions() != GetSupportedTransportVersions()) { + ParsedQuicVersion packet_version = header.version; + if (framer_.supported_versions() != GetSupportedVersions()) { // Reset framer's version if version flags change in flight. - framer_.SetSupportedTransportVersions(GetSupportedTransportVersions()); + framer_.SetSupportedVersions(GetSupportedVersions()); } if (!framer_.IsSupportedVersion(packet_version)) { if (ShouldCreateSessionForUnknownVersion(framer_.last_version_label())) { @@ -369,8 +369,8 @@ bool QuicDispatcher::OnUnauthenticatedPublicHeader( // Since the version is not supported, send a version negotiation // packet and stop processing the current packet. time_wait_list_manager()->SendVersionNegotiationPacket( - connection_id, GetSupportedTransportVersions(), - current_server_address_, current_client_address_); + connection_id, GetSupportedVersions(), current_server_address_, + current_client_address_); return false; } version = packet_version; @@ -416,14 +416,14 @@ void QuicDispatcher::ProcessUnauthenticatedHeaderFate( case kFateTimeWait: // MaybeRejectStatelessly or OnExpiredPackets might have already added the // connection to time wait, in which case it should not be added again. - if (!FLAGS_quic_reloadable_flag_quic_use_cheap_stateless_rejects || + if (!GetQuicReloadableFlag(quic_use_cheap_stateless_rejects) || !time_wait_list_manager_->IsConnectionIdInTimeWait(connection_id)) { // Add this connection_id to the time-wait state, to safely reject // future packets. QUIC_DLOG(INFO) << "Adding connection ID " << connection_id << "to time-wait list."; time_wait_list_manager_->AddConnectionIdToTimeWait( - connection_id, framer_.transport_version(), + connection_id, framer_.version(), /*connection_rejected_statelessly=*/false, nullptr); } DCHECK(time_wait_list_manager_->IsConnectionIdInTimeWait(connection_id)); @@ -475,7 +475,7 @@ QuicDispatcher::QuicPacketFate QuicDispatcher::ValidityChecks( if (header.packet_number == kInvalidPacketNumber) { return kFateTimeWait; } - if (FLAGS_quic_restart_flag_quic_enable_accept_random_ipn) { + if (GetQuicRestartFlag(quic_enable_accept_random_ipn)) { QUIC_FLAG_COUNT_N(quic_restart_flag_quic_enable_accept_random_ipn, 1, 2); // Accepting Initial Packet Numbers in 1...((2^31)-1) range... check // maximum accordingly. @@ -508,7 +508,7 @@ void QuicDispatcher::CleanUpSession(SessionMap::iterator it, !connection->termination_packets()->empty()); } time_wait_list_manager_->AddConnectionIdToTimeWait( - it->first, connection->transport_version(), should_close_statelessly, + it->first, connection->version(), should_close_statelessly, connection->termination_packets()); session_map_.erase(it); } @@ -622,7 +622,7 @@ bool QuicDispatcher::ShouldCreateSessionForUnknownVersion( } bool QuicDispatcher::OnProtocolVersionMismatch( - QuicTransportVersion /*received_version*/) { + ParsedQuicVersion /*received_version*/) { QUIC_BUG_IF( !time_wait_list_manager_->IsConnectionIdInTimeWait( current_connection_id_) && @@ -714,7 +714,7 @@ void QuicDispatcher::OnExpiredPackets( QuicConnectionId connection_id, BufferedPacketList early_arrived_packets) { time_wait_list_manager_->AddConnectionIdToTimeWait( - connection_id, framer_.transport_version(), false, nullptr); + connection_id, framer_.version(), false, nullptr); } void QuicDispatcher::ProcessBufferedChlos(size_t max_connections_to_create) { @@ -789,7 +789,7 @@ void QuicDispatcher::ProcessChlo() { if (!accept_new_connections_) { // Don't any create new connection. time_wait_list_manager()->AddConnectionIdToTimeWait( - current_connection_id(), framer()->transport_version(), + current_connection_id(), framer()->version(), /*connection_rejected_statelessly=*/false, /*termination_packets=*/nullptr); // This will trigger sending Public Reset packet. @@ -874,7 +874,7 @@ class StatelessRejectorProcessDoneCallback : public StatelessRejector::ProcessDoneCallback { public: StatelessRejectorProcessDoneCallback(QuicDispatcher* dispatcher, - QuicTransportVersion first_version) + ParsedQuicVersion first_version) : dispatcher_(dispatcher), current_client_address_(dispatcher->current_client_address_), current_server_address_(dispatcher->current_server_address_), @@ -893,21 +893,20 @@ class StatelessRejectorProcessDoneCallback QuicSocketAddress current_client_address_; QuicSocketAddress current_server_address_; std::unique_ptr<QuicReceivedPacket> current_packet_; - QuicTransportVersion first_version_; + ParsedQuicVersion first_version_; }; void QuicDispatcher::MaybeRejectStatelessly(QuicConnectionId connection_id, - QuicTransportVersion version) { + ParsedQuicVersion version) { // TODO(rch): This logic should probably live completely inside the rejector. if (!FLAGS_quic_allow_chlo_buffering || - !FLAGS_quic_reloadable_flag_quic_use_cheap_stateless_rejects || - !FLAGS_quic_reloadable_flag_enable_quic_stateless_reject_support || + !GetQuicReloadableFlag(quic_use_cheap_stateless_rejects) || + !GetQuicReloadableFlag(enable_quic_stateless_reject_support) || !ShouldAttemptCheapStatelessRejection()) { // Not use cheap stateless reject. ChloAlpnExtractor alpn_extractor; if (FLAGS_quic_allow_chlo_buffering && - !ChloExtractor::Extract(*current_packet_, - GetSupportedTransportVersions(), + !ChloExtractor::Extract(*current_packet_, GetSupportedVersions(), &alpn_extractor)) { // Buffer non-CHLO packets. ProcessUnauthenticatedHeaderFate(kFateBuffer, connection_id); @@ -919,13 +918,13 @@ void QuicDispatcher::MaybeRejectStatelessly(QuicConnectionId connection_id, } std::unique_ptr<StatelessRejector> rejector(new StatelessRejector( - version, GetSupportedTransportVersions(), crypto_config_, - &compressed_certs_cache_, helper()->GetClock(), + version.transport_version, GetSupportedTransportVersions(), + crypto_config_, &compressed_certs_cache_, helper()->GetClock(), helper()->GetRandomGenerator(), current_packet_->length(), GetClientAddress(), current_server_address_)); ChloValidator validator(session_helper_.get(), current_server_address_, rejector.get()); - if (!ChloExtractor::Extract(*current_packet_, GetSupportedTransportVersions(), + if (!ChloExtractor::Extract(*current_packet_, GetSupportedVersions(), &validator)) { ProcessUnauthenticatedHeaderFate(kFateBuffer, connection_id); return; @@ -946,7 +945,8 @@ void QuicDispatcher::MaybeRejectStatelessly(QuicConnectionId connection_id, // If we were able to make a decision about this CHLO based purely on the // information available in OnChlo, just invoke the done callback immediately. if (rejector->state() != StatelessRejector::UNKNOWN) { - ProcessStatelessRejectorState(std::move(rejector), version); + ProcessStatelessRejectorState(std::move(rejector), + version.transport_version); return; } @@ -968,7 +968,7 @@ void QuicDispatcher::OnStatelessRejectorProcessDone( const QuicSocketAddress& current_client_address, const QuicSocketAddress& current_server_address, std::unique_ptr<QuicReceivedPacket> current_packet, - QuicTransportVersion first_version) { + ParsedQuicVersion first_version) { // Stop buffering packets on this connection const auto num_erased = temporarily_buffered_connections_.erase(rejector->connection_id()); @@ -994,7 +994,8 @@ void QuicDispatcher::OnStatelessRejectorProcessDone( current_connection_id_ = rejector->connection_id(); framer_.set_version(first_version); - ProcessStatelessRejectorState(std::move(rejector), first_version); + ProcessStatelessRejectorState(std::move(rejector), + first_version.transport_version); } void QuicDispatcher::ProcessStatelessRejectorState( @@ -1051,6 +1052,10 @@ QuicDispatcher::GetSupportedTransportVersions() { return version_manager_->GetSupportedTransportVersions(); } +const ParsedQuicVersionVector& QuicDispatcher::GetSupportedVersions() { + return version_manager_->GetSupportedVersions(); +} + void QuicDispatcher::DeliverPacketsToSession( const std::list<BufferedPacket>& packets, QuicSession* session) { diff --git a/chromium/net/tools/quic/quic_dispatcher.h b/chromium/net/tools/quic/quic_dispatcher.h index ec980ee68d6..1fbc2659224 100644 --- a/chromium/net/tools/quic/quic_dispatcher.h +++ b/chromium/net/tools/quic/quic_dispatcher.h @@ -121,8 +121,7 @@ class QuicDispatcher : public QuicTimeWaitListManager::Visitor, // destined for the time wait manager. bool OnUnauthenticatedHeader(const QuicPacketHeader& header) override; void OnError(QuicFramer* framer) override; - bool OnProtocolVersionMismatch( - QuicTransportVersion received_version) override; + bool OnProtocolVersionMismatch(ParsedQuicVersion received_version) override; // The following methods should never get called because // OnUnauthenticatedPublicHeader() or OnUnauthenticatedHeader() (whichever @@ -219,6 +218,8 @@ class QuicDispatcher : public QuicTimeWaitListManager::Visitor, const QuicTransportVersionVector& GetSupportedTransportVersions(); + const ParsedQuicVersionVector& GetSupportedVersions(); + QuicConnectionId current_connection_id() { return current_connection_id_; } const QuicSocketAddress& current_server_address() { return current_server_address_; @@ -307,7 +308,7 @@ class QuicDispatcher : public QuicTimeWaitListManager::Visitor, // fate which describes what subsequent processing should be performed on the // packets, like ValidityChecks, and invokes ProcessUnauthenticatedHeaderFate. void MaybeRejectStatelessly(QuicConnectionId connection_id, - QuicTransportVersion version); + ParsedQuicVersion version); // Deliver |packets| to |session| for further processing. void DeliverPacketsToSession( @@ -326,7 +327,7 @@ class QuicDispatcher : public QuicTimeWaitListManager::Visitor, const QuicSocketAddress& current_client_address, const QuicSocketAddress& current_server_address, std::unique_ptr<QuicReceivedPacket> current_packet, - QuicTransportVersion first_version); + ParsedQuicVersion first_version); // Examine the state of the rejector and decide what to do with the current // packet. diff --git a/chromium/net/tools/quic/quic_dispatcher_test.cc b/chromium/net/tools/quic/quic_dispatcher_test.cc index 9fb6b3c7717..ae7b3770f69 100644 --- a/chromium/net/tools/quic/quic_dispatcher_test.cc +++ b/chromium/net/tools/quic/quic_dispatcher_test.cc @@ -15,6 +15,7 @@ #include "net/quic/core/crypto/quic_random.h" #include "net/quic/core/quic_crypto_stream.h" #include "net/quic/core/quic_utils.h" +#include "net/quic/core/tls_server_handshaker.h" #include "net/quic/platform/api/quic_flags.h" #include "net/quic/platform/api/quic_logging.h" #include "net/quic/platform/api/quic_str_cat.h" @@ -86,7 +87,7 @@ class TestQuicSpdyServerSession : public QuicServerSessionBase { QuicCompressedCertsCache* compressed_certs_cache) override { return new QuicCryptoServerStream( crypto_config, compressed_certs_cache, - FLAGS_quic_reloadable_flag_enable_quic_stateless_reject_support, this, + GetQuicReloadableFlag(enable_quic_stateless_reject_support), this, stream_helper()); } @@ -176,10 +177,11 @@ class QuicDispatcherTest : public QuicTest { explicit QuicDispatcherTest(std::unique_ptr<ProofSource> proof_source) : helper_(&eps_, QuicAllocator::BUFFER_POOL), alarm_factory_(&eps_), - version_manager_(AllSupportedTransportVersions()), + version_manager_(AllSupportedVersions()), crypto_config_(QuicCryptoServerConfig::TESTING, QuicRandom::GetInstance(), - std::move(proof_source)), + std::move(proof_source), + TlsServerHandshaker::CreateSslCtx()), dispatcher_(new TestDispatcher(config_, &crypto_config_, &version_manager_, @@ -240,7 +242,7 @@ class QuicDispatcherTest : public QuicTest { QuicPacketNumberLength packet_number_length, QuicPacketNumber packet_number) { ProcessPacket(client_address, connection_id, has_version_flag, - CurrentSupportedTransportVersions().front(), data, + CurrentSupportedVersions().front(), data, connection_id_length, packet_number_length, packet_number); } @@ -248,12 +250,12 @@ class QuicDispatcherTest : public QuicTest { void ProcessPacket(QuicSocketAddress client_address, QuicConnectionId connection_id, bool has_version_flag, - QuicTransportVersion version, + ParsedQuicVersion version, const string& data, QuicConnectionIdLength connection_id_length, QuicPacketNumberLength packet_number_length, QuicPacketNumber packet_number) { - QuicTransportVersionVector versions(SupportedTransportVersions(version)); + ParsedQuicVersionVector versions(SupportedVersions(version)); std::unique_ptr<QuicEncryptedPacket> packet(ConstructEncryptedPacket( connection_id, has_version_flag, false, packet_number, data, connection_id_length, packet_number_length, &versions)); @@ -387,8 +389,9 @@ TEST_F(QuicDispatcherTest, StatelessVersionNegotiation) { CreateQuicSession(1, client_address, QuicStringPiece("hq"))) .Times(0); QuicTransportVersion version = - static_cast<QuicTransportVersion>(QuicVersionMin() - 1); - ProcessPacket(client_address, 1, true, version, SerializeCHLO(), + static_cast<QuicTransportVersion>(QuicTransportVersionMin() - 1); + ParsedQuicVersion parsed_version(PROTOCOL_QUIC_CRYPTO, version); + ProcessPacket(client_address, 1, true, parsed_version, SerializeCHLO(), PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER, 1); } @@ -526,7 +529,7 @@ TEST_F(QuicDispatcherTest, OKSeqNoPacketProcessed) { TEST_F(QuicDispatcherTest, TooBigSeqNoPacketToTimeWaitListManager) { CreateTimeWaitListManager(); - FLAGS_quic_restart_flag_quic_enable_accept_random_ipn = false; + SetQuicRestartFlag(quic_enable_accept_random_ipn, false); QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); QuicConnectionId connection_id = 1; @@ -544,7 +547,7 @@ TEST_F(QuicDispatcherTest, TooBigSeqNoPacketToTimeWaitListManager) { PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER, QuicDispatcher::kMaxReasonableInitialPacketNumber + 1); connection_id = 2; - FLAGS_quic_restart_flag_quic_enable_accept_random_ipn = true; + SetQuicRestartFlag(quic_enable_accept_random_ipn, true); ProcessPacket(client_address, connection_id, true, SerializeCHLO(), PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER, kMaxRandomInitialPacketNumber + @@ -554,9 +557,6 @@ TEST_F(QuicDispatcherTest, TooBigSeqNoPacketToTimeWaitListManager) { TEST_F(QuicDispatcherTest, SupportedTransportVersionsChangeInFlight) { static_assert(arraysize(kSupportedTransportVersions) == 7u, "Supported versions out of sync"); - FLAGS_quic_reloadable_flag_quic_enable_version_38 = true; - FLAGS_quic_reloadable_flag_quic_enable_version_39 = true; - FLAGS_quic_reloadable_flag_quic_enable_version_41 = true; SetQuicFlag(&FLAGS_quic_enable_version_42, true); SetQuicFlag(&FLAGS_quic_enable_version_43, true); QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); @@ -566,10 +566,11 @@ TEST_F(QuicDispatcherTest, SupportedTransportVersionsChangeInFlight) { EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address, QuicStringPiece("hq"))) .Times(0); - ProcessPacket(client_address, connection_id, true, - static_cast<QuicTransportVersion>(QuicVersionMin() - 1), - SerializeCHLO(), PACKET_8BYTE_CONNECTION_ID, - PACKET_6BYTE_PACKET_NUMBER, 1); + ParsedQuicVersion version( + PROTOCOL_QUIC_CRYPTO, + static_cast<QuicTransportVersion>(QuicTransportVersionMin() - 1)); + ProcessPacket(client_address, connection_id, true, version, SerializeCHLO(), + PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER, 1); ++connection_id; EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address, QuicStringPiece("hq"))) @@ -611,7 +612,8 @@ TEST_F(QuicDispatcherTest, SupportedTransportVersionsChangeInFlight) { EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address, QuicStringPiece("hq"))) .Times(0); - ProcessPacket(client_address, connection_id, true, QUIC_VERSION_43, + ProcessPacket(client_address, connection_id, true, + ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43), SerializeCHLO(), PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER, 1); @@ -631,7 +633,8 @@ TEST_F(QuicDispatcherTest, SupportedTransportVersionsChangeInFlight) { base::Unretained(this), connection_id)))); EXPECT_CALL(*dispatcher_, ShouldCreateOrBufferPacketForConnection(connection_id)); - ProcessPacket(client_address, connection_id, true, QUIC_VERSION_43, + ProcessPacket(client_address, connection_id, true, + ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43), SerializeCHLO(), PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER, 1); @@ -641,7 +644,8 @@ TEST_F(QuicDispatcherTest, SupportedTransportVersionsChangeInFlight) { EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address, QuicStringPiece("hq"))) .Times(0); - ProcessPacket(client_address, connection_id, true, QUIC_VERSION_42, + ProcessPacket(client_address, connection_id, true, + ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_42), SerializeCHLO(), PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER, 1); @@ -661,67 +665,8 @@ TEST_F(QuicDispatcherTest, SupportedTransportVersionsChangeInFlight) { base::Unretained(this), connection_id)))); EXPECT_CALL(*dispatcher_, ShouldCreateOrBufferPacketForConnection(connection_id)); - ProcessPacket(client_address, connection_id, true, QUIC_VERSION_42, - SerializeCHLO(), PACKET_8BYTE_CONNECTION_ID, - PACKET_6BYTE_PACKET_NUMBER, 1); - - // Turn off version 41. - FLAGS_quic_reloadable_flag_quic_enable_version_41 = false; - ++connection_id; - EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address, - QuicStringPiece("hq"))) - .Times(0); - ProcessPacket(client_address, connection_id, true, QUIC_VERSION_41, - SerializeCHLO(), PACKET_8BYTE_CONNECTION_ID, - PACKET_6BYTE_PACKET_NUMBER, 1); - - // Turn on version 41. - FLAGS_quic_reloadable_flag_quic_enable_version_41 = true; - ++connection_id; - EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address, - QuicStringPiece("hq"))) - .WillOnce(testing::Return(CreateSession( - dispatcher_.get(), config_, connection_id, client_address, - &mock_helper_, &mock_alarm_factory_, &crypto_config_, - QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_))); - EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()), - ProcessUdpPacket(_, _, _)) - .WillOnce(testing::WithArgs<2>( - Invoke(CreateFunctor(&QuicDispatcherTest::ValidatePacket, - base::Unretained(this), connection_id)))); - EXPECT_CALL(*dispatcher_, - ShouldCreateOrBufferPacketForConnection(connection_id)); - ProcessPacket(client_address, connection_id, true, QUIC_VERSION_41, - SerializeCHLO(), PACKET_8BYTE_CONNECTION_ID, - PACKET_6BYTE_PACKET_NUMBER, 1); - - // Turn off version 39. - FLAGS_quic_reloadable_flag_quic_enable_version_39 = false; - ++connection_id; - EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address, - QuicStringPiece("hq"))) - .Times(0); - ProcessPacket(client_address, connection_id, true, QUIC_VERSION_39, - SerializeCHLO(), PACKET_8BYTE_CONNECTION_ID, - PACKET_6BYTE_PACKET_NUMBER, 1); - - // Turn on version 39. - FLAGS_quic_reloadable_flag_quic_enable_version_39 = true; - ++connection_id; - EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address, - QuicStringPiece("hq"))) - .WillOnce(testing::Return(CreateSession( - dispatcher_.get(), config_, connection_id, client_address, - &mock_helper_, &mock_alarm_factory_, &crypto_config_, - QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_))); - EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()), - ProcessUdpPacket(_, _, _)) - .WillOnce(testing::WithArgs<2>( - Invoke(CreateFunctor(&QuicDispatcherTest::ValidatePacket, - base::Unretained(this), connection_id)))); - EXPECT_CALL(*dispatcher_, - ShouldCreateOrBufferPacketForConnection(connection_id)); - ProcessPacket(client_address, connection_id, true, QUIC_VERSION_39, + ProcessPacket(client_address, connection_id, true, + ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_42), SerializeCHLO(), PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER, 1); } @@ -736,7 +681,7 @@ class MockQuicCryptoServerStream : public QuicCryptoServerStream { : QuicCryptoServerStream( &crypto_config, compressed_certs_cache, - FLAGS_quic_reloadable_flag_enable_quic_stateless_reject_support, + GetQuicReloadableFlag(enable_quic_stateless_reject_support), session, helper), handshake_confirmed_(false) {} @@ -812,8 +757,8 @@ class QuicDispatcherStatelessRejectTest // crypto_stream1_. void SetUp() override { QuicDispatcherTest::SetUp(); - FLAGS_quic_reloadable_flag_enable_quic_stateless_reject_support = - GetParam().enable_stateless_rejects_via_flag; + SetQuicReloadableFlag(enable_quic_stateless_reject_support, + GetParam().enable_stateless_rejects_via_flag); } // Returns true or false, depending on whether the server will emit @@ -905,7 +850,7 @@ TEST_P(QuicDispatcherStatelessRejectTest, ParameterizedBasicTest) { } TEST_P(QuicDispatcherStatelessRejectTest, CheapRejects) { - FLAGS_quic_reloadable_flag_quic_use_cheap_stateless_rejects = true; + SetQuicReloadableFlag(quic_use_cheap_stateless_rejects, true); CreateTimeWaitListManager(); QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); @@ -957,7 +902,7 @@ TEST_P(QuicDispatcherStatelessRejectTest, CheapRejects) { } TEST_P(QuicDispatcherStatelessRejectTest, BufferNonChlo) { - FLAGS_quic_reloadable_flag_quic_use_cheap_stateless_rejects = true; + SetQuicReloadableFlag(quic_use_cheap_stateless_rejects, true); CreateTimeWaitListManager(); const QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); @@ -1281,10 +1226,10 @@ class BufferedPacketStoreTest : QuicDispatcherTest(), client_addr_(QuicIpAddress::Loopback4(), 1234), signed_config_(new QuicSignedServerConfig) { - FLAGS_quic_reloadable_flag_quic_use_cheap_stateless_rejects = - GetParam().support_cheap_stateless_reject; - FLAGS_quic_reloadable_flag_enable_quic_stateless_reject_support = - GetParam().enable_stateless_rejects_via_flag; + SetQuicReloadableFlag(quic_use_cheap_stateless_rejects, + GetParam().support_cheap_stateless_reject); + SetQuicReloadableFlag(enable_quic_stateless_reject_support, + GetParam().enable_stateless_rejects_via_flag); } void SetUp() override { @@ -1692,8 +1637,8 @@ class AsyncGetProofTest : public QuicDispatcherTest { client_addr_(QuicIpAddress::Loopback4(), 1234), crypto_config_peer_(&crypto_config_), signed_config_(new QuicSignedServerConfig) { - FLAGS_quic_reloadable_flag_enable_quic_stateless_reject_support = true; - FLAGS_quic_reloadable_flag_quic_use_cheap_stateless_rejects = true; + SetQuicReloadableFlag(enable_quic_stateless_reject_support, true); + SetQuicReloadableFlag(quic_use_cheap_stateless_rejects, true); } void SetUp() override { @@ -2188,12 +2133,16 @@ TEST_F(AsyncGetProofTest, DispatcherFailedToPickUpVersionForAsyncProof) { // because of QUIC_INVALID_STREAM_DATA. // Send a CHLO with v39. Dispatcher framer's version is set to v39. - ProcessPacket(client_addr_, 1, true, QUIC_VERSION_39, SerializeCHLO(), - PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER, 1); + ProcessPacket(client_addr_, 1, true, + ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_39), + SerializeCHLO(), PACKET_8BYTE_CONNECTION_ID, + PACKET_6BYTE_PACKET_NUMBER, 1); // Send another CHLO with v37. Dispatcher framer's version is set to v37. - ProcessPacket(client_addr_, 2, true, QUIC_VERSION_37, SerializeCHLO(), - PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER, 1); + ProcessPacket(client_addr_, 2, true, + ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_37), + SerializeCHLO(), PACKET_8BYTE_CONNECTION_ID, + PACKET_6BYTE_PACKET_NUMBER, 1); ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 2); // Complete the ProofSource::GetProof call for v39. This would cause the diff --git a/chromium/net/tools/quic/quic_http_response_cache.cc b/chromium/net/tools/quic/quic_http_response_cache.cc index 90c221a80ff..c960fc4f02f 100644 --- a/chromium/net/tools/quic/quic_http_response_cache.cc +++ b/chromium/net/tools/quic/quic_http_response_cache.cc @@ -330,7 +330,11 @@ void QuicHttpResponseCache::AddResponseImpl(QuicStringPiece host, string QuicHttpResponseCache::GetKey(QuicStringPiece host, QuicStringPiece path) const { - return host.as_string() + path.as_string(); + string host_string = host.as_string(); + size_t port = host_string.find(':'); + if (port != string::npos) + host_string = string(host_string.c_str(), port); + return host_string + path.as_string(); } void QuicHttpResponseCache::MaybeAddServerPushResources( diff --git a/chromium/net/tools/quic/quic_http_response_cache.h b/chromium/net/tools/quic/quic_http_response_cache.h index fe9360489ec..ea840feaa6e 100644 --- a/chromium/net/tools/quic/quic_http_response_cache.h +++ b/chromium/net/tools/quic/quic_http_response_cache.h @@ -95,10 +95,8 @@ class QuicHttpResponseCache { const std::string& file_name() { return file_name_string_; } QuicStringPiece host() { return host_; } - void set_host(QuicStringPiece host) { host_ = host; } QuicStringPiece path() { return path_; } - void set_path(QuicStringPiece path) { path_ = path; } const SpdyHeaderBlock& spdy_headers() { return spdy_headers_; } diff --git a/chromium/net/tools/quic/quic_packet_printer_bin.cc b/chromium/net/tools/quic/quic_packet_printer_bin.cc index 06a251cf178..365e5ec84a0 100644 --- a/chromium/net/tools/quic/quic_packet_printer_bin.cc +++ b/chromium/net/tools/quic/quic_packet_printer_bin.cc @@ -67,11 +67,10 @@ class QuicPacketPrinter : public QuicFramerVisitorInterface { std::cerr << "OnError: " << QuicErrorCodeToString(framer->error()) << " detail: " << framer->detailed_error() << "\n"; } - bool OnProtocolVersionMismatch( - QuicTransportVersion received_version) override { + bool OnProtocolVersionMismatch(ParsedQuicVersion received_version) override { framer_->set_version(received_version); std::cerr << "OnProtocolVersionMismatch: " - << QuicVersionToString(received_version) << "\n"; + << ParsedQuicVersionToString(received_version) << "\n"; return true; } void OnPacket() override { std::cerr << "OnPacket\n"; } @@ -177,14 +176,14 @@ int main(int argc, char* argv[]) { return 1; } string hex = net::QuicTextUtils::HexDecode(argv[2]); - net::QuicTransportVersionVector versions = - net::AllSupportedTransportVersions(); + net::ParsedQuicVersionVector versions = net::AllSupportedVersions(); // Fake a time since we're not actually generating acks. net::QuicTime start(net::QuicTime::Zero()); net::QuicFramer framer(versions, start, perspective); if (!FLAGS_quic_version.empty()) { - for (net::QuicTransportVersion version : versions) { - if (net::QuicVersionToString(version) == FLAGS_quic_version) { + for (net::ParsedQuicVersion version : versions) { + if (net::QuicVersionToString(version.transport_version) == + FLAGS_quic_version) { framer.set_version(version); } } diff --git a/chromium/net/tools/quic/quic_server.cc b/chromium/net/tools/quic/quic_server.cc index bfaefc0afd0..42fb237379c 100644 --- a/chromium/net/tools/quic/quic_server.cc +++ b/chromium/net/tools/quic/quic_server.cc @@ -18,6 +18,7 @@ #include "net/quic/core/quic_crypto_stream.h" #include "net/quic/core/quic_data_reader.h" #include "net/quic/core/quic_packets.h" +#include "net/quic/core/tls_server_handshaker.h" #include "net/quic/platform/api/quic_clock.h" #include "net/quic/platform/api/quic_flags.h" #include "net/quic/platform/api/quic_logging.h" @@ -56,14 +57,14 @@ QuicServer::QuicServer(std::unique_ptr<ProofSource> proof_source, : QuicServer(std::move(proof_source), QuicConfig(), QuicCryptoServerConfig::ConfigOptions(), - AllSupportedTransportVersions(), + AllSupportedVersions(), response_cache) {} QuicServer::QuicServer( std::unique_ptr<ProofSource> proof_source, const QuicConfig& config, const QuicCryptoServerConfig::ConfigOptions& crypto_config_options, - const QuicTransportVersionVector& supported_versions, + const ParsedQuicVersionVector& supported_versions, QuicHttpResponseCache* response_cache) : port_(0), fd_(-1), @@ -73,7 +74,8 @@ QuicServer::QuicServer( config_(config), crypto_config_(kSourceAddressTokenSecret, QuicRandom::GetInstance(), - std::move(proof_source)), + std::move(proof_source), + TlsServerHandshaker::CreateSslCtx()), crypto_config_options_(crypto_config_options), version_manager_(supported_versions), packet_reader_(new QuicPacketReader()), diff --git a/chromium/net/tools/quic/quic_server.h b/chromium/net/tools/quic/quic_server.h index 9e404973156..e284941dc4d 100644 --- a/chromium/net/tools/quic/quic_server.h +++ b/chromium/net/tools/quic/quic_server.h @@ -40,7 +40,7 @@ class QuicServer : public EpollCallbackInterface { QuicServer(std::unique_ptr<ProofSource> proof_source, const QuicConfig& config, const QuicCryptoServerConfig::ConfigOptions& server_config_options, - const QuicTransportVersionVector& supported_versions, + const ParsedQuicVersionVector& supported_versions, QuicHttpResponseCache* response_cache); ~QuicServer() override; diff --git a/chromium/net/tools/quic/quic_server_bin.cc b/chromium/net/tools/quic/quic_server_bin.cc index 7c3c2bdcf81..3d18dedd43b 100644 --- a/chromium/net/tools/quic/quic_server_bin.cc +++ b/chromium/net/tools/quic/quic_server_bin.cc @@ -87,7 +87,7 @@ int main(int argc, char* argv[]) { CreateProofSource(line->GetSwitchValuePath("certificate_file"), line->GetSwitchValuePath("key_file")), config, net::QuicCryptoServerConfig::ConfigOptions(), - net::AllSupportedTransportVersions(), &response_cache); + net::AllSupportedVersions(), &response_cache); int rc = server.CreateUDPSocketAndListen( net::QuicSocketAddress(net::QuicIpAddress::Any6(), FLAGS_port)); diff --git a/chromium/net/tools/quic/quic_server_test.cc b/chromium/net/tools/quic/quic_server_test.cc index 1c3451b7743..df80fa7d7b4 100644 --- a/chromium/net/tools/quic/quic_server_test.cc +++ b/chromium/net/tools/quic/quic_server_test.cc @@ -6,6 +6,8 @@ #include "net/quic/core/crypto/quic_random.h" #include "net/quic/core/quic_utils.h" +#include "net/quic/core/tls_server_handshaker.h" +#include "net/quic/platform/api/quic_arraysize.h" #include "net/quic/platform/api/quic_flags.h" #include "net/quic/platform/api/quic_logging.h" #include "net/quic/platform/api/quic_socket_address.h" @@ -130,9 +132,9 @@ TEST_F(QuicServerEpollInTest, ProcessBufferedCHLOsOnEpollin) { ASSERT_LT(0, fd); char buf[1024]; - memset(buf, 0, arraysize(buf)); + memset(buf, 0, QUIC_ARRAYSIZE(buf)); sockaddr_storage storage = server_address_.generic_address(); - int rc = sendto(fd, buf, arraysize(buf), 0, + int rc = sendto(fd, buf, QUIC_ARRAYSIZE(buf), 0, reinterpret_cast<sockaddr*>(&storage), sizeof(storage)); if (rc < 0) { QUIC_DLOG(INFO) << errno << " " << strerror(errno); @@ -148,8 +150,9 @@ class QuicServerDispatchPacketTest : public QuicTest { QuicServerDispatchPacketTest() : crypto_config_("blah", QuicRandom::GetInstance(), - crypto_test_utils::ProofSourceForTesting()), - version_manager_(AllSupportedTransportVersions()), + crypto_test_utils::ProofSourceForTesting(), + TlsServerHandshaker::CreateSslCtx()), + version_manager_(AllSupportedVersions()), dispatcher_( config_, &crypto_config_, @@ -196,7 +199,7 @@ TEST_F(QuicServerDispatchPacketTest, DispatchPacket) { }; // clang-format on QuicReceivedPacket encrypted_valid_packet( - reinterpret_cast<char*>(valid_packet), arraysize(valid_packet), + reinterpret_cast<char*>(valid_packet), QUIC_ARRAYSIZE(valid_packet), QuicTime::Zero(), false); EXPECT_CALL(dispatcher_, ProcessPacket(_, _, _)).Times(1); diff --git a/chromium/net/tools/quic/quic_simple_client.cc b/chromium/net/tools/quic/quic_simple_client.cc index b394ae13458..1273c1bed19 100644 --- a/chromium/net/tools/quic/quic_simple_client.cc +++ b/chromium/net/tools/quic/quic_simple_client.cc @@ -36,7 +36,7 @@ namespace net { QuicSimpleClient::QuicSimpleClient( QuicSocketAddress server_address, const QuicServerId& server_id, - const QuicTransportVersionVector& supported_versions, + const ParsedQuicVersionVector& supported_versions, std::unique_ptr<ProofVerifier> proof_verifier) : QuicSpdyClientBase( server_id, diff --git a/chromium/net/tools/quic/quic_simple_client.h b/chromium/net/tools/quic/quic_simple_client.h index 5f79e0497d2..8f17f68a1d9 100644 --- a/chromium/net/tools/quic/quic_simple_client.h +++ b/chromium/net/tools/quic/quic_simple_client.h @@ -40,7 +40,7 @@ class QuicSimpleClient : public QuicSpdyClientBase { // Create a quic client, which will have events managed by the message loop. QuicSimpleClient(QuicSocketAddress server_address, const QuicServerId& server_id, - const QuicTransportVersionVector& supported_versions, + const ParsedQuicVersionVector& supported_versions, std::unique_ptr<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 c4c91aac2be..af5e63e2616 100644 --- a/chromium/net/tools/quic/quic_simple_client_bin.cc +++ b/chromium/net/tools/quic/quic_simple_client_bin.cc @@ -254,12 +254,12 @@ int main(int argc, char* argv[]) { // Build the client, and try to connect. net::QuicServerId server_id(url.host(), url.EffectiveIntPort(), net::PRIVACY_MODE_DISABLED); - net::QuicTransportVersionVector versions = - net::AllSupportedTransportVersions(); + net::ParsedQuicVersionVector versions = net::AllSupportedVersions(); if (FLAGS_quic_version != -1) { versions.clear(); - versions.push_back( - static_cast<net::QuicTransportVersion>(FLAGS_quic_version)); + versions.push_back(net::ParsedQuicVersion( + net::PROTOCOL_QUIC_CRYPTO, + static_cast<net::QuicTransportVersion>(FLAGS_quic_version))); } // For secure QUIC we need to verify the cert chain. std::unique_ptr<CertVerifier> cert_verifier(CertVerifier::CreateDefault()); @@ -288,7 +288,7 @@ int main(int argc, char* argv[]) { net::QuicErrorCode error = client.session()->error(); if (FLAGS_version_mismatch_ok && error == net::QUIC_INVALID_VERSION) { cout << "Server talks QUIC, but none of the versions supported by " - << "this client: " << QuicTransportVersionVectorToString(versions) + << "this client: " << ParsedQuicVersionVectorToString(versions) << endl; // Version mismatch is not deemed a failure. return 0; diff --git a/chromium/net/tools/quic/quic_simple_client_test.cc b/chromium/net/tools/quic/quic_simple_client_test.cc index 2c6baef3145..16ff1bfa337 100644 --- a/chromium/net/tools/quic/quic_simple_client_test.cc +++ b/chromium/net/tools/quic/quic_simple_client_test.cc @@ -16,7 +16,7 @@ TEST(QuicSimpleClientTest, Initialize) { QuicSocketAddress server_address(QuicIpAddress::Loopback4(), 80); QuicServerId server_id("hostname", server_address.port(), PRIVACY_MODE_DISABLED); - QuicTransportVersionVector versions = AllSupportedTransportVersions(); + ParsedQuicVersionVector versions = AllSupportedVersions(); QuicSimpleClient client(server_address, server_id, versions, crypto_test_utils::ProofVerifierForTesting()); EXPECT_TRUE(client.Initialize()); diff --git a/chromium/net/tools/quic/quic_simple_dispatcher.cc b/chromium/net/tools/quic/quic_simple_dispatcher.cc index 832415cc1dd..1f64cb5d6f4 100644 --- a/chromium/net/tools/quic/quic_simple_dispatcher.cc +++ b/chromium/net/tools/quic/quic_simple_dispatcher.cc @@ -51,11 +51,10 @@ QuicServerSessionBase* QuicSimpleDispatcher::CreateQuicSession( const QuicSocketAddress& client_address, QuicStringPiece /*alpn*/) { // The QuicServerSessionBase takes ownership of |connection| below. - QuicConnection* connection = - new QuicConnection(connection_id, client_address, helper(), - alarm_factory(), CreatePerConnectionWriter(), - /* owns_writer= */ true, Perspective::IS_SERVER, - GetSupportedTransportVersions()); + QuicConnection* connection = new QuicConnection( + connection_id, client_address, helper(), alarm_factory(), + CreatePerConnectionWriter(), + /* owns_writer= */ true, Perspective::IS_SERVER, GetSupportedVersions()); QuicServerSessionBase* session = new QuicSimpleServerSession( config(), connection, this, session_helper(), crypto_config(), diff --git a/chromium/net/tools/quic/quic_simple_server.cc b/chromium/net/tools/quic/quic_simple_server.cc index 4ecbf753610..6526e6ce6bb 100644 --- a/chromium/net/tools/quic/quic_simple_server.cc +++ b/chromium/net/tools/quic/quic_simple_server.cc @@ -17,6 +17,7 @@ #include "net/quic/core/quic_crypto_stream.h" #include "net/quic/core/quic_data_reader.h" #include "net/quic/core/quic_packets.h" +#include "net/quic/core/tls_server_handshaker.h" #include "net/socket/udp_server_socket.h" #include "net/tools/quic/quic_simple_dispatcher.h" #include "net/tools/quic/quic_simple_per_connection_packet_writer.h" @@ -40,7 +41,7 @@ QuicSimpleServer::QuicSimpleServer( std::unique_ptr<ProofSource> proof_source, const QuicConfig& config, const QuicCryptoServerConfig::ConfigOptions& crypto_config_options, - const QuicTransportVersionVector& supported_versions, + const ParsedQuicVersionVector& supported_versions, QuicHttpResponseCache* response_cache) : version_manager_(supported_versions), helper_( @@ -52,7 +53,8 @@ QuicSimpleServer::QuicSimpleServer( crypto_config_options_(crypto_config_options), crypto_config_(kSourceAddressTokenSecret, QuicRandom::GetInstance(), - std::move(proof_source)), + std::move(proof_source), + TlsServerHandshaker::CreateSslCtx()), read_pending_(false), synchronous_read_count_(0), read_buffer_(new IOBufferWithSize(kReadBufferSize)), @@ -146,6 +148,9 @@ void QuicSimpleServer::Shutdown() { // notify clients that they're closing. dispatcher_->Shutdown(); + if (!socket_) { + return; + } socket_->Close(); socket_.reset(); } diff --git a/chromium/net/tools/quic/quic_simple_server.h b/chromium/net/tools/quic/quic_simple_server.h index 938a7132788..b72d967e8da 100644 --- a/chromium/net/tools/quic/quic_simple_server.h +++ b/chromium/net/tools/quic/quic_simple_server.h @@ -39,7 +39,7 @@ class QuicSimpleServer { std::unique_ptr<ProofSource> proof_source, const QuicConfig& config, const QuicCryptoServerConfig::ConfigOptions& crypto_config_options, - const QuicTransportVersionVector& supported_versions, + const ParsedQuicVersionVector& supported_versions, QuicHttpResponseCache* response_cache); virtual ~QuicSimpleServer(); diff --git a/chromium/net/tools/quic/quic_simple_server_bin.cc b/chromium/net/tools/quic/quic_simple_server_bin.cc index c435d766de8..e7c44d2553c 100644 --- a/chromium/net/tools/quic/quic_simple_server_bin.cc +++ b/chromium/net/tools/quic/quic_simple_server_bin.cc @@ -90,7 +90,7 @@ int main(int argc, char* argv[]) { CreateProofSource(line->GetSwitchValuePath("certificate_file"), line->GetSwitchValuePath("key_file")), config, net::QuicCryptoServerConfig::ConfigOptions(), - net::AllSupportedTransportVersions(), &response_cache); + net::AllSupportedVersions(), &response_cache); int rc = server.Listen(net::IPEndPoint(ip, FLAGS_port)); if (rc < 0) { 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 fa7ece10834..15b24ca664f 100644 --- a/chromium/net/tools/quic/quic_simple_server_packet_writer.cc +++ b/chromium/net/tools/quic/quic_simple_server_packet_writer.cc @@ -7,7 +7,7 @@ #include "base/callback_helpers.h" #include "base/location.h" #include "base/logging.h" -#include "base/metrics/histogram_macros.h" +#include "base/metrics/histogram_functions.h" #include "net/base/io_buffer.h" #include "net/base/net_errors.h" #include "net/socket/udp_server_socket.h" @@ -87,7 +87,7 @@ WriteResult QuicSimpleServerPacketWriter::WritePacket( WriteStatus status = WRITE_STATUS_OK; if (rv < 0) { if (rv != ERR_IO_PENDING) { - UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.WriteError", -rv); + base::UmaHistogramSparse("Net.QuicSession.WriteError", -rv); status = WRITE_STATUS_ERROR; } else { status = WRITE_STATUS_BLOCKED; diff --git a/chromium/net/tools/quic/quic_simple_server_session.cc b/chromium/net/tools/quic/quic_simple_server_session.cc index 4d10c403231..42d195d32ae 100644 --- a/chromium/net/tools/quic/quic_simple_server_session.cc +++ b/chromium/net/tools/quic/quic_simple_server_session.cc @@ -6,7 +6,6 @@ #include <utility> -#include "net/quic/core/proto/cached_network_parameters.pb.h" #include "net/quic/core/quic_connection.h" #include "net/quic/platform/api/quic_flags.h" #include "net/quic/platform/api/quic_logging.h" @@ -44,7 +43,7 @@ QuicSimpleServerSession::CreateQuicCryptoServerStream( QuicCompressedCertsCache* compressed_certs_cache) { return new QuicCryptoServerStream( crypto_config, compressed_certs_cache, - FLAGS_quic_reloadable_flag_enable_quic_stateless_reject_support, this, + GetQuicReloadableFlag(enable_quic_stateless_reject_support), this, stream_helper()); } diff --git a/chromium/net/tools/quic/quic_simple_server_session_test.cc b/chromium/net/tools/quic/quic_simple_server_session_test.cc index 712fff9eeeb..d1189a52468 100644 --- a/chromium/net/tools/quic/quic_simple_server_session_test.cc +++ b/chromium/net/tools/quic/quic_simple_server_session_test.cc @@ -14,6 +14,7 @@ #include "net/quic/core/quic_connection.h" #include "net/quic/core/quic_crypto_server_stream.h" #include "net/quic/core/quic_utils.h" +#include "net/quic/core/tls_server_handshaker.h" #include "net/quic/platform/api/quic_containers.h" #include "net/quic/platform/api/quic_flags.h" #include "net/quic/platform/api/quic_socket_address.h" @@ -64,15 +65,6 @@ class QuicSimpleServerSessionPeer { QuicSimpleServerSession* s) { return s->CreateOutgoingDynamicStream(); } - - static QuicDeque<PromisedStreamInfo>* promised_streams( - QuicSimpleServerSession* s) { - return &(s->promised_streams_); - } - - static QuicStreamId hightest_promised_stream_id(QuicSimpleServerSession* s) { - return s->highest_promised_stream_id_; - } }; namespace { @@ -89,7 +81,8 @@ class MockQuicCryptoServerStream : public QuicCryptoServerStream { : QuicCryptoServerStream( crypto_config, compressed_certs_cache, - FLAGS_quic_reloadable_flag_enable_quic_stateless_reject_support, + GetQuicReloadableFlag( + enable_quic_stateless_reject_support), // NOLINT session, helper) {} ~MockQuicCryptoServerStream() override = default; @@ -118,7 +111,7 @@ class MockQuicConnectionWithSendStreamData : public MockQuicConnection { MockQuicConnectionHelper* helper, MockAlarmFactory* alarm_factory, Perspective perspective, - const QuicTransportVersionVector& supported_versions) + const ParsedQuicVersionVector& supported_versions) : MockQuicConnection(helper, alarm_factory, perspective, @@ -179,12 +172,13 @@ class MockQuicSimpleServerSession : public QuicSimpleServerSession { }; class QuicSimpleServerSessionTest - : public QuicTestWithParam<QuicTransportVersion> { + : public QuicTestWithParam<ParsedQuicVersion> { protected: QuicSimpleServerSessionTest() : crypto_config_(QuicCryptoServerConfig::TESTING, QuicRandom::GetInstance(), - crypto_test_utils::ProofSourceForTesting()), + crypto_test_utils::ProofSourceForTesting(), + TlsServerHandshaker::CreateSslCtx()), compressed_certs_cache_( QuicCompressedCertsCache::kQuicCompressedCertsCacheSize) { config_.SetMaxStreamsPerConnection(kMaxStreamsForTest, kMaxStreamsForTest); @@ -198,7 +192,7 @@ class QuicSimpleServerSessionTest connection_ = new StrictMock<MockQuicConnectionWithSendStreamData>( &helper_, &alarm_factory_, Perspective::IS_SERVER, - SupportedTransportVersions(GetParam())); + SupportedVersions(GetParam())); session_.reset(new MockQuicSimpleServerSession( config_, connection_, &owner_, &stream_helper_, &crypto_config_, &compressed_certs_cache_, &response_cache_)); @@ -236,7 +230,7 @@ class QuicSimpleServerSessionTest INSTANTIATE_TEST_CASE_P(Tests, QuicSimpleServerSessionTest, - ::testing::ValuesIn(AllSupportedTransportVersions())); + ::testing::ValuesIn(AllSupportedVersions())); TEST_P(QuicSimpleServerSessionTest, CloseStreamDueToReset) { // Open a stream, then reset it. @@ -453,7 +447,7 @@ class QuicSimpleServerSessionServerPushTest connection_ = new StrictMock<MockQuicConnectionWithSendStreamData>( &helper_, &alarm_factory_, Perspective::IS_SERVER, - SupportedTransportVersions(GetParam())); + SupportedVersions(GetParam())); session_.reset(new MockQuicSimpleServerSession( config_, connection_, &owner_, &stream_helper_, &crypto_config_, &compressed_certs_cache_, &response_cache_)); @@ -521,7 +515,7 @@ class QuicSimpleServerSessionServerPushTest INSTANTIATE_TEST_CASE_P(Tests, QuicSimpleServerSessionServerPushTest, - ::testing::ValuesIn(AllSupportedTransportVersions())); + ::testing::ValuesIn(AllSupportedVersions())); TEST_P(QuicSimpleServerSessionServerPushTest, TestPromisePushResources) { // Tests that given more than kMaxOpenStreamForTest resources, all their diff --git a/chromium/net/tools/quic/quic_simple_server_stream_test.cc b/chromium/net/tools/quic/quic_simple_server_stream_test.cc index 7a1040d1eb2..1d119ac452f 100644 --- a/chromium/net/tools/quic/quic_simple_server_stream_test.cc +++ b/chromium/net/tools/quic/quic_simple_server_stream_test.cc @@ -10,6 +10,8 @@ #include "net/quic/core/quic_utils.h" #include "net/quic/core/spdy_utils.h" +#include "net/quic/core/tls_server_handshaker.h" +#include "net/quic/platform/api/quic_arraysize.h" #include "net/quic/platform/api/quic_ptr_util.h" #include "net/quic/platform/api/quic_socket_address.h" #include "net/quic/platform/api/quic_test.h" @@ -164,19 +166,19 @@ class MockQuicSimpleServerSession : public QuicSimpleServerSession { DISALLOW_COPY_AND_ASSIGN(MockQuicSimpleServerSession); }; -class QuicSimpleServerStreamTest - : public QuicTestWithParam<QuicTransportVersion> { +class QuicSimpleServerStreamTest : public QuicTestWithParam<ParsedQuicVersion> { public: QuicSimpleServerStreamTest() - : connection_(new StrictMock<MockQuicConnection>( - &helper_, - &alarm_factory_, - Perspective::IS_SERVER, - SupportedTransportVersions(GetParam()))), + : connection_( + new StrictMock<MockQuicConnection>(&helper_, + &alarm_factory_, + Perspective::IS_SERVER, + SupportedVersions(GetParam()))), crypto_config_(new QuicCryptoServerConfig( QuicCryptoServerConfig::TESTING, QuicRandom::GetInstance(), - crypto_test_utils::ProofSourceForTesting())), + crypto_test_utils::ProofSourceForTesting(), + TlsServerHandshaker::CreateSslCtx())), compressed_certs_cache_( QuicCompressedCertsCache::kQuicCompressedCertsCacheSize), session_(connection_, @@ -232,12 +234,12 @@ class QuicSimpleServerStreamTest INSTANTIATE_TEST_CASE_P(Tests, QuicSimpleServerStreamTest, - ::testing::ValuesIn(AllSupportedTransportVersions())); + ::testing::ValuesIn(AllSupportedVersions())); TEST_P(QuicSimpleServerStreamTest, TestFraming) { EXPECT_CALL(session_, WritevData(_, _, _, _, _)) .Times(AnyNumber()) - .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData)); + .WillRepeatedly(Invoke(MockQuicSession::ConsumeData)); stream_->OnStreamHeaderList(false, kFakeFrameLen, header_list_); stream_->OnStreamFrame( QuicStreamFrame(stream_->id(), /*fin=*/false, /*offset=*/0, body_)); @@ -250,7 +252,7 @@ TEST_P(QuicSimpleServerStreamTest, TestFraming) { TEST_P(QuicSimpleServerStreamTest, TestFramingOnePacket) { EXPECT_CALL(session_, WritevData(_, _, _, _, _)) .Times(AnyNumber()) - .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData)); + .WillRepeatedly(Invoke(MockQuicSession::ConsumeData)); stream_->OnStreamHeaderList(false, kFakeFrameLen, header_list_); stream_->OnStreamFrame( @@ -264,7 +266,7 @@ TEST_P(QuicSimpleServerStreamTest, TestFramingOnePacket) { TEST_P(QuicSimpleServerStreamTest, SendQuicRstStreamNoErrorInStopReading) { EXPECT_CALL(session_, WritevData(_, _, _, _, _)) .Times(AnyNumber()) - .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData)); + .WillRepeatedly(Invoke(MockQuicSession::ConsumeData)); EXPECT_FALSE(stream_->fin_received()); EXPECT_FALSE(stream_->rst_received()); @@ -282,7 +284,7 @@ TEST_P(QuicSimpleServerStreamTest, TestFramingExtraData) { // We'll automatically write out an error (headers + body) EXPECT_CALL(session_, WriteHeadersMock(_, _, _, _, _)); EXPECT_CALL(session_, WritevData(_, _, _, _, _)) - .WillOnce(Invoke(MockQuicSession::ConsumeAllData)); + .WillOnce(Invoke(MockQuicSession::ConsumeData)); EXPECT_CALL(session_, SendRstStream(_, QUIC_STREAM_NO_ERROR, _)).Times(0); stream_->OnStreamHeaderList(false, kFakeFrameLen, header_list_); @@ -526,7 +528,7 @@ TEST_P(QuicSimpleServerStreamTest, InvalidMultipleContentLength) { EXPECT_CALL(session_, WriteHeadersMock(_, _, _, _, _)); EXPECT_CALL(session_, WritevData(_, _, _, _, _)) .Times(AnyNumber()) - .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData)); + .WillRepeatedly(Invoke(MockQuicSession::ConsumeData)); stream_->OnStreamHeaderList(true, kFakeFrameLen, header_list_); EXPECT_TRUE(QuicStreamPeer::read_side_closed(stream_)); @@ -544,7 +546,7 @@ TEST_P(QuicSimpleServerStreamTest, InvalidLeadingNullContentLength) { EXPECT_CALL(session_, WriteHeadersMock(_, _, _, _, _)); EXPECT_CALL(session_, WritevData(_, _, _, _, _)) .Times(AnyNumber()) - .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData)); + .WillRepeatedly(Invoke(MockQuicSession::ConsumeData)); stream_->OnStreamHeaderList(true, kFakeFrameLen, header_list_); EXPECT_TRUE(QuicStreamPeer::read_side_closed(stream_)); @@ -604,7 +606,7 @@ TEST_P(QuicSimpleServerStreamTest, InvalidHeadersWithFin) { 0x54, 0x54, 0x50, 0x2f, // TTP/ 0x31, 0x2e, 0x31, // 1.1 }; - QuicStringPiece data(arr, arraysize(arr)); + QuicStringPiece data(arr, QUIC_ARRAYSIZE(arr)); QuicStreamFrame frame(stream_->id(), true, 0, data); // Verify that we don't crash when we get a invalid headers in stream frame. stream_->OnStreamFrame(frame); diff --git a/chromium/net/tools/quic/quic_simple_server_test.cc b/chromium/net/tools/quic/quic_simple_server_test.cc index 3b5000cac81..66bbd33774b 100644 --- a/chromium/net/tools/quic/quic_simple_server_test.cc +++ b/chromium/net/tools/quic/quic_simple_server_test.cc @@ -7,6 +7,7 @@ #include "net/quic/core/crypto/quic_random.h" #include "net/quic/core/quic_crypto_stream.h" #include "net/quic/core/quic_utils.h" +#include "net/quic/core/tls_server_handshaker.h" #include "net/quic/platform/api/quic_test.h" #include "net/quic/test_tools/crypto_test_utils.h" #include "net/quic/test_tools/mock_quic_dispatcher.h" @@ -25,8 +26,9 @@ class QuicChromeServerDispatchPacketTest : public QuicTest { QuicChromeServerDispatchPacketTest() : crypto_config_("blah", QuicRandom::GetInstance(), - crypto_test_utils::ProofSourceForTesting()), - version_manager_(AllSupportedTransportVersions()), + crypto_test_utils::ProofSourceForTesting(), + TlsServerHandshaker::CreateSslCtx()), + version_manager_(AllSupportedVersions()), dispatcher_( config_, &crypto_config_, diff --git a/chromium/net/tools/quic/quic_spdy_client_base.cc b/chromium/net/tools/quic/quic_spdy_client_base.cc index d285648b0da..6cad4ee3c35 100644 --- a/chromium/net/tools/quic/quic_spdy_client_base.cc +++ b/chromium/net/tools/quic/quic_spdy_client_base.cc @@ -32,7 +32,7 @@ QuicSpdyClientBase::QuicDataToResend::~QuicDataToResend() = default; QuicSpdyClientBase::QuicSpdyClientBase( const QuicServerId& server_id, - const QuicTransportVersionVector& supported_versions, + const ParsedQuicVersionVector& supported_versions, const QuicConfig& config, QuicConnectionHelperInterface* helper, QuicAlarmFactory* alarm_factory, @@ -170,7 +170,7 @@ int QuicSpdyClientBase::GetNumReceivedServerConfigUpdatesFromSession() { void QuicSpdyClientBase::MaybeAddDataToResend(const SpdyHeaderBlock& headers, QuicStringPiece body, bool fin) { - if (!FLAGS_quic_reloadable_flag_enable_quic_stateless_reject_support) { + if (!GetQuicReloadableFlag(enable_quic_stateless_reject_support)) { return; } diff --git a/chromium/net/tools/quic/quic_spdy_client_base.h b/chromium/net/tools/quic/quic_spdy_client_base.h index a79a5ef9ebb..468e712c1de 100644 --- a/chromium/net/tools/quic/quic_spdy_client_base.h +++ b/chromium/net/tools/quic/quic_spdy_client_base.h @@ -69,7 +69,7 @@ class QuicSpdyClientBase : public QuicClientBase, }; QuicSpdyClientBase(const QuicServerId& server_id, - const QuicTransportVersionVector& supported_versions, + const ParsedQuicVersionVector& supported_versions, const QuicConfig& config, QuicConnectionHelperInterface* helper, QuicAlarmFactory* alarm_factory, diff --git a/chromium/net/tools/quic/quic_spdy_client_session_test.cc b/chromium/net/tools/quic/quic_spdy_client_session_test.cc index b2da7ceb7db..a41ebe13778 100644 --- a/chromium/net/tools/quic/quic_spdy_client_session_test.cc +++ b/chromium/net/tools/quic/quic_spdy_client_session_test.cc @@ -8,6 +8,7 @@ #include "net/quic/core/crypto/aes_128_gcm_12_encrypter.h" #include "net/quic/core/spdy_utils.h" +#include "net/quic/core/tls_client_handshaker.h" #include "net/quic/platform/api/quic_flags.h" #include "net/quic/platform/api/quic_ptr_util.h" #include "net/quic/platform/api/quic_socket_address.h" @@ -63,11 +64,11 @@ class TestQuicSpdyClientSession : public QuicSpdyClientSession { } }; -class QuicSpdyClientSessionTest - : public QuicTestWithParam<QuicTransportVersion> { +class QuicSpdyClientSessionTest : public QuicTestWithParam<ParsedQuicVersion> { protected: QuicSpdyClientSessionTest() - : crypto_config_(crypto_test_utils::ProofVerifierForTesting()), + : crypto_config_(crypto_test_utils::ProofVerifierForTesting(), + TlsClientHandshaker::CreateSslCtx()), promised_stream_id_(kInvalidStreamId), associated_stream_id_(kInvalidStreamId) { Initialize(); @@ -82,9 +83,9 @@ class QuicSpdyClientSessionTest void Initialize() { session_.reset(); - connection_ = new PacketSavingConnection( - &helper_, &alarm_factory_, Perspective::IS_CLIENT, - SupportedTransportVersions(GetParam())); + connection_ = new PacketSavingConnection(&helper_, &alarm_factory_, + Perspective::IS_CLIENT, + SupportedVersions(GetParam())); session_.reset(new TestQuicSpdyClientSession( DefaultQuicConfig(), connection_, QuicServerId(kServerHostname, kPort, PRIVACY_MODE_DISABLED), @@ -131,7 +132,7 @@ class QuicSpdyClientSessionTest INSTANTIATE_TEST_CASE_P(Tests, QuicSpdyClientSessionTest, - ::testing::ValuesIn(AllSupportedTransportVersions())); + ::testing::ValuesIn(AllSupportedVersions())); TEST_P(QuicSpdyClientSessionTest, CryptoConnect) { CompleteCryptoHandshake(); @@ -342,7 +343,7 @@ TEST_P(QuicSpdyClientSessionTest, InvalidFramedPacketReceived) { // Verify that a decryptable packet with bad frames does close the connection. QuicConnectionId connection_id = session_->connection()->connection_id(); - QuicTransportVersionVector versions = {GetParam()}; + ParsedQuicVersionVector versions = {GetParam()}; std::unique_ptr<QuicEncryptedPacket> packet(ConstructMisFramedEncryptedPacket( connection_id, false, false, 100, "data", PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER, &versions, Perspective::IS_SERVER)); diff --git a/chromium/net/tools/quic/quic_spdy_client_stream_test.cc b/chromium/net/tools/quic/quic_spdy_client_stream_test.cc index 361f87e0954..c8d035eb1ad 100644 --- a/chromium/net/tools/quic/quic_spdy_client_stream_test.cc +++ b/chromium/net/tools/quic/quic_spdy_client_stream_test.cc @@ -9,6 +9,7 @@ #include "base/macros.h" #include "net/quic/core/quic_utils.h" #include "net/quic/core/spdy_utils.h" +#include "net/quic/core/tls_client_handshaker.h" #include "net/quic/platform/api/quic_logging.h" #include "net/quic/platform/api/quic_socket_address.h" #include "net/quic/platform/api/quic_test.h" @@ -38,7 +39,8 @@ class MockQuicSpdyClientSession : public QuicSpdyClientSession { QuicServerId("example.com", 443, PRIVACY_MODE_DISABLED), &crypto_config_, push_promise_index), - crypto_config_(crypto_test_utils::ProofVerifierForTesting()) {} + crypto_config_(crypto_test_utils::ProofVerifierForTesting(), + TlsClientHandshaker::CreateSslCtx()) {} ~MockQuicSpdyClientSession() override = default; MOCK_METHOD1(CloseStream, void(QuicStreamId stream_id)); diff --git a/chromium/net/tools/quic/quic_time_wait_list_manager.cc b/chromium/net/tools/quic/quic_time_wait_list_manager.cc index 9f54816de89..31279b34c39 100644 --- a/chromium/net/tools/quic/quic_time_wait_list_manager.cc +++ b/chromium/net/tools/quic/quic_time_wait_list_manager.cc @@ -93,7 +93,7 @@ QuicTimeWaitListManager::~QuicTimeWaitListManager() { void QuicTimeWaitListManager::AddConnectionIdToTimeWait( QuicConnectionId connection_id, - QuicTransportVersion version, + ParsedQuicVersion version, bool connection_rejected_statelessly, std::vector<std::unique_ptr<QuicEncryptedPacket>>* termination_packets) { if (connection_rejected_statelessly) { @@ -127,7 +127,7 @@ bool QuicTimeWaitListManager::IsConnectionIdInTimeWait( return QuicContainsKey(connection_id_map_, connection_id); } -QuicTransportVersion QuicTimeWaitListManager::GetQuicVersionFromConnectionId( +ParsedQuicVersion QuicTimeWaitListManager::GetQuicVersionFromConnectionId( QuicConnectionId connection_id) { ConnectionIdMap::iterator it = connection_id_map_.find(connection_id); DCHECK(it != connection_id_map_.end()); @@ -180,7 +180,7 @@ void QuicTimeWaitListManager::ProcessPacket( void QuicTimeWaitListManager::SendVersionNegotiationPacket( QuicConnectionId connection_id, - const QuicTransportVersionVector& supported_versions, + const ParsedQuicVersionVector& supported_versions, const QuicSocketAddress& server_address, const QuicSocketAddress& client_address) { SendOrQueuePacket( @@ -308,7 +308,7 @@ void QuicTimeWaitListManager::TrimTimeWaitListIfNeeded() { QuicTimeWaitListManager::ConnectionIdData::ConnectionIdData( int num_packets_, - QuicTransportVersion version_, + ParsedQuicVersion version_, QuicTime time_added_, bool connection_rejected_statelessly) : num_packets(num_packets_), diff --git a/chromium/net/tools/quic/quic_time_wait_list_manager.h b/chromium/net/tools/quic/quic_time_wait_list_manager.h index ed0b545b77a..0bd53b87c90 100644 --- a/chromium/net/tools/quic/quic_time_wait_list_manager.h +++ b/chromium/net/tools/quic/quic_time_wait_list_manager.h @@ -68,7 +68,7 @@ class QuicTimeWaitListManager : public QuicBlockedWriterInterface { // and termination packets are expected. virtual void AddConnectionIdToTimeWait( QuicConnectionId connection_id, - QuicTransportVersion version, + ParsedQuicVersion version, bool connection_rejected_statelessly, std::vector<std::unique_ptr<QuicEncryptedPacket>>* termination_packets); @@ -100,8 +100,8 @@ class QuicTimeWaitListManager : public QuicBlockedWriterInterface { void TrimTimeWaitListIfNeeded(); // Given a ConnectionId that exists in the time wait list, returns the - // QuicTransportVersion associated with it. - QuicTransportVersion GetQuicVersionFromConnectionId( + // ParsedQuicVersion associated with it. + ParsedQuicVersion GetQuicVersionFromConnectionId( QuicConnectionId connection_id); // The number of connections on the time-wait list. @@ -111,7 +111,7 @@ class QuicTimeWaitListManager : public QuicBlockedWriterInterface { // for |supported_versions| to |client_address| from |server_address|. virtual void SendVersionNegotiationPacket( QuicConnectionId connection_id, - const QuicTransportVersionVector& supported_versions, + const ParsedQuicVersionVector& supported_versions, const QuicSocketAddress& server_address, const QuicSocketAddress& client_address); @@ -162,7 +162,7 @@ class QuicTimeWaitListManager : public QuicBlockedWriterInterface { // connection_id. struct ConnectionIdData { ConnectionIdData(int num_packets_, - QuicTransportVersion version_, + ParsedQuicVersion version_, QuicTime time_added_, bool connection_rejected_statelessly); @@ -172,7 +172,7 @@ class QuicTimeWaitListManager : public QuicBlockedWriterInterface { ~ConnectionIdData(); int num_packets; - QuicTransportVersion version; + ParsedQuicVersion version; QuicTime time_added; // These packets may contain CONNECTION_CLOSE frames, or SREJ messages. std::vector<std::unique_ptr<QuicEncryptedPacket>> termination_packets; diff --git a/chromium/net/tools/quic/quic_time_wait_list_manager_test.cc b/chromium/net/tools/quic/quic_time_wait_list_manager_test.cc index a1576767763..a4e6ffc394c 100644 --- a/chromium/net/tools/quic/quic_time_wait_list_manager_test.cc +++ b/chromium/net/tools/quic/quic_time_wait_list_manager_test.cc @@ -102,7 +102,7 @@ class QuicTimeWaitListManagerTest : public QuicTest { void AddConnectionId( QuicConnectionId connection_id, - QuicTransportVersion version, + ParsedQuicVersion version, bool connection_rejected_statelessly, std::vector<std::unique_ptr<QuicEncryptedPacket>>* packets) { time_wait_list_manager_.AddConnectionIdToTimeWait( @@ -147,7 +147,7 @@ class ValidatePublicResetPacketPredicate const std::tr1::tuple<const char*, int> packet_buffer, testing::MatchResultListener* /* listener */) const override { FramerVisitorCapturingPublicReset visitor; - QuicFramer framer(AllSupportedTransportVersions(), QuicTime::Zero(), + QuicFramer framer(AllSupportedVersions(), QuicTime::Zero(), Perspective::IS_CLIENT); framer.set_visitor(&visitor); QuicEncryptedPacket encrypted(std::tr1::get<0>(packet_buffer), @@ -190,15 +190,14 @@ TEST_F(QuicTimeWaitListManagerTest, CheckStatelessConnectionIdInTimeWait) { TEST_F(QuicTimeWaitListManagerTest, SendVersionNegotiationPacket) { std::unique_ptr<QuicEncryptedPacket> packet( - QuicFramer::BuildVersionNegotiationPacket( - connection_id_, AllSupportedTransportVersions())); + QuicFramer::BuildVersionNegotiationPacket(connection_id_, + AllSupportedVersions())); EXPECT_CALL(writer_, WritePacket(_, packet->length(), server_address_.host(), client_address_, _)) .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 1))); time_wait_list_manager_.SendVersionNegotiationPacket( - connection_id_, AllSupportedTransportVersions(), server_address_, - client_address_); + connection_id_, AllSupportedVersions(), server_address_, client_address_); EXPECT_EQ(0u, time_wait_list_manager_.num_connections()); } @@ -395,13 +394,13 @@ TEST_F(QuicTimeWaitListManagerTest, GetQuicVersionFromMap) { AddConnectionId(kConnectionId3, QuicVersionMax(), /*connection_rejected_statelessly=*/false, nullptr); - EXPECT_EQ(QuicVersionMin(), + EXPECT_EQ(QuicTransportVersionMin(), QuicTimeWaitListManagerPeer::GetQuicVersionFromConnectionId( &time_wait_list_manager_, kConnectionId1)); - EXPECT_EQ(QuicVersionMax(), + EXPECT_EQ(QuicTransportVersionMax(), QuicTimeWaitListManagerPeer::GetQuicVersionFromConnectionId( &time_wait_list_manager_, kConnectionId2)); - EXPECT_EQ(QuicVersionMax(), + EXPECT_EQ(QuicTransportVersionMax(), QuicTimeWaitListManagerPeer::GetQuicVersionFromConnectionId( &time_wait_list_manager_, kConnectionId3)); } diff --git a/chromium/net/tools/quic/stateless_rejector.cc b/chromium/net/tools/quic/stateless_rejector.cc index 668065c35e4..625898a49ca 100644 --- a/chromium/net/tools/quic/stateless_rejector.cc +++ b/chromium/net/tools/quic/stateless_rejector.cc @@ -68,8 +68,8 @@ void StatelessRejector::OnChlo(QuicTransportVersion version, DCHECK_NE(connection_id, server_designated_connection_id); DCHECK_EQ(state_, UNKNOWN); - if (!FLAGS_quic_reloadable_flag_enable_quic_stateless_reject_support || - !FLAGS_quic_reloadable_flag_quic_use_cheap_stateless_rejects || + if (!GetQuicReloadableFlag(enable_quic_stateless_reject_support) || + !GetQuicReloadableFlag(quic_use_cheap_stateless_rejects) || !QuicCryptoServerStream::DoesPeerSupportStatelessRejects(message)) { state_ = UNSUPPORTED; return; diff --git a/chromium/net/tools/quic/stateless_rejector_test.cc b/chromium/net/tools/quic/stateless_rejector_test.cc index 67a630bc139..c1e17394dfd 100644 --- a/chromium/net/tools/quic/stateless_rejector_test.cc +++ b/chromium/net/tools/quic/stateless_rejector_test.cc @@ -10,6 +10,7 @@ #include "net/quic/core/crypto/crypto_handshake_message.h" #include "net/quic/core/crypto/proof_source.h" #include "net/quic/core/quic_utils.h" +#include "net/quic/core/tls_server_handshaker.h" #include "net/quic/platform/api/quic_flags.h" #include "net/quic/platform/api/quic_logging.h" #include "net/quic/platform/api/quic_ptr_util.h" @@ -80,7 +81,8 @@ class StatelessRejectorTest : public QuicTestWithParam<TestParams> { : proof_source_(crypto_test_utils::ProofSourceForTesting()), config_(QuicCryptoServerConfig::TESTING, QuicRandom::GetInstance(), - crypto_test_utils::ProofSourceForTesting()), + crypto_test_utils::ProofSourceForTesting(), + TlsServerHandshaker::CreateSslCtx()), config_peer_(&config_), compressed_certs_cache_( QuicCompressedCertsCache::kQuicCompressedCertsCacheSize), @@ -94,10 +96,12 @@ class StatelessRejectorTest : public QuicTestWithParam<TestParams> { kDefaultMaxPacketSize, QuicSocketAddress(QuicIpAddress::Loopback4(), 12345), QuicSocketAddress(QuicIpAddress::Loopback4(), 443))) { - FLAGS_quic_reloadable_flag_enable_quic_stateless_reject_support = - GetParam().flags == ENABLED || GetParam().flags == CHEAP_DISABLED; - FLAGS_quic_reloadable_flag_quic_use_cheap_stateless_rejects = - GetParam().flags == ENABLED || GetParam().flags == STATELESS_DISABLED; + SetQuicReloadableFlag( + enable_quic_stateless_reject_support, + GetParam().flags == ENABLED || GetParam().flags == CHEAP_DISABLED); + SetQuicReloadableFlag( + quic_use_cheap_stateless_rejects, + GetParam().flags == ENABLED || GetParam().flags == STATELESS_DISABLED); // Add a new primary config. std::unique_ptr<CryptoHandshakeMessage> msg(config_.AddDefaultConfig( diff --git a/chromium/net/tools/quic/test_tools/bad_packet_writer.cc b/chromium/net/tools/quic/test_tools/bad_packet_writer.cc new file mode 100644 index 00000000000..91d5fe50bca --- /dev/null +++ b/chromium/net/tools/quic/test_tools/bad_packet_writer.cc @@ -0,0 +1,36 @@ +// Copyright 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/tools/quic/test_tools/bad_packet_writer.h" + +namespace net { +namespace test { + +BadPacketWriter::BadPacketWriter(size_t packet_causing_write_error, + int error_code) + : packet_causing_write_error_(packet_causing_write_error), + error_code_(error_code) {} + +BadPacketWriter::~BadPacketWriter() {} + +WriteResult BadPacketWriter::WritePacket(const char* buffer, + size_t buf_len, + const QuicIpAddress& self_address, + const QuicSocketAddress& peer_address, + PerPacketOptions* options) { + if (error_code_ == 0 || packet_causing_write_error_ > 0) { + if (packet_causing_write_error_ > 0) { + --packet_causing_write_error_; + } + return QuicPacketWriterWrapper::WritePacket(buffer, buf_len, self_address, + peer_address, options); + } + // It's time to cause write error. + int error_code = error_code_; + error_code_ = 0; + return WriteResult(WRITE_STATUS_ERROR, error_code); +} + +} // namespace test +} // namespace net diff --git a/chromium/net/tools/quic/test_tools/bad_packet_writer.h b/chromium/net/tools/quic/test_tools/bad_packet_writer.h new file mode 100644 index 00000000000..e8d6d4ead06 --- /dev/null +++ b/chromium/net/tools/quic/test_tools/bad_packet_writer.h @@ -0,0 +1,36 @@ +// Copyright 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 NET_TOOLS_QUIC_TEST_TOOLS_BAD_PACKET_WRITER_H_ +#define NET_TOOLS_QUIC_TEST_TOOLS_BAD_PACKET_WRITER_H_ + +#include "net/tools/quic/quic_packet_writer_wrapper.h" + +namespace net { + +namespace test { +// This packet writer allows causing packet write error with specified error +// code when writing a particular packet. +class BadPacketWriter : public QuicPacketWriterWrapper { + public: + BadPacketWriter(size_t packet_causing_write_error, int error_code); + + ~BadPacketWriter() override; + + WriteResult WritePacket(const char* buffer, + size_t buf_len, + const QuicIpAddress& self_address, + const QuicSocketAddress& peer_address, + PerPacketOptions* options) override; + + private: + size_t packet_causing_write_error_; + int error_code_; +}; + +} // namespace test + +} // namespace net + +#endif // NET_TOOLS_QUIC_TEST_TOOLS_BAD_PACKET_WRITER_H_ diff --git a/chromium/net/tools/quic/test_tools/mock_quic_time_wait_list_manager.h b/chromium/net/tools/quic/test_tools/mock_quic_time_wait_list_manager.h index a7e72efd6fb..547ed7cb8ee 100644 --- a/chromium/net/tools/quic/test_tools/mock_quic_time_wait_list_manager.h +++ b/chromium/net/tools/quic/test_tools/mock_quic_time_wait_list_manager.h @@ -21,14 +21,14 @@ class MockTimeWaitListManager : public QuicTimeWaitListManager { MOCK_METHOD4(AddConnectionIdToTimeWait, void(QuicConnectionId connection_id, - QuicTransportVersion version, + ParsedQuicVersion version, bool connection_rejected_statelessly, std::vector<std::unique_ptr<QuicEncryptedPacket>>* termination_packets)); void QuicTimeWaitListManager_AddConnectionIdToTimeWait( QuicConnectionId connection_id, - QuicTransportVersion version, + ParsedQuicVersion version, bool connection_rejected_statelessly, std::vector<std::unique_ptr<QuicEncryptedPacket>>* termination_packets) { QuicTimeWaitListManager::AddConnectionIdToTimeWait( @@ -43,7 +43,7 @@ class MockTimeWaitListManager : public QuicTimeWaitListManager { MOCK_METHOD4(SendVersionNegotiationPacket, void(QuicConnectionId connection_id, - const QuicTransportVersionVector& supported_versions, + const ParsedQuicVersionVector& supported_versions, const QuicSocketAddress& server_address, const QuicSocketAddress& client_address)); }; diff --git a/chromium/net/tools/quic/test_tools/packet_reordering_writer.cc b/chromium/net/tools/quic/test_tools/packet_reordering_writer.cc index 99c965f5d79..992b9eb07f5 100644 --- a/chromium/net/tools/quic/test_tools/packet_reordering_writer.cc +++ b/chromium/net/tools/quic/test_tools/packet_reordering_writer.cc @@ -18,10 +18,12 @@ WriteResult PacketReorderingWriter::WritePacket( const QuicSocketAddress& peer_address, PerPacketOptions* options) { if (!delay_next_) { + VLOG(2) << "Writing a non-delayed packet"; WriteResult wr = QuicPacketWriterWrapper::WritePacket( buffer, buf_len, self_address, peer_address, options); --num_packets_to_wait_; if (num_packets_to_wait_ == 0) { + VLOG(2) << "Writing a delayed packet"; // It's time to write the delayed packet. QuicPacketWriterWrapper::WritePacket( delayed_data_.data(), delayed_data_.length(), delayed_self_address_, diff --git a/chromium/net/tools/quic/test_tools/quic_test_client.cc b/chromium/net/tools/quic/test_tools/quic_test_client.cc index 83ed2993f49..73d3be66736 100644 --- a/chromium/net/tools/quic/test_tools/quic_test_client.cc +++ b/chromium/net/tools/quic/test_tools/quic_test_client.cc @@ -165,7 +165,7 @@ class MockableQuicClientEpollNetworkHelper MockableQuicClient::MockableQuicClient( QuicSocketAddress server_address, const QuicServerId& server_id, - const QuicTransportVersionVector& supported_versions, + const ParsedQuicVersionVector& supported_versions, EpollServer* epoll_server) : MockableQuicClient(server_address, server_id, @@ -177,7 +177,7 @@ MockableQuicClient::MockableQuicClient( QuicSocketAddress server_address, const QuicServerId& server_id, const QuicConfig& config, - const QuicTransportVersionVector& supported_versions, + const ParsedQuicVersionVector& supported_versions, EpollServer* epoll_server) : MockableQuicClient(server_address, server_id, @@ -190,7 +190,7 @@ MockableQuicClient::MockableQuicClient( QuicSocketAddress server_address, const QuicServerId& server_id, const QuicConfig& config, - const QuicTransportVersionVector& supported_versions, + const ParsedQuicVersionVector& supported_versions, EpollServer* epoll_server, std::unique_ptr<ProofVerifier> proof_verifier) : QuicClient( @@ -251,7 +251,7 @@ void MockableQuicClient::set_track_last_incoming_packet(bool track) { QuicTestClient::QuicTestClient( QuicSocketAddress server_address, const string& server_hostname, - const QuicTransportVersionVector& supported_versions) + const ParsedQuicVersionVector& supported_versions) : QuicTestClient(server_address, server_hostname, QuicConfig(), @@ -261,7 +261,7 @@ QuicTestClient::QuicTestClient( QuicSocketAddress server_address, const string& server_hostname, const QuicConfig& config, - const QuicTransportVersionVector& supported_versions) + const ParsedQuicVersionVector& supported_versions) : client_(new MockableQuicClient(server_address, QuicServerId(server_hostname, server_address.port(), @@ -276,7 +276,7 @@ QuicTestClient::QuicTestClient( QuicSocketAddress server_address, const string& server_hostname, const QuicConfig& config, - const QuicTransportVersionVector& supported_versions, + const ParsedQuicVersionVector& supported_versions, std::unique_ptr<ProofVerifier> proof_verifier) : client_(new MockableQuicClient(server_address, QuicServerId(server_hostname, @@ -376,7 +376,7 @@ ssize_t QuicTestClient::GetOrCreateStreamAndSendRequest( stream->WriteOrBufferBody(body.as_string(), fin, ack_listener); ret = body.length(); } - if (FLAGS_quic_reloadable_flag_enable_quic_stateless_reject_support) { + if (GetQuicReloadableFlag(enable_quic_stateless_reject_support)) { std::unique_ptr<SpdyHeaderBlock> new_headers; if (headers) { new_headers.reset(new SpdyHeaderBlock(headers->Clone())); @@ -728,8 +728,15 @@ void QuicTestClient::UseConnectionId(QuicConnectionId connection_id) { client_->UseConnectionId(connection_id); } -void QuicTestClient::MigrateSocket(const QuicIpAddress& new_host) { - client_->MigrateSocket(new_host); +bool QuicTestClient::MigrateSocket(const QuicIpAddress& new_host) { + return client_->MigrateSocket(new_host); +} + +bool QuicTestClient::MigrateSocketWithSpecifiedPort( + const QuicIpAddress& new_host, + int port) { + client_->set_local_port(port); + return client_->MigrateSocket(new_host); } QuicIpAddress QuicTestClient::bind_to_address() const { diff --git a/chromium/net/tools/quic/test_tools/quic_test_client.h b/chromium/net/tools/quic/test_tools/quic_test_client.h index 4c76a763dd3..3302b52719f 100644 --- a/chromium/net/tools/quic/test_tools/quic_test_client.h +++ b/chromium/net/tools/quic/test_tools/quic_test_client.h @@ -34,19 +34,19 @@ class MockableQuicClient : public QuicClient { public: MockableQuicClient(QuicSocketAddress server_address, const QuicServerId& server_id, - const QuicTransportVersionVector& supported_versions, + const ParsedQuicVersionVector& supported_versions, EpollServer* epoll_server); MockableQuicClient(QuicSocketAddress server_address, const QuicServerId& server_id, const QuicConfig& config, - const QuicTransportVersionVector& supported_versions, + const ParsedQuicVersionVector& supported_versions, EpollServer* epoll_server); MockableQuicClient(QuicSocketAddress server_address, const QuicServerId& server_id, const QuicConfig& config, - const QuicTransportVersionVector& supported_versions, + const ParsedQuicVersionVector& supported_versions, EpollServer* epoll_server, std::unique_ptr<ProofVerifier> proof_verifier); @@ -79,15 +79,15 @@ class QuicTestClient : public QuicSpdyStream::Visitor, public: QuicTestClient(QuicSocketAddress server_address, const std::string& server_hostname, - const QuicTransportVersionVector& supported_versions); + const ParsedQuicVersionVector& supported_versions); QuicTestClient(QuicSocketAddress server_address, const std::string& server_hostname, const QuicConfig& config, - const QuicTransportVersionVector& supported_versions); + const ParsedQuicVersionVector& supported_versions); QuicTestClient(QuicSocketAddress server_address, const std::string& server_hostname, const QuicConfig& config, - const QuicTransportVersionVector& supported_versions, + const ParsedQuicVersionVector& supported_versions, std::unique_ptr<ProofVerifier> proof_verifier); ~QuicTestClient() override; @@ -183,7 +183,12 @@ class QuicTestClient : public QuicSpdyStream::Visitor, WaitUntil(timeout_ms, [this]() { return response_size() != 0; }); } - void MigrateSocket(const QuicIpAddress& new_host); + // Migrate local address to <|new_host|, a random port>. + // Return whether the migration succeeded. + bool MigrateSocket(const QuicIpAddress& new_host); + // Migrate local address to <|new_host|, |port|>. + // Return whether the migration succeeded. + bool MigrateSocketWithSpecifiedPort(const QuicIpAddress& new_host, int port); QuicIpAddress bind_to_address() const; void set_bind_to_address(QuicIpAddress address); const QuicSocketAddress& address() const; diff --git a/chromium/net/tools/quic/test_tools/quic_test_server.cc b/chromium/net/tools/quic/test_tools/quic_test_server.cc index 39d09265a2e..172000f596c 100644 --- a/chromium/net/tools/quic/test_tools/quic_test_server.cc +++ b/chromium/net/tools/quic/test_tools/quic_test_server.cc @@ -97,7 +97,7 @@ class QuicTestDispatcher : public QuicSimpleDispatcher { QuicConnection* connection = new QuicConnection( id, client, helper(), alarm_factory(), CreatePerConnectionWriter(), /* owns_writer= */ true, Perspective::IS_SERVER, - GetSupportedTransportVersions()); + GetSupportedVersions()); QuicServerSessionBase* session = nullptr; if (stream_factory_ != nullptr || crypto_stream_factory_ != nullptr) { @@ -150,7 +150,7 @@ QuicTestServer::QuicTestServer(std::unique_ptr<ProofSource> proof_source, QuicTestServer::QuicTestServer( std::unique_ptr<ProofSource> proof_source, const QuicConfig& config, - const QuicTransportVersionVector& supported_versions, + const ParsedQuicVersionVector& supported_versions, QuicHttpResponseCache* response_cache) : QuicServer(std::move(proof_source), config, diff --git a/chromium/net/tools/quic/test_tools/quic_test_server.h b/chromium/net/tools/quic/test_tools/quic_test_server.h index cf223118a1c..13ffc4ca6a0 100644 --- a/chromium/net/tools/quic/test_tools/quic_test_server.h +++ b/chromium/net/tools/quic/test_tools/quic_test_server.h @@ -62,7 +62,7 @@ class QuicTestServer : public QuicServer { QuicHttpResponseCache* response_cache); QuicTestServer(std::unique_ptr<ProofSource> proof_source, const QuicConfig& config, - const QuicTransportVersionVector& supported_versions, + const ParsedQuicVersionVector& supported_versions, QuicHttpResponseCache* response_cache); // Create a custom dispatcher which creates custom sessions. diff --git a/chromium/net/tools/testserver/minica.py b/chromium/net/tools/testserver/minica.py index 62991ffba2e..ff35b9cd833 100644 --- a/chromium/net/tools/testserver/minica.py +++ b/chromium/net/tools/testserver/minica.py @@ -93,37 +93,14 @@ class RSA(object): return asn1.ToDER(asn1.SEQUENCE([self.m, self.e])) -def Name(cn = None, c = None, o = None): - names = asn1.SEQUENCE([]) - - if cn is not None: - names.children.append( - asn1.SET([ - asn1.SEQUENCE([ - COMMON_NAME, cn, - ]) - ]) - ) - - if c is not None: - names.children.append( - asn1.SET([ - asn1.SEQUENCE([ - COUNTRY, c, - ]) - ]) - ) - - if o is not None: - names.children.append( - asn1.SET([ - asn1.SEQUENCE([ - ORGANIZATION, o, - ]) +def Name(cn): + return asn1.SEQUENCE([ + asn1.SET([ + asn1.SEQUENCE([ + COMMON_NAME, cn, ]) - ) - - return names + ]) + ]) # The private key and root certificate name are hard coded here: @@ -225,10 +202,6 @@ def MakeCertificate( '''MakeCertificate returns a DER encoded certificate, signed by privkey.''' extensions = asn1.SEQUENCE([]) - # Default subject name fields - c = "XX" - o = "Testing Org" - if is_ca: # Root certificate. c = None @@ -306,7 +279,7 @@ def MakeCertificate( asn1.UTCTime("100101060000Z"), # NotBefore asn1.UTCTime("321201060000Z"), # NotAfter ]), - Name(cn = subject_cn, c = c, o = o), # Subject + Name(cn = subject_cn), # Subject asn1.SEQUENCE([ # SubjectPublicKeyInfo asn1.SEQUENCE([ # Algorithm PUBLIC_KEY_RSA, diff --git a/chromium/net/tools/testserver/testserver.py b/chromium/net/tools/testserver/testserver.py index 10d207dfd13..4ec483109e6 100755 --- a/chromium/net/tools/testserver/testserver.py +++ b/chromium/net/tools/testserver/testserver.py @@ -39,21 +39,9 @@ import zlib BASE_DIR = os.path.dirname(os.path.abspath(__file__)) ROOT_DIR = os.path.dirname(os.path.dirname(os.path.dirname(BASE_DIR))) -# Temporary hack to deal with tlslite 0.3.8 -> 0.4.6 upgrade. -# -# TODO(davidben): Remove this when it has cycled through all the bots and -# developer checkouts or when http://crbug.com/356276 is resolved. -try: - os.remove(os.path.join(ROOT_DIR, 'third_party', 'tlslite', - 'tlslite', 'utils', 'hmac.pyc')) -except Exception: - pass - -# Append at the end of sys.path, it's fine to use the system library. -sys.path.append(os.path.join(ROOT_DIR, 'third_party', 'pyftpdlib', 'src')) - # Insert at the beginning of the path, we want to use our copies of the library -# unconditionally. +# unconditionally (since they contain modifications from anything that might be +# obtained from e.g. PyPi). sys.path.insert(0, os.path.join(ROOT_DIR, 'third_party', 'pywebsocket', 'src')) sys.path.insert(0, os.path.join(ROOT_DIR, 'third_party', 'tlslite')) @@ -1922,11 +1910,16 @@ class ServerRunner(testserver_base.TestServerRunner): print ('AIA server started on %s:%d...' % (host, self.__ocsp_server.server_port)) + ocsp_server_port = self.__ocsp_server.server_port + if self.options.ocsp_proxy_port_number != 0: + ocsp_server_port = self.options.ocsp_proxy_port_number + server_data['ocsp_port'] = self.__ocsp_server.server_port + (pem_cert_and_key, intermediate_cert_der) = \ minica.GenerateCertKeyAndIntermediate( - subject = "127.0.0.1", - ca_issuers_url = ("http://%s:%d/ca_issuers" % - (host, self.__ocsp_server.server_port)), + subject = self.options.cert_common_name, + ca_issuers_url = + ("http://%s:%d/ca_issuers" % (host, ocsp_server_port)), serial = self.options.cert_serial) self.__ocsp_server.ocsp_response = None @@ -1995,10 +1988,14 @@ class ServerRunner(testserver_base.TestServerRunner): raise testserver_base.OptionError('unknown OCSP produced: ' + self.options.ocsp_produced) + ocsp_server_port = self.__ocsp_server.server_port + if self.options.ocsp_proxy_port_number != 0: + ocsp_server_port = self.options.ocsp_proxy_port_number + server_data['ocsp_port'] = self.__ocsp_server.server_port + (pem_cert_and_key, ocsp_der) = minica.GenerateCertKeyAndOCSP( - subject = "127.0.0.1", - ocsp_url = ("http://%s:%d/ocsp" % - (host, self.__ocsp_server.server_port)), + subject = self.options.cert_common_name, + ocsp_url = ("http://%s:%d/ocsp" % (host, ocsp_server_port)), ocsp_states = ocsp_states, ocsp_dates = ocsp_dates, ocsp_produced = ocsp_produced, @@ -2198,6 +2195,10 @@ class ServerRunner(testserver_base.TestServerRunner): default=0, type=int, help='If non-zero then the generated ' 'certificate will have this serial number') + self.option_parser.add_option('--cert-common-name', dest='cert_common_name', + default="127.0.0.1", + help='The generated certificate will have ' + 'this common name') self.option_parser.add_option('--tls-intolerant', dest='tls_intolerant', default='0', type='int', help='If nonzero, certain TLS connections ' @@ -2297,6 +2298,10 @@ class ServerRunner(testserver_base.TestServerRunner): help='If set, the OCSP server will return ' 'a tryLater status rather than the actual ' 'OCSP response.') + self.option_parser.add_option('--ocsp-proxy-port-number', default=0, + type='int', dest='ocsp_proxy_port_number', + help='Port allocated for OCSP proxy ' + 'when connection is proxied.') self.option_parser.add_option('--alert-after-handshake', dest='alert_after_handshake', default=False, action='store_true', diff --git a/chromium/net/traffic_annotation/network_traffic_annotation.h b/chromium/net/traffic_annotation/network_traffic_annotation.h index 333e839df5d..15f1aeaa84e 100644 --- a/chromium/net/traffic_annotation/network_traffic_annotation.h +++ b/chromium/net/traffic_annotation/network_traffic_annotation.h @@ -276,6 +276,12 @@ struct MutablePartialNetworkTrafficAnnotationTag { net::DefineNetworkTrafficAnnotation( \ "missing", "Function called without traffic annotation.") +// TODO(crbug.com/656607): Remove this temporary tag which is only used during +// refactoring. +#define NO_TRAFFIC_ANNOTATION_BUG_656607 \ + net::DefineNetworkTrafficAnnotation("undefined-656607", \ + "Temporary tag for crbug.com/656607.") + #undef COMPUTE_STRING_HASH #endif // NET_TRAFFIC_ANNOTATION_NETWORK_TRAFFIC_ANNOTATION_H_ diff --git a/chromium/net/url_request/network_error_logging_delegate.h b/chromium/net/url_request/network_error_logging_delegate.h index ec2238ca54e..26330d860d4 100644 --- a/chromium/net/url_request/network_error_logging_delegate.h +++ b/chromium/net/url_request/network_error_logging_delegate.h @@ -38,6 +38,8 @@ class NET_EXPORT NetworkErrorLoggingDelegate { int status_code; base::TimeDelta elapsed_time; Error type; + + bool is_reporting_upload; }; static const char kHeaderName[]; @@ -65,6 +67,11 @@ class NET_EXPORT NetworkErrorLoggingDelegate { // // |details| is the details of the network error. virtual void OnNetworkError(const ErrorDetails& details) = 0; + + // Removes all stored data associated with any origins matching + // |origin_filter| (or all origins if null). + virtual void RemoveBrowsingData( + const base::RepeatingCallback<bool(const GURL&)>& origin_filter) = 0; }; } // namespace net diff --git a/chromium/net/url_request/url_request.cc b/chromium/net/url_request/url_request.cc index 91763538afe..8cef4d5f0d1 100644 --- a/chromium/net/url_request/url_request.cc +++ b/chromium/net/url_request/url_request.cc @@ -31,6 +31,7 @@ #include "net/log/net_log.h" #include "net/log/net_log_event_type.h" #include "net/log/net_log_source_type.h" +#include "net/reporting/reporting_service.h" #include "net/ssl/ssl_cert_request_info.h" #include "net/url_request/redirect_info.h" #include "net/url_request/redirect_util.h" @@ -191,7 +192,8 @@ URLRequest::~URLRequest() { // on UserData associated with |this| and poke at it during teardown. job_.reset(); - context_->RemoveURLRequest(this); + DCHECK_EQ(1u, context_->url_requests()->count(this)); + context_->url_requests()->erase(this); int net_error = OK; // Log error only on failure, not cancellation, as even successful requests @@ -574,11 +576,12 @@ URLRequest::URLRequest(const GURL& url, received_response_content_length_(0), creation_time_(base::TimeTicks::Now()), raw_header_size_(0), + is_pac_request_(false), traffic_annotation_(traffic_annotation) { // Sanity check out environment. DCHECK(base::ThreadTaskRunnerHandle::IsSet()); - context->InsertURLRequest(this); + context->url_requests()->insert(this); net_log_.BeginEvent( NetLogEventType::REQUEST_ALIVE, base::Bind(&NetLogURLRequestConstructorCallback, &url, priority_)); @@ -1183,13 +1186,21 @@ void URLRequest::MaybeGenerateNetworkErrorLoggingReport() { details.server_ip = endpoint.address(); // TODO(juliatuttle): Plumb this. details.protocol = kProtoUnknown; - details.status_code = GetResponseCode(); - if (details.status_code == -1) + if (response_headers()) { + // HttpResponseHeaders::response_code() returns 0 if response code couldn't + // be parsed, which is also how NEL represents the same. + details.status_code = response_headers()->response_code(); + } else { details.status_code = 0; + } details.elapsed_time = base::TimeTicks::Now() - load_timing_info_.request_start; details.type = status().ToNetError(); + details.is_reporting_upload = + context()->reporting_service() && + context()->reporting_service()->RequestIsUpload(*this); + delegate->OnNetworkError(details); } #endif // BUILDFLAG(ENABLE_REPORTING) diff --git a/chromium/net/url_request/url_request.h b/chromium/net/url_request/url_request.h index 0635448f00a..60fbf78c788 100644 --- a/chromium/net/url_request/url_request.h +++ b/chromium/net/url_request/url_request.h @@ -662,6 +662,15 @@ class NET_EXPORT URLRequest : public base::SupportsUserData { // encryption, 0 for cached responses. int raw_header_size() const { return raw_header_size_; } + // True if this request was issued by the proxy service subsystem in order to + // probe/fetch a Proxy Auto Config script. + // TODO(mmenke): See if there's a way to not need this. + bool is_pac_request() const { return is_pac_request_; } + // Sets whether this is a request for a PAC script. Defaults to false. + void set_is_pac_request(bool is_pac_request) { + is_pac_request_ = is_pac_request; + } + // Returns the error status of the request. // Do not use! Going to be protected! const URLRequestStatus& status() const { return status_; } @@ -890,6 +899,9 @@ class NET_EXPORT URLRequest : public base::SupportsUserData { // The raw header size of the response. int raw_header_size_; + // True if this is a request for a PAC script. + bool is_pac_request_; + const NetworkTrafficAnnotationTag traffic_annotation_; // See Set{Request|Response}HeadersCallback() above for details. diff --git a/chromium/net/url_request/url_request_context.cc b/chromium/net/url_request/url_request_context.cc index b19870fdd75..17736d522f7 100644 --- a/chromium/net/url_request/url_request_context.cc +++ b/chromium/net/url_request/url_request_context.cc @@ -9,6 +9,7 @@ #include "base/compiler_specific.h" #include "base/debug/alias.h" #include "base/memory/ptr_util.h" +#include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" @@ -49,10 +50,10 @@ URLRequestContext::URLRequestContext() reporting_service_(nullptr), network_error_logging_delegate_(nullptr), #endif // BUILDFLAG(ENABLE_REPORTING) + url_requests_(std::make_unique<std::set<const URLRequest*>>()), enable_brotli_(false), check_cleartext_permitted_(false), - name_("unknown"), - largest_outstanding_requests_count_seen_(0) { + name_("unknown") { base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider( this, "URLRequestContext", base::ThreadTaskRunnerHandle::Get()); } @@ -134,33 +135,14 @@ void URLRequestContext::set_cookie_store(CookieStore* cookie_store) { cookie_store_ = cookie_store; } -void URLRequestContext::InsertURLRequest(const URLRequest* request) const { - url_requests_.insert(request); - if (url_requests_.size() > largest_outstanding_requests_count_seen_) { - largest_outstanding_requests_count_seen_ = url_requests_.size(); - UMA_HISTOGRAM_COUNTS_1M("Net.URLRequestContext.OutstandingRequests", - largest_outstanding_requests_count_seen_); - UMA_HISTOGRAM_SPARSE_SLOWLY( - "Net.URLRequestContext.OutstandingRequests.Type", - request->traffic_annotation().unique_id_hash_code); - } -} - -void URLRequestContext::RemoveURLRequest(const URLRequest* request) const { - DCHECK_EQ(1u, url_requests_.count(request)); - url_requests_.erase(request); -} - void URLRequestContext::AssertNoURLRequests() const { - int num_requests = url_requests_.size(); + int num_requests = url_requests_->size(); if (num_requests != 0) { // We're leaking URLRequests :( Dump the URL of the first one and record how // many we leaked so we have an idea of how bad it is. - char url_buf[128]; - const URLRequest* request = *url_requests_.begin(); - base::strlcpy(url_buf, request->url().spec().c_str(), arraysize(url_buf)); + const URLRequest* request = *url_requests_->begin(); int load_flags = request->load_flags(); - base::debug::Alias(url_buf); + DEBUG_ALIAS_FOR_GURL(url_buf, request->url()); base::debug::Alias(&num_requests); base::debug::Alias(&load_flags); CHECK(false) << "Leaked " << num_requests << " URLRequest(s). First URL: " @@ -180,7 +162,7 @@ bool URLRequestContext::OnMemoryDump( pmd->CreateAllocatorDump(dump_name); dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameObjectCount, base::trace_event::MemoryAllocatorDump::kUnitsObjects, - url_requests_.size()); + url_requests_->size()); HttpTransactionFactory* transaction_factory = http_transaction_factory(); if (transaction_factory) { HttpNetworkSession* network_session = transaction_factory->GetSession(); diff --git a/chromium/net/url_request/url_request_context.h b/chromium/net/url_request/url_request_context.h index c498ad2282e..30fc9851aa9 100644 --- a/chromium/net/url_request/url_request_context.h +++ b/chromium/net/url_request/url_request_context.h @@ -215,14 +215,10 @@ class NET_EXPORT URLRequestContext // Gets the URLRequest objects that hold a reference to this // URLRequestContext. - const std::set<const URLRequest*>& url_requests() const { - return url_requests_; + std::set<const URLRequest*>* url_requests() const { + return url_requests_.get(); } - void InsertURLRequest(const URLRequest* request) const; - - void RemoveURLRequest(const URLRequest* request) const; - // CHECKs that no URLRequests using this context remain. Subclasses should // additionally call AssertNoURLRequests() within their own destructor, // prior to implicit destruction of subclass-owned state. @@ -328,7 +324,7 @@ class NET_EXPORT URLRequestContext // be added to CopyFrom. // --------------------------------------------------------------------------- - mutable std::set<const URLRequest*> url_requests_; + std::unique_ptr<std::set<const URLRequest*>> url_requests_; // Enables Brotli Content-Encoding support. bool enable_brotli_; @@ -341,10 +337,6 @@ class NET_EXPORT URLRequestContext // to be unique. std::string name_; - // The largest number of outstanding URLRequests that have been created by - // |this| and are not yet destroyed. This doesn't need to be in CopyFrom. - mutable size_t largest_outstanding_requests_count_seen_; - THREAD_CHECKER(thread_checker_); DISALLOW_COPY_AND_ASSIGN(URLRequestContext); diff --git a/chromium/net/url_request/url_request_context_builder.cc b/chromium/net/url_request/url_request_context_builder.cc index 0d566da4c41..6bdf43edbb7 100644 --- a/chromium/net/url_request/url_request_context_builder.cc +++ b/chromium/net/url_request/url_request_context_builder.cc @@ -150,6 +150,12 @@ class ContainerURLRequestContext final : public URLRequestContext { ~ContainerURLRequestContext() override { #if BUILDFLAG(ENABLE_REPORTING) + // Destroy the NetworkErrorLoggingDelegate so that destroying the + // ReportingService (which might abort in-flight URLRequests, generating + // network errors) won't recursively try to queue more network error + // reports. + storage_.set_network_error_logging_delegate(nullptr); + // Destroy the ReportingService before the rest of the URLRequestContext, so // it cancels any pending requests it may have. storage_.set_reporting_service(nullptr); diff --git a/chromium/net/url_request/url_request_ftp_job.cc b/chromium/net/url_request/url_request_ftp_job.cc index 803758125da..1d7ff64d0fc 100644 --- a/chromium/net/url_request/url_request_ftp_job.cc +++ b/chromium/net/url_request/url_request_ftp_job.cc @@ -45,7 +45,7 @@ URLRequestFtpJob::URLRequestFtpJob( : URLRequestJob(request, network_delegate), priority_(DEFAULT_PRIORITY), proxy_service_(request_->context()->proxy_service()), - pac_request_(NULL), + proxy_resolve_request_(NULL), http_response_info_(NULL), read_in_progress_(false), ftp_transaction_factory_(ftp_transaction_factory), @@ -104,7 +104,7 @@ void URLRequestFtpJob::SetPriority(RequestPriority priority) { } void URLRequestFtpJob::Start() { - DCHECK(!pac_request_); + DCHECK(!proxy_resolve_request_); DCHECK(!ftp_transaction_); DCHECK(!http_transaction_); @@ -117,7 +117,7 @@ void URLRequestFtpJob::Start() { request_->url(), "GET", &proxy_info_, base::Bind(&URLRequestFtpJob::OnResolveProxyComplete, base::Unretained(this)), - &pac_request_, NULL, request_->net_log()); + &proxy_resolve_request_, NULL, request_->net_log()); if (rv == ERR_IO_PENDING) return; @@ -126,9 +126,9 @@ void URLRequestFtpJob::Start() { } void URLRequestFtpJob::Kill() { - if (pac_request_) { - proxy_service_->CancelPacRequest(pac_request_); - pac_request_ = nullptr; + if (proxy_resolve_request_) { + proxy_service_->CancelRequest(proxy_resolve_request_); + proxy_resolve_request_ = nullptr; } if (ftp_transaction_) ftp_transaction_.reset(); @@ -139,7 +139,7 @@ void URLRequestFtpJob::Kill() { } void URLRequestFtpJob::OnResolveProxyComplete(int result) { - pac_request_ = NULL; + proxy_resolve_request_ = NULL; if (result != OK) { OnStartCompletedAsync(result); @@ -172,9 +172,8 @@ void URLRequestFtpJob::StartFtpTransaction() { if (ftp_transaction_) { rv = ftp_transaction_->Start( &ftp_request_info_, - base::Bind(&URLRequestFtpJob::OnStartCompleted, - base::Unretained(this)), - request_->net_log()); + base::Bind(&URLRequestFtpJob::OnStartCompleted, base::Unretained(this)), + request_->net_log(), request_->traffic_annotation()); if (rv == ERR_IO_PENDING) return; } else { @@ -278,8 +277,8 @@ void URLRequestFtpJob::RestartTransactionWithAuth() { } LoadState URLRequestFtpJob::GetLoadState() const { - if (pac_request_) - return proxy_service_->GetLoadState(pac_request_); + if (proxy_resolve_request_) + return proxy_service_->GetLoadState(proxy_resolve_request_); if (proxy_info_.is_direct()) { return ftp_transaction_ ? ftp_transaction_->GetLoadState() : LOAD_STATE_IDLE; diff --git a/chromium/net/url_request/url_request_ftp_job.h b/chromium/net/url_request/url_request_ftp_job.h index b8d06db7bc2..0edb4d661d9 100644 --- a/chromium/net/url_request/url_request_ftp_job.h +++ b/chromium/net/url_request/url_request_ftp_job.h @@ -81,7 +81,7 @@ class NET_EXPORT_PRIVATE URLRequestFtpJob : public URLRequestJob { ProxyService* proxy_service_; ProxyInfo proxy_info_; - ProxyService::PacRequest* pac_request_; + ProxyService::Request* proxy_resolve_request_; FtpRequestInfo ftp_request_info_; std::unique_ptr<FtpTransaction> ftp_transaction_; diff --git a/chromium/net/url_request/url_request_http_job.cc b/chromium/net/url_request/url_request_http_job.cc index da7a1986598..d6eb1043b34 100644 --- a/chromium/net/url_request/url_request_http_job.cc +++ b/chromium/net/url_request/url_request_http_job.cc @@ -100,7 +100,7 @@ void LogTrustAnchor(const net::HashValueVector& spki_hashes) { if (id != 0) break; } - UMA_HISTOGRAM_SPARSE_SLOWLY("Net.Certificate.TrustAnchor.Request", id); + base::UmaHistogramSparse("Net.Certificate.TrustAnchor.Request", id); } // Records per-request histograms relating to Certificate Transparency @@ -593,7 +593,7 @@ void URLRequestHttpJob::AddExtraHeaders() { bool advertise_brotli = false; if (request()->context()->enable_brotli()) { if (request()->url().SchemeIsCryptographic() || - IsLocalhost(request()->url().HostNoBracketsPiece())) { + IsLocalhost(request()->url())) { advertise_brotli = true; } } 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 9d9aaaf1c3b..10b36de23a6 100644 --- a/chromium/net/url_request/url_request_http_job_unittest.cc +++ b/chromium/net/url_request/url_request_http_job_unittest.cc @@ -1575,6 +1575,7 @@ class FakeWebSocketHandshakeStream : public WebSocketHandshakeStreamBase { // Fake implementation of HttpStreamBase methods. int InitializeStream(const HttpRequestInfo* request_info, + bool can_send_early, RequestPriority priority, const NetLogWithSource& net_log, const CompletionCallback& callback) override { diff --git a/chromium/net/url_request/url_request_quic_perftest.cc b/chromium/net/url_request/url_request_quic_perftest.cc index a81ae35a556..614ef64461d 100644 --- a/chromium/net/url_request/url_request_quic_perftest.cc +++ b/chromium/net/url_request/url_request_quic_perftest.cc @@ -112,6 +112,7 @@ class URLRequestQuicPerfTest : public ::testing::Test { new HttpNetworkSession::Params); params->enable_quic = true; params->enable_user_alternate_protocol_ports = true; + params->quic_allow_remote_alt_svc = true; context_->set_host_resolver(host_resolver_.get()); context_->set_http_network_session_params(std::move(params)); context_->set_cert_verifier(&cert_verifier_); @@ -146,15 +147,15 @@ class URLRequestQuicPerfTest : public ::testing::Test { kHelloAltSvcResponse); quic_server_.reset(new QuicSimpleServer( test::crypto_test_utils::ProofSourceForTesting(), config, - net::QuicCryptoServerConfig::ConfigOptions(), - AllSupportedTransportVersions(), &response_cache_)); + net::QuicCryptoServerConfig::ConfigOptions(), AllSupportedVersions(), + &response_cache_)); int rv = quic_server_->Listen( net::IPEndPoint(net::IPAddress::IPv4AllZeros(), kAltSvcPort)); ASSERT_GE(rv, 0) << "Quic server fails to start"; CertVerifyResult verify_result; verify_result.verified_cert = ImportCertFromFile( - GetTestCertsDirectory(), "quic_test.example.com.crt"); + GetTestCertsDirectory(), "quic-chain.pem"); cert_verifier_.AddResultForCert(verify_result.verified_cert.get(), verify_result, OK); } diff --git a/chromium/net/url_request/url_request_quic_unittest.cc b/chromium/net/url_request/url_request_quic_unittest.cc index 6820bd9a4c1..615aad96fb8 100644 --- a/chromium/net/url_request/url_request_quic_unittest.cc +++ b/chromium/net/url_request/url_request_quic_unittest.cc @@ -35,9 +35,7 @@ namespace net { namespace { -// This must match the certificate used (quic_test.example.com.crt and -// quic_test.example.com.key.pkcs8). -const int kTestServerPort = 6121; +// This must match the certificate used (quic-chain.pem and quic-leaf-cert.key). const char kTestServerHost[] = "test.example.com"; // Used as a simple response from the server. const char kHelloPath[] = "/hello.txt"; @@ -53,12 +51,7 @@ class URLRequestQuicTest : public ::testing::Test { new HttpNetworkSession::Params); CertVerifyResult verify_result; verify_result.verified_cert = ImportCertFromFile( - GetTestCertsDirectory(), "quic_test.example.com.crt"); - cert_verifier_.AddResultForCertAndHost(verify_result.verified_cert.get(), - "test.example.com", verify_result, - OK); - verify_result.verified_cert = ImportCertFromFile( - GetTestCertsDirectory(), "quic_test_ecc.example.com.crt"); + GetTestCertsDirectory(), "quic-chain.pem"); cert_verifier_.AddResultForCertAndHost(verify_result.verified_cert.get(), "test.example.com", verify_result, OK); @@ -99,7 +92,7 @@ class URLRequestQuicTest : public ::testing::Test { void ExtractNetLog(NetLogEventType type, TestNetLogEntry::List* entry_list) const { - net::TestNetLogEntry::List entries; + TestNetLogEntry::List entries; net_log_.GetEntries(&entries); for (const auto& entry : entries) { @@ -114,6 +107,33 @@ class URLRequestQuicTest : public ::testing::Test { ->GetRstErrorCount(error_code); } + static const NetLogSource FindPushUrlSource( + const TestNetLogEntry::List& entries, + const std::string& push_url) { + std::string entry_push_url; + for (const auto& entry : entries) { + if (entry.phase == NetLogEventPhase::BEGIN && + entry.source.type == + NetLogSourceType::SERVER_PUSH_LOOKUP_TRANSACTION && + entry.GetStringValue("push_url", &entry_push_url) && + entry_push_url == push_url) { + return entry.source; + } + } + return NetLogSource(); + } + + static const TestNetLogEntry* FindEndBySource( + const TestNetLogEntry::List& entries, + const NetLogSource& source) { + for (const auto& entry : entries) { + if (entry.phase == NetLogEventPhase::END && + entry.source.type == source.type && entry.source.id == source.id) + return &entry; + } + return nullptr; + } + private: void StartQuicServer() { // Set up in-memory cache. @@ -126,15 +146,15 @@ class URLRequestQuicTest : public ::testing::Test { new net::ProofSourceChromium()); base::FilePath directory = GetTestCertsDirectory(); CHECK(proof_source->Initialize( - directory.Append(FILE_PATH_LITERAL("quic_test.example.com.crt")), - directory.Append(FILE_PATH_LITERAL("quic_test.example.com.key.pkcs8")), - directory.Append(FILE_PATH_LITERAL("quic_test.example.com.key.sct")))); + directory.Append(FILE_PATH_LITERAL("quic-chain.pem")), + directory.Append(FILE_PATH_LITERAL("quic-leaf-cert.key")), + base::FilePath())); server_.reset(new QuicSimpleServer( test::crypto_test_utils::ProofSourceForTesting(), config, - net::QuicCryptoServerConfig::ConfigOptions(), - AllSupportedTransportVersions(), &response_cache_)); - int rv = server_->Listen( - net::IPEndPoint(net::IPAddress::IPv4AllZeros(), kTestServerPort)); + net::QuicCryptoServerConfig::ConfigOptions(), AllSupportedVersions(), + &response_cache_)); + int rv = + server_->Listen(net::IPEndPoint(net::IPAddress::IPv4AllZeros(), 0)); EXPECT_GE(rv, 0) << "Quic server fails to start"; std::unique_ptr<MockHostResolver> resolver(new MockHostResolver()); @@ -248,7 +268,7 @@ TEST_F(URLRequestQuicTest, TestGetRequest) { EXPECT_EQ(kHelloBodyValue, delegate.data_received()); } -TEST_F(URLRequestQuicTest, CancelPushIfCached) { +TEST_F(URLRequestQuicTest, CancelPushIfCached_SomeCached) { base::RunLoop run_loop; Init(); @@ -292,7 +312,7 @@ TEST_F(URLRequestQuicTest, CancelPushIfCached) { net::TestNetLogEntry::List entries; ExtractNetLog(NetLogEventType::SERVER_PUSH_LOOKUP_TRANSACTION, &entries); - EXPECT_EQ(4u, entries.size()); + ASSERT_EQ(4u, entries.size()); std::string value; int net_error; @@ -301,22 +321,30 @@ TEST_F(URLRequestQuicTest, CancelPushIfCached) { std::string push_url_2 = base::StringPrintf("https://%s%s", kTestServerHost, "/favicon.ico"); - EXPECT_TRUE(entries[0].GetStringValue("push_url", &value)); - EXPECT_EQ(value, push_url_1); - EXPECT_TRUE(entries[1].GetStringValue("push_url", &value)); - EXPECT_EQ(value, push_url_2); + const NetLogSource source_1 = FindPushUrlSource(entries, push_url_1); + EXPECT_TRUE(source_1.IsValid()); + + // No net error code for this lookup transaction, the push is found. + const TestNetLogEntry* end_entry_1 = FindEndBySource(entries, source_1); + EXPECT_FALSE(end_entry_1->params); + EXPECT_FALSE(end_entry_1->GetIntegerValue("net_error", &net_error)); + + const NetLogSource source_2 = FindPushUrlSource(entries, push_url_2); + EXPECT_TRUE(source_2.IsValid()); + EXPECT_NE(source_1.id, source_2.id); + // Net error code -400 is found for this lookup transaction, the push is not // found in the cache. - EXPECT_TRUE(entries[2].GetIntegerValue("net_error", &net_error)); + const TestNetLogEntry* end_entry_2 = FindEndBySource(entries, source_2); + EXPECT_TRUE(end_entry_2->params); + EXPECT_TRUE(end_entry_2->GetIntegerValue("net_error", &net_error)); EXPECT_EQ(net_error, -400); - // No net error code for this lookup transaction, the push is found. - EXPECT_FALSE(entries[3].GetIntegerValue("net_error", &net_error)); // Verify the reset error count received on the server side. EXPECT_LE(1u, GetRstErrorCountReceivedByServer(QUIC_STREAM_CANCELLED)); } -TEST_F(URLRequestQuicTest, CancelPushIfCached2) { +TEST_F(URLRequestQuicTest, CancelPushIfCached_AllCached) { base::RunLoop run_loop; Init(); @@ -357,7 +385,7 @@ TEST_F(URLRequestQuicTest, CancelPushIfCached2) { EXPECT_TRUE(request_1->status().is_success()); // Send a request to /index2.html which pushes /kitten-1.jpg and /favicon.ico. - // Should cancel push for /kitten-1.jpg. + // Should cancel push for both pushed resources, since they're already cached. CheckLoadTimingDelegate delegate(true); std::string url = base::StringPrintf("https://%s%s", kTestServerHost, "/index2.html"); @@ -387,17 +415,22 @@ TEST_F(URLRequestQuicTest, CancelPushIfCached2) { std::string push_url_2 = base::StringPrintf("https://%s%s", kTestServerHost, "/favicon.ico"); - EXPECT_TRUE(entries[0].GetStringValue("push_url", &value)); - EXPECT_EQ(value, push_url_1); - - EXPECT_TRUE(entries[1].GetStringValue("push_url", &value)); - EXPECT_EQ(value, push_url_2); + const NetLogSource source_1 = FindPushUrlSource(entries, push_url_1); + EXPECT_TRUE(source_1.IsValid()); // No net error code for this lookup transaction, the push is found. - EXPECT_FALSE(entries[2].GetIntegerValue("net_error", &net_error)); + const TestNetLogEntry* end_entry_1 = FindEndBySource(entries, source_1); + EXPECT_FALSE(end_entry_1->params); + EXPECT_FALSE(end_entry_1->GetIntegerValue("net_error", &net_error)); + + const NetLogSource source_2 = FindPushUrlSource(entries, push_url_2); + EXPECT_TRUE(source_1.IsValid()); + EXPECT_NE(source_1.id, source_2.id); // No net error code for this lookup transaction, the push is found. - EXPECT_FALSE(entries[3].GetIntegerValue("net_error", &net_error)); + const TestNetLogEntry* end_entry_2 = FindEndBySource(entries, source_2); + EXPECT_FALSE(end_entry_2->params); + EXPECT_FALSE(end_entry_2->GetIntegerValue("net_error", &net_error)); // Verify the reset error count received on the server side. EXPECT_LE(2u, GetRstErrorCountReceivedByServer(QUIC_STREAM_CANCELLED)); @@ -437,14 +470,19 @@ TEST_F(URLRequestQuicTest, DoNotCancelPushIfNotFoundInCache) { std::string push_url_2 = base::StringPrintf("https://%s%s", kTestServerHost, "/favicon.ico"); - EXPECT_TRUE(entries[0].GetStringValue("push_url", &value)); - EXPECT_EQ(value, push_url_1); - EXPECT_TRUE(entries[1].GetIntegerValue("net_error", &net_error)); + const NetLogSource source_1 = FindPushUrlSource(entries, push_url_1); + EXPECT_TRUE(source_1.IsValid()); + const TestNetLogEntry* end_entry_1 = FindEndBySource(entries, source_1); + EXPECT_TRUE(end_entry_1->params); + EXPECT_TRUE(end_entry_1->GetIntegerValue("net_error", &net_error)); EXPECT_EQ(net_error, -400); - EXPECT_TRUE(entries[2].GetStringValue("push_url", &value)); - EXPECT_EQ(value, push_url_2); - EXPECT_TRUE(entries[3].GetIntegerValue("net_error", &net_error)); + const NetLogSource source_2 = FindPushUrlSource(entries, push_url_2); + EXPECT_TRUE(source_2.IsValid()); + EXPECT_NE(source_1.id, source_2.id); + const TestNetLogEntry* end_entry_2 = FindEndBySource(entries, source_2); + EXPECT_TRUE(end_entry_2->params); + EXPECT_TRUE(end_entry_2->GetIntegerValue("net_error", &net_error)); EXPECT_EQ(net_error, -400); // Verify the reset error count received on the server side. diff --git a/chromium/net/url_request/url_request_test_util.cc b/chromium/net/url_request/url_request_test_util.cc index 9a34c24e539..59bcad5ddb0 100644 --- a/chromium/net/url_request/url_request_test_util.cc +++ b/chromium/net/url_request/url_request_test_util.cc @@ -16,7 +16,7 @@ #include "net/base/host_port_pair.h" #include "net/cert/cert_verifier.h" #include "net/cert/ct_policy_enforcer.h" -#include "net/cert/multi_log_ct_verifier.h" +#include "net/cert/do_nothing_ct_verifier.h" #include "net/dns/mock_host_resolver.h" #include "net/http/http_network_session.h" #include "net/http/http_response_headers.h" @@ -82,7 +82,7 @@ void TestURLRequestContext::Init() { } if (!cert_transparency_verifier()) { context_storage_.set_cert_transparency_verifier( - std::make_unique<MultiLogCTVerifier>()); + std::make_unique<DoNothingCTVerifier>()); } if (!ct_policy_enforcer()) { context_storage_.set_ct_policy_enforcer( diff --git a/chromium/net/url_request/url_request_throttler_manager.cc b/chromium/net/url_request/url_request_throttler_manager.cc index 23ffab916d4..f879137e5d1 100644 --- a/chromium/net/url_request/url_request_throttler_manager.cc +++ b/chromium/net/url_request/url_request_throttler_manager.cc @@ -79,9 +79,9 @@ scoped_refptr<URLRequestThrottlerEntryInterface> // We only disable back-off throttling on an entry that we have // just constructed. This is to allow unit tests to explicitly override // the entry for localhost URLs. - std::string host = url.host(); - if (IsLocalhost(host)) { - if (!logged_for_localhost_disabled_ && IsLocalhost(host)) { + if (IsLocalhost(url)) { + if (!logged_for_localhost_disabled_ && IsLocalhost(url)) { + std::string host = url.host(); logged_for_localhost_disabled_ = true; net_log_.AddEvent(NetLogEventType::THROTTLING_DISABLED_FOR_HOST, NetLog::StringCallback("host", &host)); diff --git a/chromium/net/url_request/url_request_unittest.cc b/chromium/net/url_request/url_request_unittest.cc index 1aa782f31c5..01afe00bd41 100644 --- a/chromium/net/url_request/url_request_unittest.cc +++ b/chromium/net/url_request/url_request_unittest.cc @@ -6472,7 +6472,7 @@ TEST_F(URLRequestTestHTTP, ProcessPKPAndSendReport) { std::unique_ptr<base::Value> value( base::JSONReader::Read(mock_report_sender.latest_report())); ASSERT_TRUE(value); - ASSERT_TRUE(value->IsType(base::Value::Type::DICTIONARY)); + ASSERT_TRUE(value->is_dict()); base::DictionaryValue* report_dict; ASSERT_TRUE(value->GetAsDictionary(&report_dict)); std::string report_hostname; @@ -6537,7 +6537,7 @@ TEST_F(URLRequestTestHTTP, ProcessPKPReportOnly) { std::unique_ptr<base::Value> value( base::JSONReader::Read(mock_report_sender.latest_report())); ASSERT_TRUE(value); - ASSERT_TRUE(value->IsType(base::Value::Type::DICTIONARY)); + ASSERT_TRUE(value->is_dict()); base::DictionaryValue* report_dict; ASSERT_TRUE(value->GetAsDictionary(&report_dict)); std::string report_hostname; @@ -7037,12 +7037,17 @@ class TestReportingService : public ReportingService { headers_.push_back({url, header_value}); } - void RemoveBrowsingData( - int data_type_mask, - base::Callback<bool(const GURL&)> origin_filter) override { + void RemoveBrowsingData(int data_type_mask, + const base::RepeatingCallback<bool(const GURL&)>& + origin_filter) override { NOTIMPLEMENTED(); } + bool RequestIsUpload(const URLRequest& request) override { + NOTIMPLEMENTED(); + return true; + } + private: std::vector<Header> headers_; }; @@ -7060,7 +7065,8 @@ std::unique_ptr<test_server::HttpResponse> SendReportToHeader( } // namespace TEST_F(URLRequestTestHTTP, DontProcessReportToHeaderNoService) { - http_test_server()->RegisterRequestHandler(base::Bind(&SendReportToHeader)); + http_test_server()->RegisterRequestHandler( + base::BindRepeating(&SendReportToHeader)); ASSERT_TRUE(http_test_server()->Start()); GURL request_url = http_test_server()->GetURL("/"); @@ -7077,7 +7083,8 @@ TEST_F(URLRequestTestHTTP, DontProcessReportToHeaderNoService) { } TEST_F(URLRequestTestHTTP, DontProcessReportToHeaderHTTP) { - http_test_server()->RegisterRequestHandler(base::Bind(&SendReportToHeader)); + http_test_server()->RegisterRequestHandler( + base::BindRepeating(&SendReportToHeader)); ASSERT_TRUE(http_test_server()->Start()); GURL request_url = http_test_server()->GetURL("/"); @@ -7099,7 +7106,8 @@ TEST_F(URLRequestTestHTTP, DontProcessReportToHeaderHTTP) { TEST_F(URLRequestTestHTTP, ProcessReportToHeaderHTTPS) { EmbeddedTestServer https_test_server(net::EmbeddedTestServer::TYPE_HTTPS); - https_test_server.RegisterRequestHandler(base::Bind(&SendReportToHeader)); + https_test_server.RegisterRequestHandler( + base::BindRepeating(&SendReportToHeader)); ASSERT_TRUE(https_test_server.Start()); GURL request_url = https_test_server.GetURL("/"); @@ -7124,7 +7132,8 @@ TEST_F(URLRequestTestHTTP, ProcessReportToHeaderHTTPS) { TEST_F(URLRequestTestHTTP, DontProcessReportToHeaderInvalidHttps) { EmbeddedTestServer https_test_server(net::EmbeddedTestServer::TYPE_HTTPS); https_test_server.SetSSLConfig(net::EmbeddedTestServer::CERT_MISMATCHED_NAME); - https_test_server.RegisterRequestHandler(base::Bind(&SendReportToHeader)); + https_test_server.RegisterRequestHandler( + base::BindRepeating(&SendReportToHeader)); ASSERT_TRUE(https_test_server.Start()); GURL request_url = https_test_server.GetURL("/"); @@ -7184,6 +7193,11 @@ class TestNetworkErrorLoggingDelegate : public NetworkErrorLoggingDelegate { errors_.push_back(details); } + void RemoveBrowsingData(const base::RepeatingCallback<bool(const GURL&)>& + origin_filter) override { + NOTREACHED(); + } + private: std::vector<Header> headers_; std::vector<ErrorDetails> errors_; @@ -7199,10 +7213,16 @@ std::unique_ptr<test_server::HttpResponse> SendNelHeader( return std::move(http_response); } +std::unique_ptr<test_server::HttpResponse> SendEmptyResponse( + const test_server::HttpRequest& request) { + return base::MakeUnique<test_server::RawHttpResponse>("", ""); +} + } // namespace TEST_F(URLRequestTestHTTP, DontProcessNelHeaderNoDelegate) { - http_test_server()->RegisterRequestHandler(base::Bind(&SendNelHeader)); + http_test_server()->RegisterRequestHandler( + base::BindRepeating(&SendNelHeader)); ASSERT_TRUE(http_test_server()->Start()); GURL request_url = http_test_server()->GetURL("/"); @@ -7219,7 +7239,8 @@ TEST_F(URLRequestTestHTTP, DontProcessNelHeaderNoDelegate) { } TEST_F(URLRequestTestHTTP, DontProcessNelHeaderHttp) { - http_test_server()->RegisterRequestHandler(base::Bind(&SendNelHeader)); + http_test_server()->RegisterRequestHandler( + base::BindRepeating(&SendNelHeader)); ASSERT_TRUE(http_test_server()->Start()); GURL request_url = http_test_server()->GetURL("/"); @@ -7241,7 +7262,7 @@ TEST_F(URLRequestTestHTTP, DontProcessNelHeaderHttp) { TEST_F(URLRequestTestHTTP, ProcessNelHeaderHttps) { EmbeddedTestServer https_test_server(net::EmbeddedTestServer::TYPE_HTTPS); - https_test_server.RegisterRequestHandler(base::Bind(&SendNelHeader)); + https_test_server.RegisterRequestHandler(base::BindRepeating(&SendNelHeader)); ASSERT_TRUE(https_test_server.Start()); GURL request_url = https_test_server.GetURL("/"); @@ -7266,7 +7287,7 @@ TEST_F(URLRequestTestHTTP, ProcessNelHeaderHttps) { TEST_F(URLRequestTestHTTP, DontProcessNelHeaderInvalidHttps) { EmbeddedTestServer https_test_server(net::EmbeddedTestServer::TYPE_HTTPS); https_test_server.SetSSLConfig(net::EmbeddedTestServer::CERT_MISMATCHED_NAME); - https_test_server.RegisterRequestHandler(base::Bind(&SendNelHeader)); + https_test_server.RegisterRequestHandler(base::BindRepeating(&SendNelHeader)); ASSERT_TRUE(https_test_server.Start()); GURL request_url = https_test_server.GetURL("/"); @@ -7335,7 +7356,7 @@ TEST_F(URLRequestTestHTTP, DISABLED_DontForwardErrorToNelHttp) { URLRequestFilter::GetInstance()->ClearHandlers(); } -TEST_F(URLRequestTestHTTP, ForwardErrorToNelHttps) { +TEST_F(URLRequestTestHTTP, ForwardErrorToNelHttps_Mock) { URLRequestFailedJob::AddUrlHandler(); GURL request_url = @@ -7362,6 +7383,34 @@ TEST_F(URLRequestTestHTTP, ForwardErrorToNelHttps) { URLRequestFilter::GetInstance()->ClearHandlers(); } +// Also test with a real server, to exercise interactions with +// URLRequestHttpJob. +TEST_F(URLRequestTestHTTP, ForwardErrorToNelHttps_Real) { + EmbeddedTestServer https_test_server(net::EmbeddedTestServer::TYPE_HTTPS); + https_test_server.RegisterRequestHandler( + base::BindRepeating(&SendEmptyResponse)); + ASSERT_TRUE(https_test_server.Start()); + GURL request_url = https_test_server.GetURL("/"); + + TestNetworkDelegate network_delegate; + TestNetworkErrorLoggingDelegate nel_delegate; + TestURLRequestContext context(true); + context.set_network_delegate(&network_delegate); + context.set_network_error_logging_delegate(&nel_delegate); + context.Init(); + + TestDelegate d; + std::unique_ptr<URLRequest> request(context.CreateRequest( + request_url, DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS)); + request->Start(); + base::RunLoop().Run(); + + ASSERT_EQ(1u, nel_delegate.errors().size()); + EXPECT_EQ(request_url, nel_delegate.errors()[0].uri); + EXPECT_EQ(0, nel_delegate.errors()[0].status_code); + EXPECT_EQ(ERR_EMPTY_RESPONSE, nel_delegate.errors()[0].type); +} + #endif // BUILDFLAG(ENABLE_REPORTING) TEST_F(URLRequestTestHTTP, ContentTypeNormalizationTest) { @@ -10489,9 +10538,8 @@ static CertStatus ExpectedCertStatusForFailedOnlineEVRevocationCheck() { } static bool SystemSupportsOCSP() { -#if defined(OS_ANDROID) || defined(OS_FUCHSIA) +#if defined(OS_ANDROID) // TODO(jnd): http://crbug.com/117478 - EV verification is not yet supported. - // TODO(crbug.com/776575): OCSP tests currently fail on Fuchsia. return false; #else return true; @@ -11189,14 +11237,13 @@ TEST_F(HTTPSAIATest, AIAFetching) { EXPECT_EQ(OK, d.request_status()); EXPECT_EQ(0u, cert_status & CERT_STATUS_ALL_ERRORS); ASSERT_TRUE(r->ssl_info().cert); - EXPECT_EQ(2u, r->ssl_info().cert->GetIntermediateCertificates().size()); + EXPECT_EQ(2u, r->ssl_info().cert->intermediate_buffers().size()); } else { EXPECT_EQ(CERT_STATUS_AUTHORITY_INVALID, cert_status & CERT_STATUS_ALL_ERRORS); } ASSERT_TRUE(r->ssl_info().unverified_cert); - EXPECT_EQ( - 0u, r->ssl_info().unverified_cert->GetIntermediateCertificates().size()); + EXPECT_EQ(0u, r->ssl_info().unverified_cert->intermediate_buffers().size()); } class HTTPSHardFailTest : public HTTPSOCSPTest { @@ -11378,7 +11425,8 @@ TEST_F(HTTPSEVCRLSetTest, FreshCRLSetCovered) { SpawnedTestServer::SSLOptions::CERT_AUTO); ssl_options.ocsp_status = SpawnedTestServer::SSLOptions::OCSP_INVALID_RESPONSE; - ScopedSetCRLSet set_crlset(CRLSet::ForTesting(false, &kOCSPTestCertSPKI, "")); + ScopedSetCRLSet set_crlset( + CRLSet::ForTesting(false, &kOCSPTestCertSPKI, "", "", {})); CertStatus cert_status; DoConnection(ssl_options, &cert_status); @@ -11484,7 +11532,7 @@ TEST_F(HTTPSCRLSetTest, CRLSetRevoked) { ssl_options.ocsp_status = SpawnedTestServer::SSLOptions::OCSP_OK; ssl_options.cert_serial = 10; ScopedSetCRLSet set_crlset( - CRLSet::ForTesting(false, &kOCSPTestCertSPKI, "\x0a")); + CRLSet::ForTesting(false, &kOCSPTestCertSPKI, "\x0a", "", {})); CertStatus cert_status = 0; DoConnection(ssl_options, &cert_status); @@ -11496,6 +11544,55 @@ TEST_F(HTTPSCRLSetTest, CRLSetRevoked) { EXPECT_FALSE( static_cast<bool>(cert_status & CERT_STATUS_REV_CHECKING_ENABLED)); } + +TEST_F(HTTPSCRLSetTest, CRLSetRevokedBySubject) { +#if defined(OS_ANDROID) + LOG(WARNING) << "Skipping test because system doesn't support CRLSets"; + return; +#endif + + SpawnedTestServer::SSLOptions ssl_options( + SpawnedTestServer::SSLOptions::CERT_AUTO); + ssl_options.ocsp_status = SpawnedTestServer::SSLOptions::OCSP_OK; + static const char kCommonName[] = "Test CN"; + ssl_options.cert_common_name = kCommonName; + + { + ScopedSetCRLSet set_crlset( + CRLSet::ForTesting(false, nullptr, "", kCommonName, {})); + + CertStatus cert_status = 0; + DoConnection(ssl_options, &cert_status); + + // If the certificate is recorded as revoked in the CRLSet, that should be + // reflected without online revocation checking. + EXPECT_EQ(CERT_STATUS_REVOKED, cert_status & CERT_STATUS_ALL_ERRORS); + EXPECT_FALSE(cert_status & CERT_STATUS_IS_EV); + EXPECT_FALSE( + static_cast<bool>(cert_status & CERT_STATUS_REV_CHECKING_ENABLED)); + } + + const uint8_t kTestServerSPKISHA256[32] = { + 0xb3, 0x91, 0xac, 0x73, 0x32, 0x54, 0x7f, 0x7b, 0x8a, 0x62, 0x77, + 0x73, 0x1d, 0x45, 0x7b, 0x23, 0x46, 0x69, 0xef, 0x6f, 0x05, 0x3d, + 0x07, 0x22, 0x15, 0x18, 0xd6, 0x10, 0x8b, 0xa1, 0x49, 0x33, + }; + const std::string spki_hash( + reinterpret_cast<const char*>(kTestServerSPKISHA256), + sizeof(kTestServerSPKISHA256)); + + { + ScopedSetCRLSet set_crlset( + CRLSet::ForTesting(false, nullptr, "", kCommonName, {spki_hash})); + + CertStatus cert_status = 0; + DoConnection(ssl_options, &cert_status); + + // When the correct SPKI hash is specified, the connection should succeed + // even though the subject is listed in the CRLSet. + EXPECT_EQ(0u, cert_status & CERT_STATUS_ALL_ERRORS); + } +} #endif // !defined(OS_IOS) #if !BUILDFLAG(DISABLE_FTP_SUPPORT) && !defined(OS_ANDROID) && \ diff --git a/chromium/net/websockets/websocket_basic_handshake_stream.cc b/chromium/net/websockets/websocket_basic_handshake_stream.cc index 66f5ab5f4a7..47113a243e5 100644 --- a/chromium/net/websockets/websocket_basic_handshake_stream.cc +++ b/chromium/net/websockets/websocket_basic_handshake_stream.cc @@ -17,8 +17,8 @@ #include "base/bind.h" #include "base/compiler_specific.h" #include "base/logging.h" +#include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" -#include "base/metrics/sparse_histogram.h" #include "base/stl_util.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_piece.h" @@ -35,6 +35,7 @@ #include "net/http/http_stream_parser.h" #include "net/socket/client_socket_handle.h" #include "net/socket/websocket_transport_client_socket_pool.h" +#include "net/traffic_annotation/network_traffic_annotation.h" #include "net/websockets/websocket_basic_stream.h" #include "net/websockets/websocket_deflate_parameters.h" #include "net/websockets/websocket_deflate_predictor.h" @@ -311,11 +312,12 @@ WebSocketBasicHandshakeStream::~WebSocketBasicHandshakeStream() = default; int WebSocketBasicHandshakeStream::InitializeStream( const HttpRequestInfo* request_info, + bool can_send_early, RequestPriority priority, const NetLogWithSource& net_log, const CompletionCallback& callback) { url_ = request_info->url; - state_.Initialize(request_info, priority, net_log, callback); + state_.Initialize(request_info, can_send_early, priority, net_log, callback); return OK; } @@ -363,8 +365,10 @@ int WebSocketBasicHandshakeStream::SendRequest( request->headers.CopyFrom(enriched_headers); connect_delegate_->OnStartOpeningHandshake(std::move(request)); - return parser()->SendRequest( - state_.GenerateRequestLine(), enriched_headers, response, callback); + // TODO(crbug.com/656607): Add propoer annotation. + return parser()->SendRequest(state_.GenerateRequestLine(), enriched_headers, + NO_TRAFFIC_ANNOTATION_BUG_656607, response, + callback); } int WebSocketBasicHandshakeStream::ReadResponseHeaders( @@ -527,7 +531,7 @@ int WebSocketBasicHandshakeStream::ValidateResponse(int rv) { if (rv >= 0) { const HttpResponseHeaders* headers = http_response_info_->headers.get(); const int response_code = headers->response_code(); - UMA_HISTOGRAM_SPARSE_SLOWLY("Net.WebSocket.ResponseCode", response_code); + base::UmaHistogramSparse("Net.WebSocket.ResponseCode", response_code); switch (response_code) { case HTTP_SWITCHING_PROTOCOLS: OnFinishOpeningHandshake(); diff --git a/chromium/net/websockets/websocket_basic_handshake_stream.h b/chromium/net/websockets/websocket_basic_handshake_stream.h index 06bc3338090..10be3500776 100644 --- a/chromium/net/websockets/websocket_basic_handshake_stream.h +++ b/chromium/net/websockets/websocket_basic_handshake_stream.h @@ -44,6 +44,7 @@ class NET_EXPORT_PRIVATE WebSocketBasicHandshakeStream // HttpStreamBase methods int InitializeStream(const HttpRequestInfo* request_info, + bool can_send_early, RequestPriority priority, const NetLogWithSource& net_log, const CompletionCallback& callback) override; diff --git a/chromium/net/websockets/websocket_basic_stream_test.cc b/chromium/net/websockets/websocket_basic_stream_test.cc index 7061e4b581d..da8d228d513 100644 --- a/chromium/net/websockets/websocket_basic_stream_test.cc +++ b/chromium/net/websockets/websocket_basic_stream_test.cc @@ -19,6 +19,7 @@ #include "base/macros.h" #include "net/base/test_completion_callback.h" #include "net/log/test_net_log.h" +#include "net/socket/socket_tag.h" #include "net/socket/socket_test_util.h" #include "net/test/gtest_util.h" #include "testing/gmock/include/gmock/gmock.h" @@ -134,7 +135,7 @@ class WebSocketBasicStreamSocketTest : public WebSocketBasicStreamTest { std::unique_ptr<ClientSocketHandle> transport_socket( new ClientSocketHandle); scoped_refptr<MockTransportSocketParams> params; - transport_socket->Init("a", params, MEDIUM, + transport_socket->Init("a", params, MEDIUM, SocketTag(), ClientSocketPool::RespectLimits::ENABLED, CompletionCallback(), &pool_, net_log_.bound()); return transport_socket; diff --git a/chromium/net/websockets/websocket_end_to_end_test.cc b/chromium/net/websockets/websocket_end_to_end_test.cc index 40909d22cfe..d869f837c68 100644 --- a/chromium/net/websockets/websocket_end_to_end_test.cc +++ b/chromium/net/websockets/websocket_end_to_end_test.cc @@ -227,23 +227,10 @@ class TestProxyDelegateWithProxyInfo : public ProxyDelegate { resolved_proxy_info_.proxy_info = *result; } - void OnTunnelConnectCompleted(const HostPortPair& endpoint, - const HostPortPair& proxy_server, - int net_error) override {} void OnFallback(const ProxyServer& bad_proxy, int net_error) override {} - void OnBeforeTunnelRequest(const HostPortPair& proxy_server, - HttpRequestHeaders* extra_headers) override {} - void OnTunnelHeadersReceived( - const HostPortPair& origin, - const HostPortPair& proxy_server, - const HttpResponseHeaders& response_headers) override {} bool IsTrustedSpdyProxy(const net::ProxyServer& proxy_server) override { return true; } - void GetAlternativeProxy( - const GURL& url, - const ProxyServer& resolved_proxy_server, - ProxyServer* alternative_proxy_server) const override {} void OnAlternativeProxyBroken( const ProxyServer& alternative_proxy_server) override {} diff --git a/chromium/net/websockets/websocket_handshake_stream_create_helper_test.cc b/chromium/net/websockets/websocket_handshake_stream_create_helper_test.cc index 515d48ca1f1..17e2d2625ac 100644 --- a/chromium/net/websockets/websocket_handshake_stream_create_helper_test.cc +++ b/chromium/net/websockets/websocket_handshake_stream_create_helper_test.cc @@ -17,6 +17,7 @@ #include "net/http/http_response_info.h" #include "net/log/net_log_with_source.h" #include "net/socket/client_socket_handle.h" +#include "net/socket/socket_tag.h" #include "net/socket/socket_test_util.h" #include "net/test/gtest_util.h" #include "net/websockets/websocket_basic_handshake_stream.h" @@ -49,7 +50,7 @@ class MockClientSocketHandleFactory { socket_factory_maker_.SetExpectations(expect_written, return_to_read); std::unique_ptr<ClientSocketHandle> socket_handle(new ClientSocketHandle); socket_handle->Init("a", scoped_refptr<MockTransportSocketParams>(), MEDIUM, - ClientSocketPool::RespectLimits::ENABLED, + SocketTag(), ClientSocketPool::RespectLimits::ENABLED, CompletionCallback(), &pool_, NetLogWithSource()); return socket_handle; } @@ -122,7 +123,7 @@ class WebSocketHandshakeStreamCreateHelperTest : public ::testing::Test { request_info.method = "GET"; request_info.load_flags = LOAD_DISABLE_CACHE; int rv = - handshake->InitializeStream(&request_info, DEFAULT_PRIORITY, + handshake->InitializeStream(&request_info, true, DEFAULT_PRIORITY, NetLogWithSource(), CompletionCallback()); EXPECT_THAT(rv, IsOk()); diff --git a/chromium/net/websockets/websocket_stream.cc b/chromium/net/websockets/websocket_stream.cc index bfc155c741b..e88a65a173e 100644 --- a/chromium/net/websockets/websocket_stream.cc +++ b/chromium/net/websockets/websocket_stream.cc @@ -7,8 +7,8 @@ #include <utility> #include "base/logging.h" +#include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" -#include "base/metrics/sparse_histogram.h" #include "base/time/time.h" #include "base/timer/timer.h" #include "net/base/load_flags.h" @@ -313,13 +313,12 @@ void Delegate::OnResponseStarted(URLRequest* request, int net_error) { DCHECK_NE(ERR_IO_PENDING, net_error); // All error codes, including OK and ABORTED, as with // Net.ErrorCodesForMainFrame3 - UMA_HISTOGRAM_SPARSE_SLOWLY("Net.WebSocket.ErrorCodes", -net_error); - if (net::IsLocalhost(request->url().HostNoBrackets())) { - UMA_HISTOGRAM_SPARSE_SLOWLY("Net.WebSocket.ErrorCodes_Localhost", - -net_error); + base::UmaHistogramSparse("Net.WebSocket.ErrorCodes", -net_error); + if (net::IsLocalhost(request->url())) { + base::UmaHistogramSparse("Net.WebSocket.ErrorCodes_Localhost", -net_error); } else { - UMA_HISTOGRAM_SPARSE_SLOWLY("Net.WebSocket.ErrorCodes_NotLocalhost", - -net_error); + base::UmaHistogramSparse("Net.WebSocket.ErrorCodes_NotLocalhost", + -net_error); } if (net_error != OK) { |